예제 #1
0
 def updateMap(self, m: Map) -> Map:
     if len(m.id) != 24:
         return m
     result = mapCol.update_one({'_id': ObjectId(m.id)},
                                {'$set': m.toDBMap()},
                                upsert=True)
     if result.upserted_id:
         m.id = str(result.upserted_id)
     return m
예제 #2
0
 def __init__(self):
     self.direction = 'down'
     self.hero_stat_statusbar = None
     self.level = 1
     self.view = View(self.level)
     self.map = Map()
     self.hero = Hero(self.map.occupied_tile_position)
     self.game_start(self.level)
     self.view.master.mainloop()
예제 #3
0
def add_map_to_database(user_id, map_name, map_description):
    """Add map to database"""
    url_hash = uuid.uuid4() #generate random uuid (universal unique identifier) for map
    map_hex = url_hash.hex
    new_map = Map(user_id=user_id, 
                    map_name=map_name, 
                    map_description=map_description, 
                    map_url_hash=map_hex)
    db.session.add(new_map)
    db.session.commit()
예제 #4
0
    def runTest(self):
        size = [10, 5]
        self.assertEqual(5, len(Map.generate_map(size)))

        ocean_test = Map('config.json')
        self.assertEqual(False, ocean_test.check_prey(0, 0))
        self.assertEqual(False, ocean_test.check_predator(1, 1))
        self.assertEqual(True, ocean_test.check_move(ocean_test.predators[0], 0))
예제 #5
0
    def _map_init(self, map_msg):
        row_num = map_msg["rows"]
        col_num = map_msg["cols"]

        input_cells = [[Cell(row=row, col=col) for col in range(col_num)] for row in range(row_num)]

        paths = [Path(id=path["id"], cells=[input_cells[cell["row"]][cell["col"]] for cell in path["cells"]]
                      ) for path in map_msg["paths"]]
        kings = [King(player_id=king["playerId"], center=input_cells[king["center"]["row"]][king["center"]["col"]],
                      hp=king["hp"],
                      attack=king["attack"], range=king["range"], target=None, target_cell=None, is_alive=True)
                 for king in map_msg["kings"]]

        self.players = [Player(player_id=map_msg["kings"][i]["playerId"], king=kings[i], deck=[],
                               hand=[], ap=self.game_constants.max_ap,
                               paths_from_player=self._get_paths_starting_with(kings[i].center, paths),
                               path_to_friend=self._find_path_starting_and_ending_with(kings[i].center,
                                                                                       kings[i ^ 1].center, paths),
                               units=[], cast_area_spell=None, cast_unit_spell=None,
                               duplicate_units=[],
                               hasted_units=[],
                               played_units=[],
                               died_units=[],
                               range_upgraded_unit=None,
                               damage_upgraded_unit=None,
                               spells=[]) for i in range(4)]

        for player in self.players:
            player.paths_from_player.remove(player.path_to_friend)

        self.player = self.players[0]
        self.player_friend = self.players[1]
        self.player_first_enemy = self.players[2]
        self.player_second_enemy = self.players[3]

        self.map = Map(row_num=row_num, col_num=col_num, paths=paths, kings=kings, cells=input_cells, units=[])
예제 #6
0
 def get(self):
     global is_generated
     if is_generated:
         self.response.out.write("Fake database already generated")
         return
     #generate maps
     rand_maps = []
     for i in range(1, 50):
         rand_maps.append(Map.random())
     index = search.Index(maps.MAP_INDEX)
     index.put(rand_maps)
     #base_stations
     put_base_stations()
     for i in range(1, 300):
         put_random_scan()
     is_generated = True
     self.response.out.write("Database generated, fire away ;-)")
예제 #7
0
 def get(self):
     global is_generated
     if is_generated:
         self.response.out.write("Fake database already generated")
         return
     #generate maps
     rand_maps = []
     for i in range(1, 50):
         rand_maps.append(Map.random())
     index = search.Index(maps.MAP_INDEX)
     index.put(rand_maps)
     #base_stations
     put_base_stations()
     for i in range(1, 300):
         put_random_scan()
     is_generated = True
     self.response.out.write("Database generated, fire away ;-)")
예제 #8
0
 def saveMap(self, m: Map) -> Map:
     result = mapCol.insert_one(m.toDBMap())
     m.id = str(result.inserted_id)
     return m
예제 #9
0
 def assembleMap(self, item: dict) -> Map:
     m = Map(item)
     m.id = str(item['_id'])
     return m
예제 #10
0
    def post(self):
        name = self.get_body_argument('name')
        planSize = self.get_body_arguments('planSize')
        planUnix = self.get_body_argument('planUnit')
        actualSize = self.get_body_arguments('actualSize')
        actualUnit = self.get_body_argument('actualUnit')
        originInPlan = self.get_body_arguments('originInPlan')
        rotationAngle = self.get_body_arguments('rotationAngle')
        originInActual = self.get_body_arguments('originInActual')
        isClockwise = bool(int(self.get_body_argument('isClockwise', False)))

        standardVector = self.get_body_argument('standardVector', '0,1')
        standardVector = [float(item) for item in standardVector.split(',')]

        if len(planSize) > 1:
            actualSize = [float(item) for item in actualSize]
        else:
            actualSize = [float(item) for item in actualSize[0].split(',')]

        if len(planSize) > 1:
            planSize = [float(item) for item in planSize]
        else:
            planSize = [float(item) for item in planSize[0].split(',')]

        if len(originInPlan) > 1:
            originInPlan = [float(item) for item in originInPlan]
        else:
            originInPlan = [float(item) for item in originInPlan[0].split(',')]

        if len(rotationAngle) > 1:
            rotationAngle = [float(item) for item in rotationAngle]
        else:
            rotationAngle = [
                float(item) for item in rotationAngle[0].split(',')
            ]

        if len(originInActual) > 1:
            originInActual = [float(item) for item in originInActual]
        else:
            originInActual = [
                float(item) for item in originInActual[0].split(',')
            ]

        planImage = self.request.files['planImage']
        originName = planImage[0]['filename']
        filename = name + os.path.splitext(originName)[-1]
        fileBody = planImage[0]['body']
        planPath = localFileAdapter.save(filename, fileBody)

        mapDict = {
            'name': name,
            'planSize': planSize,
            'planUnix': planUnix,
            'actualSize': actualSize,
            'actualUnit': actualUnit,
            'originInPlan': originInPlan,
            'planPath': planPath,
            'originInActual': originInActual,
            'rotationAngle': rotationAngle,
            'isClockwise': isClockwise,
            'standardVector': standardVector
        }
        logging.info(mapDict)
        m = Map(mapDict)
        m = mapService.saveMap(m)
        self.write({'code': 0, 'data': m.toJsonMap()})
예제 #11
0
 def __init__(self):
     self.m = Map()
     self.service = Service()
     self.d = Drone(0, 0)
예제 #12
0
class UI:
    def __init__(self):
        self.m = Map()
        self.service = Service()
        self.d = Drone(0, 0)

    def prinMenu(self):
        print("1. AStar")
        print("2. Greedy")
        choice = int(input("Option: "))
        return choice

    def main(self):
        astar_or_greedy = self.prinMenu()
        # we create the map
        self.m.randomMap()
        #m.saveMap("test2.map")
        #self.m.loadMap("test1.map")

        # initialize the pygame module
        pygame.init()
        # load and set the logo
        logo = pygame.image.load("logo32x32.png")
        pygame.display.set_icon(logo)
        pygame.display.set_caption("Path in simple environment")

        # we position the drone somewhere in the area
        x = randint(0, 19)
        y = randint(0, 19)

        #random_ending
        destination_x = randint(0, 19)
        destination_y = randint(0, 19)

        while self.m.surface[destination_x][destination_y] != 0:
            destination_x = randint(0, 19)
            destination_y = randint(0, 19)

        print("Final " + str(destination_x) + " " + str(destination_y))

        #create drona
        self.d = Drone(x, y)

        # create a surface on screen that has the size of 400 x 480
        screen = pygame.display.set_mode((400, 400))
        screen.fill(WHITE)

        # define a variable to control the main loop
        running = True

        # main loop
        while running:
            # event handling, gets all event from the event queue
            for event in pygame.event.get():
                # only do something if the event is of type QUIT
                if event.type == pygame.QUIT:
                    # change the value to False, to exit the main loop
                    running = False

                if event.type == KEYDOWN:
                    self.d.move(self.m)  #this call will be erased

            screen.blit(self.d.mapWithDrone(self.m.image()), (0, 0))
            pygame.display.flip()

        if astar_or_greedy == 1:
            path = self.service.searchAStar(self.m, x, y, destination_x,
                                            destination_y)
        else:
            path = self.service.searchGreedy(self.m, x, y, destination_x,
                                             destination_y)
        if path:
            screen.blit(self.service.displayWithPath(self.m.image(), path),
                        (0, 0))
        pygame.display.flip()
        time.sleep(5)
        pygame.quit()
