<commit_before>void AnalysisTrainFromStandardToMuonAODLocal(char* filein= "AliAODs.root",
                                             char* fileout= "AliMuonAOD.root",
				             char* dirChain= ".",
				             char* dirData= "."){

// Macro to produce a MUON-AOD, i.e. a replica of the standard AOD, containing only events
// where at least one muon is present
//
// - The input files are the ESD (used only for tag creation) and the standard AOD.
//   Tags files are created from all the ESD/AOD files placed in the directory dirData
//   and in its subdirectories.
// - The selection of the muon events is based on the AOD tags.
// - The content of the MUON-AOD can be defined by the user with some settings as
//   SetNeedsTracksBranchReplication(), SetNeedsVerticesBranchReplication()
//   (defined in STEER/AliAODHandler.h)...

    gSystem->Load("libTree.so");
    gSystem->Load("libGeom.so");
    gSystem->Load("libVMC.so");
    gSystem->Load("libPhysics.so");

    // Load par files
    SetupPar("STEERBase");
    SetupPar("ESD");
    SetupPar("AOD");
    SetupPar("ANALYSIS");
    SetupPar("ANALYSISalice");
    SetupPar("PWG3base");
    SetupPar("PWG3muon");

    // Create ESD tag files
    printf("Creating ESD Tags\n");
    AliESDTagCreator *tesd = new AliESDTagCreator();
    tesd->SetStorage(0);
    tesd->ReadLocalCollection(dirData);

    // Create AOD tag files
    printf("Creating AOD Tags\n");
    AliAODTagCreator *t = new AliAODTagCreator();
    t->SetStorage(0);
    t->ReadLocalCollection(dirData);

    AliTagAnalysis *TagAna = new AliTagAnalysis("AOD");

    // Define tag cuts to select only events with muons
    printf("Defining Tags cuts to select events containing at least one muon\n");
    AliRunTagCuts *runCuts = new AliRunTagCuts();
    AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();
    AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();
    AliEventTagCuts *evCuts = new AliEventTagCuts();
    evCuts->SetNMuonRange(1,10);

    // Create the chain of interesting events
    TChain* chain = 0x0;
    TagAna->ChainLocalTags(dirChain);
    chain = TagAna->QueryTags(runCuts,lhcCuts,detCuts,evCuts);

    // Define aod input handler
    AliAODInputHandler* aodInputHandler = new AliAODInputHandler();

    // Define aod output handler
    AliAODHandler* aodOutputHandler = new AliAODHandler();

    // Create non standard AOD
    aodOutputHandler->SetCreateNonStandardAOD();

    // Select the branches to be written in the MUON-AOD
    aodOutputHandler->SetNeedsHeaderReplication();
    aodOutputHandler->SetNeedsTracksBranchReplication();
    aodOutputHandler->SetNeedsVerticesBranchReplication();
    //aodOutputHandler->SetNeedsV0sBranchReplication();
    //aodOutputHandler->SetNeedsTrackletsBranchReplication();
    //aodOutputHandler->SetNeedsPMDClustersBranchReplication();
    //aodOutputHandler->SetNeedsJetsBranchReplication();
    //aodOutputHandler->SetNeedsFMDClustersBranchReplication();
    //aodOutputHandler->SetNeedsCaloClustersBranchReplication();

    aodOutputHandler->SetOutputFileName(fileout);

     // Define the analysis manager
    AliAnalysisManager *mgr  = new AliAnalysisManager("AOD Manager", "AOD Manager");
    mgr->SetInputEventHandler(aodInputHandler);
    mgr->SetOutputEventHandler(aodOutputHandler);
    //mgr->SetDebugLevel(10);

    AliAnalysisTaskFromStandardToMuonAOD *aodfilter = new AliAnalysisTaskFromStandardToMuonAOD("AOD Filter");
    mgr->AddTask(aodfilter);

    // Create containers for input/output
    AliAnalysisDataContainer *cinput1 = mgr->CreateContainer("cchain",TChain::Class(),
							     AliAnalysisManager::kInputContainer);
    AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("tree", TTree::Class(),
							      AliAnalysisManager::kOutputContainer, "default");

    mgr->ConnectInput(aodfilter,0,cinput1);
    mgr->ConnectOutput(aodfilter,0,coutput1);

    // Run the analysis
    printf("CHAIN HAS %d ENTRIES\n",(Int_t)chain->GetEntries());
    mgr->InitAnalysis();
    mgr->PrintStatus();
    mgr->StartAnalysis("local",chain);
}

Int_t setupPar(const char* pararchivename) {
  ///////////////////
  // Setup PAR File//
  ///////////////////
  if (pararchivename) {
    char processline[1024];
    sprintf(processline,".! tar xvzf %s.par",pararchivename);
    gROOT->ProcessLine(processline);
    const char* ocwd = gSystem->WorkingDirectory();
    gSystem->ChangeDirectory(pararchivename);

    // check for BUILD.sh and execute
    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
      printf("*******************************\n");
      printf("*** Building PAR archive    ***\n");
      printf("*******************************\n");

      if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
        Error("runAnalysis","Cannot Build the PAR Archive! - Abort!");
        return -1;
      }
    }
    // check for SETUP.C and execute
    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
      printf("*******************************\n");
      printf("*** Setup PAR archive       ***\n");
      printf("*******************************\n");
      gROOT->Macro("PROOF-INF/SETUP.C");
    }

    gSystem->ChangeDirectory("../");
  }

  return 1;
}

//______________________________________________________________________________
void SetupPar(char* pararchivename)
{
    if (pararchivename) {
	char processline[1024];
	sprintf(processline,".! tar xvzf %s.par",pararchivename);
	gROOT->ProcessLine(processline);
	TString ocwd = gSystem->WorkingDirectory();
	gSystem->ChangeDirectory(pararchivename);

	// check for BUILD.sh and execute
	if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
	    printf("*******************************\n");
	    printf("*** Building PAR archive    ***\n");
	    printf("*******************************\n");

	    if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
		Error("runProcess","Cannot Build the PAR Archive! - Abort!");
		return -1;
	    }
	}
	// check for SETUP.C and execute
	if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
	    printf("*******************************\n");
	    printf("*** Setup PAR archive       ***\n");
	    printf("*******************************\n");
	    gROOT->Macro("PROOF-INF/SETUP.C");
	}

	gSystem->ChangeDirectory(ocwd.Data());
   printf("Current dir: %s\n", ocwd.Data());
    }
}
<commit_msg>Removing dependence on ESD files and new possibility for selecting muon multiplicity in the forward region (Enrico, Roberta)<commit_after>void AnalysisTrainFromStandardToMuonAODLocal(char* filein= "AliAODs.root",
                                             char* fileout= "AliMuonAOD.root",
				             char* dirChain= ".",
				             char* dirData= ".",
					     Int_t nev=123456789){

// Macro to produce a MUON-AOD, i.e. a replica of the standard AOD, containing only events
// where at least one muon is present
//
// - The input files are the standard AOD and the AOD.tag.root files
// - The AOD.tag file can be:
//      1) the one previously created together with the AOD file (i.e. from
//         AnalysisTrainMuonLocal.C)
//      2) created on the fly with this macro
// - The selection of the muon events is based on the AOD tags
// - The content of the MUON-AOD can be defined by the user with some settings as
//   SetNeedsTracksBranchReplication(), SetNeedsVerticesBranchReplication()
//   (defined in STEER/AliAODHandler.h)...

    gSystem->Load("libTree.so");
    gSystem->Load("libGeom.so");
    gSystem->Load("libVMC.so");
    gSystem->Load("libPhysics.so");
    gSystem->Load("libSTEER.so");              // for aliroot based analysis
    gSystem->Load("libPWG3muon.so");  // for aliroot based analysis

    // Load par files, if the analysis is par based
    // SetupPar("STEERBase");
    // SetupPar("ESD");
    // SetupPar("AOD");
    // SetupPar("ANALYSIS");
    // SetupPar("ANALYSISalice");
    // SetupPar("PWG3muon");

    // Uncomment the following lines if the AOD tag file has to be created on the fly
    // printf("Creating AOD Tags on the fly\n");
    // AliAODTagCreator *t = new AliAODTagCreator();
    // t->SetStorage(0);
    // t->ReadLocalCollection(dirData);

    AliTagAnalysis *TagAna = new AliTagAnalysis("AOD");

    // Define tag cuts to select events containing at least one muon in the dimuon spectrometer
    printf("Defining Tags cuts to select events containing at least one muon in the dimuon spectrometer\n");
    AliRunTagCuts *runCuts = new AliRunTagCuts();
    AliLHCTagCuts *lhcCuts = new AliLHCTagCuts();
    AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();
    AliEventTagCuts *evCuts = new AliEventTagCuts();
    evCuts->SetNFWMuonRange(1,10);

    // Create the chain of interesting events
    TChain* chain = 0x0;
    TagAna->ChainLocalTags(dirChain);
    TagAna->SetType("AOD");
    chain = TagAna->QueryTags(runCuts,lhcCuts,detCuts,evCuts);
    Info("AnalysisTrainFromStandardToMuonAOD",Form("CHAIN HAS %d ENTRIES",(Int_t)chain->GetEntries()));

    // Define aod input handler
    AliAODInputHandler* aodInputHandler = new AliAODInputHandler();

    // Define aod output handler
    AliAODHandler* aodOutputHandler = new AliAODHandler();

    // Create non standard AOD
    aodOutputHandler->SetCreateNonStandardAOD();

    // Select the branches to be replicated in the MUON-AOD
    aodOutputHandler->SetNeedsHeaderReplication();
    aodOutputHandler->SetNeedsTracksBranchReplication();
    aodOutputHandler->SetNeedsVerticesBranchReplication();
    aodOutputHandler->SetNeedsV0sBranchReplication();
    aodOutputHandler->SetNeedsTrackletsBranchReplication();
    aodOutputHandler->SetNeedsPMDClustersBranchReplication();
    aodOutputHandler->SetNeedsJetsBranchReplication();
    aodOutputHandler->SetNeedsFMDClustersBranchReplication();
    aodOutputHandler->SetNeedsCaloClustersBranchReplication();

    aodOutputHandler->SetOutputFileName(fileout);

     // Define the analysis manager
    AliAnalysisManager *mgr  = new AliAnalysisManager("AOD Manager", "AOD Manager");
    mgr->SetInputEventHandler(aodInputHandler);
    mgr->SetOutputEventHandler(aodOutputHandler);
    //mgr->SetDebugLevel(10);

    AliAnalysisTaskFromStandardToMuonAOD *aodfilter = new AliAnalysisTaskFromStandardToMuonAOD("AOD Filter");
    mgr->AddTask(aodfilter);

    // Create containers for input/output
    AliAnalysisDataContainer *cinput1 = mgr->CreateContainer("cchain",TChain::Class(),
							     AliAnalysisManager::kInputContainer);
    AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("tree", TTree::Class(),
							      AliAnalysisManager::kOutputContainer, "default");

    mgr->ConnectInput(aodfilter,0,cinput1);
    mgr->ConnectOutput(aodfilter,0,coutput1);

    // Run the analysis
    printf("CHAIN HAS %d ENTRIES\n",(Int_t)chain->GetEntries());
    mgr->InitAnalysis();
    mgr->PrintStatus();
    mgr->StartAnalysis("local",chain,nev);
}

Int_t setupPar(const char* pararchivename) {
  ///////////////////
  // Setup PAR File//
  ///////////////////
  if (pararchivename) {
    char processline[1024];
    sprintf(processline,".! tar xvzf %s.par",pararchivename);
    gROOT->ProcessLine(processline);
    const char* ocwd = gSystem->WorkingDirectory();
    gSystem->ChangeDirectory(pararchivename);

    // check for BUILD.sh and execute
    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
      printf("*******************************\n");
      printf("*** Building PAR archive    ***\n");
      printf("*******************************\n");

      if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
        Error("runAnalysis","Cannot Build the PAR Archive! - Abort!");
        return -1;
      }
    }
    // check for SETUP.C and execute
    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
      printf("*******************************\n");
      printf("*** Setup PAR archive       ***\n");
      printf("*******************************\n");
      gROOT->Macro("PROOF-INF/SETUP.C");
    }

    gSystem->ChangeDirectory("../");
  }

  return 1;
}

