def game_instance(): game_map = MapGenerator(5, 5).generate(GAME_MAP) # Initialize game engine game_engine = GameEngine(game_map) map_proxy = MapProxy(game_engine) game_object_proxy = GameObjectProxy(game_engine) game_control_proxy = GameControlProxy(game_engine) game_uncertainty_proxy = GameUncertaintyProxy(game_engine) # Register defender defender = Player(map_proxy, game_object_proxy, game_control_proxy, game_uncertainty_proxy) game_engine.register_player(defender, PlayerResources(1000, 10), []) # Register attacker attacker = AIPlayer(map_proxy, game_object_proxy, game_control_proxy, game_uncertainty_proxy) game_engine.register_player(attacker, PlayerResources(200, 0, 0), []) game_engine.start(500) game_engine.spawn_unit(SpawnInformation(defender, GameObjectType.BASE, OffsetPosition(0, 0), [], [])) game_engine.spawn_unit(SpawnInformation(attacker, GameObjectType.DEMON, OffsetPosition(0, -2), [], [])) game_engine.spawn_unit(SpawnInformation(attacker, GameObjectType.DEMON, OffsetPosition(-1, -1), [], [])) attacker.initialize() return map_proxy, game_object_proxy, game_control_proxy, game_uncertainty_proxy, defender, attacker, game_engine
def pl(self): print("FUUUCK") pos = OffsetPosition(-3, -4).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.ENT, pos, [], [])) pos = OffsetPosition(-4, -3).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.ENT, pos, [], []))
def __river_start_position(self) -> Position: """ Get river start position """ left_bottom_corner = OffsetPosition(-self.__horizontal_radius, self.__vertical_radius) right_bottom_corner = OffsetPosition(self.__horizontal_radius, self.__vertical_radius) while True: starting_position = self.__pick_random_position( self.__border_tiles) if starting_position != left_bottom_corner and starting_position != right_bottom_corner: break return starting_position
def build_base(self, position_q: int, position_r: int): Logger.log('Building base') self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.BASE, OffsetPosition(int(position_q), int(position_r)), [], []))
def test_spawn_different_role(game_control_proxy, defender): with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.DEMON, OffsetPosition(1, 1), [], []) game_control_proxy.spawn_unit(si) assert 'Attempt to spawn unit of different role!' in str(exc.value)
def test_spawn_on_edge(game_control_proxy, defender): with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.ARCHER, OffsetPosition(-1, -2), [], []) game_control_proxy.spawn_unit(si) assert 'Cannot spawn unit defender unit on the map edge.' in str(exc.value)
def test_spawn_second_base(game_control_proxy, defender): with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.BASE, OffsetPosition(1, 1), [], []) game_control_proxy.spawn_unit(si) assert 'You cannot spawn additional base!' in str(exc.value)
def __init__(self, width: int, height: int, seed: int = None): """ :param width: - width of the map (must be ood number) :param height: - height of the map (must be odd number) :param seed: - random seed for generating map """ self.__width = width self.__height = height self.__vertical_radius = (height - 1) // 2 self.__horizontal_radius = (width - 1) // 2 self.__game_map = GameMap(width, height) self.__border_tiles = self.__game_map.border_tiles self.__initialize_generator_config() if not seed: seed = Config.MAP_RANDOM_SEED if not seed: seed = int.from_bytes(os.urandom(50), 'big') Config.MAP_RANDOM_SEED = seed random.seed(seed) self.__base_random_list = self.create_base_random_list() for i in range(-self.__vertical_radius, self.__vertical_radius + 1): for j in range(-self.__horizontal_radius, self.__horizontal_radius + 1): self.__game_map.set_tile(OffsetPosition(i, j), Field())
def test_spawn_unit_out_of_map(game_control_proxy, defender): with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.ARCHER, OffsetPosition(0, -5), [], []) game_control_proxy.spawn_unit(si) assert 'Position is not on the map!' in str(exc.value)
def test_spawn_unit_not_visible_tile(game_control_proxy, defender): with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.ARCHER, OffsetPosition(0, -2), [], []) game_control_proxy.spawn_unit(si) assert 'Attempt to spawn unit at not visible tile!' in str(exc.value)
def tiles(self): """ Iterator for all map tiles """ for y in range(-self.__horizontal_radius, self.__horizontal_radius + 1): for x in range(-self.__vertical_radius, self.__vertical_radius + 1): yield OffsetPosition(y, x)
def border_tiles(self) -> Set[Position]: """ Retrieves set of tiles on the edge of game map :return: Set of border tiles """ border_tiles = set() for x in range(-self.__horizontal_radius, self.__horizontal_radius + 1): border_tiles.add(OffsetPosition(x, -self.__vertical_radius)) border_tiles.add(OffsetPosition(x, self.__vertical_radius)) for y in range(-self.__vertical_radius, self.__vertical_radius + 1): border_tiles.add(OffsetPosition(-self.__horizontal_radius, y)) border_tiles.add(OffsetPosition(self.__horizontal_radius, y)) return border_tiles
def test_spawn_insufficient_resources(game_control_proxy, defender): flexmock(Ent).should_receive('cost').and_return(5000) with pytest.raises(IllegalActionException) as exc: si = SpawnInformation(defender, GameObjectType.ENT, OffsetPosition(1, 1), [], []) game_control_proxy.spawn_unit(si) assert 'Insufficient resources!' in str(exc.value)
def __generate_tiles(self): """ Generate all tiles (without water) """ for i in range(-self.__vertical_radius, self.__vertical_radius + 1): for j in range(-self.__horizontal_radius, self.__horizontal_radius + 1): position = OffsetPosition(i, j) if self.__game_map[position].terrain_type != TerrainType.RIVER: self.__game_map.set_tile( position, self.get_random_terrain_type(position))
def test_compute_accessible_tiles(map_proxy): assert map_proxy.compute_accessible_tiles(OffsetPosition(0, 0), 2) == { OffsetPosition(-1, -2): 0, OffsetPosition(-1, -1): 1, OffsetPosition(1, -1): 1, OffsetPosition(1, 0): 0, OffsetPosition(0, 1): 0, OffsetPosition(0, 0): 2, }
def free_sides(self): free_pos = set() pos = OffsetPosition(-1, -5).offset if not self.map_proxy.is_position_occupied(pos): free_pos.add(pos) pos = OffsetPosition(-2, -5).offset if not self.map_proxy.is_position_occupied(pos): free_pos.add(pos) pos = OffsetPosition(-5, -3).offset if not self.map_proxy.is_position_occupied(pos): free_pos.add(pos) pos = OffsetPosition(-5, -2).offset if not self.map_proxy.is_position_occupied(pos): free_pos.add(pos) free_pos.intersection_update(self.map_proxy.get_player_visible_tiles()) return free_pos
def build_base(self, x, y): # Custom log messages n = FilterFactory().attack_filter(AttackNearestFilter) Logger.log('Building base') base_pos = OffsetPosition(x, y).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.BASE, base_pos, [n], [])) base_pos = OffsetPosition(-5, -5).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.MAGICIAN, base_pos, [n], [])) base_pos = OffsetPosition(-4, -5).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.MAGICIAN, base_pos, [n], [])) base_pos = OffsetPosition(-5, -4).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.MAGICIAN, base_pos, [n], [])) base_pos = OffsetPosition(-4, -3).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.ARCHER, base_pos, [n], [])) base_pos = OffsetPosition(-3, -5).offset self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.ARCHER, base_pos, [n], []))
def __init__(self, width: int, height: int, tiles: List[List[Union['TerrainType', str]]] = None): self.__size = (width, height) if width % 2 == 0 or height % 2 == 0: raise IllegalArgumentException('Map size must be odd numbers') if width < 3: raise IllegalArgumentException('Map width must be greater than 2') if height < 3: raise IllegalArgumentException('Map height must be greater than 2') self.__width = width self.__height = height self.__vertical_radius = (height - 1) // 2 self.__horizontal_radius = (width - 1) // 2 self.__visible_tiles_cache = {} self.__tiles = [] # type: List[List[Union[Terrain,None]]] for i in range(height): self.__tiles.append([]) for j in range(width): self.__tiles[i].append(None) if tiles: for y, terrain_list in enumerate(tiles): for x, terrain_type in enumerate(terrain_list): position = OffsetPosition(x - self.__horizontal_radius, y - self.__vertical_radius) if type(terrain_type) is TerrainType: self.set_tile(position, terrain_type.value) elif type(terrain_type) is str: _terrain_type = TerrainType.from_char( terrain_type).value if _terrain_type is None: raise IllegalArgumentException( 'Invalid tile character {}'.format( terrain_type)) self.set_tile( position, TerrainType.from_char(terrain_type).value) else: raise IllegalArgumentException( 'Map tiles could be TerrainType enum or string representation!' )
def build_base(self, position_q: int, position_r: int): # Custom log messages Logger.log('Building base') empty_filter = FilterFactory().attack_filter(EmptyAttackFilter) dummy_filter = FilterFactory().attack_filter(DummyAttackFilter, 'Base attacking') # Create instance of default filter strongest_filter = FilterFactory().attack_filter(AttackStrongestFilter) self.game_control_proxy.spawn_unit( SpawnInformation(self.player, GameObjectType.BASE, OffsetPosition(int(position_q), int(position_r)), [], []))
class EvenOffsetDirection(Enum): """ Direction of neighbours on hexagon grid defined with Offset position Be careful that directions are different for odd and even columns """ UPPER = OffsetPosition(0, -1) RIGHT_UPPER = OffsetPosition(+1, 0) RIGHT_LOWER = OffsetPosition(+1, +1) LOWER = OffsetPosition(0, 1) LEFT_LOWER = OffsetPosition(-1, 0) LEFT_UPPER = OffsetPosition(-1, 0)
def __create_linked_list(self): """ Create linked list for iterating over edge tiles """ # In the corners, there are more than one neighbor. Precedence list will chose correct one precedence = { OffsetPosition(self.__game_map.horizontal_radius, self.__game_map.vertical_radius), OffsetPosition(-self.__game_map.horizontal_radius, self.__game_map.vertical_radius), OffsetPosition(self.__game_map.horizontal_radius, -self.__game_map.vertical_radius), OffsetPosition(-self.__game_map.horizontal_radius, -self.__game_map.vertical_radius), OffsetPosition(-self.__game_map.horizontal_radius + 2, -self.__game_map.vertical_radius) } first = OffsetPosition(-self.__game_map.horizontal_radius, -self.__game_map.vertical_radius) second = OffsetPosition(-self.__game_map.horizontal_radius + 1, -self.__game_map.vertical_radius) self.__border_tiles.push_back(first) self.__border_tiles.push_back(second) tiles = self.__game_map.border_tiles tiles.remove(first) tiles.remove(second) current = self.__border_tiles.head.value while tiles: _next_set = set(current.get_all_neighbours()).intersection(tiles) if len(_next_set) > 1: _next_set = _next_set.intersection(precedence) _next = _next_set.pop() current = _next self.__border_tiles.push_back(_next) tiles.remove(_next) self.__border_tiles.head.next = self.__border_tiles.tail self.__border_tiles.tail.previous = self.__border_tiles.head
def found_good(self): inner = self.map_proxy.get_inner_tiles() border = self.map_proxy.get_border_tiles() ban = set() ban.update(border) for x in border: a = x.get_all_neighbours() for z in a: ban.add(z) for pos in inner: if self.map_proxy.get_terrain_type( pos).name == "FOREST" or self.map_proxy.get_terrain_type( pos).name == "HILL" or self.map_proxy.get_terrain_type( pos).name == "VILLAGE" and pos not in ban: z = pos.get_all_neighbours() flag = True for a in z: if a in border: flag = False if flag: return pos.offset return OffsetPosition(0, 0).offset
def list_positions_first_round(self): if not self.map_proxy.player_have_base(self.player): return None base_position = self.map_proxy.get_bases_positions().pop() positions_first_round = [] positions_first_round.append( OffsetPosition(base_position.offset.q, base_position.offset.r - 1)) positions_first_round.append( OffsetPosition(base_position.offset.q + 1, base_position.offset.r)) positions_first_round.append( OffsetPosition(base_position.offset.q + 1, base_position.offset.r + 1)) positions_first_round.append( OffsetPosition(base_position.offset.q, base_position.offset.r + 1)) positions_first_round.append( OffsetPosition(base_position.offset.q - 1, base_position.offset.r + 1)) positions_first_round.append( OffsetPosition(base_position.offset.q - 1, base_position.offset.r)) return positions_first_round
def appropriate_positions_first_round(self, coordinate): if not self.map_proxy.player_have_base(self.player): return [] base_position = self.map_proxy.get_bases_positions().pop() all_positions = self.base_neighbours() visible_positions = self.map_proxy.get_player_visible_tiles() border_positions = self.map_proxy.get_border_tiles() res = [] if coordinate == 'N': pos = OffsetPosition(int(base_position.offset.q), int(base_position.offset.r - 1)) if pos in all_positions and pos in visible_positions and pos not in border_positions: res.append(pos) elif coordinate == 'S': pos = OffsetPosition(int(base_position.offset.q), int(base_position.offset.r + 1)) if pos in all_positions and pos in visible_positions and pos not in border_positions: res.append(pos) elif coordinate == 'W': pos = [ OffsetPosition(int(base_position.offset.q - 1), int(base_position.offset.r - 1)), OffsetPosition(int(base_position.offset.q - 1), int(base_position.offset.r + 1)) ] for p in pos: if p in all_positions and p in visible_positions and p not in border_positions: res.append(p) else: pos = [ OffsetPosition(int(base_position.offset.q + 1), int(base_position.offset.r - 1)), OffsetPosition(int(base_position.offset.q + 1), int(base_position.offset.r + 1)) ] for p in pos: if p in all_positions and p in visible_positions and p not in border_positions: res.append(p) return res
def actual_tiles_for_attack(self): return [ OffsetPosition(0, 2), OffsetPosition(0, -2), OffsetPosition(2, 0), OffsetPosition(-2, 0), OffsetPosition(2, 1), OffsetPosition(-2, -1), OffsetPosition(1, 2), OffsetPosition(-1, -2), OffsetPosition(-1, 2), OffsetPosition(1, -2), OffsetPosition(-2, 1), OffsetPosition(2, -1), OffsetPosition(1, 1), OffsetPosition(-1, 1) ]
def get_number_of_neighbours(self): return len([ x for x in OffsetPosition(0, 0).get_all_neighbours() if self.map_proxy.is_position_occupied(x) ])
def test_get_player_visible_tiles(map_proxy): assert map_proxy.get_player_visible_tiles() == { OffsetPosition(-2, -1), OffsetPosition(-1, -2), OffsetPosition(-2, 0), OffsetPosition(-1, -1), OffsetPosition(0, -1), OffsetPosition(1, -2), OffsetPosition(-1, 0), OffsetPosition(0, 0), OffsetPosition(1, -1), OffsetPosition(2, -1), OffsetPosition(-1, 1), OffsetPosition(0, 1), OffsetPosition(1, 0), OffsetPosition(2, 0), OffsetPosition(0, 2), OffsetPosition(1, 1), OffsetPosition(2, 1), }
def test_compute_visible_tiles(map_proxy): assert map_proxy.compute_visible_tiles(OffsetPosition(0, 0), 2) == { OffsetPosition(-2, -1), OffsetPosition(-1, -2), OffsetPosition(-2, 0), OffsetPosition(-1, -1), OffsetPosition(0, -1), OffsetPosition(1, -2), OffsetPosition(-1, 0), OffsetPosition(0, 0), OffsetPosition(1, -1), OffsetPosition(2, -1), OffsetPosition(-1, 1), OffsetPosition(0, 1), OffsetPosition(1, 0), OffsetPosition(2, 0), OffsetPosition(0, 2), OffsetPosition(1, 1), OffsetPosition(2, 1), }
def free_tile(self, x): base_q = self.map_proxy.get_bases_positions().pop().offset.q base_r = self.map_proxy.get_bases_positions().pop().offset.r pos = OffsetPosition if x == "1": pos = OffsetPosition(base_q - 1, base_r - 1) if x == "2": pos = OffsetPosition(base_q, base_r - 1) if x == "3": pos = OffsetPosition(base_q + 1, base_r - 1) if x == "4": pos = OffsetPosition(base_q + 1, base_r) if x == "5": pos = OffsetPosition(base_q, base_r + 1) if x == "6": pos = OffsetPosition(base_q - 1, base_r) if x == "7": pos = OffsetPosition(base_q - 2, base_r - 1) if x == "8": pos = OffsetPosition(base_q + 2, base_r - 1) if x == "9": pos = OffsetPosition(base_q - 2, base_r + 1) if x == "10": pos = OffsetPosition(base_q + 2, base_r + 1) if x == "11": pos = OffsetPosition(base_q, base_r + 2) if x == "12": pos = OffsetPosition(base_q, base_r - 2) if x == "13": pos = OffsetPosition(base_q + 2, base_r) if x == "14": pos = OffsetPosition(base_q - 2, base_r) if x == "15": pos = OffsetPosition(base_q + 1, base_r + 2) if x == "16": pos = OffsetPosition(base_q + 1, base_r - 2) if x == "17": pos = OffsetPosition(base_q - 1, base_r + 2) if x == "18": pos = OffsetPosition(base_q - 1, base_r - 2) print("===================") print(pos) print(x) print(self.map_proxy.get_bases_positions().pop()) print("===================") visible = self.map_proxy.get_player_visible_tiles() border = self.map_proxy.get_border_tiles() if not self.map_proxy.is_position_occupied(pos) and pos in visible\ and pos not in border and self.map_proxy.is_position_on_map(pos): return pos
def __generate_river(self): """ Generate rivver tiles. There will be only one river with starting and ending at the map edge""" def filter_river_neighbour(position, ancestor): _neighbours = [ self.__game_map[x].terrain_type for x in self.__game_map.filter_positions_on_map( position.get_all_neighbours()) if ancestor != x ] if TerrainType.RIVER in _neighbours: return False return True if random.random() < self.river_prob: current = self.__river_start_position() river_length = 1 self.__game_map.set_tile(current, River()) while True: # Filter neighbours on map neighbours = self.__game_map.filter_positions_on_map( current.get_all_neighbours()) # Filter neighbours which are not RIVER neighbours = [ x for x in neighbours if self.__game_map[x].terrain_type != TerrainType.RIVER ] # Filter neighbours which are have not river as neighbour neighbours = [ x for x in neighbours if filter_river_neighbour(x, current) ] # Filter border tiles under size factor if river_length < 3: neighbours = [ x for x in neighbours if not self.__game_map.position_on_edge(x) ] neighbours.sort(key=lambda x: (x.length( ) + 1 if self.__game_map.position_on_edge(x) else 0)) if neighbours: for i in range(6): neighbours.append(neighbours[0]) # If cannot continue generate new river if not neighbours: for i in range(-self.__vertical_radius, self.__vertical_radius + 1): for j in range(-self.__horizontal_radius, self.__horizontal_radius + 1): self.__game_map.set_tile(OffsetPosition(i, j), Field()) self.__generate_river() break neighbour = random.choice(neighbours) self.__game_map.set_tile(neighbour, River()) if self.__game_map.position_on_edge(neighbour): break else: current = neighbour river_length += 1