예제 #13
0
class World:
    DEBUGGING_MODE = False
    LOG_FILE_POINTER = None
    _shortest_path = dict()

    def __init__(self, world=None, queue=None):
        self._start_time = 0
        self._init_message = None
        self._game_constants = None

        self._turn_updates = None

        self._map = None
        self._base_units = None
        self._current_turn = 0

        self._players = []
        self._player = None
        self._player_friend = None
        self._player_first_enemy = None
        self._player_second_enemy = None
        self._spells = []
        self._cast_spells = []

        if world is not None:
            self._init_message = world._init_message
            self._game_constants = world._game_constants

            self._turn_updates = TurnUpdates(turn_updates=world._turn_updates)

            self._map = world._map
            self._base_units = world._base_units
            self._spells = world._spells
            self._current_turn = world._current_turn

            self._players = world._players
            self._player = world._player
            self._player_friend = world._player_friend
            self._player_first_enemy = world._player_first_enemy
            self._player_second_enemy = world._player_second_enemy
            self._cast_spells = world._cast_spells

            self._queue = world._queue
        else:
            self._queue = queue

        if len(World._shortest_path) == 0:
            self._pre_process_shortest_path()

    def _pre_process_shortest_path(self):
        def path_count(paths_from_player, paths_from_friend, path_to_friend):
            shortest_path = [[None for i in range(self._map.col_num)]
                             for j in range(self._map.row_num)]
            shortest_dist = [[0 for i in range(self._map.col_num)]
                             for j in range(self._map.row_num)]
            for p in paths_from_player:
                num = 0
                for c in p.cells:
                    row = c.row
                    col = c.col
                    if shortest_path[row][col] is None:
                        shortest_path[row][col] = p
                        shortest_dist[row][col] = num
                    elif shortest_dist[row][col] > num:
                        shortest_dist[row][col] = num
                        shortest_path[row][col] = p
                    num += 1

            l = len(path_to_friend.cells)
            for p in paths_from_friend:
                num = l - 1
                for c in p.cells:
                    row = c.row
                    col = c.col
                    if shortest_path[row][col] is None:
                        shortest_path[row][col] = p
                        shortest_dist[row][col] = num
                    elif shortest_dist[row][col] > num:
                        shortest_dist[row][col] = num
                        shortest_path[row][col] = p
                    num += 1
            return shortest_path

        for player in self._players:
            World._shortest_path.update({
                player.player_id:
                path_count(
                    player.paths_from_player,
                    self._get_friend_by_id(player.player_id).paths_from_player,
                    player.path_to_friend)
            })

    def _get_current_time_millis(self):
        return int(round(time.time() * 1000))

    def _get_time_past(self):
        return self._get_current_time_millis() - self._start_time

    def _game_constant_init(self, game_constants_msg):
        self._game_constants = GameConstants(
            max_ap=game_constants_msg["maxAP"],
            max_turns=game_constants_msg["maxTurns"],
            turn_timeout=game_constants_msg["turnTimeout"],
            pick_timeout=game_constants_msg["pickTimeout"],
            turns_to_upgrade=game_constants_msg["turnsToUpgrade"],
            turns_to_spell=game_constants_msg["turnsToSpell"],
            damage_upgrade_addition=game_constants_msg[
                "damageUpgradeAddition"],
            range_upgrade_addition=game_constants_msg["rangeUpgradeAddition"],
            hand_size=game_constants_msg["handSize"],
            deck_size=game_constants_msg["deckSize"],
            ap_addition=game_constants_msg["apAddition"])

    def _find_path_starting_and_ending_with(self, first, last, paths):
        for path in paths:
            c_path = Path(path=path)
            if c_path.cells[0] == first and c_path.cells[-1] == last:
                return c_path
            c_path.cells.reverse()
            if c_path.cells[0] == first and c_path.cells[-1] == last:
                return c_path
        return None

    def _map_init(self, map_msg):
        row_num = map_msg["rows"]
        col_num = map_msg["cols"]

        input_cells = [[Cell(row=row, col=col) for col in range(col_num)]
                       for row in range(row_num)]

        paths = [
            Path(id=path["id"],
                 cells=[
                     input_cells[cell["row"]][cell["col"]]
                     for cell in path["cells"]
                 ]) for path in map_msg["paths"]
        ]
        kings = [
            King(player_id=king["playerId"],
                 center=input_cells[king["center"]["row"]][king["center"]
                                                           ["col"]],
                 hp=king["hp"],
                 attack=king["attack"],
                 range=king["range"],
                 target=None,
                 target_cell=None,
                 is_alive=True) for king in map_msg["kings"]
        ]

        self._players = [
            Player(player_id=map_msg["kings"][i]["playerId"],
                   king=kings[i],
                   deck=[],
                   hand=[],
                   ap=self._game_constants.max_ap,
                   paths_from_player=self._get_paths_starting_with(
                       kings[i].center, paths),
                   path_to_friend=self._find_path_starting_and_ending_with(
                       kings[i].center, kings[i ^ 1].center, paths),
                   units=[],
                   cast_area_spell=None,
                   cast_unit_spell=None,
                   duplicate_units=[],
                   hasted_units=[],
                   played_units=[],
                   died_units=[],
                   range_upgraded_unit=None,
                   damage_upgraded_unit=None,
                   spells=[]) for i in range(4)
        ]

        for player in self._players:
            player.paths_from_player.remove(player.path_to_friend)

        self._player = self._players[0]
        self._player_friend = self._players[1]
        self._player_first_enemy = self._players[2]
        self._player_second_enemy = self._players[3]

        self._map = Map(row_num=row_num,
                        col_num=col_num,
                        paths=paths,
                        kings=kings,
                        cells=input_cells,
                        units=[])

    def _base_unit_init(self, msg):
        self._base_units = [
            BaseUnit(type_id=b_unit["typeId"],
                     max_hp=b_unit["maxHP"],
                     base_attack=b_unit["baseAttack"],
                     base_range=b_unit["baseRange"],
                     target_type=UnitTarget.get_value(b_unit["target"]),
                     is_flying=b_unit["isFlying"],
                     is_multiple=b_unit["isMultiple"],
                     ap=b_unit["ap"]) for b_unit in msg
        ]

    def _get_base_unit_by_id(self, type_id):
        for base_unit in self._base_units:
            if base_unit.type_id == type_id:
                return base_unit
        return None

    def _spells_init(self, msg):
        self._spells = [
            Spell(type=SpellType.get_value(spell["type"]),
                  type_id=spell["typeId"],
                  duration=spell["duration"],
                  priority=spell["priority"],
                  range=spell["range"],
                  power=spell["power"],
                  target=SpellTarget.get_value(spell["target"]),
                  is_damaging=spell["power"] < 0) for spell in msg
        ]

    def _handle_init_message(self, msg):
        self._init_message = msg
        self._start_time = self._get_current_time_millis()
        self._game_constant_init(msg['gameConstants'])
        self._map_init(msg["map"])
        self._base_unit_init(msg["baseUnits"])
        self._spells_init(msg["spells"])
        self._current_turn = 0

    def _handle_turn_kings(self, msg):
        for king_msg in msg:
            self.get_player_by_id(
                king_msg["playerId"]).king.is_alive = king_msg["isAlive"]
            self.get_player_by_id(
                king_msg["playerId"]).king.hp = king_msg["hp"]
            if king_msg["target"] != -1:
                self.get_player_by_id(
                    king_msg["playerId"]).king.target = self.get_unit_by_id(
                        king_msg["target"])
                self.get_player_by_id(king_msg["playerId"]
                                      ).king.target_cell = self.get_unit_by_id(
                                          king_msg["target"]).cell
            else:
                self.get_player_by_id(king_msg["playerId"]).king.target = None
                self.get_player_by_id(
                    king_msg["playerId"]).king.target_cell = None

    def _handle_turn_units(self, msg, is_dead_unit=False):
        if not is_dead_unit:
            self._map._clear_units()
            for player in self._players:
                player.units.clear()
                player.played_units.clear()
                player.hasted_units.clear()
                player.duplicate_units.clear()
                player.range_upgraded_unit = None
                player.damage_upgraded_unit = None
        else:
            for player in self._players:
                player.died_units.clear()

        unit_input_list = []

        for unit_msg in msg:
            unit_id = unit_msg["unitId"]
            player = self.get_player_by_id(player_id=unit_msg["playerId"])
            base_unit = self._base_units[unit_msg["typeId"]]

            if not unit_msg['target'] == -1:
                target_cell = Cell(row=unit_msg["targetCell"]["row"],
                                   col=unit_msg["targetCell"]["col"])
            else:
                target_cell = None
            unit = Unit(
                unit_id=unit_id,
                base_unit=base_unit,
                cell=self._map.get_cell(unit_msg["cell"]["row"],
                                        unit_msg["cell"]["col"]),
                path=self._map.get_path_by_id(unit_msg["pathId"]),
                hp=unit_msg["hp"],
                damage_level=unit_msg["damageLevel"],
                range_level=unit_msg["rangeLevel"],
                is_duplicate=unit_msg["isDuplicate"],
                is_hasted=unit_msg["isHasted"],
                range=unit_msg["range"],
                attack=unit_msg["attack"],
                target=None,  # will be set later when all units are in set
                target_cell=target_cell,
                affected_spells=[
                    self.get_cast_spell_by_id(cast_spell_id)
                    for cast_spell_id in unit_msg["affectedSpells"]
                ],
                target_if_king=None
                if self.get_player_by_id(unit_msg["target"]) is None else
                self.get_player_by_id(unit_msg["target"]).king,
                player_id=unit_msg["playerId"])
            unit_input_list.append(unit)

            if unit.path is not None:
                if self.get_player_by_id(
                        unit.player_id
                ).king.center in unit.path.cells and unit.path.cells[
                        0] != self.get_player_by_id(
                            unit.player_id).king.center:
                    unit.path = Path(path=unit.path)
                    unit.path.cells.reverse()
                if self._get_friend_by_id(
                        unit.player_id
                ).king.center in unit.path.cells and unit.path.cells[
                        0] != self._get_friend_by_id(
                            unit.player_id).king.center:
                    unit.path = Path(path=unit.path)
                    unit.path.cells.reverse()

            if not is_dead_unit:
                self._map._add_unit_in_cell(unit.cell.row, unit.cell.col, unit)
                player.units.append(unit)
                if unit_msg["wasDamageUpgraded"]:
                    player.damage_upgraded_unit = unit
                if unit_msg["wasRangeUpgraded"]:
                    player.range_upgraded_unit = unit
                if unit_msg["wasPlayedThisTurn"]:
                    player.played_units.append(unit)
                if unit.is_hasted:
                    player.hasted_units.append(unit)
                if unit.is_duplicate:
                    player.duplicate_units.append(unit)
            else:
                player.died_units.append(unit)

        for i in range(len(unit_input_list)):
            unit = unit_input_list[i]
            if unit.target_if_king is not None:
                unit.target = None
            else:
                unit.target = self.get_unit_by_id(msg[i]["target"])

    def _handle_turn_cast_spells(self, msg):
        self._cast_spells = []
        for cast_spell_msg in msg:
            spell = self.get_spell_by_id(cast_spell_msg["typeId"])
            cell = self._map.get_cell(cast_spell_msg["cell"]["row"],
                                      cast_spell_msg["cell"]["col"])
            affected_units = [
                self.get_unit_by_id(affected_unit_id)
                for affected_unit_id in cast_spell_msg["affectedUnits"]
            ]
            if spell.is_area_spell():
                cast_area_spell = CastAreaSpell(
                    spell=spell,
                    id=cast_spell_msg["id"],
                    caster_id=cast_spell_msg["casterId"],
                    cell=cell,
                    remaining_turns=cast_spell_msg["remainingTurns"],
                    affected_units=affected_units)
                self._cast_spells.append(cast_area_spell)
                if cast_spell_msg["wasCastThisTurn"]:
                    self.get_player_by_id(cast_spell_msg["casterId"]
                                          ).cast_area_spell = cast_area_spell

            elif spell.is_unit_spell():
                cast_unit_spell = CastUnitSpell(
                    spell=spell,
                    id=cast_spell_msg["id"],
                    caster_id=cast_spell_msg["casterId"],
                    cell=cell,
                    unit=self.get_unit_by_id(cast_spell_msg["unitId"]),
                    path=self._map.get_path_by_id(cast_spell_msg["pathId"]),
                    affected_units=affected_units)
                self._cast_spells.append(cast_unit_spell)
                if cast_spell_msg["wasCastThisTurn"]:
                    self.get_player_by_id(cast_spell_msg["casterId"]
                                          ).cast_unit_spell = cast_unit_spell

    def get_cast_spell_by_id(self, id: int) -> Optional["CastSpell"]:
        for cast_spell in self._cast_spells:
            if cast_spell.id == id:
                return cast_spell
        return None

    def _handle_turn_message(self, msg):
        self._start_time = self._get_current_time_millis()
        self._handle_init_message(self._init_message)
        self._current_turn = msg['currTurn']
        self._player.deck = [
            self._get_base_unit_by_id(deck_type_id)
            for deck_type_id in msg["deck"]
        ]
        self._player.hand = [
            self._get_base_unit_by_id(hand_type_id)
            for hand_type_id in msg["hand"]
        ]
        self._handle_turn_units(msg=msg["diedUnits"], is_dead_unit=True)
        self._handle_turn_cast_spells(msg["castSpells"])
        self._handle_turn_units(msg["units"])
        self._handle_turn_kings(msg["kings"])
        self._turn_updates = TurnUpdates(
            received_spell=msg["receivedSpell"],
            friend_received_spell=msg["friendReceivedSpell"],
            got_range_upgrade=msg["gotRangeUpgrade"],
            got_damage_upgrade=msg["gotDamageUpgrade"],
            available_range_upgrades=msg["availableRangeUpgrades"],
            available_damage_upgrades=msg["availableDamageUpgrades"])

        self._player.set_spells(
            [self.get_spell_by_id(spell_id) for spell_id in msg["mySpells"]])
        self._player_friend.set_spells([
            self.get_spell_by_id(spell_id) for spell_id in msg["friendSpells"]
        ])
        self._player.ap = msg["remainingAP"]

    def choose_hand_by_id(self, type_ids: List[int]) -> None:
        message = Message(type="pick", turn=self.get_current_turn(), info=None)
        if type_ids is not None:
            for type_id in type_ids:
                if type(type_id) is not int:
                    Logs.show_log("type_ids are not int")
                    return

            message.info = {"units": type_ids}
            self._queue.put(message)
        else:
            Logs.show_log(
                "choose_hand_by_id function called with None type_eds")

    # in the first turn 'deck picking' give unit_ids or list of unit names to pick in that turn
    def choose_hand(self, base_units: List[BaseUnit]) -> None:
        message = Message(type="pick", turn=self.get_current_turn(), info=None)
        if base_units is not None:
            for base_unit in base_units:
                if type(base_unit) is not BaseUnit:
                    Logs.show_log("base_units is not an array of BaseUnits")
                    return
            message.info = {"units": [unit.type_id for unit in base_units]}
            self._queue.put(message)
        else:
            Logs.show_log("choose_hand function called with None base_units")

    def get_me(self) -> Player:
        return self._player

    def get_friend(self) -> Player:
        return self._player_friend

    def _get_friend_by_id(self, player_id):
        if self._player.player_id == player_id:
            return self._player_friend
        elif self._player_friend.player_id == player_id:
            return self._player
        elif self._player_first_enemy.player_id == player_id:
            return self._player_second_enemy
        elif self._player_second_enemy.player_id == player_id:
            return self._player_first_enemy
        else:
            Logs.show_log(
                "get_friend_by_id function no player with given player_id")
            return None

    def get_first_enemy(self) -> Player:
        return self._player_first_enemy

    def get_second_enemy(self) -> Player:
        return self._player_second_enemy

    def get_map(self) -> Map:
        return self._map

    # return a list of paths crossing one cell
    def get_paths_crossing_cell(self,
                                cell: Cell = None,
                                row: int = None,
                                col: int = None) -> List[Path]:
        if cell is None:
            if row is None or col is None:
                Logs.show_log(
                    "get_paths_crossing cell function called with no valid argument"
                )
                return []
            cell = self._map.get_cell(row, col)

        if not isinstance(cell, Cell):
            Logs.show_log("Given cell is invalid!")
            return []

        paths = []
        for p in self._map.paths:
            if cell in p.cells:
                paths.append(p)
        return paths

    # return a list of units in a cell
    def get_cell_units(self,
                       cell: Cell = None,
                       row: int = None,
                       col: int = None) -> List[Unit]:
        if cell is None:
            if row is None and col is None:
                Logs.show_log(
                    "get_paths_crossing cell function called with no valid argument"
                )
                return []
            cell = self._map.get_cell(row, col)
        if not isinstance(cell, Cell):
            Logs.show_log("Given cell is invalid!")
            return []
        return cell.units

    # return the shortest path from player_id fortress to cell
    # this path is in the available path list
    # path may cross from friend
    def get_shortest_path_to_cell(self,
                                  from_player_id: int = None,
                                  from_player: Player = None,
                                  cell: Cell = None,
                                  row: int = None,
                                  col: int = None) -> Optional["Path"]:
        if from_player is not None:
            from_player_id = from_player.player_id
        elif from_player_id is None:
            return None

        if self.get_player_by_id(from_player_id) is None:
            return None

        if cell is None:
            if row is None or col is None:
                return None
            cell = self._map.get_cell(row, col)
        shortest_path_from_player = World._shortest_path.get(
            from_player_id, None)
        if shortest_path_from_player is None:
            return None
        return shortest_path_from_player[cell.row][cell.col]

    # place unit with type_id in path_id
    def put_unit(self,
                 type_id: int = None,
                 path_id: int = None,
                 base_unit: BaseUnit = None,
                 path: Path = None) -> None:
        fail = False
        if type_id is not None and type(type_id) is not int:
            Logs.show_log(
                "put_unit function called with invalid type_id argument!")
            fail = True
        if path_id is not None and type(path_id) is not int:
            Logs.show_log(
                "put_unit function called with invalid path_id argument!")
            fail = True
        if base_unit is not None and type(base_unit) is not BaseUnit:
            Logs.show_log(
                "put_unit function called with invalid base_unit argument")
            fail = True
        if path is not None and type(path) is not Path:
            Logs.show_log(
                "put_unit function called with invalid path argument")
            fail = True
        if fail is True:
            return

        if base_unit is not None:
            type_id = base_unit.type_id
        if path is not None:
            path_id = path.id
        if path_id is None or type_id is None:
            return None
        if type_id is None:
            Logs.show_log("type_id is None in cast_area spell function call!")
            return

        message = Message(turn=self.get_current_turn(),
                          type="putUnit",
                          info={
                              "typeId": type_id,
                              "pathId": path_id
                          })
        self._queue.put(message)

    # return the number of turns passed
    def get_current_turn(self) -> int:
        return self._current_turn

    def get_remaining_time(self) -> int:
        if self.get_current_turn() > 0:
            return self._game_constants.turn_timeout - self._get_time_past()
        else:
            return self._game_constants.pick_timeout - self._get_time_past()

    # put unit_id in path_id in position 'index' all spells of one kind have the same id
    def cast_unit_spell(self,
                        unit: Unit = None,
                        unit_id: int = None,
                        path: Path = None,
                        path_id: int = None,
                        cell: Cell = None,
                        row: int = None,
                        col: int = None,
                        spell: Spell = None,
                        spell_id: int = None) -> None:
        if spell is None and spell_id is None:
            Logs.show_log(
                "cast_unit_spell function called with no spell input!")
            return None
        if spell is None:
            if type(spell_id) is not int:
                Logs.show_log(
                    "spell_id is not an integer in cast_unit_spell function call!"
                )
                return
            spell = self.get_spell_by_id(spell_id)

        if row is not None and col is not None:
            if type(row) is not int or type(col) is not int:
                Logs.show_log(
                    "row and column arguments are invalid in cast_unit_spell function call"
                )
                return
            cell = Cell(row, col)

        if unit is not None:
            if type(unit) is not Unit:
                Logs.show_log(
                    "unit argument is invalid in cast_unit_spell function call"
                )
                return
            unit_id = unit.unit_id
        if path is not None:
            if type(path) is not Path:
                Logs.show_log(
                    "path argument is invalid in cast_unit_spell function call"
                )
                return
            path_id = path.id

        if type(unit_id) is not int:
            Logs.show_log(
                "unit_id argument is invalid in cast_unit_spell function call")
            return

        if type(path_id) is not int:
            Logs.show_log(
                "path_id argument is invalid in cast_unit_spell function call")
            return

        message = Message(type="castSpell",
                          turn=self.get_current_turn(),
                          info={
                              "typeId": spell.type_id,
                              "cell": {
                                  "row": cell.row,
                                  "col": cell.col
                              },
                              "unitId": unit_id,
                              "pathId": path_id
                          })
        self._queue.put(message)

    # cast spell in the cell 'center'
    def cast_area_spell(self,
                        center: Cell = None,
                        row: int = None,
                        col: int = None,
                        spell: Spell = None,
                        spell_id: int = None) -> None:
        if spell is None:
            if spell_id is None or type(spell_id) is not int:
                Logs.show_log("no valid spell selected in cast_area_spell!")
                return
            spell = self.get_spell_by_id(spell_id)
        if type(spell) is not Spell:
            Logs.show_log("no valid spell selected in cast_area_spell!")
            return

        if row is not None and col is not None:
            center = self._map.get_cell(row, col)

        if center is not None:
            message = Message(type="castSpell",
                              turn=self.get_current_turn(),
                              info={
                                  "typeId": spell.type_id,
                                  "cell": {
                                      "row": center.row,
                                      "col": center.col
                                  },
                                  "unitId": -1,
                                  "pathId": -1
                              })
            self._queue.put(message)
        else:
            Logs.show_log("invalid cell selected in cast_area_spell")

    # returns a list of units the spell casts effects on
    def get_area_spell_targets(self,
                               center: Cell = None,
                               row: int = None,
                               col: int = None,
                               spell: Spell = None,
                               type_id: int = None) -> List["Unit"]:
        if spell is None:
            if type_id is not None:
                spell = self.get_cast_spell_by_id(type_id)
            else:
                return []
        if type(spell) is not Spell:
            Logs.show_log("invalid spell chosen in get_area_spell_targets")
            return []
        if not spell.is_area_spell():
            return []
        if center is None:
            center = Cell(row, col)
        ls = []
        for i in range(max(0, center.row - spell.range),
                       min(center.row + spell.range + 1, self._map.row_num)):
            for j in range(
                    max(0, center.col - spell.range),
                    min(center.col + spell.range + 1, self._map.col_num)):
                cell = self._map.get_cell(i, j)
                for u in cell.units:
                    if self._is_unit_targeted(u, spell.target):
                        ls.append(u)
        return ls

    def _is_unit_targeted(self, unit, spell_target):
        if spell_target == SpellTarget.SELF:
            if unit in self._player.units:
                return True
        elif spell_target == SpellTarget.ALLIED:
            if unit in self._player_friend.units or unit in self._player.units:
                return True
        elif spell_target == SpellTarget.ENEMY:
            if unit in self._player_first_enemy.units or unit in self._player_second_enemy.units:
                return True
        return False

    # every once in a while you can upgrade, this returns the remaining time for upgrade
    def get_remaining_turns_to_upgrade(self) -> int:
        rem_turn = (self._game_constants.turns_to_upgrade -
                    self._current_turn) % self._game_constants.turns_to_upgrade
        if rem_turn == 0:
            return self._game_constants.turns_to_upgrade
        return rem_turn

    # every once in a while a spell is given this remains the remaining time to get new spell
    def get_remaining_turns_to_get_spell(self) -> int:
        rem_turn = (self._game_constants.turns_to_spell -
                    self._current_turn) % self._game_constants.turns_to_spell
        if rem_turn == 0:
            return self._game_constants.turns_to_spell
        return rem_turn

    # returns a list of spells casted on a cell
    def get_range_upgrade_number(self) -> int:
        return self._turn_updates.available_range_upgrade

    def get_damage_upgrade_number(self) -> int:
        return self._turn_updates.available_damage_upgrade

    # returns the spell given in that turn
    def get_received_spell(self) -> Optional["Spell"]:
        spell_id = self._turn_updates.received_spell
        spell = self.get_spell_by_id(spell_id)
        return spell

    # returns the spell given in that turn to friend
    def get_friend_received_spell(self) -> Optional["Spell"]:
        spell_id = self._turn_updates.friend_received_spell
        spell = self.get_spell_by_id(spell_id)
        return spell

    def upgrade_unit_range(self,
                           unit: Unit = None,
                           unit_id: int = None) -> None:
        if unit is not None:
            unit_id = unit.unit_id

        if unit_id is not None and type(unit_id) is int:
            self._queue.put(
                Message(type="rangeUpgrade",
                        turn=self.get_current_turn(),
                        info={"unitId": unit_id}))
        else:
            Logs.show_log("invalid unit or unit_id in upgrade_unit_range")

    def upgrade_unit_damage(self,
                            unit: Unit = None,
                            unit_id: int = None) -> None:
        if unit is not None:
            unit_id = unit.unit_id

        if unit_id is not None and type(unit_id) is int:
            self._queue.put(
                Message(type="damageUpgrade",
                        turn=self.get_current_turn(),
                        info={"unitId": unit_id}))
        else:
            Logs.show_log("invalid unit or unit_id in upgrade_unit_damage")

    def get_all_base_units(self) -> List[BaseUnit]:
        return copy.deepcopy(self._base_units)

    def get_all_spells(self) -> List[Spell]:
        return copy.deepcopy(self._spells)

    def get_king_by_id(self, player_id: int) -> Optional["King"]:
        for p in self._players:
            if p.player_id == player_id:
                return p.king
        return None

    def get_base_unit_by_id(self, type_id: int) -> Optional["BaseUnit"]:
        for bu in self._base_units:
            if bu.type_id == type_id:
                return bu
        return None

    # returns unit in map with a unit_id
    def get_unit_by_id(self, unit_id: int) -> Optional["Unit"]:
        for unit in self._map.units:
            if unit.unit_id == unit_id:
                return unit
        return None

    def get_player_by_id(self, player_id: int) -> Optional["Player"]:
        for player in self._players:
            if player.player_id == player_id:
                return player
        return None

    def get_spell_by_id(self, type_id: int) -> Optional["Spell"]:
        for spell in self._spells:
            if spell.type_id == type_id:
                return spell
        return None

    def get_game_constants(self) -> GameConstants:
        return self._game_constants

    def _get_paths_starting_with(self, first, paths):
        ret = []
        for path in paths:
            c_path = Path(path=path)
            if c_path.cells[-1] == first:
                c_path.cells.reverse()
            if c_path.cells[0] == first:
                ret.append(c_path)
        return ret

    def _handle_end_message(self, scores_list_msg):
        return dict([(score["playerId"], score["score"])
                     for score in scores_list_msg])
