/**
  * creates land move for user
  *
  * @param $id_user int
  * @param $id_game int
  * @param $round int
  * @param $steps array(int step_nr => int id_zarea) -> step_nr counting from 1 to x
  * @param $units array(int id_unit => count)
  * @throws NullPointerException
  * @throws ModelException
  * @return ModelLandMove
  */
 public static function createLandMove($id_user, $id_game, $round, $steps, $units)
 {
     SQLCommands::init(intval($id_game));
     // CREATE MOVE
     $query = 'create_move';
     $dict = array();
     $dict[':id_user'] = intval($id_user);
     $dict[':id_phase'] = PHASE_LANDMOVE;
     $dict[':round'] = $round;
     DataSource::Singleton()->epp($query, $dict);
     $id_move = DataSource::getInstance()->getLastInsertId();
     try {
         // INSERT MOVE STEPS
         $x = 0;
         foreach ($steps as $step => $id_zarea) {
             ++$x;
             ModelGameArea::getGameArea((int) $id_game, (int) $id_zarea);
             if (!isset($steps[$x])) {
                 throw new ModelException('Cannot create landmove, steps not consistent.');
             }
             $query = 'insert_area_for_move';
             $dict = array();
             $dict[':id_move'] = intval($id_move);
             $dict[':step'] = intval($step);
             $dict[':id_zarea'] = intval($id_zarea);
             DataSource::Singleton()->epp($query, $dict);
         }
         $id_zarea_start = (int) $steps[1];
         // INSERT UNITS
         foreach ($units as $id_unit => $count) {
             ModelLandUnit::getModelById($id_unit);
             $zUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit((int) $id_game, $id_zarea_start, (int) $id_user, (int) $id_unit);
             $query = 'insert_land_units_for_move';
             $dict = array();
             $dict[':id_zunit'] = $zUnit->getId();
             $dict[':id_move'] = intval($id_move);
             $dict[':count'] = intval($count);
             DataSource::Singleton()->epp($query, $dict);
         }
     } catch (ModelException $ex) {
         self::flagMoveDeleted();
         throw $ex;
     } catch (NullPointerException $ex) {
         self::flagMoveDeleted();
         throw $ex;
     }
     return self::$moves[$id_game][$id_move] = new ModelLandMove((int) $id_user, (int) $id_game, PHASE_LANDMOVE, (int) $id_move, (int) $round, false, $steps, $units);
 }
 private function executeAttack($id_target_area, array $moves)
 {
     // 0. init empty arrays for attacker/defender units
     $units_attacker = array();
     $units_defender = array();
     // 1. get units for defender
     $target_area = ModelGameArea::getGameArea($this->id_game, $id_target_area);
     $id_defender = $target_area->getIdUser();
     $iter = ModelLandUnit::iterator();
     while ($iter->hasNext()) {
         /* @var ModelLandUnit $unit */
         $unit = $iter->next();
         $units_attacker[$unit->getId()] = 0;
         $landUnit_defender = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_defender, $unit->getId());
         $units_defender[$unit->getId()] = $landUnit_defender->getCount();
     }
     // 2. add up all units for attacker (multiple moves possible, check already finished moves from NML-fights)
     // 2.a subtract units from originating country
     $id_attacker = 0;
     foreach ($moves as $id_move) {
         $move = ModelLandMove::getLandMove($this->id_game, $id_move);
         $id_user = $move->getIdUser();
         $id_attacker = $id_user;
         $steps = $move->getSteps();
         $from = reset($steps);
         $units = $move->getUnits();
         foreach ($units as $id_unit => $count) {
             $landUnit_from = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $from, $id_user, $id_unit);
             $landUnit_from->addCount($count * -1);
             $units_attacker[$id_unit] += $count;
         }
     }
     // 3. calculate winner and remaining units
     $attacker_wins = $this->calculateFight($units_attacker, $units_defender);
     // 3.a update defender units
     $iter = ModelLandUnit::iterator();
     while ($iter->hasNext()) {
         /* @var ModelLandUnit $unit */
         $unit = $iter->next();
         $landUnit_defender = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_defender, $unit->getId());
         $landUnit_defender->setCount($units_defender[$unit->getId()]);
     }
     // 4. update target country units (and user if attacker won)
     if ($attacker_wins) {
         // 4.a update attacker units
         $iter = ModelLandUnit::iterator();
         while ($iter->hasNext()) {
             /* @var ModelLandUnit $unit */
             $unit = $iter->next();
             $landUnit_attacker = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_target_area, $id_attacker, $unit->getId());
             $landUnit_attacker->setCount($units_attacker[$unit->getId()]);
         }
         // 4.b update country owner
         $area = ModelGameArea::getGameArea($this->id_game, $id_target_area);
         $area->setIdUser($id_attacker);
         // 4.c check ships
         // TODO : implement ship takeover or ship destruction
     }
     // 4. flag all moves as finished
     foreach ($moves as $id_move) {
         $this->finished_moves[] = $id_move;
     }
 }
 /**
  * run the game logic
  *
  * @throws LogicException
  * @return void
  */
 public function run()
 {
     if (!$this->checkIfValid()) {
         throw new LogicException('Game ' . $this->id_game . ' not valid for processing.');
     }
     $this->startProcessing();
     try {
         // run through moves for each user
         $iter = ModelSelectStartMove::iterator($this->id_game);
         while ($iter->hasNext()) {
             // areas to select for user
             $selectStartMove = $iter->next();
             $regions_selected = $selectStartMove->getRegions();
             // array(int option_number => array(int id_zarea))
             $id_user = $selectStartMove->getIdUser();
             /* @var $iigi ModelIsInGameInfo */
             $iigi = ModelIsInGameInfo::getIsInGameInfo($id_user, $this->id_game);
             $id_set = $iigi->getIdStartingSet();
             foreach ($regions_selected as $option_number => $areas) {
                 $regions = ModelStartRegion::getRegionsForSetAndOption($id_set, $option_number);
                 // array(int id_area => ModelStartRegion)
                 foreach ($areas as $id_zarea) {
                     $gameArea = ModelGameArea::getGameArea($this->id_game, $id_zarea);
                     $id_area = $gameArea->getIdArea();
                     /* @var $region ModelStartRegion */
                     $region = $regions[$id_area];
                     $id_option = $region->getIdOptionType();
                     $unit_count = ModelOptionType::getOptionType($id_option)->getUnits();
                     // set user for game area
                     $gameArea->setIdUser($id_user);
                     // create units for user
                     $iterUnits = ModelLandUnit::iterator();
                     while ($iterUnits->hasNext()) {
                         $landUnit = $iterUnits->next();
                         $id_unit = $landUnit->getId();
                         $inGameLandUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_zarea, $id_user, $id_unit);
                         $inGameLandUnit->setCount($unit_count);
                     }
                 }
             }
         }
         // add units to all empty game-areas
         $iter = ModelGameArea::iterator(NEUTRAL_COUNTRY, $this->id_game);
         while ($iter->hasNext()) {
             /* @var $gameArea ModelGameArea */
             $gameArea = $iter->next();
             if ($gameArea->getIdType() !== TYPE_LAND) {
                 continue;
             }
             $count = $gameArea->getProductivity();
             if ($gameArea->getIdResource() === RESOURCE_OIL) {
                 ++$count;
             }
             $iterUnits = ModelLandUnit::iterator();
             while ($iterUnits->hasNext()) {
                 $landUnit = $iterUnits->next();
                 $id_unit = $landUnit->getId();
                 $inGameLandUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $gameArea->getId(), NEUTRAL_COUNTRY, $id_unit);
                 $inGameLandUnit->setCount($count);
             }
         }
         $this->finishProcessing();
     } catch (\Exception $ex) {
         $this->logger->fatal($ex);
         $this->rollback();
     }
 }
 /**
  * creates land move for user
  *
  * @param $id_user int
  * @param $id_game int
  * @param $round int
  * @param $id_zarea int id_zarea
  * @param $units array(int id_unit => count)
  * @throws NullPointerException
  * @throws ModelException
  * @return ModelProductionMove
  */
 public static function createProductionMove($id_user, $id_game, $round, $id_zarea, $units)
 {
     SQLCommands::init(intval($id_game));
     // CREATE MOVE
     $query = 'create_move';
     $dict = array();
     $dict[':id_user'] = intval($id_user);
     $dict[':id_phase'] = PHASE_PRODUCTION;
     $dict[':round'] = $round;
     DataSource::Singleton()->epp($query, $dict);
     $id_move = DataSource::getInstance()->getLastInsertId();
     try {
         // INSERT MOVE STEPS
         ModelGameArea::getGameArea((int) $id_game, (int) $id_zarea);
         $query = 'insert_area_for_move';
         $dict = array();
         $dict[':id_move'] = intval($id_move);
         $dict[':step'] = intval(1);
         $dict[':id_zarea'] = intval($id_zarea);
         DataSource::Singleton()->epp($query, $dict);
         // INSERT UNITS
         foreach ($units as $id_unit => $count) {
             ModelLandUnit::getModelById($id_unit);
             $zUnit = ModelInGameLandUnit::getModelByIdZAreaUserUnit((int) $id_game, $id_zarea, (int) $id_user, (int) $id_unit);
             $query = 'insert_land_units_for_move';
             $dict = array();
             $dict[':id_zunit'] = $zUnit->getId();
             $dict[':id_move'] = intval($id_move);
             $dict[':count'] = intval($count);
             DataSource::Singleton()->epp($query, $dict);
         }
     } catch (ModelException $ex) {
         self::flagMoveDeleted();
         throw $ex;
     } catch (NullPointerException $ex) {
         self::flagMoveDeleted();
         throw $ex;
     }
     return self::$moves[$id_game][$id_move] = new ModelProductionMove((int) $id_user, (int) $id_game, PHASE_PRODUCTION, (int) $id_move, (int) $round, false, $id_zarea, $units);
 }
 private function executeProduction(ModelProductionMove $move)
 {
     $id_user = $move->getIdUser();
     $id_zarea = $move->getIdZArea();
     foreach ($move->getUnits() as $id_unit => $count) {
         $inGameLandUnits = ModelInGameLandUnit::getModelByIdZAreaUserUnit($this->id_game, $id_zarea, $id_user, $id_unit);
         $inGameLandUnits->addCount($count);
     }
     if (!isset($this->spent_production[$id_user])) {
         $this->spent_production[$id_user] = 0;
     }
     $this->spent_production[$id_user] += $move->getCost();
 }