Guest User

Example Meatshields AI Logic

a guest
Aug 24th, 2017
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 39.56 KB | None | 0 0
  1. <?php
  2.  
  3. abstract class TestAI extends AI {
  4.   static function getNextMove($gameInfo, $playerId) {
  5.     $vectorMapName = 'Map_' . $gameInfo['map_name'];
  6.     if (!class_exists($vectorMapName)) {
  7.       $vectorMapName = 'Map';
  8.     }
  9.     $vectors = $vectorMapName::getWaypointVectors();
  10.     $gameInfo = static::populateInfoArrays($gameInfo, $playerId);
  11.     $move = static::chooseMove($gameInfo, $playerId, $vectors);
  12.  
  13.     $purchase = false;
  14.     if (empty($move)) {
  15.       $purchase = static::purchaseUnit($gameInfo, $playerId, $vectors);
  16.     }
  17.  
  18.     $endTurn = false;
  19.     if (empty($move) && empty($purchase)) {
  20.       $endTurn = true;
  21.     }
  22.  
  23.     return ['move' => $move, 'purchase' => $purchase, 'end_turn' => $endTurn];
  24.   }
  25.  
  26.   static function chooseMove($gameInfo, $playerId, $vectors) {
  27.     $moveData = false;
  28.     $moveOptions = [
  29.       'movementPaths' => [],
  30.       'attackPaths' => [],
  31.       'rangedAttackPaths' => [],
  32.       'capturePaths' => []
  33.     ];
  34.  
  35.     // WRITE SOME LOGIC HERE TO DECIDE *WHICH* UNIT MOVES FIRST, NOT JUST ITERATING THROUGH
  36.  
  37.     // First, get all available options for moves
  38.     foreach ($gameInfo['owned_units'] as $unit) {
  39.       $movementPaths = [];
  40.       $attackPaths = [];
  41.       $rangedAttackPaths = [];
  42.       $capturePaths = [];
  43.  
  44.       if ($unit['moved'] == 1) {
  45.         continue;
  46.       }
  47.  
  48.       // Get an array structure of all tiles and recursively all tiles that could be moved to
  49.       // from that tile. Repeated until unit would be out of movement
  50.       $paths = static::getPaths($gameInfo, $playerId, $vectors, $unit);
  51.  
  52.       // Take the previous array and create a new array indexed by each tile id and containing
  53.       // the path of tiles that got this unit there.
  54.       $mappedPaths = [];
  55.       foreach ($paths as $path) {
  56.         static::mapTilePaths($gameInfo, $path, [], $mappedPaths);
  57.       }
  58.       // Add the tile that the unit starts on
  59.       $mappedPaths[$unit['tile_id']] = [
  60.         'path' => [],
  61.         'x' => $unit['x_coordinate'],
  62.         'y' => $unit['y_coordinate'],
  63.         'movesLeft' => intval($unit['unit_name']::MOVEMENT)
  64.       ];
  65.  
  66.       if ($unit['unit_name']::MOVE_THEN_ATTACK) {
  67.         $attackPaths = static::getAttackPaths($gameInfo, $mappedPaths, $unit);
  68.       } else {
  69.         $rangedAttackPaths = static::getRangedAttackPaths($gameInfo, $mappedPaths, $unit);
  70.       }
  71.  
  72.       if ($unit['unit_name']::CAN_CAPTURE) {
  73.         $capturePaths = static::getCapturePaths($gameInfo, $mappedPaths, $unit);
  74.       }
  75.  
  76.       if (!empty($attackPaths)) {
  77.         $moveOptions['attackPaths'][$unit['tile_id']] = $attackPaths;
  78.         $moveOptions['attackPaths'][$unit['tile_id']]['unit_name'] = $unit['unit_name'];
  79.         $moveOptions['attackPaths'][$unit['tile_id']]['x'] = $unit['x_coordinate'];
  80.         $moveOptions['attackPaths'][$unit['tile_id']]['y'] = $unit['y_coordinate'];
  81.         $moveOptions['attackPaths'][$unit['tile_id']]['tile_id'] = $unit['tile_id'];
  82.       }
  83.  
  84.       if (!empty($rangedAttackPaths)) {
  85.         $moveOptions['rangedAttackPaths'][$unit['tile_id']] = $rangedAttackPaths;
  86.         $moveOptions['rangedAttackPaths'][$unit['tile_id']]['unit_name'] = $unit['unit_name'];
  87.         $moveOptions['rangedAttackPaths'][$unit['tile_id']]['x'] = $unit['x_coordinate'];
  88.         $moveOptions['rangedAttackPaths'][$unit['tile_id']]['y'] = $unit['y_coordinate'];
  89.         $moveOptions['rangedAttackPaths'][$unit['tile_id']]['tile_id'] = $unit['tile_id'];
  90.       }
  91.  
  92.       if (!empty($capturePaths)) {
  93.         $moveOptions['capturePaths'][$unit['tile_id']] = $capturePaths;
  94.         $moveOptions['capturePaths'][$unit['tile_id']]['unit_name'] = $unit['unit_name'];
  95.         $moveOptions['capturePaths'][$unit['tile_id']]['x'] = $unit['x_coordinate'];
  96.         $moveOptions['capturePaths'][$unit['tile_id']]['y'] = $unit['y_coordinate'];
  97.         $moveOptions['capturePaths'][$unit['tile_id']]['tile_id'] = $unit['tile_id'];
  98.       }
  99.  
  100.       if (!empty($mappedPaths)) {
  101.         $moveOptions['movementPaths'][$unit['tile_id']] = $mappedPaths;
  102.         $moveOptions['movementPaths'][$unit['tile_id']]['unit_name'] = $unit['unit_name'];
  103.         $moveOptions['movementPaths'][$unit['tile_id']]['x'] = $unit['x_coordinate'];
  104.         $moveOptions['movementPaths'][$unit['tile_id']]['y'] = $unit['y_coordinate'];
  105.         $moveOptions['movementPaths'][$unit['tile_id']]['tile_id'] = $unit['tile_id'];
  106.       }
  107.     }
  108.  
  109.     // Then go through options and attempt to accomplish them in this order:
  110.     // 1) Start/finish capturing any available building
  111.     // 2) Attack with all ranged units
  112.     // 3) Attack with all melee units
  113.     // 4) Move all remaining units along the waypoint path toward enemy
  114.     // When all of these steps have been exhausted for every unit, end turn
  115.     if (!empty($moveOptions['capturePaths'])) {
  116.       $moveData = self::getCaptureMoveData($moveOptions);
  117.     }
  118.  
  119.     if (empty($moveData) && !empty($moveOptions['rangedAttackPaths'])) {
  120.       $moveData = self::getRangedAttackMoveData($moveOptions);
  121.     }
  122.  
  123.     if (empty($moveData) && !empty($moveOptions['attackPaths'])) {
  124.       $moveData = self::getAttackPathsMoveData($moveOptions);
  125.     }
  126.  
  127.     if (empty($moveData) && !empty($moveOptions['movementPaths'])) {
  128.       $moveData = self::getNormalMoveData($moveOptions, $vectors, $gameInfo, $playerId);
  129.     }
  130.  
  131.     // If, after all our options, a unit still doesn't have anywhere to be, try stumbling around
  132.     if (empty($moveData) && !empty($moveOptions['movementPaths'])) {
  133.       $moveData = self::getStumbleMoveData($moveOptions, $gameInfo);
  134.     }
  135.  
  136.     return $moveData;
  137.   }
  138.  
  139.   static function getCaptureMoveData($moveOptions) {
  140.     $keys = array_keys($moveOptions['capturePaths']);
  141.     $unitToMove = $moveOptions['capturePaths'][$keys[0]];
  142.  
  143.     $movements = [];
  144.     $unitChoices = array_keys($unitToMove);
  145.     $unitChoice = $unitToMove[$unitChoices[0]];
  146.  
  147.     foreach ($unitChoice['path'] as $tile) {
  148.       $movements[] = [
  149.           'xCoordinate' => intval($tile['x']),
  150.           'yCoordinate' => intval($tile['y'])
  151.       ];
  152.     }
  153.  
  154.     $moveData = [
  155.         'x_coordinate' => $unitToMove['x'],
  156.         'y_coordinate' => $unitToMove['y'],
  157.         'movements' => $movements,
  158.         'unit_action' => 'capture'
  159.     ];
  160.     return $moveData;
  161.   }
  162.  
  163.   static function getRangedAttackMoveData($moveOptions) {
  164.     $keys = array_keys($moveOptions['rangedAttackPaths']);
  165.     $unitToAttackWith = $moveOptions['rangedAttackPaths'][$keys[0]];
  166.  
  167.     $targets = array_keys($unitToAttackWith);
  168.     $target = $unitToAttackWith[$targets[0]];
  169.  
  170.     $moveData = [
  171.         'x_coordinate' => $unitToAttackWith['x'],
  172.         'y_coordinate' => $unitToAttackWith['y'],
  173.         'movements' => [],
  174.         'x_coord_attack' => $target['x'],
  175.         'y_coord_attack' => $target['y']
  176.     ];
  177.  
  178.     return $moveData;
  179.   }
  180.  
  181.   static function getAttackPathsMoveData($moveOptions) {
  182.     $keys = array_keys($moveOptions['attackPaths']);
  183.  
  184.     $highestDmg = -999;
  185.     $highestDamageUnit = false;
  186.     $highestDamageUnitTarget = false;
  187.     foreach ($keys as $unit) {
  188.       $unitToAttackWith = $moveOptions['attackPaths'][$unit];
  189.       $unitTargetOptions = array_keys($unitToAttackWith);
  190.       foreach ($unitTargetOptions as $targetOption) {
  191.         if (is_numeric($targetOption)) {
  192.           $outputDmg = $unitToAttackWith[$targetOption]['outputDmg'];
  193.           $returnDmg = $unitToAttackWith[$targetOption]['returnDmg'];
  194.           if (($outputDmg * 2) > $returnDmg) {
  195.             $damageDelta = $outputDmg - $returnDmg;
  196.             if ($damageDelta > $highestDmg) {
  197.               $highestDmg = $damageDelta;
  198.               $highestDamageUnit = $unitToAttackWith;
  199.               $highestDamageUnitTarget = $targetOption;
  200.             }
  201.           }
  202.         }
  203.       }
  204.     }
  205.  
  206.     if (empty($highestDamageUnit)) {
  207.       return false;
  208.     }
  209.  
  210.     $movements = [];
  211.     foreach ($highestDamageUnit[$highestDamageUnitTarget]['path'] as $tile) {
  212.       $movements[] = [
  213.           'xCoordinate' => intval($tile['x']),
  214.           'yCoordinate' => intval($tile['y'])
  215.       ];
  216.     }
  217.  
  218.     $moveData = [
  219.         'x_coordinate' => $highestDamageUnit['x'],
  220.         'y_coordinate' => $highestDamageUnit['y'],
  221.         'movements' => $movements,
  222.         'x_coord_attack' => $highestDamageUnit[$highestDamageUnitTarget]['x'],
  223.         'y_coord_attack' => $highestDamageUnit[$highestDamageUnitTarget]['y']
  224.     ];
  225.  
  226.     return $moveData;
  227.   }
  228.  
  229.   static function getNormalMoveData($moveOptions, $vectors, $gameInfo, $playerId) {
  230.  
  231.     $keys = array_keys($moveOptions['movementPaths']);
  232.     $unitToMove = $moveOptions['movementPaths'][$keys[0]];
  233.  
  234.     $waypointMovements = [];
  235.     $tileOptions = array_keys($unitToMove);
  236.     foreach ($tileOptions as $tileOption) {
  237.       foreach ($vectors as $i => $vector) {
  238.         if ((isset($unitToMove[$tileOption]['x'])) &&
  239.             (isset($unitToMove[$tileOption]['y'])) &&
  240.             ($unitToMove[$tileOption]['x'] == $vector['destination_x_coordinate']) &&
  241.             ($unitToMove[$tileOption]['y'] == $vector['destination_y_coordinate']) &&
  242.             ($gameInfo['players'][$playerId]['turn_order'] == $vector['offensive_turn_order'])) {
  243.               $tileInfo = $unitToMove[$tileOption];
  244.               $tileInfo['vectorIndex'] = $i;
  245.               $waypointMovements[] = $tileInfo;
  246.             }
  247.       }
  248.     }
  249.  
  250.     // Remove the tiles that aren't the ones farthest along the path
  251.     $waypointsToRemove = [];
  252.     foreach ($waypointMovements as $i => $waypoint) {
  253.       foreach ($waypointMovements as $j => $comparePoint) {
  254.         if ($i == $j) continue;
  255.         if (($vectors[$comparePoint['vectorIndex']]['origin_x_coordinate'] == $vectors[$waypoint['vectorIndex']]['destination_x_coordinate']) &&
  256.             ($vectors[$comparePoint['vectorIndex']]['origin_y_coordinate'] == $vectors[$waypoint['vectorIndex']]['destination_y_coordinate'])) {
  257.               $waypointsToRemove[] = $i;
  258.             }
  259.       }
  260.     }
  261.  
  262.     foreach ($waypointsToRemove as $i) {
  263.       unset($waypointMovements[$i]);
  264.     }
  265.     $waypointMovements = array_filter($waypointMovements);
  266.  
  267.     $alignedOptions = [];
  268.     if (!empty($waypointMovements)) {
  269.       shuffle($waypointMovements);
  270.       $chosenProximityWaypoint = $waypointMovements[0];
  271.       $possibleNextPoints = [];
  272.       foreach ($vectors as $vector) {
  273.         if (($vector['origin_x_coordinate'] == $chosenProximityWaypoint['x']) &&
  274.             ($vector['origin_y_coordinate'] == $chosenProximityWaypoint['y']) &&
  275.             ($vector['offensive_turn_order'] == $gameInfo['players'][$playerId]['turn_order'])) {
  276.               $possibleNextPoints[] = $vector;
  277.             }
  278.       }
  279.  
  280.       $chosenDestination = false;
  281.       foreach ($possibleNextPoints as $possibleNextPoint) {
  282.         if (($possibleNextPoint['destination_x_coordinate'] == $unitToMove['x']) ||
  283.             ($possibleNextPoint['destination_y_coordinate'] == $unitToMove['y'])) {
  284.               $chosenDestination = $possibleNextPoint;
  285.             }
  286.       }
  287.       if (!empty($possibleNextPoints)) {
  288.         if (empty($chosenDestination)) {
  289.           shuffle($possibleNextPoints);
  290.           $chosenDestination = $possibleNextPoints[0];
  291.         }
  292.  
  293.         if ($chosenProximityWaypoint['x'] == $chosenDestination['destination_x_coordinate']) {
  294.           $movementX = $chosenProximityWaypoint['x'];
  295.         } else {
  296.           $movementY = $chosenProximityWaypoint['y'];
  297.         }
  298.  
  299.         if (isset($movementX)) {
  300.           foreach ($unitToMove as $option) {
  301.             if (isset($option['x']) && ($option['x'] == $movementX)) {
  302.               $alignedOptions[] = $option;
  303.             }
  304.           }
  305.         } else {
  306.           foreach ($unitToMove as $option) {
  307.             if (isset($option['y']) && ($option['y'] == $movementY)) {
  308.               $alignedOptions[] = $option;
  309.             }
  310.           }
  311.         }
  312.  
  313.         $filteredOptions = [];
  314.         foreach ($alignedOptions as $alignedOption) {
  315.           if (empty($gameInfo['tiles'][$alignedOption['x']][$alignedOption['y']]['unit_name'])) {
  316.             $filteredOptions[] = $alignedOption;
  317.           } else {
  318.             if (($unitToMove['x'] == $alignedOption['x']) && ($unitToMove['y'] == $alignedOption['y'])) {
  319.               $filteredOptions[] = $alignedOption;
  320.             }
  321.           }
  322.         }
  323.         $alignedOptions = $filteredOptions;
  324.  
  325.         $closestOption = false;
  326.         $closestDistance = 999999;
  327.         foreach ($alignedOptions as $alignedOption) {
  328.           if (isset($movementX)) {
  329.             $distance = abs($alignedOption['y'] - $chosenDestination['destination_y_coordinate']);
  330.           } else {
  331.             $distance = abs($alignedOption['x'] - $chosenDestination['destination_x_coordinate']);
  332.           }
  333.           if ($distance < $closestDistance) {
  334.             $closestOption = $alignedOption;
  335.             $closestDistance = $distance;
  336.           }
  337.         }
  338.  
  339.         $movements = [];
  340.         if (!empty($closestOption)) {
  341.           foreach ($closestOption['path'] as $tile) {
  342.             $movements[] = [
  343.                 'xCoordinate' => intval($tile['x']),
  344.                 'yCoordinate' => intval($tile['y'])
  345.             ];
  346.           }
  347.  
  348.           $moveData = [
  349.               'x_coordinate' => $unitToMove['x'],
  350.               'y_coordinate' => $unitToMove['y'],
  351.               'movements' => $movements
  352.           ];
  353.  
  354.           return $moveData;
  355.         }
  356.       }
  357.     }
  358.     return false;
  359.   }
  360.  
  361.   static function getStumbleMoveData($moveOptions, $gameInfo) {
  362.     $keys = array_keys($moveOptions['movementPaths']);
  363.     $unitToMove = $moveOptions['movementPaths'][$keys[0]];
  364.     $moveData = [
  365.         'x_coordinate' => $unitToMove['x'],
  366.         'y_coordinate' => $unitToMove['y']
  367.     ];
  368.     unset($unitToMove['unit_name']);
  369.     unset($unitToMove['x']);
  370.     unset($unitToMove['y']);
  371.     unset($unitToMove['tile_id']);
  372.     $unitToMove = array_filter($unitToMove);
  373.  
  374.     if (!empty($unitToMove)) {
  375.       $filteredOptions = [];
  376.       foreach ($unitToMove as $moveOption) {
  377.         if (empty($gameInfo['tiles'][$moveOption['x']][$moveOption['y']]['unit_name'])) {
  378.           $filteredOptions[] = $moveOption;
  379.         }
  380.       }
  381.       $unitToMove = $filteredOptions;
  382.  
  383.       if (empty($unitToMove)) {
  384.         $moveData['movements'] = [];
  385.       } else {
  386.         shuffle($unitToMove);
  387.         $pathChoice = $unitToMove[0];
  388.         $movements = [];
  389.         foreach ($pathChoice['path'] as $tile) {
  390.           $movements[] = [
  391.               'xCoordinate' => intval($tile['x']),
  392.               'yCoordinate' => intval($tile['y'])
  393.           ];
  394.         }
  395.  
  396.         $moveData['movements'] = $movements;
  397.         return $moveData;
  398.       }
  399.     }
  400.     return false;
  401.   }
  402.  
  403.   static function getPaths($gameInfo, $playerId, $vectors, $unit) {
  404.     $movesLeft = intval($unit['unit_name']::MOVEMENT);
  405.     $moves = self::getPathsRecursive($gameInfo, $playerId, $unit, $unit, $movesLeft);
  406.     return $moves;
  407.   }
  408.  
  409.   static function getPathsRecursive($gameInfo, $playerId, $unit, $tile, $movesLeft) {
  410.     if ($movesLeft <= 0) {
  411.       return [];
  412.     }
  413.  
  414.     $validTiles = [];
  415.  
  416.     // Check north tile
  417.     $northX = intval($tile['x_coordinate']);
  418.     $northY = intval($tile['y_coordinate']) - 1;
  419.     if (isset($gameInfo['tiles'][$northX]) && isset($gameInfo['tiles'][$northX][$northY])) {
  420.       $northTile = $gameInfo['tiles'][$northX][$northY];
  421.  
  422.       if (self::isValidMoveTile($northTile, $movesLeft, $unit)) {
  423.         $tileToAdd = [
  424.           'tileId' => $northTile['tile_id'],
  425.           'x' => $northTile['x_coordinate'],
  426.           'y' => $northTile['y_coordinate'],
  427.           'movesLeft' => $movesLeft - $unit['unit_name']::getMovementCost($northTile['terrain_name'])
  428.         ];
  429.         $childTiles = static::getPathsRecursive($gameInfo, $playerId, $unit, $northTile,
  430.           $movesLeft - $unit['unit_name']::getMovementCost($northTile['terrain_name']));
  431.         $tileToAdd['childTiles'] = $childTiles;
  432.         $validTiles[] = $tileToAdd;
  433.       }
  434.     }
  435.  
  436.     // Check east tile
  437.     $eastX = intval($tile['x_coordinate']) + 1;
  438.     $eastY = intval($tile['y_coordinate']);
  439.     if (isset($gameInfo['tiles'][$eastX]) && isset($gameInfo['tiles'][$eastX][$eastY])) {
  440.       $eastTile = $gameInfo['tiles'][$eastX][$eastY];
  441.  
  442.       if (self::isValidMoveTile($eastTile, $movesLeft, $unit)) {
  443.         $tileToAdd = [
  444.           'tileId' => $eastTile['tile_id'],
  445.           'x' => $eastTile['x_coordinate'],
  446.           'y' => $eastTile['y_coordinate'],
  447.           'movesLeft' => $movesLeft - $unit['unit_name']::getMovementCost($eastTile['terrain_name'])
  448.         ];
  449.         $childTiles = static::getPathsRecursive($gameInfo, $playerId, $unit, $eastTile,
  450.           $movesLeft - $unit['unit_name']::getMovementCost($eastTile['terrain_name']));
  451.         $tileToAdd['childTiles'] = $childTiles;
  452.         $validTiles[] = $tileToAdd;
  453.       }
  454.     }
  455.  
  456.     // Check south tile
  457.     $southX = intval($tile['x_coordinate']);
  458.     $southY = intval($tile['y_coordinate']) + 1;
  459.     if (isset($gameInfo['tiles'][$southX]) && isset($gameInfo['tiles'][$southX][$southY])) {
  460.       $southTile = $gameInfo['tiles'][$southX][$southY];
  461.  
  462.       if (self::isValidMoveTile($southTile, $movesLeft, $unit)) {
  463.         $tileToAdd = [
  464.           'tileId' => $southTile['tile_id'],
  465.           'x' => $southTile['x_coordinate'],
  466.           'y' => $southTile['y_coordinate'],
  467.           'movesLeft' => $movesLeft - $unit['unit_name']::getMovementCost($southTile['terrain_name'])
  468.         ];
  469.         $childTiles = static::getPathsRecursive($gameInfo, $playerId, $unit, $southTile,
  470.           $movesLeft - $unit['unit_name']::getMovementCost($southTile['terrain_name']));
  471.         $tileToAdd['childTiles'] = $childTiles;
  472.         $validTiles[] = $tileToAdd;
  473.       }
  474.     }
  475.  
  476.     // Check west tile
  477.     $westX = intval($tile['x_coordinate']) - 1;
  478.     $westY = intval($tile['y_coordinate']);
  479.     if (isset($gameInfo['tiles'][$westX]) && isset($gameInfo['tiles'][$westX][$westY])) {
  480.       $westTile = $gameInfo['tiles'][$westX][$westY];
  481.  
  482.       if (self::isValidMoveTile($westTile, $movesLeft, $unit)) {
  483.         $tileToAdd = [
  484.           'tileId' => $westTile['tile_id'],
  485.           'x' => $westTile['x_coordinate'],
  486.           'y' => $westTile['y_coordinate'],
  487.           'movesLeft' => $movesLeft - $unit['unit_name']::getMovementCost($westTile['terrain_name'])
  488.         ];
  489.         $childTiles = static::getPathsRecursive($gameInfo, $playerId, $unit, $westTile,
  490.           $movesLeft - $unit['unit_name']::getMovementCost($westTile['terrain_name']));
  491.         $tileToAdd['childTiles'] = $childTiles;
  492.         $validTiles[] = $tileToAdd;
  493.       }
  494.     }
  495.  
  496.     return $validTiles;
  497.   }
  498.  
  499.   static function isValidMoveTile($tile, $movesLeft, $unit) {
  500.     if ($tile['tile_id'] == $unit['tile_id']) {
  501.       return false;
  502.     }
  503.  
  504.     if (!empty($tile['unit_team_name']) && $tile['unit_team_name'] != $unit['unit_team_name']) {
  505.       return false;
  506.     }
  507.  
  508.     $movementCost = $unit['unit_name']::getMovementCost($tile['terrain_name']);
  509.     if (($movementCost < 0) || ($movesLeft < $movementCost)) {
  510.       return false;
  511.     }
  512.  
  513.     return true;
  514.   }
  515.  
  516.   static function mapTilePaths($gameInfo, $tile, $pathArr, &$mappedPaths) {
  517.     $newPathArr = $pathArr;
  518.     $newPathArr[] = $tile;
  519.  
  520.     if (isset($mappedPaths[$tile['tileId']])) {
  521.       if ($mappedPaths[$tile['tileId']]['movesLeft'] < $tile['movesLeft']) {
  522.         $mappedPaths[$tile['tileId']] = [
  523.           'path' => $newPathArr,
  524.           'x' => $tile['x'],
  525.           'y' => $tile['y'],
  526.           'movesLeft' => $tile['movesLeft']
  527.         ];
  528.       }
  529.     } else {
  530.       $mappedPaths[$tile['tileId']] = [
  531.           'path' => $newPathArr,
  532.           'x' => $tile['x'],
  533.           'y' => $tile['y'],
  534.           'movesLeft' => $tile['movesLeft']
  535.       ];
  536.     }
  537.  
  538.     foreach ($tile['childTiles'] as $childTile) {
  539.       static::mapTilePaths($gameInfo, $childTile, $newPathArr, $mappedPaths);
  540.     }
  541.   }
  542.  
  543.   static function getAttackPaths($gameInfo, $mappedPaths, $attackingUnit) {
  544.     $attackPaths = [];
  545.     if (!$attackingUnit['unit_name']::CAN_ATTACK) {
  546.       return [];
  547.     }
  548.  
  549.     $attackerHP = $attackingUnit['health'];
  550.     $attackerBaseHP = $attackingUnit['unit_name']::HEALTH;
  551.  
  552.     foreach ($mappedPaths as $tileId => $path) {
  553.  
  554.       // Skip checking path
  555.       if (!empty($gameInfo['tiles'][$path['x']][$path['y']]['deployed_unit_id']) &&
  556.         ($gameInfo['tiles'][$path['x']][$path['y']]['deployed_unit_id'] != $attackingUnit['deployed_unit_id'])) {
  557.         continue;
  558.       }
  559.  
  560.       $attackTile = $gameInfo['tiles'][$path['x']][$path['y']];
  561.  
  562.       // Check north tile
  563.       $northX = intval($path['x']);
  564.       $northY = intval($path['y']) - 1;
  565.       if (isset($gameInfo['tiles'][$northX]) && isset($gameInfo['tiles'][$northX][$northY])) {
  566.         $northTile = $gameInfo['tiles'][$northX][$northY];
  567.  
  568.         if (!empty($northTile['unit_team_name']) && ($northTile['unit_team_name'] != $attackingUnit['unit_team_name'])) {
  569.           $baseOutputDmg = $attackingUnit['unit_name']::getBaseOutputDamage($northTile['unit_name']);
  570.           $outputDmg = intval(($baseOutputDmg * ($attackerHP / $attackerBaseHP)) * (1 - ($northTile['defense'] / 10)));
  571.  
  572.           $newDefenderHP = $northTile['health'] - $outputDmg;
  573.           $defenderBaseHP = $northTile['unit_name']::HEALTH;
  574.           $baseReturnDmg = $northTile['unit_name']::getBaseOutputDamage($attackingUnit['unit_name']);
  575.           $returnDmg = intval(($baseReturnDmg * ($newDefenderHP / $defenderBaseHP)) * (1 - ($attackTile['defense'] / 10)));
  576.  
  577.           if (empty($attackPaths[$northTile['tile_id']])) {
  578.             $attackPaths[$northTile['tile_id']] = [
  579.               'path' => $path['path'],
  580.               'x' => $northTile['x_coordinate'],
  581.               'y' => $northTile['y_coordinate'],
  582.               'movesLeft' => $path['movesLeft'],
  583.               'outputDmg' => $outputDmg,
  584.               'returnDmg' => $returnDmg
  585.             ];
  586.           } else if ($path['movesLeft'] > $attackPaths[$northTile['tile_id']]['movesLeft']) {
  587.             $attackPaths[$northTile['tile_id']] = [
  588.               'path' => $path['path'],
  589.               'x' => $northTile['x_coordinate'],
  590.               'y' => $northTile['y_coordinate'],
  591.               'movesLeft' => $path['movesLeft'],
  592.               'outputDmg' => $outputDmg,
  593.               'returnDmg' => $returnDmg
  594.             ];
  595.           }
  596.         }
  597.       }
  598.  
  599.       // Check east tile
  600.       $eastX = intval($path['x']) + 1;
  601.       $eastY = intval($path['y']);
  602.       if (isset($gameInfo['tiles'][$eastX]) && isset($gameInfo['tiles'][$eastX][$eastY])) {
  603.         $eastTile = $gameInfo['tiles'][$eastX][$eastY];
  604.  
  605.         if (!empty($eastTile['unit_team_name']) && ($eastTile['unit_team_name'] != $attackingUnit['unit_team_name'])) {
  606.           $baseOutputDmg = $attackingUnit['unit_name']::getBaseOutputDamage($eastTile['unit_name']);
  607.           $outputDmg = intval(($baseOutputDmg * ($attackerHP / $attackerBaseHP)) * (1 - ($eastTile['defense'] / 10)));
  608.  
  609.           $newDefenderHP = $eastTile['health'] - $outputDmg;
  610.           $defenderBaseHP = $eastTile['unit_name']::HEALTH;
  611.           $baseReturnDmg = $eastTile['unit_name']::getBaseOutputDamage($attackingUnit['unit_name']);
  612.           $returnDmg = intval(($baseReturnDmg * ($newDefenderHP / $defenderBaseHP)) * (1 - ($attackTile['defense'] / 10)));
  613.  
  614.           if (empty($attackPaths[$eastTile['tile_id']])) {
  615.             $attackPaths[$eastTile['tile_id']] = [
  616.               'path' => $path['path'],
  617.               'x' => $eastTile['x_coordinate'],
  618.               'y' => $eastTile['y_coordinate'],
  619.               'movesLeft' => $path['movesLeft'],
  620.               'outputDmg' => $outputDmg,
  621.               'returnDmg' => $returnDmg
  622.             ];
  623.           } else if ($path['movesLeft'] > $attackPaths[$eastTile['tile_id']]['movesLeft']) {
  624.             $attackPaths[$eastTile['tile_id']] = [
  625.               'path' => $path['path'],
  626.               'x' => $eastTile['x_coordinate'],
  627.               'y' => $eastTile['y_coordinate'],
  628.               'movesLeft' => $path['movesLeft'],
  629.               'outputDmg' => $outputDmg,
  630.               'returnDmg' => $returnDmg
  631.             ];
  632.           }
  633.         }
  634.       }
  635.  
  636.       // Check south tile
  637.       $southX = intval($path['x']);
  638.       $southY = intval($path['y']) + 1;
  639.       if (isset($gameInfo['tiles'][$southX]) && isset($gameInfo['tiles'][$southX][$southY])) {
  640.         $southTile = $gameInfo['tiles'][$southX][$southY];
  641.  
  642.         if (!empty($southTile['unit_team_name']) && ($southTile['unit_team_name'] != $attackingUnit['unit_team_name'])) {
  643.           $baseOutputDmg = $attackingUnit['unit_name']::getBaseOutputDamage($southTile['unit_name']);
  644.           $outputDmg = intval(($baseOutputDmg * ($attackerHP / $attackerBaseHP)) * (1 - ($southTile['defense'] / 10)));
  645.  
  646.           $newDefenderHP = $southTile['health'] - $outputDmg;
  647.           $defenderBaseHP = $southTile['unit_name']::HEALTH;
  648.           $baseReturnDmg = $southTile['unit_name']::getBaseOutputDamage($attackingUnit['unit_name']);
  649.           $returnDmg = intval(($baseReturnDmg * ($newDefenderHP / $defenderBaseHP)) * (1 - ($attackTile['defense'] / 10)));
  650.  
  651.           if (empty($attackPaths[$southTile['tile_id']])) {
  652.             $attackPaths[$southTile['tile_id']] = [
  653.               'path' => $path['path'],
  654.               'x' => $southTile['x_coordinate'],
  655.               'y' => $southTile['y_coordinate'],
  656.               'movesLeft' => $path['movesLeft'],
  657.               'outputDmg' => $outputDmg,
  658.               'returnDmg' => $returnDmg
  659.             ];
  660.           } else if ($path['movesLeft'] > $attackPaths[$southTile['tile_id']]['movesLeft']) {
  661.             $attackPaths[$southTile['tile_id']] = [
  662.               'path' => $path['path'],
  663.               'x' => $southTile['x_coordinate'],
  664.               'y' => $southTile['y_coordinate'],
  665.               'movesLeft' => $path['movesLeft'],
  666.               'outputDmg' => $outputDmg,
  667.               'returnDmg' => $returnDmg
  668.             ];
  669.           }
  670.         }
  671.       }
  672.  
  673.       // Check west tile
  674.       $westX = intval($path['x']) - 1;
  675.       $westY = intval($path['y']);
  676.       if (isset($gameInfo['tiles'][$westX]) && isset($gameInfo['tiles'][$westX][$westY])) {
  677.         $westTile = $gameInfo['tiles'][$westX][$westY];
  678.  
  679.         if (!empty($westTile['unit_team_name']) && ($westTile['unit_team_name'] != $attackingUnit['unit_team_name'])) {
  680.           $baseOutputDmg = $attackingUnit['unit_name']::getBaseOutputDamage($westTile['unit_name']);
  681.           $outputDmg = intval(($baseOutputDmg * ($attackerHP / $attackerBaseHP)) * (1 - ($westTile['defense'] / 10)));
  682.  
  683.           $newDefenderHP = $westTile['health'] - $outputDmg;
  684.           $defenderBaseHP = $westTile['unit_name']::HEALTH;
  685.           $baseReturnDmg = $westTile['unit_name']::getBaseOutputDamage($attackingUnit['unit_name']);
  686.           $returnDmg = intval(($baseReturnDmg * ($newDefenderHP / $defenderBaseHP)) * (1 - ($attackTile['defense'] / 10)));
  687.  
  688.           if (empty($attackPaths[$westTile['tile_id']])) {
  689.             $attackPaths[$westTile['tile_id']] = [
  690.               'path' => $path['path'],
  691.               'x' => $westTile['x_coordinate'],
  692.               'y' => $westTile['y_coordinate'],
  693.               'movesLeft' => $path['movesLeft'],
  694.               'outputDmg' => $outputDmg,
  695.               'returnDmg' => $returnDmg
  696.             ];
  697.           } else if ($path['movesLeft'] > $attackPaths[$westTile['tile_id']]['movesLeft']) {
  698.             $attackPaths[$westTile['tile_id']] = [
  699.               'path' => $path['path'],
  700.               'x' => $westTile['x_coordinate'],
  701.               'y' => $westTile['y_coordinate'],
  702.               'movesLeft' => $path['movesLeft'],
  703.               'outputDmg' => $outputDmg,
  704.               'returnDmg' => $returnDmg
  705.             ];
  706.           }
  707.         }
  708.       }
  709.     }
  710.     return $attackPaths;
  711.   }
  712.  
  713.   static function getRangedAttackPaths($gameInfo, $mappedPaths, $attackingUnit) {
  714.     $attackPaths = [];
  715.     if (!$attackingUnit['unit_name']::CAN_ATTACK) {
  716.       return [];
  717.     }
  718.  
  719.     foreach ($gameInfo['tiles'] as $x => $tileColumn) {
  720.       foreach ($tileColumn as $y => $tile) {
  721.         $distance = abs((intval($x) - intval($attackingUnit['x_coordinate']))) +
  722.          abs(intval($y) - intval($attackingUnit['y_coordinate']));
  723.         if ($distance >= $attackingUnit['unit_name']::RANGE_DISTANCE_START &&
  724.             $distance <= $attackingUnit['unit_name']::RANGE_DISTANCE_END) {
  725.           if (!empty($tile['unit_team_name']) && ($tile['unit_team_name'] != $attackingUnit['unit_team_name'])) {
  726.             $attackPaths[$tile['tile_id']] = [
  727.               'path' => [],
  728.               'x' => $x,
  729.               'y' => $y
  730.             ];
  731.           }
  732.         }
  733.       }
  734.     }
  735.     return $attackPaths;
  736.   }
  737.  
  738.   static function getCapturePaths($gameInfo, $mappedPaths, $capturingUnit) {
  739.     $capturePaths = [];
  740.  
  741.     $capturingTile = $gameInfo['tiles'][$capturingUnit['x_coordinate']][$capturingUnit['y_coordinate']];
  742.     if (!empty($capturingUnit['capture_remaining']) && ($capturingTile['building_team_name'] != $capturingUnit['unit_team_name'])) {
  743.       $capturePaths[$capturingUnit['tile_id']] = [
  744.         'path' => [],
  745.         'x' => $capturingUnit['x_coordinate'],
  746.         'y' => $capturingUnit['y_coordinate']
  747.       ];
  748.       return $capturePaths;
  749.     }
  750.  
  751.     foreach ($mappedPaths as $path) {
  752.       $tile = $gameInfo['tiles'][$path['x']][$path['y']];
  753.       if (class_exists($tile['terrain_name'])) {
  754.         if ($tile['building_team_name'] != $capturingUnit['unit_team_name']) {
  755.           if (empty($tile['unit_name'])) {
  756.             $capturePaths[$tile['tile_id']] = [
  757.               'path' => $path['path'],
  758.               'x' => $tile['x_coordinate'],
  759.               'y' => $tile['y_coordinate']
  760.             ];
  761.           }
  762.         }
  763.       }
  764.     }
  765.     return $capturePaths;
  766.   }
  767.  
  768.   static function purchaseUnit($gameInfo, $playerId, $vectors) {
  769.     $buildingTiles = [];
  770.     foreach ($gameInfo['tiles'] as $x => $tileColumn) {
  771.       foreach ($tileColumn as $y => $tile) {
  772.         $terrainName = $tile['terrain_name'];
  773.         if (!empty($tile['building_army_name']) &&
  774.             empty($tile['unit_name']) &&
  775.             ($tile['building_army_name'] == $gameInfo['players'][$playerId]['army_name']) &&
  776.             class_exists($terrainName) &&
  777.             !empty($terrainName::getProducableUnits())) {
  778.  
  779.           $buildingTiles[] = $tile;
  780.         }
  781.       }
  782.     }
  783.  
  784.     $unitToBuy = false;
  785.     if (!empty($buildingTiles)) {
  786.       shuffle($buildingTiles);
  787.  
  788.       $unitToBuy = self::getWeightedUnitDecision($gameInfo, $playerId);
  789.  
  790.       if (!empty($unitToBuy)) {
  791.         $unitToBuy = [
  792.           'x_coordinate' => $buildingTiles[0]['x_coordinate'],
  793.           'y_coordinate' => $buildingTiles[0]['y_coordinate'],
  794.           'unit_name' => $unitToBuy
  795.         ];
  796.       }
  797.     }
  798.  
  799.     return $unitToBuy;
  800.   }
  801.  
  802.   static function getWeightedUnitDecision($gameInfo, $playerId) {
  803.     $purchaseableUnits = ['Boulder','Brimstone','Centaur','Giant','Knight','Mage','Mount','Ninja','Troll'];
  804.     $unitWeights = [];
  805.     $affordableUnits = [];
  806.     foreach ($purchaseableUnits as $unit) {
  807.       if ($unit::PRICE <= $gameInfo['players'][$playerId]['funds']) {
  808.         $unitWeights[$unit] = 1;
  809.         $affordableUnits[] = $unit;
  810.       }
  811.     }
  812.  
  813.     // Check to see if bot has any units at all
  814.     $unitCount = count($gameInfo['owned_units']);
  815.     if ($unitCount < 1) {
  816.       return 'Knight';
  817.     }
  818.  
  819.     // Check if bot needs more units that can capture
  820.     $numUnitsCanCapture = 0;
  821.     foreach ($gameInfo['owned_units'] as $unit) {
  822.       if ($unit['unit_name']::CAN_CAPTURE) {
  823.         $numUnitsCanCapture++;
  824.       }
  825.     }
  826.  
  827.     $percentForceCanCapture = ($numUnitsCanCapture / $unitCount) * 100;
  828.     if (($percentForceCanCapture < 9) || ($numUnitsCanCapture < 3)) {
  829.       if (in_array('Knight', $affordableUnits)) $unitWeights['Knight']+= 10;
  830.       if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja']+= 10;
  831.     }
  832.  
  833.     // Assign weights to purchaseable units based on enemy units
  834.     foreach ($gameInfo['enemy_units'] as $enemyUnit) {
  835.       switch ($enemyUnit['unit_name']) {
  836.         case 'Knight':
  837.         case 'Ninja':
  838.         case 'Archer':
  839.           if (in_array('Knight', $affordableUnits)) $unitWeights['Knight'] += 1;
  840.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  841.           if (in_array('Mount', $affordableUnits)) $unitWeights['Mount'] += 1.3;
  842.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 1.3;
  843.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 1;
  844.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 1;
  845.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 1;
  846.           break;
  847.         case 'Mount':
  848.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  849.           if (in_array('Mount', $affordableUnits)) $unitWeights['Ninja'] += 1;
  850.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 2;
  851.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 2;
  852.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 2;
  853.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 2;
  854.           break;
  855.         case 'Boulder':
  856.           if (in_array('Knight', $affordableUnits)) $unitWeights['Knight'] += 1;
  857.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  858.           if (in_array('Mount', $affordableUnits)) $unitWeights['Ninja'] += 1;
  859.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 2;
  860.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 2;
  861.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 2;
  862.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 2;
  863.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 2;
  864.           break;
  865.         case 'Unicorn':
  866.           if (in_array('Knight', $affordableUnits)) $unitWeights['Knight'] += 1;
  867.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  868.           if (in_array('Mount', $affordableUnits)) $unitWeights['Ninja'] += 1;
  869.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  870.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 2;
  871.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 2;
  872.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  873.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 2;
  874.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 2;
  875.           break;
  876.         case 'Mage':
  877.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  878.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  879.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 1;
  880.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 2;
  881.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  882.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 2;
  883.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 2;
  884.           break;
  885.         case 'Centaur':
  886.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 1;
  887.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  888.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 3;
  889.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  890.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 4;
  891.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 4;
  892.           break;
  893.         case 'Net':
  894.           if (in_array('Knight', $affordableUnits)) $unitWeights['Knight'] += 1;
  895.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 2;
  896.           if (in_array('Mount', $affordableUnits)) $unitWeights['Ninja'] += 2;
  897.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  898.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 3;
  899.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 3;
  900.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  901.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 3;
  902.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 3;
  903.           break;
  904.         case 'Brimstone':
  905.           if (in_array('Knight', $affordableUnits)) $unitWeights['Knight'] += 1;
  906.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 2;
  907.           if (in_array('Mount', $affordableUnits)) $unitWeights['Ninja'] += 2;
  908.           if (in_array('Mage', $affordableUnits)) $unitWeights['Mage'] += 3;
  909.           if (in_array('Centaur', $affordableUnits)) $unitWeights['Centaur'] += 3;
  910.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  911.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 3;
  912.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 3;
  913.           break;
  914.         case 'Troll':
  915.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 2;
  916.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  917.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  918.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 4;
  919.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 5;
  920.           break;
  921.         case 'Giant':
  922.           if (in_array('Ninja', $affordableUnits)) $unitWeights['Ninja'] += 2;
  923.           if (in_array('Boulder', $affordableUnits)) $unitWeights['Boulder'] += 1;
  924.           if (in_array('Brimstone', $affordableUnits)) $unitWeights['Brimstone'] += 1;
  925.           if (in_array('Troll', $affordableUnits)) $unitWeights['Troll'] += 5;
  926.           if (in_array('Giant', $affordableUnits)) $unitWeights['Giant'] += 5;
  927.           break;
  928.       }
  929.     }
  930.  
  931.     // Adjust weights to purchaseable units based on owned units
  932.     $ownedUnitCountArr = [];
  933.     foreach ($gameInfo['owned_units'] as $unit) {
  934.       if (!empty($unitWeights[$unit['unit_name']])) {
  935.         $unitWeights[$unit['unit_name']] = $unitWeights[$unit['unit_name']] * 0.75;
  936.       }
  937.       if (empty($ownedUnitCountArr[$unit['unit_name']])) {
  938.         $ownedUnitCountArr[$unit['unit_name']] = 1;
  939.       } else {
  940.         $ownedUnitCountArr[$unit['unit_name']] += 1;
  941.       }
  942.     }
  943.  
  944.     // Adjust weights to purchaseable units based on missing unit variety
  945.     foreach ($affordableUnits as $unitName) {
  946.       if (empty($ownedUnitCountArr[$unitName])) {
  947.         $unitWeights[$unitName] += 1;
  948.       }
  949.     }
  950.  
  951.     // Pick the winner
  952.     if (empty($unitWeights)) {
  953.       return false;
  954.     }
  955.  
  956.     $candidateUnitNames = array_keys($unitWeights);
  957.     $chosenUnitName = $candidateUnitNames[0];
  958.     $chosenUnitScore = $unitWeights[$chosenUnitName];
  959.     foreach ($unitWeights as $unitName => $unitScore) {
  960.       if ($unitScore == $chosenUnitScore) {
  961.         if ($unitName::PRICE < $chosenUnitName::PRICE) {
  962.           $chosenUnitName = $unitName;
  963.           $chosenUnitScore = $unitScore;
  964.         }
  965.       } else if ($unitScore > $chosenUnitScore) {
  966.         $chosenUnitName = $unitName;
  967.         $chosenUnitScore = $unitScore;
  968.       }
  969.     }
  970.  
  971.     // Save money if we have enough knights and ninjas
  972.     if ($chosenUnitName == 'Knight' || $chosenUnitName == 'Ninja') {
  973.       if ((count($gameInfo['owned_units']) > 7) && ($percentForceCanCapture > 40)) {
  974.         return false;
  975.       }
  976.     }
  977.  
  978.     return $chosenUnitName;
  979.   }
  980. }
Advertisement
Add Comment
Please, Sign In to add comment