예제 #14
0
class Game():
    def __init__(self):
        self.direction = 'down'
        self.hero_stat_statusbar = None
        self.level = 1
        self.view = View(self.level)
        self.map = Map()
        self.hero = Hero(self.map.occupied_tile_position)
        self.game_start(self.level)
        self.view.master.mainloop()

    def game_start(self, level):
        self.hero_move_number = 0
        self.map.next_level_map()
        self.view.display_map(self.map.occupied_tile_position)
        self.view.statusbar_text(self.level, self.hero_stat_statusbar)
        self.hero.position = self.hero.randomize_position(
            self.map.occupied_tile_position)
        self.view.display_intro(self.level)
        self.generate_enemies(level)
        self.hero.restore_health()
        self.enemy_stat_statusbar = None
        self.input_event()

# *********************Events**********************

    def input_event(self):
        self.view.master.bind('<s>', self.set_move)
        self.view.master.bind('<w>', self.set_move)
        self.view.master.bind('<a>', self.set_move)
        self.view.master.bind('<d>', self.set_move)
        self.view.master.bind('<space>', self.battle)
        self.view.master.bind('<Escape>', self.quit)

    def set_move(self, event):
        if event.char == 'w':
            self.hero.position, self.map.occupied_tile_position = self.hero.move(
                self.hero.moves['up'], self.map.occupied_tile_position)
            self.direction = 'up'
        elif event.char == 's':
            self.hero.position, self.map.occupied_tile_position = self.hero.move(
                self.hero.moves['down'], self.map.occupied_tile_position)
            self.direction = 'down'
        elif event.char == 'a':
            self.hero.position, self.map.occupied_tile_position = self.hero.move(
                self.hero.moves['left'], self.map.occupied_tile_position)
            self.direction = 'left'
        elif event.char == 'd':
            self.hero.position, self.map.occupied_tile_position = self.hero.move(
                self.hero.moves['right'], self.map.occupied_tile_position)
            self.direction = 'right'
        self.hero_move_number += 1
        self.view.display_hero(self.hero.position, self.direction,
                               self.hero.isDead)
        self.generate_enemy_moves()
        self.view.display_enemies(self.enemy_list)
        self.update_hero_status()
        self.enemy_stat_statusbar = None
        self.view.statusbar_text(self.level, self.hero_stat_statusbar)
        if self.hero_move_number > 0:
            self.start()

    def generate_enemy_moves(self):
        if self.hero_move_number % 2:
            for enemy in self.enemy_list:
                enemy.position, self.map.occupied_tile_position = enemy.move(
                    choice(list(enemy.moves.values())),
                    self.map.occupied_tile_position)

    def battle(self, event):
        x_coord = self.hero.position[0] + self.hero.moves[self.direction][0]
        y_coord = self.hero.position[1] + self.hero.moves[self.direction][1]
        attack_coords = [x_coord, y_coord]
        attacked_enemy = self.check_attacked_enemy(attack_coords)
        if attacked_enemy == None:
            return
        attacked_enemy.current_HP -= max(
            self.hero.stats[2] + randint(1, 6) - attacked_enemy.stats[1], 0)
        self.hero.current_HP -= max(
            attacked_enemy.stats[2] + randint(1, 6) - self.hero.stats[1], 0)
        self.view.display_attack(self.hero.position, attacked_enemy.position)
        self.update_hero_status()
        self.update_enemy_stats(attacked_enemy)
        self.view.statusbar_text(self.level, self.hero_stat_statusbar,
                                 self.enemy_stat_statusbar)
        if attacked_enemy.current_HP <= 0:
            self.kill_enemy(attacked_enemy)
        if self.hero.current_HP <= 0:
            self.game_over()

    def check_attacked_enemy(self, attack_coords):
        attacked_enemy = None
        if len(self.enemy_list) != 0:
            for enemy in self.enemy_list:
                if enemy.position == attack_coords:
                    attacked_enemy = enemy
        return attacked_enemy

    def kill_enemy(self, attacked_enemy):
        self.map.occupied_tile_position[attacked_enemy.position[1]][
            attacked_enemy.position[0]] = 0
        self.enemy_list.remove(attacked_enemy)
        self.view.display_enemies(self.enemy_list)
        self.view.display_kill(attacked_enemy.position)
        self.hero.level_up()
        if attacked_enemy.has_key == True:
            self.hero.has_key = True
        if type(attacked_enemy) == Boss:
            self.hero.has_killed_boss = True
        if self.hero.has_key == True and self.hero.has_killed_boss == True:
            self.new_game()

    def game_over(self):
        self.enemy_list = []
        self.hero.isDead = True
        self.view.display_enemies(self.enemy_list)
        self.view.display_hero(self.hero.position, self.direction,
                               self.hero.isDead)
        self.view.display_game_over()

    def new_game(self):
        self.level += 1
        self.game_start(self.level)
        self.hero.has_killed_boss = False
        self.hero.has_key = False

    def quit(self, event):
        self.view.master.destroy()

    def start(self):
        self.view.delete_pictures()
        self.view.display_hero(self.hero.position, self.direction,
                               self.hero.isDead)
        self.view.display_enemies(self.enemy_list)

    def update_hero_status(self):
        self.hero_stat_statusbar = self.hero.stats[:]
        self.hero_stat_statusbar.append(self.hero.current_HP)
        self.hero_stat_statusbar.append(self.hero.has_key)

    def update_enemy_stats(self, attacked_enemy):
        self.enemy_stat_statusbar = attacked_enemy.stats[:]
        self.enemy_stat_statusbar.append(attacked_enemy.current_HP)
        if type(attacked_enemy) == Boss:
            self.enemy_stat_statusbar.append('boss')
        else:
            self.enemy_stat_statusbar.append('skeleton')