//______________________________________________________________________________
void SetupPar(char* pararchivename)
{
    if (pararchivename) {
	char processline[1024];
	sprintf(processline,".! tar xvzf %s.par",pararchivename);
	gROOT->ProcessLine(processline);
	TString ocwd = gSystem->WorkingDirectory();
	gSystem->ChangeDirectory(pararchivename);

	// check for BUILD.sh and execute
	if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
	    printf("*******************************\n");
	    printf("*** Building PAR archive    ***\n");
	    printf("*******************************\n");

	    if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
		Error("runProcess","Cannot Build the PAR Archive! - Abort!");
		return -1;
	    }
	}
	// check for SETUP.C and execute
	if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
	    printf("*******************************\n");
	    printf("*** Setup PAR archive       ***\n");
	    printf("*******************************\n");
	    gROOT->Macro("PROOF-INF/SETUP.C");
	}

	gSystem->ChangeDirectory(ocwd.Data());
   printf("Current dir: %s\n", ocwd.Data());
    }
}
<|endoftext|>


<commit_before>//===--------------------------------------------------------------------------------*- C++ -*-===//
//                          _
//                         | |
//                       __| | __ ___      ___ ___
//                      / _` |/ _` \ \ /\ / / '_  |
//                     | (_| | (_| |\ V  V /| | | |
//                      \__,_|\__,_| \_/\_/ |_| |_| - Compiler Toolchain
//
//
//  This file is distributed under the MIT License (MIT).
//  See LICENSE.txt for details.
//
//===------------------------------------------------------------------------------------------===//

#include "IcoChainSizes.h"

#include "dawn/AST/LocationType.h"
#include "dawn/Support/HashCombine.h"

#include <assert.h>
#include <unordered_set>

