def non_combat_movement_phase(self, game: Game) -> None: ''' This is the function used in the non-combat phase. In this phase it is only allowed to move units in tiles that the current player own. The units are moved with the function game.move_unit(from_tile, to_tile, unit) This is just an example of how movement can be implemented. :param game: Is the object of the game that contains the map, units etc.. ''' while len(game.movable) > 0: if r.random() > 0.5: unit = game.movable[0] pos = unit.get_position() possible = [] for tile in game.map.board[pos[0]][pos[1]].neighbours: if tile.owner == game.current_player: possible.append(tile) if len(possible) == 0: game.movable.remove(game.movable[0]) break to_tile = r.choice(possible) if to_tile.owner == game.current_player: game.move_unit_friendly(game.map.board[pos[0]][pos[1]], to_tile, unit) else: break game.next_phase()
def non_combat_movement_phase(self, game: Game): """ This will force the bot to always advance towards the enemy In the non-combat moving phase. """ game.border_tiles = game.calculate_border() while len(game.movable) > 0: unit = game.movable[0] position = unit.get_position() new_tile = (-1, None) possible_tiles = [] for tile in game.map.board[position[0]][position[1]].neighbours: if tile.owner == unit.owner: for border_tile in game.border_tiles: value = game.calculate_distance_between_tiles( tile, border_tile) if new_tile[0] > value or new_tile[1] is None: new_tile = (value, tile) if value == 0: possible_tiles.append(tile) if new_tile[0] == 0: min_units = (-1, None) for tile in possible_tiles: if len(tile.units) < min_units[0] or min_units[1] is None: min_units = (len(tile.units), tile) game.move_unit_friendly( game.map.board[position[0]][position[1]], new_tile[1], unit) elif new_tile[0] == -1: game.movable.remove(game.movable[0]) elif new_tile[1] is not None: game.move_unit_friendly( game.map.board[position[0]][position[1]], new_tile[1], unit) game.next_phase()
def purchase_phase(self, game: Game): ''' In this phase, one should only buy units. The purchased units are placed into game.purchases. :param game: Is the object of the game that contains the map, units etc.. ''' while True: possible = game.recruitable() if len(possible) == 0: game.next_phase() break choice = r.randint(0, len(possible) - 1) game.recruit_unit(choice)
def moving_phase(self, game: Game)-> None: ''' This function will calculate the odds of winning the battle, if the chance is greater than the threshold defined, it will attack. :param game: Is the object of the game that contains the map, units etc.. ''' game.battles = [] while len(game.movable) > 0: if r.random() > 0.01: unit = game.movable[0] position = unit.get_position() to_tile = r.choice(game.map.board[position[0]][position[1]].neighbours) if to_tile.owner != game.current_player: all_units = game.find_movable_in_tile(position) attack_score = self.calc_winning_odds(all_units, to_tile.units) if attack_score > self.attack_threshold: for current_unit in all_units: game.move_unit(game.map.board[position[0]][position[1]], to_tile, current_unit) else: game.move_unit(game.map.board[position[0]][position[1]], to_tile, unit) else: break game.phase = 2.5
def __init__(self): bot = NewBot2(attack_threshold=0.1) bot2 = NewBot2(attack_threshold=0.35) germany = Nation(name='Germany', human=False, bot=bot) russia = Nation(name='Russia', human=False, bot=bot2) x, y = 4, 4 self.game = Game(size=(4, 4), nations=[germany, russia])
def moving_phase(self, game: Game): ''' This is the phase where one is supposed to move units, in friendly and unfriendly territory. If the unit is moved to a unfriendly tile, it will become a battle zone. The units are moved with the function game.move_unit(from_tile, to_tile, unit) :param game: Is the object of the game that contains the map, units etc.. ''' game.battles = [] while len(game.movable) > 0: if r.random() > 0.01: unit = game.movable[0] pos = unit.get_position() to_tile = r.choice(game.map.board[pos[0]][pos[1]].neighbours) if to_tile.owner != game.current_player: self.moved[to_tile.cords.__str__()] = pos game.move_unit(game.map.board[pos[0]][pos[1]], to_tile, unit) else: break game.phase = 2.5
def unit_placement_phase(self, game: Game): ''' This is the phase where one is to place the units purchased in the purchasing phase. One is only allowed to place units in a tile where there is industry. This functions randomly distributes the units. :param game: Is the object of the game that contains the map, units etc.. ''' if game.current_player in game.purchases and len( game.deployable_places) > 0: while len(game.purchases[game.current_player]) > 0: i = r.randint(0, len(game.deployable_places) - 1) tile = game.deployable_places[i] unit = game.purchases[game.current_player][0] game.purchases[game.current_player].remove(unit) tile.units.append(unit) unit.set_position(tile.cords) if game.is_there_a_winner()[0]: return True else: game.reset_all_units() if not game.valid_board()[0]: print(game.map.board) else: game.next_phase()
def prioritize_casualties(self, game: Game, values): """ This bot will prioritize to delete infs over tanks. """ to_be_deleted = dict() if 'Inf' in values[0]: if len(values[0]['Inf']) >= values[1]: for unit in values[0]['Inf']: if unit.type not in to_be_deleted: to_be_deleted[unit.type] = [] to_be_deleted[unit.type].append(unit) if len(to_be_deleted[unit.type]) == values[1]: break elif len(values[0]['Inf']) < values[1]: for unit in values[0]['Inf']: if unit.type not in to_be_deleted: to_be_deleted[unit.type] = [] to_be_deleted[unit.type].append(unit) diff = values[1] - len(to_be_deleted[unit.type]) for unit in values[0]['Tank']: if unit.type not in to_be_deleted: to_be_deleted[unit.type] = [] to_be_deleted[unit.type].append(unit) if len(to_be_deleted[unit.type]) == diff: break elif 'Tank' in values[0]: for unit in values[0]['Tank']: if unit.type not in to_be_deleted: to_be_deleted[unit.type] = [] to_be_deleted[unit.type].append(unit) if len(to_be_deleted[unit.type]) == values[1]: break for key in to_be_deleted: game.take_casualties(to_be_deleted, to_be_deleted[key][0].type, len(to_be_deleted[key]))
def prioritize_casualties(self, game: Game, values: tuple) -> None: ''' This function is used to randomly pick units to delete after a battle. After the units has been selected they are deleted by the use of game.take_casualties(). :param game: Is the object of the game that contains the map, units etc.. :param values: A tuple with units (dict), hit counter. ''' to_be_deleted = dict() attacker_types = list(values[0].keys()) for i in range(values[1]): unit_type = r.choice(attacker_types) unit = values[0][unit_type][0] if unit.type not in to_be_deleted: to_be_deleted[unit.type] = [] to_be_deleted[unit.type].append(unit) values[0][unit_type].remove(unit) if len(values[0][unit_type]) == 0: values[0].pop(unit_type, None) attacker_types = list(values[0].keys()) for key in to_be_deleted: game.take_casualties(to_be_deleted, to_be_deleted[key][0].type, len(to_be_deleted[key]))
def run_game(self, bot_1, bot_2): germany = Nation(name=str(bot_1.__module__), bot=bot_1) russia = Nation(name=str(bot_2.__module__), bot=bot_2) results = {} number_of_rounds = 100 for i in range(0, number_of_rounds): game = Game(size=(6, 6), nations=[germany, russia]) while True: game.bot() is_there_a_winner, winner = game.is_there_a_winner() if is_there_a_winner: if 'winner' not in results: results['winner'] = {} results['avg_rounds'] = {} if winner not in results['winner']: results['winner'][winner.name] = 0 results['avg_rounds'][winner.name] = 0 results['winner'][winner.name] += 1 results['avg_rounds'][ winner.name] += game.turn / number_of_rounds break return results
def combat_phase(self, game: Game) -> None: ''' This is the function thas performs the battle. It starts by picking a battle from the list of battles. This is done by using the function game.do_battle(battle_cords). (read that doc string if in doubt) :param game: Is the object of the game that contains the map, units etc.. :return: ''' while len(game.battles) > 0: results = game.do_battle(game.battles[0]) attacker = results[0] defender = results[1] attack_finished = False defend_finished = False if attacker[1] > 0: attacker_count = game.find_unit_count(attacker[0]) if attacker[1] >= attacker_count: game.take_casualties(attacker[0], 'All', attacker_count) attack_finished = True else: game.current_player.bot.prioritize_casualties( game, attacker) if defender[1] > 0: defender_count = game.find_unit_count(defender[0]) if defender[1] >= defender_count: game.take_casualties(defender[0], 'All', defender_count) defend_finished = True else: defender_keys = list(defender[0].keys()) if not defender[0][defender_keys[0]][0].owner.human: defender[0][defender_keys[0]][ 0].owner.bot.prioritize_casualties(game, defender) else: game.current_player = defender[0][ defender_keys[0]][0].owner return defender if defend_finished and not attack_finished: game.conquer_tile( game.map.board[game.battles[0][0]][game.battles[0][1]], game.current_player) if attack_finished or defend_finished: game.battles.remove(game.battles[0]) game.phase = 3
def initialization_phase(self, game: Game): ''' Prepares for the turn. Read the docstring @phase_0() :param game: Is the object of the game that contains the map, units etc.. ''' game.phase_0()
def moving_phase(self, game: Game): ''' This function would make the bot always move towards the enemy industry in an attempt to capture it, and then 'starve' them of units. :param game: Is the object of the game that contains the map, units etc.. :return: ''' game.battles = [] # Locate enemy industry target_tile = None for w in game.map.board: for h in w: if len(h.constructions) > 0 and h.owner.name is not game.current_player.name: target_tile = h if target_tile is not None: while len(game.movable) > 0: unit = game.movable[0] position = unit.get_position() new_tile = (-1, None) possible_tiles = [] for tile in game.map.board[position[0]][position[1]].neighbours: value = game.calculate_distance_between_tiles(tile, target_tile) if new_tile[0] > value or new_tile[1] is None: new_tile = (value, tile) if value == 0: possible_tiles.append(tile) if new_tile[0] == 0: min_units = (-1, None) for tile in possible_tiles: if len(tile.units) < min_units[0] or min_units[1] is None: min_units = (len(tile.units), tile) game.move_unit(game.map.board[position[0]][position[1]], new_tile[1], unit) elif new_tile[0] == -1: game.movable.remove(game.movable[0]) elif new_tile[1] is not None: game.move_unit(game.map.board[position[0]][position[1]], new_tile[1], unit) elif target_tile is None: while len(game.movable) > 0: if r.random() > 0.01: unit = game.movable[0] position = unit.get_position() to_tile = r.choice(game.map.board[position[0]][position[1]].neighbours) if to_tile.owner != game.current_player: all_units = game.find_movable_in_tile(position) attack_score = self.calc_winning_odds(all_units, to_tile.units) if attack_score > 0.15: for current_unit in all_units: game.move_unit(game.map.board[position[0]][position[1]], to_tile, current_unit) else: game.move_unit(game.map.board[position[0]][position[1]], to_tile, unit) else: break game.phase = 2.5
def purchase_inf(self, game: Game): game.recruit_unit(1)