# *****************Generate enemies*******************

    def generate_enemies(self, level):
        self.boss = Boss(self.map.wall_position, level)
        self.enemy_list = [self.boss]
        for i in range(self.map.number_of_skeletons):
            skeleton_name = 'skeleton' + str(i)
            self.skeleton_name = Skeleton(self.map.wall_position, level)
            if skeleton_name[-1:] == '0':
                self.skeleton_name.has_key = True
            self.enemy_list.append(self.skeleton_name)
예제 #15
0
def play_game(level, life_num):
    ''' Here is the play_game function'''
    # -------- SET LEVEL DIFFICULTY -----------
    # level = input("How many ennemies (0 to 10) ? ")
    # while int(level) not in range(11):
    #     level = input("Ennemies must be between 0 and 10 : ")
    Sprite.LEVEL = int(level)  # from 0 to 10

    # -------- INITIALIZE -----------
    # DEFINE MAP
    map_game = Map('structures/Structure' + str(level) + '.csv')

    # OPEN A NEW WINDOW
    size = (15 * map_game.SPRITE_WIDTH, 15 * map_game.SPRITE_WIDTH)
    screen = py.display.set_mode(size)
    py.display.set_caption("Mac Gyver escapes")
    # CLEAR THE SCREEN TO black.
    black = (0, 0, 0)
    white = (255, 255, 255)
    screen.fill(black)

    # DRAW MAP WITH TILES
    tiles = Sprite('floor-tiles-20x20', map_game, (5, 0), 20)
    map_game.draw(tiles, screen)
    font = py.font.Font('ressource/ARCADECLASSIC.ttf', 25)
    level_text = font.render('L ' + str(level), 0, white)
    level_text_rect = level_text.get_rect()

    # INITIALIZE PERSONS ON THE MAP
    macgyver = Person('macgyver', map_game)
    guardian = Person('guardian', map_game)
    ennemies = []
    ennemies_images = Sprite('personnages', map_game, (0, 0), 32).surfs
    for i in range(len(ennemies_images)):
        ennemy = Person('ennemy', map_game)
        while ennemy.distance(
                macgyver) <= 1:  # NOT TO LOOSE AT THE BEGINNING OF GAME
            ennemy = Person('ennemy', map_game)
        ennemy.image = ennemies_images[i]
        ennemies.append(ennemy)

    # INITIALIZE OBJECTS ON THE MAP
    objects = Objects(map_game)
    objects_pos = [object.position for object in objects.list]

    # THE LOOP WILL CARRY ON UNTIL THE USER EXIT THE GAME.
    carry_on = True  # WHILE NOT QUIT
    playing = True  # WHILE NOT WIN AND NOT LOOSE
    update = True  # WHEN KEY PRESSED
    win = False
    loose = False

    # THE CLOCK WILL BE USED TO CONTROL HOW FAST THE SCREEN UPDATES
    clock = py.time.Clock()
    py.key.set_repeat(400, 30)

    # ----------------------------------- MAIN PROGRAM LOOP -----------
    while carry_on:
        key_pressed = 0
        for event in py.event.get():  # USER DID SOMETHING
            if event.type == py.QUIT or py.key.get_pressed()[
                    py.K_ESCAPE]:  # IF USER CLICKED CLOSE
                carry_on = False  # FLAG THAT WE ARE DONE SO WE EXIT THIS LOOP
                return 'quit'
            # LISTEN FOR PRESSED KEY
            if event.type == py.KEYDOWN:
                key_pressed = event.key
                update = True
                if win:
                    return 'win'
                if loose:
                    return 'loose'
        # ------------------------------- EVENTS -----
        if update:
            # MOVE ENNEMIES ON THE MAP
            for ennemy in ennemies:
                (x_en, y_en) = ennemy.position
                seed(datetime.now())
                ennemy_move = choice(
                    [py.K_UP, py.K_DOWN, py.K_RIGHT, py.K_LEFT])
                ennemy.move(ennemy_move, map_game)
                # UPDATE LAST POSITION
                tiles.draw_sprite(map_game.decoration[(x_en, y_en)], screen,
                                  x_en * map_game.SPRITE_WIDTH,
                                  y_en * map_game.SPRITE_WIDTH)

            # MOVE MACGYVER ON THE MAP
            (x_mac1, y_mac1) = macgyver.position
            if playing:
                macgyver.move(key_pressed, map_game)
            # UPDATE LAST POSITION
            tiles.draw_sprite(map_game.decoration[(x_mac1, y_mac1)], screen,
                              x_mac1 * map_game.SPRITE_WIDTH,
                              y_mac1 * map_game.SPRITE_WIDTH)

            # ----------------------------- DRAWING CODE GOES HERE -----
            # DRAW OBJECT ON THE MAP
            for stuff in objects.list:
                stuff.draw_object(screen,
                                  stuff.position[0] * map_game.SPRITE_WIDTH,
                                  stuff.position[1] * map_game.SPRITE_WIDTH)

            # REDRAW PERSONS
            guardian.draw_person(screen,
                                 guardian.position[0] * map_game.SPRITE_WIDTH,
                                 guardian.position[1] * map_game.SPRITE_WIDTH)
            macgyver.draw_person(screen,
                                 macgyver.position[0] * map_game.SPRITE_WIDTH,
                                 macgyver.position[1] * map_game.SPRITE_WIDTH)
            for ennemy in ennemies:
                ennemy.draw_person(screen,
                                   ennemy.position[0] * map_game.SPRITE_WIDTH,
                                   ennemy.position[1] * map_game.SPRITE_WIDTH)

            # REDRAW LIVES & LEVEL
            heart = py.transform.scale(py.image.load('ressource/heart.png'),
                                       (int(map_game.SPRITE_WIDTH / 2),
                                        int(map_game.SPRITE_WIDTH / 2)))
            for i in range(life_num):
                screen.blit(heart, (20 * i + 10, 5))
            screen.blit(level_text,
                        (screen.get_width() - level_text_rect.width - 10, 5))

            # MAC GYVER TAKE AN OBJECT ON THE MAP
            if macgyver.position in objects_pos:
                # GET INDEX OF OBJECT
                object_found_ind = objects_pos.index(macgyver.position)
                # CLEAR POSITION ON THE MAP
                del objects_pos[object_found_ind]
                # CLEAR OBJECT FROM OBJECTS LIST
                del objects.list[object_found_ind]

            # COMPUTE DISTANCE FROM ENNEMIES
            dist_from_ennemies = [
                macgyver.distance(ennemy) for ennemy in ennemies
            ]
            dist_from_ennemies.append(macgyver.distance(guardian))

            # MAC GYVER WIN OR DIE
            if min(dist_from_ennemies) <= 1.0:
                playing = False
                if objects.list == [] and macgyver.distance(guardian) == 1:
                    py.display.set_caption("IT'S A WIN!")
                    end_print('you_win', 'Press any key to continue', screen)
                    win = True
                else:
                    if life_num == 1:
                        message = 'GAME OVER'
                    else:
                        message = 'Press any key to continue'
                    py.display.set_caption("YOU DIE!")
                    end_print('you_lose', message, screen)
                    loose = True

            # --- GO AHEAD AND UPDATE THE SCREEN WITH WHAT WE'VE DRAWN. ---
            py.display.flip()
        update = False
        # --- LIMIT TO 60 FRAMES PER SECOND ---
        clock.tick(60)