namespace dawn {

using connection_t = std::tuple<ast::LocationType, ast::LocationType>;

using grid_location_t = std::tuple<int, int, int>;

/******************************************************************************
 *  We encode the grid as follows:
 *
 * \|{-1, 1}                 \|{0, 1}                  \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, 1, 0}         |\     {0, 1, 0}          |\
 *  | \                       | \                       |
 *  |  \                      |  \                      |
 *  |   \       {-1, 0, 1}    |   \       {0, 0, 1}     |
 *  |    \                    |    \                    |
 *  |     \                   |     \                   |
 *  |      \                  |      \                  |
 *  |       \                 |       \                 |
 *  |        \                |        \                |
 *  |         \               |         \               |
 *  |          \{-1, 0, 1}    |          \{0, 0, 1}     |
 *  |           \             |           \             |
 *  |            \            |            \            |
 *  |             \           |             \           |
 *  |{-1, 0, 2}    \          |{0, 0, 2}     \          |
 *  |               \         |               \         |
 *  |                \        |                \        |
 *  |                 \       |                 \       |
 *  |                  \      |                  \      |
 *  |                   \     |                   \     |
 *  |                    \    |                    \    |
 *  |   {-1, 0, 0}        \   |   {0, 0, 0}         \   |
 *  |                      \  |                      \  |
 *  |                       \ |                       \ |
 * \|{-1, 0}                 \|{0, 0}                  \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, 0, 0}         |\     {0, 0, 0}          |\
 *  | \                       | \                       |
 *  |  \                      |  \                      |
 *  |   \       {-1, -1, 1}   |   \       {0, -1, 1}    |
 *  |    \                    |    \                    |
 *  |     \                   |     \                   |
 *  |      \                  |      \                  |
 *  |       \                 |       \                 |
 *  |        \                |        \                |
 *  |         \               |         \               |
 *  |          \{-1, -1, 1}   |          \{0, -1, 1}    |
 *  |           \             |           \             |
 *  |            \            |            \            |
 *  |             \           |             \           |
 *  |{-1, -1, 2}   \          |{0, -1, 2}    \          |
 *  |               \         |               \         |
 *  |                \        |                \        |
 *  |                 \       |                 \       |
 *  |                  \      |                  \      |
 *  |                   \     |                   \     |
 *  |                    \    |                    \    |
 *  |   {-1, -1, 0}       \   |   {0, -1, 0}        \   |
 *  |                      \  |                      \  |
 *  |                       \ |                       \ |
 * \|{-1, -1}                \|{0, -1}                 \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, -1, 0}        |\     {0, -1, 0}         |\
 *
 *
 * Which is described by this general pattern:
 *
 *  |\
 *  | \
 *  |  \
 *  |   \       {x, y, 1}
 *  |    \
 *  |     \
 *  |      \
 *  |       \
 *  |        \
 *  |         \
 *  |          \{x, y, 1}
 *  |           \
 *  |            \
 *  |             \
 *  |{x, y, 2}     \
 *  |               \
 *  |                \
 *  |                 \
 *  |                  \
 *  |                   \
 *  |                    \
 *  |   {x, y, 0}         \
 *  |                      \
 *  |                       \
 *  |{x, y}                  \
 *  *-------------------------
 *         {x, y, 0}
 *
 * Note: Each location type uses a separate _id-space_.
 * {x, y, 0} can both mean an edge or cell. It's up to the user to ensure
 * they know what location type is meant.
 * To make the implementation easier, vertices are encoded also
 * as `std::tuple<int, int, int>` ({x, y, 0}).
 */

static std::array<grid_location_t, 6> get_vertex_to_edge(const grid_location_t& vertex) {
  const auto [x, y, _] = vertex;
  return {{
      {x, y, 0},
      {x, y, 2},
      {x - 1, y, 0},
      {x - 1, y, 1},
      {x, y - 1, 1},
      {x, y - 1, 2},
  }};
}

static std::array<grid_location_t, 6> get_vertex_to_cell(const grid_location_t& vertex) {
  const auto [x, y, _] = vertex;
  return {{
      {x, y, 0},
      {x - 1, y, 0},
      {x - 1, y, 1},
      {x, y - 1, 0},
      {x, y - 1, 1},
      {x - 1, y - 1, 1},
  }};
}

static std::array<grid_location_t, 2> get_edge_to_vertex(const grid_location_t& edge) {
  const auto [x, y, e] = edge;
  if(e == 0) {
    return {{{x, y, 0}, {x + 1, y, 0}}};
  } else if(e == 1) {
    return {{{x + 1, y, 0}, {x, y + 1, 0}}};
  } else if(e == 2) {
    return {{{x, y, 0}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid edge type");
  }
}

static std::array<grid_location_t, 2> get_edge_to_cell(const grid_location_t& edge) {
  const auto [x, y, e] = edge;
  if(e == 0) {
    return {{{x, y, 0}, {x, y - 1, 1}}};
  } else if(e == 1) {
    return {{{x, y, 0}, {x, y, 1}}};
  } else if(e == 2) {
    return {{{x, y, 0}, {x - 1, y, 1}}};
  } else {
    throw std::runtime_error("Invalid edge type");
  }
}

static std::array<grid_location_t, 3> get_cell_to_vertex(const grid_location_t& cell) {
  const auto [x, y, c] = cell;
  if(c == 0) {
    return {{{x, y, 0}, {x + 1, y, 0}, {x, y + 1, 0}}};
  } else if(c == 1) {
    return {{{x + 1, y + 1, 0}, {x + 1, y, 0}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid cell type");
  }
}

static std::array<grid_location_t, 3> get_cell_to_edge(const grid_location_t& cell) {
  const auto [x, y, c] = cell;
  if(c == 0) {
    return {{{x, y, 0}, {x, y, 1}, {x, y, 2}}};
  } else if(c == 1) {
    return {{{x, y, 1}, {x + 1, y, 2}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid cell type");
  }
}

int ICOChainSize(const ast::NeighborChain& chain) {

  assert(1 < chain.size());

  auto previous_location_type = chain[0];
  std::unordered_set<grid_location_t> previous_locations{{0, 0, 0}};

  for(ast::NeighborChain::size_type i = 1; i < chain.size(); ++i) {

    const auto current_location_type = chain[i];
    std::unordered_set<grid_location_t> current_locations;

    assert(previous_location_type != current_location_type);
    const connection_t connection{previous_location_type, current_location_type};

    // Vertices -> Edges
    if(connection == connection_t{ast::LocationType::Vertices, ast::LocationType::Edges}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_vertex_to_edge(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Vertices -> Cells
    } else if(connection == connection_t{ast::LocationType::Vertices, ast::LocationType::Cells}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_vertex_to_cell(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Edges -> Vertices
    } else if(connection == connection_t{ast::LocationType::Edges, ast::LocationType::Vertices}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_edge_to_vertex(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Edges -> Cells
    } else if(connection == connection_t{ast::LocationType::Edges, ast::LocationType::Cells}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_edge_to_cell(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Cells -> Vertices
    } else if(connection == connection_t{ast::LocationType::Cells, ast::LocationType::Vertices}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_cell_to_vertex(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Cells -> Edges
    } else if(connection == connection_t{ast::LocationType::Cells, ast::LocationType::Edges}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_cell_to_edge(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
    } else {
      assert(false);
    }

    previous_locations = std::move(current_locations);
    previous_location_type = current_location_type;
  }

  if(chain.front() == chain.back()) {
    // we don't include the starting location
    return previous_locations.size() - 1;
  } else {
    return previous_locations.size();
  }
}
} // namespace dawn<commit_msg>Fix include in IcoChainSizes.cpp (#1060)<commit_after>//===--------------------------------------------------------------------------------*- C++ -*-===//
//                          _
//                         | |
//                       __| | __ ___      ___ ___
//                      / _` |/ _` \ \ /\ / / '_  |
//                     | (_| | (_| |\ V  V /| | | |
//                      \__,_|\__,_| \_/\_/ |_| |_| - Compiler Toolchain
//
//
//  This file is distributed under the MIT License (MIT).
//  See LICENSE.txt for details.
//
//===------------------------------------------------------------------------------------------===//

#include "IcoChainSizes.h"

#include "dawn/AST/LocationType.h"
#include "dawn/Support/HashCombine.h"

#include <stdexcept>
#include <assert.h>
#include <unordered_set>

namespace dawn {

using connection_t = std::tuple<ast::LocationType, ast::LocationType>;

using grid_location_t = std::tuple<int, int, int>;

/******************************************************************************
 *  We encode the grid as follows:
 *
 * \|{-1, 1}                 \|{0, 1}                  \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, 1, 0}         |\     {0, 1, 0}          |\
 *  | \                       | \                       |
 *  |  \                      |  \                      |
 *  |   \       {-1, 0, 1}    |   \       {0, 0, 1}     |
 *  |    \                    |    \                    |
 *  |     \                   |     \                   |
 *  |      \                  |      \                  |
 *  |       \                 |       \                 |
 *  |        \                |        \                |
 *  |         \               |         \               |
 *  |          \{-1, 0, 1}    |          \{0, 0, 1}     |
 *  |           \             |           \             |
 *  |            \            |            \            |
 *  |             \           |             \           |
 *  |{-1, 0, 2}    \          |{0, 0, 2}     \          |
 *  |               \         |               \         |
 *  |                \        |                \        |
 *  |                 \       |                 \       |
 *  |                  \      |                  \      |
 *  |                   \     |                   \     |
 *  |                    \    |                    \    |
 *  |   {-1, 0, 0}        \   |   {0, 0, 0}         \   |
 *  |                      \  |                      \  |
 *  |                       \ |                       \ |
 * \|{-1, 0}                 \|{0, 0}                  \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, 0, 0}         |\     {0, 0, 0}          |\
 *  | \                       | \                       |
 *  |  \                      |  \                      |
 *  |   \       {-1, -1, 1}   |   \       {0, -1, 1}    |
 *  |    \                    |    \                    |
 *  |     \                   |     \                   |
 *  |      \                  |      \                  |
 *  |       \                 |       \                 |
 *  |        \                |        \                |
 *  |         \               |         \               |
 *  |          \{-1, -1, 1}   |          \{0, -1, 1}    |
 *  |           \             |           \             |
 *  |            \            |            \            |
 *  |             \           |             \           |
 *  |{-1, -1, 2}   \          |{0, -1, 2}    \          |
 *  |               \         |               \         |
 *  |                \        |                \        |
 *  |                 \       |                 \       |
 *  |                  \      |                  \      |
 *  |                   \     |                   \     |
 *  |                    \    |                    \    |
 *  |   {-1, -1, 0}       \   |   {0, -1, 0}        \   |
 *  |                      \  |                      \  |
 *  |                       \ |                       \ |
 * \|{-1, -1}                \|{0, -1}                 \|
 * -*-------------------------*-------------------------*-
 *  |\     {-1, -1, 0}        |\     {0, -1, 0}         |\
 *
 *
 * Which is described by this general pattern:
 *
 *  |\
 *  | \
 *  |  \
 *  |   \       {x, y, 1}
 *  |    \
 *  |     \
 *  |      \
 *  |       \
 *  |        \
 *  |         \
 *  |          \{x, y, 1}
 *  |           \
 *  |            \
 *  |             \
 *  |{x, y, 2}     \
 *  |               \
 *  |                \
 *  |                 \
 *  |                  \
 *  |                   \
 *  |                    \
 *  |   {x, y, 0}         \
 *  |                      \
 *  |                       \
 *  |{x, y}                  \
 *  *-------------------------
 *         {x, y, 0}
 *
 * Note: Each location type uses a separate _id-space_.
 * {x, y, 0} can both mean an edge or cell. It's up to the user to ensure
 * they know what location type is meant.
 * To make the implementation easier, vertices are encoded also
 * as `std::tuple<int, int, int>` ({x, y, 0}).
 */

static std::array<grid_location_t, 6> get_vertex_to_edge(const grid_location_t& vertex) {
  const auto [x, y, _] = vertex;
  return {{
      {x, y, 0},
      {x, y, 2},
      {x - 1, y, 0},
      {x - 1, y, 1},
      {x, y - 1, 1},
      {x, y - 1, 2},
  }};
}

static std::array<grid_location_t, 6> get_vertex_to_cell(const grid_location_t& vertex) {
  const auto [x, y, _] = vertex;
  return {{
      {x, y, 0},
      {x - 1, y, 0},
      {x - 1, y, 1},
      {x, y - 1, 0},
      {x, y - 1, 1},
      {x - 1, y - 1, 1},
  }};
}

static std::array<grid_location_t, 2> get_edge_to_vertex(const grid_location_t& edge) {
  const auto [x, y, e] = edge;
  if(e == 0) {
    return {{{x, y, 0}, {x + 1, y, 0}}};
  } else if(e == 1) {
    return {{{x + 1, y, 0}, {x, y + 1, 0}}};
  } else if(e == 2) {
    return {{{x, y, 0}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid edge type");
  }
}

static std::array<grid_location_t, 2> get_edge_to_cell(const grid_location_t& edge) {
  const auto [x, y, e] = edge;
  if(e == 0) {
    return {{{x, y, 0}, {x, y - 1, 1}}};
  } else if(e == 1) {
    return {{{x, y, 0}, {x, y, 1}}};
  } else if(e == 2) {
    return {{{x, y, 0}, {x - 1, y, 1}}};
  } else {
    throw std::runtime_error("Invalid edge type");
  }
}

static std::array<grid_location_t, 3> get_cell_to_vertex(const grid_location_t& cell) {
  const auto [x, y, c] = cell;
  if(c == 0) {
    return {{{x, y, 0}, {x + 1, y, 0}, {x, y + 1, 0}}};
  } else if(c == 1) {
    return {{{x + 1, y + 1, 0}, {x + 1, y, 0}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid cell type");
  }
}

static std::array<grid_location_t, 3> get_cell_to_edge(const grid_location_t& cell) {
  const auto [x, y, c] = cell;
  if(c == 0) {
    return {{{x, y, 0}, {x, y, 1}, {x, y, 2}}};
  } else if(c == 1) {
    return {{{x, y, 1}, {x + 1, y, 2}, {x, y + 1, 0}}};
  } else {
    throw std::runtime_error("Invalid cell type");
  }
}

int ICOChainSize(const ast::NeighborChain& chain) {

  assert(1 < chain.size());

  auto previous_location_type = chain[0];
  std::unordered_set<grid_location_t> previous_locations{{0, 0, 0}};

  for(ast::NeighborChain::size_type i = 1; i < chain.size(); ++i) {

    const auto current_location_type = chain[i];
    std::unordered_set<grid_location_t> current_locations;

    assert(previous_location_type != current_location_type);
    const connection_t connection{previous_location_type, current_location_type};

    // Vertices -> Edges
    if(connection == connection_t{ast::LocationType::Vertices, ast::LocationType::Edges}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_vertex_to_edge(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Vertices -> Cells
    } else if(connection == connection_t{ast::LocationType::Vertices, ast::LocationType::Cells}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_vertex_to_cell(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Edges -> Vertices
    } else if(connection == connection_t{ast::LocationType::Edges, ast::LocationType::Vertices}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_edge_to_vertex(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Edges -> Cells
    } else if(connection == connection_t{ast::LocationType::Edges, ast::LocationType::Cells}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_edge_to_cell(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Cells -> Vertices
    } else if(connection == connection_t{ast::LocationType::Cells, ast::LocationType::Vertices}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_cell_to_vertex(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
      // Cells -> Edges
    } else if(connection == connection_t{ast::LocationType::Cells, ast::LocationType::Edges}) {
      for(const auto& previous_location : previous_locations) {
        const auto neighbors = get_cell_to_edge(previous_location);
        current_locations.insert(neighbors.cbegin(), neighbors.cend());
      }
    } else {
      assert(false);
    }

    previous_locations = std::move(current_locations);
    previous_location_type = current_location_type;
  }

  if(chain.front() == chain.back()) {
    // we don't include the starting location
    return previous_locations.size() - 1;
  } else {
    return previous_locations.size();
  }
}
} // namespace dawn
<|endoftext|>


<commit_before>#include "ui_root.h"
#include "ui_widget.h"
#include "halley/core/api/audio_api.h"
#include "ui_painter.h"
#include "halley/audio/audio_position.h"
#include "halley/audio/audio_clip.h"
#include "halley/maths/random.h"

using namespace Halley;

UIRoot* UIRoot::getRoot()
{
	return this;
}

const UIRoot* UIRoot::getRoot() const
{
	return this;
}

const String& UIRoot::getId() const
{
	return id;
}

UIRoot::UIRoot(AudioAPI* audio, Rect4f rect)
	: id("root")
	, dummyInput(std::make_shared<InputButtonBase>(4))
	, uiRect(rect)
	, audio(audio)
	, mouseRemap([](Vector2f p) { return p; })
{

}

void UIRoot::setRect(Rect4f rect, Vector2f overscan)
{
	uiRect = Rect4f(rect.getTopLeft() + overscan, rect.getBottomRight() - overscan);
	this->overscan = overscan;
}

Rect4f UIRoot::getRect() const
{
	return uiRect;
}

void UIRoot::update(Time t, UIInputType activeInputType, spInputDevice mouse, spInputDevice manual)
{
	auto joystickType = manual->getJoystickType();
	bool first = true;

	do {
		// Spawn & Update input
		addNewChildren(activeInputType);
		if (activeInputType == UIInputType::Mouse) {
			updateMouse(mouse);
		}
		updateInput(manual);

		// Update children
		for (auto& c: getChildren()) {
			c->doUpdate(first ? UIWidgetUpdateType::First : UIWidgetUpdateType::Full, t, activeInputType, joystickType);
		}
		first = false;
		removeDeadChildren();

		// Layout all widgets
		runLayout();

		// Update again, to reflect what happened >_>
		for (auto& c: getChildren()) {
			c->doUpdate(UIWidgetUpdateType::Partial, 0, activeInputType, joystickType);
		}

		// For subsequent iterations, make sure t = 0
		t = 0;
	} while (isWaitingToSpawnChildren());
}

void UIRoot::updateMouse(spInputDevice mouse)
{
	// Check where we should be mouse overing.
	// If the mouse hasn't moved, keep the last one.
	std::shared_ptr<UIWidget> underMouse;
	Vector2f mousePos = mouseRemap(mouse->getPosition() + uiRect.getTopLeft() - overscan);
	if (true || (mousePos - lastMousePos).squaredLength() > 0.01f) {
		// Go through all root-level widgets and find the actual widget under the mouse
		underMouse = getWidgetUnderMouse(mousePos);
		lastMousePos = mousePos;
	} else {
		underMouse = currentMouseOver.lock();
	}

	// Click
	if (mouse->isButtonPressed(0)) {
		mouseHeld = true;
		setFocus(underMouse);
		if (underMouse) {
			mouse->clearButtonPress(0);
			underMouse->pressMouse(mousePos, 0);
		}
	}

	// Release click
	auto focus = currentFocus.lock();
	if (mouse->isButtonReleased(0)) {
		mouseHeld = false;
		if (focus) {
			focus->releaseMouse(mousePos, 0);
			mouse->clearButtonRelease(0);
		}
	}

	// Mouse wheel
	int wheelDelta = mouse->getWheelMove();
	if (wheelDelta != 0 && underMouse) {
		underMouse->sendEvent(UIEvent(UIEventType::MouseWheel, "mouse", wheelDelta));
	}

	// If the mouse is held, but it's over a different component from the focused one, don't mouse over anything
	auto activeMouseOver = underMouse;
	if (mouseHeld && focus) {
		if (focus != underMouse) {
			activeMouseOver.reset();
		}
		focus->onMouseOver(mousePos);
	} else if (activeMouseOver) {
		activeMouseOver->onMouseOver(mousePos);
	}
	updateMouseOver(activeMouseOver);
}

void UIRoot::updateInputTree(const spInputDevice& input, UIWidget& widget, std::vector<UIWidget*>& inputTargets, UIInput::Priority& bestPriority, bool accepting)
{
	if (!widget.isActive()) {
		return;
	}

	if (!widget.isEnabled()) {
		accepting = false;
	}

	for (auto& c: widget.getChildren()) {
		// Depth-first
		updateInputTree(input, *c, inputTargets, bestPriority, accepting);
	}

	if (widget.inputButtons) {
		widget.inputResults.reset();
		if (accepting) {
			auto priority = widget.getInputPriority();

			if (int(priority) > int(bestPriority)) {
				bestPriority = priority;
				inputTargets.clear();
			}
			if (priority == bestPriority) {
				inputTargets.push_back(&widget);
			}
		}
	}
}

void UIRoot::updateInput(spInputDevice input)
{
	auto& cs = getChildren();
	std::vector<UIWidget*> inputTargets;
	UIInput::Priority bestPriority = UIInput::Priority::Lowest;

	bool accepting = true;
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& c = *cs[i];
		updateInputTree(input, c, inputTargets, bestPriority, accepting);

		if (c.isMouseBlocker()) {
			accepting = false;
		}
	}

	for (auto& target: inputTargets) {
		auto& b = *target->inputButtons;
		auto& results = target->inputResults;
		results.reset();
		if (b.accept != -1) {
			results.setButton(UIInput::Button::Accept, input->isButtonPressed(b.accept), input->isButtonReleased(b.accept), input->isButtonDown(b.accept));
		}
		if (b.cancel != -1) {
			results.setButton(UIInput::Button::Cancel, input->isButtonPressed(b.cancel), input->isButtonReleased(b.cancel), input->isButtonDown(b.cancel));
		}
		if (b.prev != -1) {
			results.setButton(UIInput::Button::Prev, input->isButtonPressed(b.prev), input->isButtonReleased(b.prev), input->isButtonDown(b.prev));
		}
		if (b.next != -1) {
			results.setButton(UIInput::Button::Next, input->isButtonPressed(b.next), input->isButtonReleased(b.next), input->isButtonDown(b.next));
		}
		if (b.hold != -1) {
			results.setButton(UIInput::Button::Hold, input->isButtonPressed(b.hold), input->isButtonReleased(b.hold), input->isButtonDown(b.hold));
		}
		results.setAxis(UIInput::Axis::X, (b.xAxis != -1 ? input->getAxis(b.xAxis) : 0) + (b.xAxisAlt != -1 ? input->getAxis(b.xAxisAlt) : 0));
		results.setAxis(UIInput::Axis::Y, (b.yAxis != -1 ? input->getAxis(b.yAxis) : 0) + (b.yAxisAlt != -1 ? input->getAxis(b.yAxisAlt) : 0));
		results.setAxisRepeat(UIInput::Axis::X, (b.xAxis != -1 ? input->getAxisRepeat(b.xAxis) : 0) + (b.xAxisAlt != -1 ? input->getAxisRepeat(b.xAxisAlt) : 0));
		results.setAxisRepeat(UIInput::Axis::Y, (b.yAxis != -1 ? input->getAxisRepeat(b.yAxis) : 0) + (b.yAxisAlt != -1 ? input->getAxisRepeat(b.yAxisAlt) : 0));
	}
}

void UIRoot::mouseOverNext(bool forward)
{
	auto widgets = collectWidgets();

	if (widgets.empty()) {
		return;
	}

	size_t nextIdx = 0;
	auto current = currentMouseOver.lock();
	if (current) {
		auto i = std::find(widgets.begin(), widgets.end(), current);
		if (i != widgets.end()) {
			nextIdx = ((i - widgets.begin()) + widgets.size() + (forward ? 1 : -1)) % widgets.size();
		}
	}

	updateMouseOver(widgets[nextIdx]);
}

void UIRoot::runLayout()
{
	for (auto& c: getChildren()) {
		c->layout();
	}
}

void UIRoot::setFocus(std::shared_ptr<UIWidget> focus)
{
	auto curFocus = currentFocus.lock();
	if (curFocus != focus) {
		if (curFocus) {
			curFocus->setFocused(false);
		}

		currentFocus = focus;
		if (focus) {
			focus->setFocused(true);
		}
	}
}

void UIRoot::updateMouseOver(const std::shared_ptr<UIWidget>& underMouse)
{
	auto curMouseOver = currentMouseOver.lock();
	if (curMouseOver != underMouse) {
		if (curMouseOver) {
			curMouseOver->setMouseOver(false);
		}
		if (underMouse) {
			underMouse->setMouseOver(true);
		}
		currentMouseOver = underMouse;
	}
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse(Vector2f mousePos, bool includeDisabled) const
{
	auto& cs = getChildren();
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& curRootWidget = cs[i];
		auto widget = getWidgetUnderMouse(curRootWidget, mousePos, includeDisabled);
		if (widget) {
			return widget;
		} else {
			if (curRootWidget->isMouseBlocker()) {
				return {};
			}
		}
	}
	return {};
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse(const std::shared_ptr<UIWidget>& start, Vector2f mousePos, bool includeDisabled) const
{
	if (!start->isActive() || (!includeDisabled && !start->isEnabled())) {
		return {};
	}

	// Depth first
	for (auto& c: start->getChildren()) {
		auto result = getWidgetUnderMouse(c, mousePos, includeDisabled);
		if (result) {
			return result;
		}
	}

	auto rect = start->getMouseRect();
	if (start->canInteractWithMouse() && rect.contains(mousePos)) {
		return start;
	} else {
		return {};
	}
}

void UIRoot::setUIMouseRemapping(std::function<Vector2f(Vector2f)> remapFunction) {
	Expects(remapFunction);
	mouseRemap = remapFunction;
}

void UIRoot::unsetUIMouseRemapping() {
	mouseRemap = [](Vector2f p) { return p; };
}

std::vector<std::shared_ptr<UIWidget>> UIRoot::collectWidgets()
{
	std::vector<std::shared_ptr<UIWidget>> output;
	if (getChildren().empty()) {
		return {};
	}
	collectWidgets(getChildren().back(), output);
	return output;
}

void UIRoot::collectWidgets(const std::shared_ptr<UIWidget>& start, std::vector<std::shared_ptr<UIWidget>>& output)
{
	for (auto& c: start->getChildren()) {
		collectWidgets(c, output);
	}

	if (start->canInteractWithMouse()) {
		output.push_back(start);
	}
}

void UIRoot::draw(SpritePainter& painter, int mask, int layer)
{
	UIPainter p(painter, mask, layer);

	for (auto& c: getChildren()) {
		c->doDraw(p);
	}
}

Maybe<AudioHandle> UIRoot::playSound(const String& eventName)
{
	if (audio && !eventName.isEmpty()) {
		return audio->postEvent(eventName, AudioPosition::makeUI(0.0f));
	}

	return {};
}

void UIRoot::sendEvent(UIEvent&&) const
{
	// Unhandled event
}

bool UIRoot::hasModalUI() const
{
	for (auto& c: getChildren()) {
		if (c->isModal()) {
			return true;
		}
	}
	return false;
}

bool UIRoot::isMouseOverUI() const
{
	return static_cast<bool>(currentMouseOver.lock());
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse() const
{
	return currentMouseOver.lock();
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouseIncludingDisabled() const
{
	return getWidgetUnderMouse(lastMousePos, true);
}

UIWidget* UIRoot::getCurrentFocus() const
{
	return currentFocus.lock().get();
}
<commit_msg>UI doesn't count as modal if it's inactive.<commit_after>#include "ui_root.h"
#include "ui_widget.h"
#include "halley/core/api/audio_api.h"
#include "ui_painter.h"
#include "halley/audio/audio_position.h"
#include "halley/audio/audio_clip.h"
#include "halley/maths/random.h"

using namespace Halley;

UIRoot* UIRoot::getRoot()
{
	return this;
}

const UIRoot* UIRoot::getRoot() const
{
	return this;
}

const String& UIRoot::getId() const
{
	return id;
}

UIRoot::UIRoot(AudioAPI* audio, Rect4f rect)
	: id("root")
	, dummyInput(std::make_shared<InputButtonBase>(4))
	, uiRect(rect)
	, audio(audio)
	, mouseRemap([](Vector2f p) { return p; })
{

}

void UIRoot::setRect(Rect4f rect, Vector2f overscan)
{
	uiRect = Rect4f(rect.getTopLeft() + overscan, rect.getBottomRight() - overscan);
	this->overscan = overscan;
}

Rect4f UIRoot::getRect() const
{
	return uiRect;
}

void UIRoot::update(Time t, UIInputType activeInputType, spInputDevice mouse, spInputDevice manual)
{
	auto joystickType = manual->getJoystickType();
	bool first = true;

	do {
		// Spawn & Update input
		addNewChildren(activeInputType);
		if (activeInputType == UIInputType::Mouse) {
			updateMouse(mouse);
		}
		updateInput(manual);

		// Update children
		for (auto& c: getChildren()) {
			c->doUpdate(first ? UIWidgetUpdateType::First : UIWidgetUpdateType::Full, t, activeInputType, joystickType);
		}
		first = false;
		removeDeadChildren();

		// Layout all widgets
		runLayout();

		// Update again, to reflect what happened >_>
		for (auto& c: getChildren()) {
			c->doUpdate(UIWidgetUpdateType::Partial, 0, activeInputType, joystickType);
		}

		// For subsequent iterations, make sure t = 0
		t = 0;
	} while (isWaitingToSpawnChildren());
}

void UIRoot::updateMouse(spInputDevice mouse)
{
	// Check where we should be mouse overing.
	// If the mouse hasn't moved, keep the last one.
	std::shared_ptr<UIWidget> underMouse;
	Vector2f mousePos = mouseRemap(mouse->getPosition() + uiRect.getTopLeft() - overscan);
	if (true || (mousePos - lastMousePos).squaredLength() > 0.01f) {
		// Go through all root-level widgets and find the actual widget under the mouse
		underMouse = getWidgetUnderMouse(mousePos);
		lastMousePos = mousePos;
	} else {
		underMouse = currentMouseOver.lock();
	}

	// Click
	if (mouse->isButtonPressed(0)) {
		mouseHeld = true;
		setFocus(underMouse);
		if (underMouse) {
			mouse->clearButtonPress(0);
			underMouse->pressMouse(mousePos, 0);
		}
	}

	// Release click
	auto focus = currentFocus.lock();
	if (mouse->isButtonReleased(0)) {
		mouseHeld = false;
		if (focus) {
			focus->releaseMouse(mousePos, 0);
			mouse->clearButtonRelease(0);
		}
	}

	// Mouse wheel
	int wheelDelta = mouse->getWheelMove();
	if (wheelDelta != 0 && underMouse) {
		underMouse->sendEvent(UIEvent(UIEventType::MouseWheel, "mouse", wheelDelta));
	}

	// If the mouse is held, but it's over a different component from the focused one, don't mouse over anything
	auto activeMouseOver = underMouse;
	if (mouseHeld && focus) {
		if (focus != underMouse) {
			activeMouseOver.reset();
		}
		focus->onMouseOver(mousePos);
	} else if (activeMouseOver) {
		activeMouseOver->onMouseOver(mousePos);
	}
	updateMouseOver(activeMouseOver);
}

void UIRoot::updateInputTree(const spInputDevice& input, UIWidget& widget, std::vector<UIWidget*>& inputTargets, UIInput::Priority& bestPriority, bool accepting)
{
	if (!widget.isActive()) {
		return;
	}

	if (!widget.isEnabled()) {
		accepting = false;
	}

	for (auto& c: widget.getChildren()) {
		// Depth-first
		updateInputTree(input, *c, inputTargets, bestPriority, accepting);
	}

	if (widget.inputButtons) {
		widget.inputResults.reset();
		if (accepting) {
			auto priority = widget.getInputPriority();

			if (int(priority) > int(bestPriority)) {
				bestPriority = priority;
				inputTargets.clear();
			}
			if (priority == bestPriority) {
				inputTargets.push_back(&widget);
			}
		}
	}
}

void UIRoot::updateInput(spInputDevice input)
{
	auto& cs = getChildren();
	std::vector<UIWidget*> inputTargets;
	UIInput::Priority bestPriority = UIInput::Priority::Lowest;

	bool accepting = true;
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& c = *cs[i];
		updateInputTree(input, c, inputTargets, bestPriority, accepting);

		if (c.isMouseBlocker()) {
			accepting = false;
		}
	}

	for (auto& target: inputTargets) {
		auto& b = *target->inputButtons;
		auto& results = target->inputResults;
		results.reset();
		if (b.accept != -1) {
			results.setButton(UIInput::Button::Accept, input->isButtonPressed(b.accept), input->isButtonReleased(b.accept), input->isButtonDown(b.accept));
		}
		if (b.cancel != -1) {
			results.setButton(UIInput::Button::Cancel, input->isButtonPressed(b.cancel), input->isButtonReleased(b.cancel), input->isButtonDown(b.cancel));
		}
		if (b.prev != -1) {
			results.setButton(UIInput::Button::Prev, input->isButtonPressed(b.prev), input->isButtonReleased(b.prev), input->isButtonDown(b.prev));
		}
		if (b.next != -1) {
			results.setButton(UIInput::Button::Next, input->isButtonPressed(b.next), input->isButtonReleased(b.next), input->isButtonDown(b.next));
		}
		if (b.hold != -1) {
			results.setButton(UIInput::Button::Hold, input->isButtonPressed(b.hold), input->isButtonReleased(b.hold), input->isButtonDown(b.hold));
		}
		results.setAxis(UIInput::Axis::X, (b.xAxis != -1 ? input->getAxis(b.xAxis) : 0) + (b.xAxisAlt != -1 ? input->getAxis(b.xAxisAlt) : 0));
		results.setAxis(UIInput::Axis::Y, (b.yAxis != -1 ? input->getAxis(b.yAxis) : 0) + (b.yAxisAlt != -1 ? input->getAxis(b.yAxisAlt) : 0));
		results.setAxisRepeat(UIInput::Axis::X, (b.xAxis != -1 ? input->getAxisRepeat(b.xAxis) : 0) + (b.xAxisAlt != -1 ? input->getAxisRepeat(b.xAxisAlt) : 0));
		results.setAxisRepeat(UIInput::Axis::Y, (b.yAxis != -1 ? input->getAxisRepeat(b.yAxis) : 0) + (b.yAxisAlt != -1 ? input->getAxisRepeat(b.yAxisAlt) : 0));
	}
}

void UIRoot::mouseOverNext(bool forward)
{
	auto widgets = collectWidgets();

	if (widgets.empty()) {
		return;
	}

	size_t nextIdx = 0;
	auto current = currentMouseOver.lock();
	if (current) {
		auto i = std::find(widgets.begin(), widgets.end(), current);
		if (i != widgets.end()) {
			nextIdx = ((i - widgets.begin()) + widgets.size() + (forward ? 1 : -1)) % widgets.size();
		}
	}

	updateMouseOver(widgets[nextIdx]);
}

void UIRoot::runLayout()
{
	for (auto& c: getChildren()) {
		c->layout();
	}
}

void UIRoot::setFocus(std::shared_ptr<UIWidget> focus)
{
	auto curFocus = currentFocus.lock();
	if (curFocus != focus) {
		if (curFocus) {
			curFocus->setFocused(false);
		}

		currentFocus = focus;
		if (focus) {
			focus->setFocused(true);
		}
	}
}

void UIRoot::updateMouseOver(const std::shared_ptr<UIWidget>& underMouse)
{
	auto curMouseOver = currentMouseOver.lock();
	if (curMouseOver != underMouse) {
		if (curMouseOver) {
			curMouseOver->setMouseOver(false);
		}
		if (underMouse) {
			underMouse->setMouseOver(true);
		}
		currentMouseOver = underMouse;
	}
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse(Vector2f mousePos, bool includeDisabled) const
{
	auto& cs = getChildren();
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& curRootWidget = cs[i];
		auto widget = getWidgetUnderMouse(curRootWidget, mousePos, includeDisabled);
		if (widget) {
			return widget;
		} else {
			if (curRootWidget->isMouseBlocker()) {
				return {};
			}
		}
	}
	return {};
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse(const std::shared_ptr<UIWidget>& start, Vector2f mousePos, bool includeDisabled) const
{
	if (!start->isActive() || (!includeDisabled && !start->isEnabled())) {
		return {};
	}

	// Depth first
	for (auto& c: start->getChildren()) {
		auto result = getWidgetUnderMouse(c, mousePos, includeDisabled);
		if (result) {
			return result;
		}
	}

	auto rect = start->getMouseRect();
	if (start->canInteractWithMouse() && rect.contains(mousePos)) {
		return start;
	} else {
		return {};
	}
}

void UIRoot::setUIMouseRemapping(std::function<Vector2f(Vector2f)> remapFunction) {
	Expects(remapFunction);
	mouseRemap = remapFunction;
}

void UIRoot::unsetUIMouseRemapping() {
	mouseRemap = [](Vector2f p) { return p; };
}

std::vector<std::shared_ptr<UIWidget>> UIRoot::collectWidgets()
{
	std::vector<std::shared_ptr<UIWidget>> output;
	if (getChildren().empty()) {
		return {};
	}
	collectWidgets(getChildren().back(), output);
	return output;
}

void UIRoot::collectWidgets(const std::shared_ptr<UIWidget>& start, std::vector<std::shared_ptr<UIWidget>>& output)
{
	for (auto& c: start->getChildren()) {
		collectWidgets(c, output);
	}

	if (start->canInteractWithMouse()) {
		output.push_back(start);
	}
}

void UIRoot::draw(SpritePainter& painter, int mask, int layer)
{
	UIPainter p(painter, mask, layer);

	for (auto& c: getChildren()) {
		c->doDraw(p);
	}
}

Maybe<AudioHandle> UIRoot::playSound(const String& eventName)
{
	if (audio && !eventName.isEmpty()) {
		return audio->postEvent(eventName, AudioPosition::makeUI(0.0f));
	}

	return {};
}

void UIRoot::sendEvent(UIEvent&&) const
{
	// Unhandled event
}

bool UIRoot::hasModalUI() const
{
	for (auto& c: getChildren()) {
		if (c->isActive() && c->isModal()) {
			return true;
		}
	}
	return false;
}

bool UIRoot::isMouseOverUI() const
{
	return static_cast<bool>(currentMouseOver.lock());
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouse() const
{
	return currentMouseOver.lock();
}

std::shared_ptr<UIWidget> UIRoot::getWidgetUnderMouseIncludingDisabled() const
{
	return getWidgetUnderMouse(lastMousePos, true);
}

UIWidget* UIRoot::getCurrentFocus() const
{
	return currentFocus.lock().get();
}
<|endoftext|>


<commit_before>/*
	date: 20 05 2015
*/

//4 x 4 matrix exp

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll mod = 1e9 + 7;

ll start[4][4] = {{1, 1, 1, 1}, {1, 0, 0, 0},
					{0, 1, 0, 0}, {0, 0, 1, 0}};

ll tmp[4][4];

void mul(ll A[4][4], ll B[4][4]) {
	ll cell;
	for (ll i = 0; i < 4; ++i) {
		for (ll j = 0; j < 4; ++j) {
			cell = 0;
			for (ll a = 0; a < 4; ++a) {
				cell += (A[i][a]*B[a][j])%mod;
				cell %= mod;
			}
			tmp[i][j] = cell;
		}
	}
	memcpy(A, tmp, 16*sizeof(ll));
}

void power(ll T[4][4], ll n) {
	if (n == 0 || n == 1) return;
	power(T, n/2);
	mul(T, T);
	if (n%2) mul(T, start);
}

ll tetra(ll n) {
	if (n <= 2) return 0;
	if (n == 3) return 1;

	ll T[4][4];
	memcpy(T, start, 16*sizeof(ll));
	power(T, n - 3);

	return T[0][0];
}

ll sum(ll m) {
	return (3*tetra(0) + 2*tetra(1) + tetra(2) - tetra(4) +
				tetra(m + 4) - 2*tetra(m + 1) - tetra(m + 2) + mod)%mod;
}

int main() {
	ios::sync_with_stdio(0);

	ll t; cin >> t;
	while (t--) {
		ll n, m; cin >> n >> m;
		cout << ((((sum(m) - sum(n - 1) + mod) % mod) * 333333336) % mod) << "\n";
	}

	return 0;
}
<commit_msg>Update TETRAHRD.cxx<commit_after>/*
	date: 20 05 2015
*/

//4 x 4 matrix exponentitation

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll mod = 1e9 + 7;

ll start[4][4] = {{1, 1, 1, 1}, {1, 0, 0, 0},
					{0, 1, 0, 0}, {0, 0, 1, 0}};

ll tmp[4][4];

void mul(ll A[4][4], ll B[4][4]) {
	ll cell;
	for (ll i = 0; i < 4; ++i) {
		for (ll j = 0; j < 4; ++j) {
			cell = 0;
			for (ll a = 0; a < 4; ++a) {
				cell += (A[i][a]*B[a][j])%mod;
				cell %= mod;
			}
			tmp[i][j] = cell;
		}
	}
	memcpy(A, tmp, 16*sizeof(ll));
}

void power(ll T[4][4], ll n) {
	if (n == 0 || n == 1) return;
	power(T, n/2);
	mul(T, T);
	if (n%2) mul(T, start);
}

ll tetra(ll n) {
	if (n <= 2) return 0;
	if (n == 3) return 1;

	ll T[4][4];
	memcpy(T, start, 16*sizeof(ll));
	power(T, n - 3);

	return T[0][0];
}

ll sum(ll m) {
	return (3*tetra(0) + 2*tetra(1) + tetra(2) - tetra(4) +
				tetra(m + 4) - 2*tetra(m + 1) - tetra(m + 2) + mod)%mod;
}

int main() {
	ios::sync_with_stdio(0);

	ll t; cin >> t;
	while (t--) {
		ll n, m; cin >> n >> m;
		cout << ((((sum(m) - sum(n - 1) + mod) % mod) * 333333336) % mod) << "\n";
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>

#include <sampgdk/a_players.h>
#include <sampgdk/a_samp.h>
#include <sampgdk/core.h>
#include <sampgdk/plugin.h>

static ThisPlugin helloworld;

void SAMPGDK_CALL Timer(int /*timerid*/, void */*param*/) {
	ServerLog::Printf("timer!");
}

PLUGIN_EXPORT bool PLUGIN_CALL OnGameModeInit() {
	SetGameModeText("Hello, World!");

	AddPlayerClass(0, 1958.3783f, 1343.1572f, 15.3746f, 269.1425f, 0, 0, 0, 0, 0, 0);

	ServerLog::Printf("------------------------------------------\n");
	ServerLog::Printf("      HelloWorld gamemode got loaded.     \n");
	ServerLog::Printf("------------------------------------------\n");

	SetTimer(1000, true, Timer, 0);

	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerConnect(int playerid) {
	SendClientMessage(playerid, 0xFFFFFFFF, "Welcome to the HelloWorld server!");
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerRequestClass(int playerid, int classid) {
	SetPlayerPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraLookAt(playerid, 1958.3783f, 1343.1572f, 15.3746f, CAMERA_CUT);
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerCommandText(int playerid, const char *cmdtext) {
	if (std::strcmp(cmdtext, "/hello") == 0) {
		char name[MAX_PLAYER_NAME];
		GetPlayerName(playerid, name, MAX_PLAYER_NAME);
		char message[128];
		std::sprintf(message, "Hello, %s!", name);
		SendClientMessage(playerid, 0x00FF00FF, message);
		return true;
	}
	if (std::strcmp(cmdtext, "/pos") == 0) {
		float x, y, z;
		GetPlayerPos(playerid, &x, &y, &z);
		char message[128];
		std::sprintf(message, "You are at (%f, %f, %f)", x, y, z);
		SendClientMessage(playerid, 0xFFFFFFFF, message);
		return true;
	}
	return false;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_PROCESS_TICK;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	helloworld.Load(ppData);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	helloworld.Unload();
}

PLUGIN_EXPORT void PLUGIN_CALL ProcessTick() {
	helloworld.ProcessTimers();
}
<commit_msg>Fix MSVC compile warning<commit_after>#include <cstdio>
#include <cstring>

#include <sampgdk/a_players.h>
#include <sampgdk/a_samp.h>
#include <sampgdk/core.h>
#include <sampgdk/plugin.h>

static ThisPlugin helloworld;

void SAMPGDK_CALL Timer(int /*timerid*/, void* /*param*/) {
	ServerLog::Printf("timer!");
}

PLUGIN_EXPORT bool PLUGIN_CALL OnGameModeInit() {
	SetGameModeText("Hello, World!");

	AddPlayerClass(0, 1958.3783f, 1343.1572f, 15.3746f, 269.1425f, 0, 0, 0, 0, 0, 0);

	ServerLog::Printf("------------------------------------------\n");
	ServerLog::Printf("      HelloWorld gamemode got loaded.     \n");
	ServerLog::Printf("------------------------------------------\n");

	SetTimer(1000, true, Timer, 0);

	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerConnect(int playerid) {
	SendClientMessage(playerid, 0xFFFFFFFF, "Welcome to the HelloWorld server!");
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerRequestClass(int playerid, int classid) {
	SetPlayerPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraLookAt(playerid, 1958.3783f, 1343.1572f, 15.3746f, CAMERA_CUT);
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerCommandText(int playerid, const char *cmdtext) {
	if (std::strcmp(cmdtext, "/hello") == 0) {
		char name[MAX_PLAYER_NAME];
		GetPlayerName(playerid, name, MAX_PLAYER_NAME);
		char message[128];
		std::sprintf(message, "Hello, %s!", name);
		SendClientMessage(playerid, 0x00FF00FF, message);
		return true;
	}
	if (std::strcmp(cmdtext, "/pos") == 0) {
		float x, y, z;
		GetPlayerPos(playerid, &x, &y, &z);
		char message[128];
		std::sprintf(message, "You are at (%f, %f, %f)", x, y, z);
		SendClientMessage(playerid, 0xFFFFFFFF, message);
		return true;
	}
	return false;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_PROCESS_TICK;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	helloworld.Load(ppData);
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	helloworld.Unload();
}

PLUGIN_EXPORT void PLUGIN_CALL ProcessTick() {
	helloworld.ProcessTimers();
}
<|endoftext|>


<commit_before>/*
 * Streams.cpp
 *****************************************************************************
 * Copyright (C) 2014 - VideoLAN and VLC authors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "Streams.hpp"
#include "http/HTTPConnection.hpp"
#include "http/HTTPConnectionManager.h"
#include "playlist/BaseRepresentation.h"
#include "playlist/SegmentChunk.hpp"
#include "plumbing/SourceStream.hpp"
#include "plumbing/CommandsQueue.hpp"
#include "tools/Debug.hpp"
#include <vlc_demux.h>

using namespace adaptive;
using namespace adaptive::http;

AbstractStream::AbstractStream(demux_t * demux_)
{
    p_realdemux = demux_;
    format = StreamFormat::UNSUPPORTED;
    currentChunk = NULL;
    eof = false;
    dead = false;
    disabled = false;
    discontinuity = false;
    segmentTracker = NULL;
    demuxersource = NULL;
    commandsqueue = NULL;
    demuxer = NULL;
    fakeesout = NULL;
    vlc_mutex_init(&lock);
}

bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker, HTTPConnectionManager *conn)
{
    /* Don't even try if not supported or already init */
    if((unsigned)format_ == StreamFormat::UNSUPPORTED || demuxersource)
        return false;

    demuxersource = new (std::nothrow) ChunksSourceStream( VLC_OBJECT(p_realdemux), this );
    if(demuxersource)
    {
        CommandsFactory *factory = new (std::nothrow) CommandsFactory();
        if(factory)
        {
            commandsqueue = new (std::nothrow) CommandsQueue(factory);
            if(commandsqueue)
            {
                fakeesout = new (std::nothrow) FakeESOut(p_realdemux->out, commandsqueue);
                if(fakeesout)
                {
                    /* All successfull */
                    fakeesout->setExtraInfoProvider( this );
                    format = format_;
                    segmentTracker = tracker;
                    segmentTracker->registerListener(this);
                    connManager = conn;
                    return true;
                }
                delete commandsqueue;
                commandsqueue = NULL;
            }
            else
            {
                delete factory;
            }
        }
        delete demuxersource;
    }

    return false;
}

AbstractStream::~AbstractStream()
{
    delete currentChunk;
    delete segmentTracker;

    delete demuxer;
    delete demuxersource;
    delete fakeesout;
    delete commandsqueue;

    vlc_mutex_destroy(&lock);
}

void AbstractStream::prepareFormatChange()
{
    if(demuxer)
    {
        /* Enqueue Del Commands for all current ES */
        demuxer->drain();
        /* Enqueue Del Commands for all current ES */
        fakeesout->scheduleAllForDeletion();
        fakeesout->schedulePCRReset();
        commandsqueue->Commit();
        /* ignoring demuxer's own Del commands */
        commandsqueue->setDrop(true);
        delete demuxer;
        commandsqueue->setDrop(false);
        demuxer = NULL;
    }
}

void AbstractStream::setLanguage(const std::string &lang)
{
    language = lang;
}

void AbstractStream::setDescription(const std::string &desc)
{
    description = desc;
}

bool AbstractStream::isDead() const
{
    return dead;
}

mtime_t AbstractStream::getPCR() const
{
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    mtime_t pcr = (dead || disabled) ? VLC_TS_INVALID : commandsqueue->getPCR();
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return pcr;
}

mtime_t AbstractStream::getMinAheadTime() const
{
    if(!segmentTracker)
        return 0;
    return segmentTracker->getMinAheadTime();
}

mtime_t AbstractStream::getFirstDTS() const
{
    mtime_t dts;
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    if(dead || disabled)
    {
        dts = VLC_TS_INVALID;
    }
    else
    {
        dts = commandsqueue->getFirstDTS();
        if(dts == VLC_TS_INVALID)
            dts = commandsqueue->getPCR();
    }
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return dts;
}

int AbstractStream::esCount() const
{
    return fakeesout->esCount();
}

bool AbstractStream::seekAble() const
{
    return (demuxer &&
            !fakeesout->restarting() &&
            !discontinuity &&
            !commandsqueue->isFlushing() );
}

bool AbstractStream::isSelected() const
{
    return fakeesout->hasSelectedEs();
}

bool AbstractStream::reactivate(mtime_t basetime)
{
    if(setPosition(basetime, false))
    {
        disabled = false;
        return true;
    }
    else
    {
        eof = true; /* can't reactivate */
        return false;
    }
}

bool AbstractStream::startDemux()
{
    if(demuxer)
        return false;

    demuxersource->Reset();
    demuxer = createDemux(format);
    if(!demuxer)
        msg_Err(p_realdemux, "Failed to create demuxer");

    return !!demuxer;
}

bool AbstractStream::restartDemux()
{
    if(!demuxer)
    {
        return startDemux();
    }
    else if(demuxer->reinitsOnSeek())
    {
        /* Push all ES as recycling candidates */
        fakeesout->recycleAll();
        /* Restart with ignoring pushes to queue */
        return demuxer->restart(commandsqueue);
    }
    commandsqueue->Commit();
    return true;
}

bool AbstractStream::isDisabled() const
{
    return disabled;
}

bool AbstractStream::drain()
{
    return fakeesout->drain();
}

AbstractStream::buffering_status AbstractStream::bufferize(mtime_t nz_deadline,
                                                           unsigned i_min_buffering, unsigned i_extra_buffering)
{
    vlc_mutex_lock(&lock);

    /* Ensure it is configured */
    if(!segmentTracker || !connManager || dead)
    {
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }

    /* Disable streams that are not selected (alternate streams) */
    if(esCount() && !isSelected() && !fakeesout->restarting())
    {
        disabled = true;
        segmentTracker->reset();
        commandsqueue->Abort(false);
        msg_Dbg(p_realdemux, "deactivating stream %s", format.str().c_str());
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }

    if(commandsqueue->isFlushing())
    {
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_suspended;
    }

    if(!demuxer)
    {
        format = segmentTracker->getCurrentFormat();
        if(!startDemux())
        {
            /* If demux fails because of probing failure / wrong format*/
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on format change" );
                prepareFormatChange();
                discontinuity = false;
                commandsqueue->setFlush();
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
            }
            dead = true; /* Prevent further retries */
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
        }
        setTimeOffset();
    }

    const int64_t i_total_buffering = i_min_buffering + i_extra_buffering;

    mtime_t i_demuxed = commandsqueue->getDemuxedAmount();
    if(i_demuxed < i_total_buffering) /* not already demuxed */
    {
        if(!segmentTracker->segmentsListReady()) /* Live Streams */
        {
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_suspended;
        }

        nz_deadline = commandsqueue->getBufferingLevel() +
                     (i_total_buffering - commandsqueue->getDemuxedAmount()) / (CLOCK_FREQ/4);

        /* need to read, demuxer still buffering, ... */
        vlc_mutex_unlock(&lock);
        int i_ret = demuxer->demux(nz_deadline);
        vlc_mutex_lock(&lock);
        if(i_ret != VLC_DEMUXER_SUCCESS)
        {
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on discontinuity" );
                prepareFormatChange();
                discontinuity = false;
                commandsqueue->setFlush();
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
            }
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
        }
        i_demuxed = commandsqueue->getDemuxedAmount();
    }
    vlc_mutex_unlock(&lock);

    if(i_demuxed < i_total_buffering) /* need to read more */
    {
        if(i_demuxed < i_min_buffering)
            return AbstractStream::buffering_lessthanmin; /* high prio */
        return AbstractStream::buffering_ongoing;
    }
    return AbstractStream::buffering_full;
}

AbstractStream::status AbstractStream::dequeue(mtime_t nz_deadline, mtime_t *pi_pcr)
{
    vlc_mutex_locker locker(&lock);

    *pi_pcr = nz_deadline;

    if (disabled || dead)
        return AbstractStream::status_eof;

    if(commandsqueue->isFlushing())
    {
        *pi_pcr = commandsqueue->Process(p_realdemux->out, VLC_TS_0 + nz_deadline);
        if(!commandsqueue->isEmpty())
            return AbstractStream::status_demuxed;

        if(!commandsqueue->isEOF())
        {
            commandsqueue->Abort(true); /* reset buffering level and flags */
            return AbstractStream::status_discontinuity;
        }
    }

    if(commandsqueue->isEOF())
    {
        *pi_pcr = nz_deadline;
        return AbstractStream::status_eof;
    }

    AdvDebug(msg_Dbg(p_realdemux, "Stream %s pcr %ld dts %ld deadline %ld buflevel %ld",
                     description.c_str(), commandsqueue->getPCR(), commandsqueue->getFirstDTS(),
                     nz_deadline, commandsqueue->getBufferingLevel()));

    if(nz_deadline + VLC_TS_0 <= commandsqueue->getBufferingLevel()) /* demuxed */
    {
        *pi_pcr = commandsqueue->Process( p_realdemux->out, VLC_TS_0 + nz_deadline );
        return AbstractStream::status_demuxed;
    }

    return AbstractStream::status_buffering;
}

block_t * AbstractStream::readNextBlock()
{
    if (currentChunk == NULL && !eof)
        currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);

    if(discontinuity)
    {
        msg_Info(p_realdemux, "Encountered discontinuity");
        /* Force stream/demuxer to end for this call */
        return NULL;
    }

    if(currentChunk == NULL)
    {
        eof = true;
        return NULL;
    }

    const bool b_segment_head_chunk = (currentChunk->getBytesRead() == 0);

    block_t *block = currentChunk->readBlock();
    if(block == NULL)
    {
        delete currentChunk;
        currentChunk = NULL;
        return NULL;
    }

    if (currentChunk->isEmpty())
    {
        delete currentChunk;
        currentChunk = NULL;
    }

    block = checkBlock(block, b_segment_head_chunk);

    return block;
}

bool AbstractStream::setPosition(mtime_t time, bool tryonly)
{
    if(!seekAble())
        return false;

    bool ret = segmentTracker->setPositionByTime(time, demuxer->reinitsOnSeek(), tryonly);
    if(!tryonly && ret)
    {
        if(demuxer->reinitsOnSeek())
        {
            if(currentChunk)
                delete currentChunk;
            currentChunk = NULL;

            if( !restartDemux() )
                dead = true;

            setTimeOffset();
        }
        else commandsqueue->Abort( true );

        es_out_Control(p_realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                       VLC_TS_0 + time);
    }
    return ret;
}

mtime_t AbstractStream::getPlaybackTime() const
{
    return segmentTracker->getPlaybackTime();
}

void AbstractStream::runUpdates()
{
    if(!isDisabled())
        segmentTracker->updateSelected();
}

void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
{
    if(!p_fmt->psz_language && !language.empty())
        p_fmt->psz_language = strdup(language.c_str());
    if(!p_fmt->psz_description && !description.empty())
        p_fmt->psz_description = strdup(description.c_str());
}

void AbstractStream::setTimeOffset()
{
    /* Check if we need to set an offset as the demuxer
     * will start from zero from seek point */
    if(demuxer && demuxer->alwaysStartsFromZero())
        fakeesout->setTimestampOffset(segmentTracker->getPlaybackTime());
    else
        fakeesout->setTimestampOffset(0);
}

void AbstractStream::trackerEvent(const SegmentTrackerEvent &event)
{
    switch(event.type)
    {
        case SegmentTrackerEvent::DISCONTINUITY:
            discontinuity = true;
            break;

        case SegmentTrackerEvent::FORMATCHANGE:
            /* Check if our current demux is still valid */
            if(*event.u.format.f != format)
            {
                /* Format has changed between segments, we need to drain and change demux */
                msg_Info(p_realdemux, "Changing stream format %s -> %s",
                         format.str().c_str(), event.u.format.f->str().c_str());
                format = *event.u.format.f;

                /* This is an implict discontinuity */
                discontinuity = true;
            }
            break;

        case SegmentTrackerEvent::SWITCHING:
        default:
            break;
    }
}
<commit_msg>demux: adaptive: don't show err for unsupported demuxers<commit_after>/*
 * Streams.cpp
 *****************************************************************************
 * Copyright (C) 2014 - VideoLAN and VLC authors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "Streams.hpp"
#include "http/HTTPConnection.hpp"
#include "http/HTTPConnectionManager.h"
#include "playlist/BaseRepresentation.h"
#include "playlist/SegmentChunk.hpp"
#include "plumbing/SourceStream.hpp"
#include "plumbing/CommandsQueue.hpp"
#include "tools/Debug.hpp"
#include <vlc_demux.h>

using namespace adaptive;
using namespace adaptive::http;

AbstractStream::AbstractStream(demux_t * demux_)
{
    p_realdemux = demux_;
    format = StreamFormat::UNSUPPORTED;
    currentChunk = NULL;
    eof = false;
    dead = false;
    disabled = false;
    discontinuity = false;
    segmentTracker = NULL;
    demuxersource = NULL;
    commandsqueue = NULL;
    demuxer = NULL;
    fakeesout = NULL;
    vlc_mutex_init(&lock);
}

bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker, HTTPConnectionManager *conn)
{
    /* Don't even try if not supported or already init */
    if((unsigned)format_ == StreamFormat::UNSUPPORTED || demuxersource)
        return false;

    demuxersource = new (std::nothrow) ChunksSourceStream( VLC_OBJECT(p_realdemux), this );
    if(demuxersource)
    {
        CommandsFactory *factory = new (std::nothrow) CommandsFactory();
        if(factory)
        {
            commandsqueue = new (std::nothrow) CommandsQueue(factory);
            if(commandsqueue)
            {
                fakeesout = new (std::nothrow) FakeESOut(p_realdemux->out, commandsqueue);
                if(fakeesout)
                {
                    /* All successfull */
                    fakeesout->setExtraInfoProvider( this );
                    format = format_;
                    segmentTracker = tracker;
                    segmentTracker->registerListener(this);
                    connManager = conn;
                    return true;
                }
                delete commandsqueue;
                commandsqueue = NULL;
            }
            else
            {
                delete factory;
            }
        }
        delete demuxersource;
    }

    return false;
}

AbstractStream::~AbstractStream()
{
    delete currentChunk;
    delete segmentTracker;

    delete demuxer;
    delete demuxersource;
    delete fakeesout;
    delete commandsqueue;

    vlc_mutex_destroy(&lock);
}

void AbstractStream::prepareFormatChange()
{
    if(demuxer)
    {
        /* Enqueue Del Commands for all current ES */
        demuxer->drain();
        /* Enqueue Del Commands for all current ES */
        fakeesout->scheduleAllForDeletion();
        fakeesout->schedulePCRReset();
        commandsqueue->Commit();
        /* ignoring demuxer's own Del commands */
        commandsqueue->setDrop(true);
        delete demuxer;
        commandsqueue->setDrop(false);
        demuxer = NULL;
    }
}

void AbstractStream::setLanguage(const std::string &lang)
{
    language = lang;
}

void AbstractStream::setDescription(const std::string &desc)
{
    description = desc;
}

bool AbstractStream::isDead() const
{
    return dead;
}

mtime_t AbstractStream::getPCR() const
{
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    mtime_t pcr = (dead || disabled) ? VLC_TS_INVALID : commandsqueue->getPCR();
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return pcr;
}

mtime_t AbstractStream::getMinAheadTime() const
{
    if(!segmentTracker)
        return 0;
    return segmentTracker->getMinAheadTime();
}

mtime_t AbstractStream::getFirstDTS() const
{
    mtime_t dts;
    vlc_mutex_lock(const_cast<vlc_mutex_t *>(&lock));
    if(dead || disabled)
    {
        dts = VLC_TS_INVALID;
    }
    else
    {
        dts = commandsqueue->getFirstDTS();
        if(dts == VLC_TS_INVALID)
            dts = commandsqueue->getPCR();
    }
    vlc_mutex_unlock(const_cast<vlc_mutex_t *>(&lock));
    return dts;
}

int AbstractStream::esCount() const
{
    return fakeesout->esCount();
}

bool AbstractStream::seekAble() const
{
    return (demuxer &&
            !fakeesout->restarting() &&
            !discontinuity &&
            !commandsqueue->isFlushing() );
}

bool AbstractStream::isSelected() const
{
    return fakeesout->hasSelectedEs();
}

bool AbstractStream::reactivate(mtime_t basetime)
{
    if(setPosition(basetime, false))
    {
        disabled = false;
        return true;
    }
    else
    {
        eof = true; /* can't reactivate */
        return false;
    }
}

bool AbstractStream::startDemux()
{
    if(demuxer)
        return false;

    demuxersource->Reset();
    demuxer = createDemux(format);
    if(!demuxer && format != StreamFormat())
        msg_Err(p_realdemux, "Failed to create demuxer");

    return !!demuxer;
}

bool AbstractStream::restartDemux()
{
    if(!demuxer)
    {
        return startDemux();
    }
    else if(demuxer->reinitsOnSeek())
    {
        /* Push all ES as recycling candidates */
        fakeesout->recycleAll();
        /* Restart with ignoring pushes to queue */
        return demuxer->restart(commandsqueue);
    }
    commandsqueue->Commit();
    return true;
}

bool AbstractStream::isDisabled() const
{
    return disabled;
}

bool AbstractStream::drain()
{
    return fakeesout->drain();
}

AbstractStream::buffering_status AbstractStream::bufferize(mtime_t nz_deadline,
                                                           unsigned i_min_buffering, unsigned i_extra_buffering)
{
    vlc_mutex_lock(&lock);

    /* Ensure it is configured */
    if(!segmentTracker || !connManager || dead)
    {
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }

    /* Disable streams that are not selected (alternate streams) */
    if(esCount() && !isSelected() && !fakeesout->restarting())
    {
        disabled = true;
        segmentTracker->reset();
        commandsqueue->Abort(false);
        msg_Dbg(p_realdemux, "deactivating stream %s", format.str().c_str());
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_end;
    }

    if(commandsqueue->isFlushing())
    {
        vlc_mutex_unlock(&lock);
        return AbstractStream::buffering_suspended;
    }

    if(!demuxer)
    {
        format = segmentTracker->getCurrentFormat();
        if(!startDemux())
        {
            /* If demux fails because of probing failure / wrong format*/
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on format change" );
                prepareFormatChange();
                discontinuity = false;
                commandsqueue->setFlush();
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
            }
            dead = true; /* Prevent further retries */
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
        }
        setTimeOffset();
    }

    const int64_t i_total_buffering = i_min_buffering + i_extra_buffering;

    mtime_t i_demuxed = commandsqueue->getDemuxedAmount();
    if(i_demuxed < i_total_buffering) /* not already demuxed */
    {
        if(!segmentTracker->segmentsListReady()) /* Live Streams */
        {
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_suspended;
        }

        nz_deadline = commandsqueue->getBufferingLevel() +
                     (i_total_buffering - commandsqueue->getDemuxedAmount()) / (CLOCK_FREQ/4);

        /* need to read, demuxer still buffering, ... */
        vlc_mutex_unlock(&lock);
        int i_ret = demuxer->demux(nz_deadline);
        vlc_mutex_lock(&lock);
        if(i_ret != VLC_DEMUXER_SUCCESS)
        {
            if(discontinuity)
            {
                msg_Dbg( p_realdemux, "Flushing on discontinuity" );
                prepareFormatChange();
                discontinuity = false;
                commandsqueue->setFlush();
                vlc_mutex_unlock(&lock);
                return AbstractStream::buffering_ongoing;
            }
            commandsqueue->setEOF();
            vlc_mutex_unlock(&lock);
            return AbstractStream::buffering_end;
        }
        i_demuxed = commandsqueue->getDemuxedAmount();
    }
    vlc_mutex_unlock(&lock);

    if(i_demuxed < i_total_buffering) /* need to read more */
    {
        if(i_demuxed < i_min_buffering)
            return AbstractStream::buffering_lessthanmin; /* high prio */
        return AbstractStream::buffering_ongoing;
    }
    return AbstractStream::buffering_full;
}

AbstractStream::status AbstractStream::dequeue(mtime_t nz_deadline, mtime_t *pi_pcr)
{
    vlc_mutex_locker locker(&lock);

    *pi_pcr = nz_deadline;

    if (disabled || dead)
        return AbstractStream::status_eof;

    if(commandsqueue->isFlushing())
    {
        *pi_pcr = commandsqueue->Process(p_realdemux->out, VLC_TS_0 + nz_deadline);
        if(!commandsqueue->isEmpty())
            return AbstractStream::status_demuxed;

        if(!commandsqueue->isEOF())
        {
            commandsqueue->Abort(true); /* reset buffering level and flags */
            return AbstractStream::status_discontinuity;
        }
    }

    if(commandsqueue->isEOF())
    {
        *pi_pcr = nz_deadline;
        return AbstractStream::status_eof;
    }

    AdvDebug(msg_Dbg(p_realdemux, "Stream %s pcr %ld dts %ld deadline %ld buflevel %ld",
                     description.c_str(), commandsqueue->getPCR(), commandsqueue->getFirstDTS(),
                     nz_deadline, commandsqueue->getBufferingLevel()));

    if(nz_deadline + VLC_TS_0 <= commandsqueue->getBufferingLevel()) /* demuxed */
    {
        *pi_pcr = commandsqueue->Process( p_realdemux->out, VLC_TS_0 + nz_deadline );
        return AbstractStream::status_demuxed;
    }

    return AbstractStream::status_buffering;
}

block_t * AbstractStream::readNextBlock()
{
    if (currentChunk == NULL && !eof)
        currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);

    if(discontinuity)
    {
        msg_Info(p_realdemux, "Encountered discontinuity");
        /* Force stream/demuxer to end for this call */
        return NULL;
    }

    if(currentChunk == NULL)
    {
        eof = true;
        return NULL;
    }

    const bool b_segment_head_chunk = (currentChunk->getBytesRead() == 0);

    block_t *block = currentChunk->readBlock();
    if(block == NULL)
    {
        delete currentChunk;
        currentChunk = NULL;
        return NULL;
    }

    if (currentChunk->isEmpty())
    {
        delete currentChunk;
        currentChunk = NULL;
    }

    block = checkBlock(block, b_segment_head_chunk);

    return block;
}

bool AbstractStream::setPosition(mtime_t time, bool tryonly)
{
    if(!seekAble())
        return false;

    bool ret = segmentTracker->setPositionByTime(time, demuxer->reinitsOnSeek(), tryonly);
    if(!tryonly && ret)
    {
        if(demuxer->reinitsOnSeek())
        {
            if(currentChunk)
                delete currentChunk;
            currentChunk = NULL;

            if( !restartDemux() )
                dead = true;

            setTimeOffset();
        }
        else commandsqueue->Abort( true );

        es_out_Control(p_realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
                       VLC_TS_0 + time);
    }
    return ret;
}

mtime_t AbstractStream::getPlaybackTime() const
{
    return segmentTracker->getPlaybackTime();
}

void AbstractStream::runUpdates()
{
    if(!isDisabled())
        segmentTracker->updateSelected();
}

void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
{
    if(!p_fmt->psz_language && !language.empty())
        p_fmt->psz_language = strdup(language.c_str());
    if(!p_fmt->psz_description && !description.empty())
        p_fmt->psz_description = strdup(description.c_str());
}

void AbstractStream::setTimeOffset()
{
    /* Check if we need to set an offset as the demuxer
     * will start from zero from seek point */
    if(demuxer && demuxer->alwaysStartsFromZero())
        fakeesout->setTimestampOffset(segmentTracker->getPlaybackTime());
    else
        fakeesout->setTimestampOffset(0);
}

void AbstractStream::trackerEvent(const SegmentTrackerEvent &event)
{
    switch(event.type)
    {
        case SegmentTrackerEvent::DISCONTINUITY:
            discontinuity = true;
            break;

        case SegmentTrackerEvent::FORMATCHANGE:
            /* Check if our current demux is still valid */
            if(*event.u.format.f != format)
            {
                /* Format has changed between segments, we need to drain and change demux */
                msg_Info(p_realdemux, "Changing stream format %s -> %s",
                         format.str().c_str(), event.u.format.f->str().c_str());
                format = *event.u.format.f;

                /* This is an implict discontinuity */
                discontinuity = true;
            }
            break;

        case SegmentTrackerEvent::SWITCHING:
        default:
            break;
    }
}
<|endoftext|>


<commit_before>//Mancala AI
//Copyright Matthew Chandler 2012

#include <iostream>
#include <vector>

//board:
//2 rows of 6 bowls
//2 larger bowls for scoring (stores)
//
//Rules
//play is CCW
//ending in player's own store yields extra turn
//ending in empty bowl earns that piece and all those in the bowl across from it
//game ends when a player has no legal moves left
//
//good heuristics:
//score - opponent's score
//possibly good:
//number of availible moves
//seeds in play
//seed distribution (large piles waiting to be collected? seed ratio between sides)
//possibilty of extra turns
//if we wanted to, we could use a genetic algorithm for determining the importance of each of these
//
//representation
//circular array?
//  11 10 9  8  7  6
//  0  1  2  3  4  5
//  p1 store, p2 store
//From there, we would need logic to add to player's own store and skip the opponents.
//if we abstract out the actual array indexes, we can use 2 starting pointers to easily flip the board
//With that in mind, it might be better to use a Digraph, so we can have a truly circular setup
//each node could have a next, prev, and across pointer, and one that points to the stores for the ends (NULL otherwise)
//
//
//
//If we wanted to get really fancy, we could do 3D graphics with particle physics for the seeds.

struct Bowl
{
public:
    Bowl(const int Count = 0, const int Next = 0, const int Across = 0):
        count(Count), next(Next), across(Across)
    {}

    int count;
    int next, across;
};

class Board
{
public:
    Board(const int Num_bowls = 6, const int Num_seeds = 4):
    num_bowls(Num_bowls), num_seeds(Num_seeds)
    {
        bowls.resize(2 * num_bowls + 2);
        p1_start = 0;
        p1_store = num_bowls;
        p2_start = num_bowls + 1;
        p2_store = 2 * num_bowls + 1;

        for(size_t i = 0; i < bowls.size(); ++i)
        {
            if(i < bowls.size() - 1)
                bowls[i].next = i + 1;
            else
                bowls[i].next = 0;

            if(i != (size_t)num_bowls && i != 2 * (size_t)num_bowls + 1)
            {
                bowls[i].across = 2 * num_bowls - i;
                bowls[i].count = num_seeds;
            }
        }
    }
    //perform a move
    //returns true if the move earns an extra turn
    bool move(int bowl)
    {
        if(bowl < 0 || bowl >= num_bowls)
            return false;
        bowl += p1_start;
        int seeds = bowls[bowl].count;
        if(seeds == 0)
            return false;
        bowls[bowl].count = 0;
        //make the move
        for(int i = 0; i < seeds; ++i)
        {
            bowl = bowls[bowl].next;
            if(bowl == p2_store)
                bowl = bowls[bowl].next;
            bowls[bowl].count += 1;
        }
        //extra turn if we land in our own store
        if(bowl == p1_store)
            return true;

        //if we land in an empty bowl, we get the last seed sown and all the seeds from the bowl across
        if(bowls[bowl].count == 1 && bowls[bowls[bowl].across].count > 0)
        {
            bowls[p1_store].count += 1 + bowls[bowls[bowl].across].count;
            bowls[bowls[bowl].across].count = 0;
            bowls[bowl].count = 0;
        }
        return false;
    }

    //swap sides of the board
    void swapsides()
    {
        std::swap(p1_start, p2_start);
        std::swap(p1_store, p2_store);
    }

    //heuristics to evaluate the board status
    int evaluate() const
    {
        //simple
        return bowls[p1_store].count - bowls[p2_store].count;
    }

    void crapprint() const //delete me!
    {
        std::cout<<bowls[p2_store].count<<std::endl;
        for(int i = p1_start; i < p1_start + 6; ++i)
            std::cout<<bowls[i].count<<"\t"<<bowls[bowls[i].across].count<<std::endl;
        std::cout<<bowls[p1_store].count<<std::endl;
    }

    int num_bowls, num_seeds;
    std::vector<Bowl> bowls;
    int p1_start, p2_start;
    int p1_store, p2_store;
};

int choosemove(Board b) //purposely doing pass by value here
{
    int best = 0;
    int best_i = 0;
    //loop over available moves
    for(int i =0; i < 6; ++i)
    {
        if(b.bowls[b.p1_start + 1].count <= 0)
            continue;
        Board sub_b = b;
        sub_b.move(i);
        if(sub_b.evaluate() > best)
        {
            best = sub_b.evaluate();
            best_i = i;
        }
    }
    return best_i;
}

int main()
{
    return 0;
}
<commit_msg>improved crapprint<commit_after>//Mancala AI
//Copyright Matthew Chandler 2012

#include <iostream>
#include <iomanip>
#include <vector>
#include <limits>

//board:
//2 rows of 6 bowls
//2 larger bowls for scoring (stores)
//
//Rules
//play is CCW
//ending in player's own store yields extra turn
//ending in empty bowl earns that piece and all those in the bowl across from it
//game ends when a player has no legal moves left
//
//good heuristics:
//score - opponent's score
//possibly good:
//number of availible moves
//seeds in play
//seed distribution (large piles waiting to be collected? seed ratio between sides)
//possibilty of extra turns
//if we wanted to, we could use a genetic algorithm for determining the importance of each of these
//
//representation
//circular array?
//  11 10 9  8  7  6
//  0  1  2  3  4  5
//  p1 store, p2 store
//From there, we would need logic to add to player's own store and skip the opponents.
//if we abstract out the actual array indexes, we can use 2 starting pointers to easily flip the board
//With that in mind, it might be better to use a Digraph, so we can have a truly circular setup
//each node could have a next, prev, and across pointer, and one that points to the stores for the ends (NULL otherwise)
//
//
//
//If we wanted to get really fancy, we could do 3D graphics with particle physics for the seeds.

struct Bowl
{
public:
    Bowl(const int Count = 0, const int Next = 0, const int Across = 0):
        count(Count), next(Next), across(Across)
    {}

    int count;
    int next, across;
};

class Board
{
public:
    Board(const int Num_bowls = 6, const int Num_seeds = 4):
    num_bowls(Num_bowls), num_seeds(Num_seeds)
    {
        bowls.resize(2 * num_bowls + 2);
        p1_start = 0;
        p1_store = num_bowls;
        p2_start = num_bowls + 1;
        p2_store = 2 * num_bowls + 1;

        for(size_t i = 0; i < bowls.size(); ++i)
        {
            if(i < bowls.size() - 1)
                bowls[i].next = i + 1;
            else
                bowls[i].next = 0;

            if(i != (size_t)num_bowls && i != 2 * (size_t)num_bowls + 1)
            {
                bowls[i].across = 2 * num_bowls - i;
                bowls[i].count = num_seeds;
            }
        }
    }
    //perform a move
    //returns true if the move earns an extra turn
    bool move(int bowl)
    {
        if(bowl < 0 || bowl >= num_bowls)
            return false;
        bowl += p1_start;
        int seeds = bowls[bowl].count;
        if(seeds == 0)
            return false;
        bowls[bowl].count = 0;
        //make the move
        for(int i = 0; i < seeds; ++i)
        {
            bowl = bowls[bowl].next;
            if(bowl == p2_store)
                bowl = bowls[bowl].next;
            bowls[bowl].count += 1;
        }
        //extra turn if we land in our own store
        if(bowl == p1_store)
            return true;

        //if we land in an empty bowl, we get the last seed sown and all the seeds from the bowl across
        if(bowls[bowl].count == 1 && bowls[bowls[bowl].across].count > 0)
        {
            bowls[p1_store].count += 1 + bowls[bowls[bowl].across].count;
            bowls[bowls[bowl].across].count = 0;
            bowls[bowl].count = 0;
        }
        return false;
    }

    //swap sides of the board
    void swapsides()
    {
        std::swap(p1_start, p2_start);
        std::swap(p1_store, p2_store);
    }

    //heuristics to evaluate the board status
    int evaluate() const
    {
        //simple
        return bowls[p1_store].count - bowls[p2_store].count;
    }

    void crapprint() const //delete me!
    {
        std::cout<<"    ";
        for(int i = p1_start; i < p1_start + 6; ++i)
            std::cout<<std::setw(2)<<std::setfill(' ')<<bowls[bowls[i].across].count<<" ";
        std::cout<<std::endl;
        std::cout<<std::setw(2)<<std::setfill(' ')<<bowls[p2_store].count<<std::setw(3*7)<<" "<<std::setw(2)<<bowls[p1_store].count<<std::endl;
        std::cout<<"    ";
        for(int i = p1_start; i < p1_start + 6; ++i)
            std::cout<<std::setw(2)<<std::setfill(' ')<<bowls[i].count<<" ";
        std::cout<<std::endl;
        std::cout<<"    ";
        for(int i = 0; i < 6 ; ++i)
            std::cout<<std::setw(2)<<std::setfill(' ')<<i<<" ";
        std::cout<<std::endl;
    }

    int num_bowls, num_seeds;
    std::vector<Bowl> bowls;
    int p1_start, p2_start;
    int p1_store, p2_store;
};

int choosemove(Board b) //purposely doing pass by value here
{
    int best = 0;
    int best_i = 0;
    //loop over available moves
    for(int i =0; i < 6; ++i)
    {
        if(b.bowls[b.p1_start + 1].count <= 0)
            continue;
        Board sub_b = b;
        sub_b.move(i);
        if(sub_b.evaluate() > best)
        {
            best = sub_b.evaluate();
            best_i = i;
        }
    }
    return best_i;
}

int main()
{
    return 0;
}
<|endoftext|>