예제 #16
0
파일: world.py 프로젝트: aghn648/_NOOBS
class World(ABC):
    DEBUGGING_MODE = False
    LOG_FILE_POINTER = None

    def __init__(self, world=None, queue=None):
        self.game_constants = None

        self.turn_updates = None

        self.map = None
        self.base_units = None
        self.current_turn = 0

        self.players = []
        self.player = None
        self.player_friend = None
        self.player_first_enemy = None
        self.player_second_enemy = None
        self.spells = []
        self.cast_spells = []

        if world is not None:
            self.game_constants = world.game_constants

            self.turn_updates = TurnUpdates(turn_updates=world.turn_updates)

            self.map = world.map
            self.base_units = world.base_units
            self.spells = world.spells
            self.current_turn = world.current_turn

            self.players = world.players
            self.player = world.player
            self.player_friend = world.player_friend
            self.player_first_enemy = world.player_first_enemy
            self.player_second_enemy = world.player_second_enemy
            self.cast_spells = world.cast_spells

            self.queue = world.queue
        else:
            self.queue = queue

    def get_current_time_millis(self):
        return int(round(time.time() * 1000))

    def get_time_past(self):
        return self.get_current_time_millis() - self.start_time

    def get_player_by_id(self, player_id):
        for player in self.players:
            if player.player_id == player_id:
                return player
        return None

    def get_spell_by_id(self, type_id):
        for spell in self.spells:
            if spell.type_id == type_id:
                return spell
        return None

    def _game_constant_init(self, game_constants_msg):
        self.game_constants = GameConstants(
            max_ap=game_constants_msg["maxAP"],
            max_turns=game_constants_msg["maxTurns"],
            turn_timeout=game_constants_msg["turnTimeout"],
            pick_timeout=game_constants_msg["pickTimeout"],
            turns_to_upgrade=game_constants_msg["turnsToUpgrade"],
            turns_to_spell=game_constants_msg["turnsToSpell"],
            damage_upgrade_addition=game_constants_msg[
                "damageUpgradeAddition"],
            range_upgrade_addition=game_constants_msg["rangeUpgradeAddition"],
            hand_size=game_constants_msg["handSize"],
            deck_size=game_constants_msg["deckSize"])

    def _find_path_starting_and_ending_with(self, first, last, paths):
        for path in paths:
            c_path = Path(path=path)
            if c_path.cells[0] == first and c_path.cells[-1] == last:
                return c_path
            c_path.cells.reverse()
            if c_path.cells[0] == first and c_path.cells[-1] == last:
                return c_path
        return None

    def _map_init(self, map_msg):
        row_num = map_msg["rows"]
        col_num = map_msg["cols"]

        input_cells = [[Cell(row=row, col=col) for col in range(col_num)]
                       for row in range(row_num)]

        paths = [
            Path(id=path["id"],
                 cells=[
                     input_cells[cell["row"]][cell["col"]]
                     for cell in path["cells"]
                 ]) for path in map_msg["paths"]
        ]
        kings = [
            King(player_id=king["playerId"],
                 center=input_cells[king["center"]["row"]][king["center"]
                                                           ["col"]],
                 hp=king["hp"],
                 attack=king["attack"],
                 range=king["range"],
                 target=None,
                 target_cell=None,
                 is_alive=True) for king in map_msg["kings"]
        ]

        self.players = [
            Player(player_id=map_msg["kings"][i]["playerId"],
                   king=kings[i],
                   deck=[],
                   hand=[],
                   ap=self.game_constants.max_ap,
                   paths_from_player=self._get_paths_starting_with(
                       kings[i].center, paths),
                   path_to_friend=self._find_path_starting_and_ending_with(
                       kings[i].center, kings[i ^ 1].center, paths),
                   units=[],
                   cast_area_spell=None,
                   cast_unit_spell=None,
                   duplicate_units=[],
                   hasted_units=[],
                   played_units=[],
                   died_units=[],
                   range_upgraded_unit=None,
                   damage_upgraded_unit=None,
                   spells=[]) for i in range(4)
        ]

        for player in self.players:
            player.paths_from_player.remove(player.path_to_friend)

        self.player = self.players[0]
        self.player_friend = self.players[1]
        self.player_first_enemy = self.players[2]
        self.player_second_enemy = self.players[3]

        self.map = Map(row_num=row_num,
                       column_num=col_num,
                       paths=paths,
                       kings=kings,
                       cells=input_cells,
                       units=[])

    # returns unit in map with a unit_id
    def get_unit_by_id(self, unit_id):
        for unit in self.map.units:
            if unit.unit_id == unit_id:
                return unit
        return None

    def _base_unit_init(self, msg):
        self.base_units = [
            BaseUnit(type_id=b_unit["typeId"],
                     max_hp=b_unit["maxHP"],
                     base_attack=b_unit["baseAttack"],
                     base_range=b_unit["baseRange"],
                     target_type=UnitTarget.get_value(b_unit["target"]),
                     is_flying=b_unit["isFlying"],
                     is_multiple=b_unit["isMultiple"],
                     ap=b_unit["ap"]) for b_unit in msg
        ]

    def _get_base_unit_by_id(self, type_id):
        for base_unit in self.base_units:
            if base_unit.type_id == type_id:
                return base_unit
        return None

    def _spells_init(self, msg):
        self.spells = [
            Spell(type=SpellType.get_value(spell["type"]),
                  type_id=spell["typeId"],
                  duration=spell["duration"],
                  priority=spell["priority"],
                  range=spell["range"],
                  power=spell["power"],
                  target=SpellTarget.get_value(spell["target"]),
                  is_damaging=False) for spell in msg
        ]

    def _handle_init_message(self, msg):
        self._game_constant_init(msg['gameConstants'])
        self._map_init(msg["map"])
        self._base_unit_init(msg["baseUnits"])
        self._spells_init(msg["spells"])

    def _handle_turn_kings(self, msg):
        for king_msg in msg:
            hp = king_msg["hp"] if (king_msg["hp"] > 0
                                    and king_msg["isAlive"]) else -1
            self.get_player_by_id(king_msg["playerId"]).king.hp = hp
            self.get_player_by_id(king_msg["playerId"]).king.target = king_msg[
                "target"] if king_msg["target"] != -1 else None

    def _handle_turn_units(self, msg, is_dead_unit=False):
        if not is_dead_unit:
            self.map.clear_units()
            for player in self.players:
                player.units.clear()
                player.played_units.clear()
                player.hasted_units.clear()
                player.duplicate_units.clear()
                player.range_upgraded_unit = None
                player.damage_upgraded_unit = None
        else:
            for player in self.players:
                player.died_units.clear()

        for unit_msg in msg:
            unit_id = unit_msg["unitId"]
            player = self.get_player_by_id(player_id=unit_msg["playerId"])
            base_unit = self.base_units[unit_msg["typeId"]]

            if not unit_msg['target'] == -1:
                target_cell = Cell(row=unit_msg["targetCell"]["row"],
                                   col=unit_msg["targetCell"]["col"])
            else:
                target_cell = None
            unit = Unit(unit_id=unit_id,
                        base_unit=base_unit,
                        cell=self.map.get_cell(unit_msg["cell"]["row"],
                                               unit_msg["cell"]["col"]),
                        path=self.map.get_path_by_id(unit_msg["pathId"]),
                        hp=unit_msg["hp"],
                        damage_level=unit_msg["damageLevel"],
                        range_level=unit_msg["rangeLevel"],
                        is_duplicate=unit_msg["isDuplicate"],
                        is_hasted=unit_msg["isHasted"],
                        range=unit_msg["range"],
                        attack=unit_msg["attack"],
                        target=unit_msg["target"],
                        target_cell=target_cell,
                        affected_spells=[
                            self.get_cast_spell_by_id(cast_spell_id)
                            for cast_spell_id in unit_msg["affectedSpells"]
                        ],
                        target_if_king=None
                        if self.get_player_by_id(unit_msg["target"]) == None
                        else self.get_player_by_id(unit_msg["target"]).king,
                        player_id=unit_msg["playerId"])
            if not is_dead_unit:
                self.map.add_unit_in_cell(unit.cell.row, unit.cell.col, unit)
                player.units.append(unit)
                if unit_msg["wasDamageUpgraded"]:
                    player.damage_upgraded_unit = unit
                if unit_msg["wasRangeUpgraded"]:
                    player.range_upgraded_unit = unit
                if unit_msg["wasPlayedThisTurn"]:
                    player.played_units.append(unit)
                if unit.is_hasted:
                    player.hasted_units.append(unit)
                if unit.is_duplicate:
                    player.duplicate_units.append(unit)
            else:
                player.died_units.append(unit)
        for unit in self.map.units:
            if unit.target == -1 or unit.target_if_king != None:
                unit.target = None
            else:
                unit.target = self.map.get_unit_by_id(unit.target)

    def _handle_turn_cast_spells(self, msg):
        self.cast_spells = []
        for cast_spell_msg in msg:
            spell = self.get_spell_by_id(cast_spell_msg["typeId"])
            cell = self.map.get_cell(cast_spell_msg["cell"]["row"],
                                     cast_spell_msg["cell"]["col"])
            affected_units = [
                self.get_unit_by_id(affected_unit_id)
                for affected_unit_id in cast_spell_msg["affectedUnits"]
            ]
            if spell.is_area_spell():
                self.cast_spells.append(
                    CastAreaSpell(
                        spell=spell,
                        id=cast_spell_msg["id"],
                        caster_id=cast_spell_msg["casterId"],
                        cell=cell,
                        remaining_turns=cast_spell_msg["remainingTurns"],
                        affected_units=affected_units))
            elif spell.is_unit_spell():
                self.cast_spells.append(
                    CastUnitSpell(
                        spell=spell,
                        id=cast_spell_msg["id"],
                        caster_id=cast_spell_msg["casterId"],
                        cell=cell,
                        unit=self.get_unit_by_id(cast_spell_msg["unitId"]),
                        path=self.map.get_path_by_id(cast_spell_msg["pathId"]),
                        affected_units=affected_units))

    def get_cast_spell_by_id(self, id):
        for cast_spell in self.cast_spells:
            if cast_spell.id == id:
                return cast_spell
        return None

    def _handle_turn_message(self, msg):
        self.current_turn = msg['currTurn']
        self.player.deck = [
            self._get_base_unit_by_id(deck_type_id)
            for deck_type_id in msg["deck"]
        ]
        self.player.hand = [
            self._get_base_unit_by_id(hand_type_id)
            for hand_type_id in msg["hand"]
        ]
        self._handle_turn_kings(msg["kings"])
        self._handle_turn_units(msg["units"])
        self._handle_turn_units(msg=msg["diedUnits"], is_dead_unit=True)
        self._handle_turn_cast_spells(msg["castSpells"])

        self.turn_updates = TurnUpdates(
            received_spell=msg["receivedSpell"],
            friend_received_spell=msg["friendReceivedSpell"],
            got_range_upgrade=msg["gotRangeUpgrade"],
            got_damage_upgrade=msg["gotDamageUpgrade"],
            available_range_upgrades=msg["availableRangeUpgrades"],
            available_damage_upgrades=msg["availableDamageUpgrades"])

        self.player.set_spells(
            [self.get_spell_by_id(spell_id) for spell_id in msg["mySpells"]])
        self.player_friend.set_spells([
            self.get_spell_by_id(spell_id) for spell_id in msg["friendSpells"]
        ])
        self.player.ap = msg["remainingAP"]

        self.start_time = self.get_current_time_millis()

    # in the first turn 'deck picking' give unit_ids or list of unit names to pick in that turn
    def choose_deck(self, type_ids=None, base_units=None):
        message = Message(type="pick", turn=self.get_current_turn(), info=None)
        if type_ids is not None:
            message.info = {"units": type_ids}
        elif base_units is not None:
            message.info = {"units": [unit.type_id for unit in base_units]}
        self.queue.put(message)

    def get_me(self):
        return self.player

    def get_friend(self):
        return self.player_friend

    def get_friend_by_id(self, player_id):
        if self.player.player_id == player_id:
            return self.player_friend
        elif self.player_friend.player_id == player_id:
            return self.player
        elif self.player_first_enemy.player_id == player_id:
            return self.player_second_enemy
        elif self.player_second_enemy.player_id == player_id:
            return self.player_first_enemy
        else:
            return None

    def get_first_enemy(self):
        return self.player_first_enemy

    def get_second_enemy(self):
        return self.player_second_enemy

    def get_map(self):
        return self.map

    # return a list of paths crossing one cell
    def get_paths_crossing_cell(self, cell=None, row=None, col=None):
        if cell is None:
            if row is None or col is None:
                return
            cell = self.map.get_cell(row, col)

        paths = []
        for p in self.map.paths:
            if cell in p.cells:
                paths.append(p)
        return paths

    # return a list of units in a cell
    def get_cell_units(self, cell=None, row=None, col=None):
        if cell is None:
            if row is None and col is None:
                return None
            cell = self.map.get_cell(row, col)
        return cell.units

    # return the shortest path from player_id fortress to cell
    # this path is in the available path list
    # path may cross from friend
    def get_shortest_path_to_cell(self,
                                  from_player_id=None,
                                  from_player=None,
                                  cell=None,
                                  row=None,
                                  col=None):
        def path_count(paths):
            shortest_path = None
            count = 0
            for p in paths:
                count_num = 0
                for c in p.cells:
                    if c == cell:
                        if shortest_path is None:
                            count = count_num
                            shortest_path = p

                        elif count_num < count:
                            count = count_num
                            shortest_path = p
                    count_num += 1
            return shortest_path

        if from_player is not None:
            from_player_id = from_player.player_id
        if cell is None:
            if row is None or col is None:
                return
            cell = self.map.get_cell(row, col)
        p = path_count(self.get_player_by_id(from_player_id).paths_from_player)
        if p is None:
            ls = [self.get_player_by_id(from_player_id).path_to_friend]
            ptf = path_count(ls)
            if ptf is None:
                pff = path_count(
                    self.get_friend_by_id(from_player_id).paths_from_player)
                if pff is None:
                    return None
                return pff
            return ptf
        return p

    # place unit with type_id in path_id
    def put_unit(self, type_id=None, path_id=None, base_unit=None, path=None):
        if base_unit is not None:
            type_id = base_unit.type_id
        if path is not None:
            path_id = path.id
        if path_id is None or type_id is None:
            return None
        message = Message(turn=self.get_current_turn(),
                          type="putUnit",
                          info={
                              "typeId": type_id,
                              "pathId": path_id
                          })
        self.queue.put(message)

    # return the number of turns passed
    def get_current_turn(self):
        return self.current_turn

    # put unit_id in path_id in position 'index' all spells of one kind have the same id
    def cast_unit_spell(self,
                        unit=None,
                        unit_id=None,
                        path=None,
                        path_id=None,
                        cell=None,
                        row=None,
                        col=None,
                        spell=None,
                        spell_id=None):
        if spell is None and spell_id is None:
            return None
        if spell is None:
            spell = self.get_spell_by_id(spell_id)
        if row is not None and col is not None:
            cell = Cell(row, col)
        if unit is not None:
            unit_id = unit.unit_id
        if path is not None:
            path_id = path.id
        message = Message(type="castSpell",
                          turn=self.get_current_turn(),
                          info={
                              "typeId": spell.type_id,
                              "cell": {
                                  "row": cell.row,
                                  "col": cell.col
                              },
                              "unitId": unit_id,
                              "pathId": path_id
                          })
        self.queue.put(message)

    # cast spell in the cell 'center'
    def cast_area_spell(self,
                        center=None,
                        row=None,
                        col=None,
                        spell=None,
                        spell_id=None):
        if spell is None:
            spell = self.get_spell_by_id(spell_id)
        if row is not None and col is not None:
            center = self.map.get_cell(row, col)

        if center is not None:
            message = Message(type="castSpell",
                              turn=self.get_current_turn(),
                              info={
                                  "typeId": spell.type_id,
                                  "cell": {
                                      "row": center.row,
                                      "col": center.col
                                  },
                                  "unitId": -1,
                                  "pathId": -1
                              })
            self.queue.put(message)

    # returns a list of units the spell casts effects on
    # NOT CORRECT!!! #
    def get_area_spell_targets(self,
                               center,
                               row=None,
                               col=None,
                               spell=None,
                               type_id=None):
        if spell is None:
            if type_id is not None:
                spell = self.get_cast_spell_by_id(type_id)
            else:
                return []
        if not spell.is_area_spell():
            return []
        if center is None:
            center = Cell(row, col)
        ls = []
        for i in range(max(0, center.row - spell.range),
                       min(center.row + spell.range, self.map.row_num)):
            for j in range(max(0, center.col - spell.range),
                           min(center.col + spell.range, self.map.column_num)):
                cell = self.map.get_cell(i, j)
                for u in cell.units:
                    if self._is_unit_targeted(u, spell.target):
                        ls.append(u)

    def _is_unit_targeted(self, unit, spell_target):
        if spell_target == 1:
            if unit in self.player.units:
                return True
        elif spell_target == 2:
            if unit in self.player_friend or unit in self.player.units:
                return True
        elif spell_target == 3:
            if unit in self.player_first_enemy or unit in self.player_second_enemy:
                return True
        return False

    # every once in a while you can upgrade, this returns the remaining time for upgrade
    def get_remaining_turns_to_upgrade(self):
        rem_turn = (self.game_constants.turns_to_upgrade -
                    self.current_turn) % self.game_constants.turns_to_upgrade
        if rem_turn == 0:
            return self.game_constants.turns_to_upgrade
        return rem_turn

    # every once in a while a spell is given this remains the remaining time to get new spell
    def get_remaining_turns_to_get_spell(self):
        rem_turn = (self.game_constants.turns_to_spell -
                    self.current_turn) % self.game_constants.turns_to_spell
        if rem_turn == 0:
            return self.game_constants.turns_to_spell
        return rem_turn

    # returns a list of spells casted on a cell
    def get_range_upgrade_number(self):
        return self.turn_updates.available_range_upgrade

    def get_damage_upgrade_number(self):
        return self.turn_updates.available_damage_upgrade

    # returns the spell given in that turn
    def get_received_spell(self):
        spell_id = self.turn_updates.received_spell
        spell = self.get_spell_by_id(spell_id)
        return spell

    # returns the spell given in that turn to friend
    def get_friend_received_spell(self):
        spell_id = self.turn_updates.friend_received_spell
        spell = self.get_spell_by_id(spell_id)
        return spell

    def upgrade_unit_range(self, unit=None, unit_id=None):
        if unit is not None:
            unit_id = unit.unit_id

        if unit_id is not None:
            self.queue.put(
                Message(type="rangeUpgrade",
                        turn=self.get_current_turn(),
                        info={"unitId": unit_id}))

    def upgrade_unit_damage(self, unit=None, unit_id=None):
        if unit is not None:
            unit_id = unit.unit_id

        if unit_id is not None:
            self.queue.put(
                Message(type="damageUpgrade",
                        turn=self.get_current_turn(),
                        info={"unitId": unit_id}))

    def get_player_hasted_units(self, player_id):
        return [
            unit for unit in self.get_player_by_id(player_id=player_id).units
            if unit.is_hasted > 0
        ]

    def get_player_played_units(self, player_id):
        return [
            unit for unit in self.get_player_by_id(player_id=player_id).units
            if unit.was_played_this_turn
        ]

    def get_all_base_unit(self):
        return copy.deepcopy(self.base_units)

    def get_all_spells(self):
        return copy.deepcopy(self.spells)

    def get_king_by_id(self, player_id):
        for p in self.players:
            if p.player_id == player_id:
                return p.king

        return None

    def get_base_unit_by_id(self, type_id):
        for bu in self.base_units:
            if bu.type_id == type_id:
                return bu
        return None

    def get_game_constants(self):
        return self.game_constants

    def _get_paths_starting_with(self, first, paths):
        ret = []
        for path in paths:
            c_path = Path(path=path)
            if c_path.cells[-1] == first:
                c_path.cells.reverse()
            if c_path.cells[0] == first:
                ret.append(c_path)
        return ret

    def _handle_end_message(self, scores_list_msg):
        return dict([(score["playerId"], score["score"])
                     for score in scores_list_msg])