diff --git a/AI.py b/AI.py index f5c1f31..3208bf6 100644 --- a/AI.py +++ b/AI.py @@ -1,8 +1,17 @@ +from random import Random + + class AI: def pick(self, world): + self.r = Random() print("pick") - world.choose_deck([1, 2, 3 , 4]) + world.choose_deck([1, 2, 3, 4]) + print(world.put_unit(type_id=1, path=world.map.paths[self.r.randint(1, 4)])) + if len(world.player.units) > 0: + print(world.player.units[0].cell) def turn(self, world): print("turn") + if len(world.player.units) > 0: + print(world.player.units[0].cell) diff --git a/controller.py b/controller.py index a1a490c..3cfe65b 100644 --- a/controller.py +++ b/controller.py @@ -1,4 +1,3 @@ -import json import os import sys import threading @@ -26,7 +25,6 @@ def __init__(self): # change with switcher def handle_message(self, message): - print("got message") if message[ServerConstants.KEY_TYPE] == ServerConstants.MESSAGE_TYPE_INIT: self.world._handle_init_message(message[ServerConstants.KEY_INFO]) new_world = World(world=self.world) @@ -65,7 +63,6 @@ def run(): World.LOG_FILE_POINTER.write('------send message to server-----\n ' + message.__str__()) self.network.send(message) - Thread(target=run, daemon=True).start() def read_settings(self): diff --git a/game.py b/game.py deleted file mode 100644 index 8726d95..0000000 --- a/game.py +++ /dev/null @@ -1,357 +0,0 @@ -import copy - -from model import CastUnitSpell, CastAreaSpell, Message, Cell -from world import World - - -class Game(World): - # 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): - print("----------GI---------------") - 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]} - print(message.__dict__) - return message - - def get_my_id(self): - return self.player.player_id - - def get_friend_id(self): - return self.player_friend.player_id - - 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_id(self): - return self.player_first_enemy.player_id - - def get_second_enemy_id(self): - return self.player_second_enemy.player_id - - # returns a cell that is the fortress of player with player_id - def get_player_position(self, player_id): - player = self.get_player_by_id(player_id) - if player is not None: - return player.king.center - - # return a list of paths starting from the fortress of player with player_id - # the beginning is from player_id fortress cell - def get_paths_from_player(self, player_id): - paths = [] - player_king_cell = self.get_player_position(player_id) - for p in self.map.paths: - first_cell = p.cells[0] - last_cell = p.cells[len(p.cells) - 1] - if first_cell == player_king_cell: - paths.append(p) - continue - if last_cell == player_king_cell: - p.cells.reverse() - paths.append(p) - continue - - # returns the path from player_id to its friend beginning from player_id's fortress - def get_path_to_friend(self, player_id): - player_king_cell = self.get_player_position(player_id) - friend_king_cell = self.get_player_position(self.get_friend_by_id(player_id)) - for p in self.map.paths: - first_cell = p.cells[0] - last_cell = p.cells[len(p.cells) - 1] - if first_cell == player_king_cell and last_cell == friend_king_cell: - return p - if last_cell == player_king_cell and first_cell == friend_king_cell: - p.cells.reverse() - return p - - def get_map_row_num(self): - return self.map.row_count - - def get_map_col_num(self): - return self.map.column_count - - # 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 = Cell(row, col) - - paths = [] - for p in self.map.paths: - if cell in p.cells: - paths.append(p) - return paths - - # return units of player that are currently in map - def get_player_units(self, player_id): - player = self.get_player_by_id(player_id) - return player.units - - # return a list of units in a cell - def get_cell_units(self, cell): - 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, player_id, cell=None, row=None, col=None): - if cell is None: - if row is None or col is None: - return - cell = Cell(row, col) - - shortest_path_to_cell = self.shortest_path.get(player_id) - if shortest_path_to_cell[cell.row][cell.col] == -1: - return None - return shortest_path_to_cell[cell.row][cell.col] - - # returns the limit of ap for each player - def get_max_ap(self): - return self.game_constants.max_ap - - # get remaining ap - def get_remaining_ap(self): - return self.player.ap - - # returns a list of units in hand - def get_hand(self): - return self.player.hand - - # returns a list of units in deck - def get_deck(self): - return self.player.deck - - # 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.path_id - if path_id is None or type_id is None: - return - e = Event("putUnit", [type_id, path_id]) - self.queue.put(e) - - # return the number of turns passed - def get_current_turn(self): - return self.current_turn - - # return the limit of turns - def get_max_turns(self): - return self.game_constants.max_turns - - # return the time left to pick units and put in deck in the first turn - def get_pick_timeout(self): - return self.game_constants.pick_timeout - - # a constant limit for each turn - def get_turn_timeout(self): - return self.game_constants.turn_timeout - - # returns the time left for turn (miliseconds) - def get_remaining_time(self, ): - return self.get_turn_timeout() - self.get_time_past() - - # returns the health point remaining for each player - def get_player_hp(self, player_id): - player = self.get_player_by_id(player_id) - return player.king.hp - - # put unit_id in path_id in position 'index' all spells of one kind have the same id - def cast_unit_spell(self, unit_id, path_id, index, spell=None, spell_id=None): - path = None - for p in self.map.paths: - if p.path_id == path_id: - path = p - break - cell = path.cells[index] - if spell is None: - spell = self.get_spell_by_type_id(spell_id) - e = Message(type="castSpell", turn=self.get_current_turn() - , info=[spell.type, [cell.row, cell.col], unit_id, path_id]) - self.queue.put(e) - - # 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_type_id(spell_id) - if row is not None and col is not None: - e = Message(type="castSpell", turn=self.get_current_turn() - , info=[spell.type, [row, col], -1, -1]) - self.queue.put(e) - elif center is not None: - e = Message(type="castSpell", turn=self.get_current_turn() - , info=[spell.type, [center.row, center.col], -1, -1]) - self.queue.put(e) - - # returns a list of units the spell casts effects on - def get_area_spell_targets(self, center, row=None, col=None, spell=None, spell_id=None): - if spell is None: - if spell_id is not None: - spell = self.get_cast_spell_by_type(spell_id) - if center is not None: - pass - - # every once in a while you can upgrade, this returns the remaining time for upgrade - def get_remaining_turns_to_upgrade(self): - return self.game_constants.turns_to_upgrade - - # 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): - return self.game_constants.turns_to_spell - - # returns area spells that are casted in last turn and returns other players spells also - def get_cast_area_spell(self, player_id): - return [cast_spell_i for cast_spell_i in self.cast_spell.values() - if cast_spell_i.caster_id and isinstance(cast_spell_i, CastAreaSpell)] - - # returns unit spells that are casted in last turn and returns other players spells also - def get_cast_unit_spell(self, player_id): - return [cast_spell_i for cast_spell_i in self.cast_spell.values() - if cast_spell_i.caster_id and isinstance(cast_spell_i, CastUnitSpell)] - - def get_cast_spells_on_unit(self, unit=None, unit_id=None): - pass - - # def get_active_poisons_on_unit(self, unit_id=None, unit=None): - # temp_unit = unit - # if unit_id is not None: - # temp_unit = self.get_unit_by_id(unit_id) - # if isinstance(temp_unit, Unit): - # return temp_unit.active_poisons - # return None - - # returns a list of spells casted on a cell - def get_range_upgrade_number(self, player_id): - return self.turn_updates.available_range_upgrade - - def get_damage_upgrade_number(self, player_id): - return self.turn_updates.available_damage_upgrade - - def get_spells_list(self): - return self.player.spells - - # get current available spells as a dictionary - def get_spells(self): - return_dict = dict() - for spell in self.player.spells: - if spell in return_dict: - return_dict[spell] += 1 - else: - return_dict[spell] = 1 - return return_dict - - # returns the spell given in that turn - def get_received_spell(self): - spell_type_id = self.turn_updates.received_spell - if spell_type_id == -1: - return None - else: - return self.get_spell_by_type_id(spell_type_id) - - # returns the spell given in that turn to friend - def get_friend_received_spell(self): - spell_type_id = self.turn_updates.friend_received_spell - if spell_type_id == -1: - return None - else: - return self.get_spell_by_type_id(spell_type_id) - - def upgrade_unit_range(self, unit=None, unit_id=None): - if unit is not None: - self.queue.put(Message(type="rangeUpgrade", turn=self.get_current_turn() - , info=[unit.unit_id])) - elif unit_id is not None: - self.queue.put(Message(type="rangeUpgrade", turn=self.get_current_turn() - , info=unit_id)) - - def upgrade_unit_damage(self, unit=None, unit_id=None): - if unit is not None: - self.queue.put(Message(type="damageUpgrade", turn=self.get_current_turn(), info={ - "unitId": unit.unit_id - })) - elif unit_id is not None: - self.queue.put(Message(type="damageUpgrade", turn=self.get_current_turn(), info={ - "unitId": unit.unit_id - })) - - def get_player_duplicate_unit(self, player_id): - unit_list = [] - for u in self.get_player_by_id(player_id).units: - if u.is_clone: - unit_list.append(u) - return unit_list - - 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_unit_target(self, unit=None, unit_id=None): - if unit_id is None: - if unit is None: - return None - unit_id = unit.unit_id - - target_id = self.get_unit_by_id(unit_id).target_id - unit = self.get_unit_by_id(target_id) - return unit - - def get_unit_target_cell(self, unit=None, unit_id=None): - if unit_id is None: - if unit is None: - return None - unit_id = unit.unit_id - - target_id = self.get_unit_by_id(unit_id).target_id - cell = self.get_unit_by_id(unit_id).target_cell - unit = self.get_unit_by_id(target_id) - if unit is None: - return None - - return cell - - def get_king_target(self, player_id): - king = self.get_player_by_id(player_id).king - return self.get_unit_by_id(king.target_id) - - def get_king_target_cell(self, player_id): - king = self.get_player_by_id(player_id).king - return king.target_cell - - def get_king_unit_is_attacking_to(self, unit=None, unit_id=None): - if unit is not None: - unit_id = unit.unit_id - unit = self.get_unit_by_id(unit_id) - for p in self.players: - if unit.target_id == p.player_id: - return p.player_id - return -1 - - def get_all_base_unit(self): - return copy.deepcopy(self.base_units) - - def get_all_spells(self): - return copy.deepcopy(self.spells) - -# def get_player_clone_units(self, player_id): -# return [unit for unit in self.get_player_by_id(player_id=player_id) if unit.is_clone > 0] -# - -# def get_player_poisoned_units(self, player_id): -# return [unit for unit in self.get_player_by_id(player_id=player_id) if unit.active_poisons > 0] -# diff --git a/model.py b/model.py index e61be4a..8d8e948 100644 --- a/model.py +++ b/model.py @@ -2,20 +2,19 @@ class Map: - def __init__(self, row_count, column_count, paths, kings): + def __init__(self, row_count, column_count, paths, kings, cells): self.row_count = row_count self.column_count = column_count self.paths = paths self.units = [] self.kings = kings - self._cells = [[Cell(row=row, col=col) for col in range(column_count)] for row in range(row_count)] + self.cells = cells def get_cell(self, row, column): - return self._cells[row][column] - + return self.cells[row][column] def clear_units(self): - for row in self._cells: + for row in self.cells: for cell in row: cell.clear_units() @@ -26,7 +25,7 @@ def get_path_by_id(self, path_id): return None def add_unit_in_cell(self, row, column, unit): - self._cells[row][column].add_unit(unit) + self.cells[row][column].add_unit(unit) class Player: @@ -39,6 +38,12 @@ def __init__(self, player_id, king): self.upgrade_tokens = 0 self.king = king self.units = [] + self.dead_units = [] + + def __str__(self): + return "".format(self.player_id, self.king.center.row, self.king.center.col) class Unit: @@ -64,11 +69,11 @@ def __init__(self, unit_id, base_unit, cell, path, hp, is_hasted, is_clone, dama self.target_cell = target_cell - class SpellTarget(Enum): SELF = 1 ALLIED = 2 ENEMY = 3 + @staticmethod def get_value(string): if string == "SELF": @@ -79,11 +84,13 @@ def get_value(string): return SpellTarget.ENEMY return None + class SpellType(Enum): HP = 1 TELE = 2 DUPLICATE = 3 HASTE = 4 + @staticmethod def get_value(string): if string == "HP": @@ -126,6 +133,9 @@ def __eq__(self, other): return self.col == other.col and self.row == other.row + def __str__(self): + return "".format(self.row, self.col) + def clear_units(self): self.units.clear() @@ -140,6 +150,11 @@ def __init__(self, path_id=0, cells=None): self.cells = cells self.path_id = path_id + def __str__(self): + return "".format(self.path_id, ["({}, {})".format(cell.row, cell.col) for cell in self.cells]) + class Deck: def __init__(self): @@ -165,29 +180,12 @@ def __init__(self, target_id, center=None, hp=0, attack=0, range=0): self.range = range self.target_id = target_id -# -# class AreaSpell(Spell): -# def __init__(self, type_id, turn_effect, range, power, is_damaging): -# super().__init__(type_id=type_id, turn_effect=turn_effect) -# self.range = range -# self.power = power -# self.is_damaging = is_damaging -# -# -# class UnitSpell(Spell): -# def __init__(self, type_id, turn_effect): -# super().__init__(type_id=type_id, turn_effect=turn_effect) -# class Message: - def __init__(self, turn, type, info): self.type = type self.info = info self.turn = turn - # - # def add_arg(self, arg): - # self.args.append(arg) class CastSpell: diff --git a/network.py b/network.py index ef6fb50..be9d793 100644 --- a/network.py +++ b/network.py @@ -27,7 +27,7 @@ def connect(self): connected = True self.send(Message(type=ServerConstants.CONFIG_KEY_TOKEN, turn=0, - info={ServerConstants.CONFIG_KEY_TOKEN:self.token} + info={ServerConstants.CONFIG_KEY_TOKEN: self.token} )) init = self.receive() if init[ServerConstants.KEY_TYPE] == "wrong token": @@ -53,7 +53,6 @@ def send(self, message): def receive(self): while self.receive_flag: - # print("received") self.result += self.s.recv(1024) if b'\x00' in self.result: ans = json.loads(self.result[:self.result.index(b'\x00')].decode('UTF-8')) diff --git a/world.py b/world.py index 9492973..c30fab1 100644 --- a/world.py +++ b/world.py @@ -1,7 +1,9 @@ +import copy import time from abc import ABC -from model import AreaSpell, UnitSpell, BaseUnit, Map, King, Cell, Path, Player, GameConstants, TurnUpdates, CastAreaSpell, CastUnitSpell, Unit +from model import BaseUnit, Map, King, Cell, Path, Player, GameConstants, TurnUpdates, \ + CastAreaSpell, CastUnitSpell, Unit, Spell, Message #################### Soalat? @@ -20,8 +22,6 @@ def __init__(self, world=None, queue=None): self.map = None self.base_units = None - self.area_spells = None - self.unit_spells = None self.current_turn = 0 self.players = [] @@ -29,8 +29,8 @@ def __init__(self, world=None, queue=None): self.player_friend = None self.player_first_enemy = None self.player_second_enemy = None - - self.cast_spell = None + self.spells = None + self.cast_spells = None if world is not None: self.game_constants = world.game_constants @@ -39,11 +39,8 @@ def __init__(self, world=None, queue=None): self.map = world.map self.base_units = world.base_units - self.area_spells = world.area_spells - self.unit_spells = world.unit_spells + self.spells = world.spells self.current_turn = world.current_turn - self.received_spell = world.received_spell - self.friend_received_spell = world.friend_received_spell self.shortest_path = dict() self.players = world.players @@ -51,7 +48,9 @@ def __init__(self, world=None, queue=None): self.player_friend = world.player_friend self.player_first_enemy = world.player_first_enemy self.player_second_enemy = world.player_second_enemy - self.cast_spell = world.cast_spell + self.cast_spells = world.cast_spells + + self.queue = world.queue else: self.queue = queue @@ -68,11 +67,8 @@ def get_player_by_id(self, player_id): return None def get_spell_by_type_id(self, type_id): - for spell in self.area_spells: - if spell.type == type_id: - return spell - for spell in self.unit_spells: - if spell.type == type_id: + for spell in self.spells: + if spell.type_id == type_id: return spell return None @@ -89,17 +85,20 @@ def _game_constant_init(self, game_constants_msg): def _map_init(self, map_msg): row_num = map_msg["rows"] col_num = map_msg["cols"] - paths = [Path(path["id"], [Cell(cell["row"], cell["col"]) for cell in path["cells"]] + + input_cells = [[Cell(row=row, col=col) for col in range(col_num)] for row in range(row_num)] + + paths = [Path(path["id"], [input_cells[cell["row"]][cell["col"]] for cell in path["cells"]] ) for path in map_msg["paths"]] - kings = [King(center=Cell(king["center"]["row"], king["center"]["col"]), hp=king["hp"], - attack=king["attack"], range=king["range"]) + kings = [King(center=input_cells[king["center"]["row"]][king["center"]["col"]], hp=king["hp"], + attack=king["attack"], range=king["range"], target_id=-1) for king in map_msg["kings"]] self.players = [Player(player_id=map_msg["kings"][i]["playerId"], king=kings[i]) for i in range(4)] 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_count=row_num, column_count=col_num, paths=paths, kings=kings) + self.map = Map(row_count=row_num, column_count=col_num, paths=paths, kings=kings, cells=input_cells) def get_unit_by_id(self, unit_id): for unit in self.map.units: @@ -108,21 +107,29 @@ def get_unit_by_id(self, unit_id): return None def _base_unit_init(self, msg): - self.base_units = dict([(b_unit["typeId"], BaseUnit(type_id=b_unit["typeId"], max_hp=b_unit["maxHP"], - base_attack=b_unit["baseAttack"], - base_range=b_unit["baseRange"], target=b_unit["target"], - is_flying=b_unit["isFlying"], - is_multiple=b_unit["isMultiple"])) - for b_unit in 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=b_unit["target"], + is_flying=b_unit["isFlying"], + is_multiple=b_unit["isMultiple"]) + 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): - for spell in msg: - if msg["isAreaSpell"]: - self.area_spells.append(AreaSpell(type_id=spell["typeId"], turn_effect=spell["turnEffect"], - range=spell["range"], power=spell["power"], - is_damaging=spell["isDamaging"])) - else: - self.unit_spells.append(UnitSpell(type_id=spell["typeId"], turn_effect=spell["turnEffect"])) + self.spells = [Spell(type=spell["type"], + type_id=spell["typeId"], + duration=spell["duration"], + priority=spell["priority"], + range=spell["range"], + power=spell["power"], + target=spell["target"]) + for spell in msg] def _handle_init_message(self, msg): # if World.DEBUGGING_MODE: @@ -136,13 +143,19 @@ def _handle_init_message(self, msg): def _handle_turn_kings(self, msg): for king_msg in msg: - hp = king_msg["hp"] if king_msg["hp"] >= 0 else -1 + hp = king_msg["hp"] if king_msg["hp"] > 0 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"] + + 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() + else: + for player in self.players: + player.dead_units.clear() - def _handle_turn_units(self, msg): - self.map.clear_units() - for player in self.players: - player.units.clear() for unit_msg in msg: unit_id = unit_msg["unitId"] player = self.get_player_by_id(player_id=unit_msg["playerId"]) @@ -160,38 +173,50 @@ def _handle_turn_units(self, msg): active_poisons=unit_msg["activePoisons"], range=unit_msg("range"), attack=unit_msg("attack"), - was_played_this_turn=unit_msg("wasPlayedThisTurn")) - self.map.add_unit_in_cell(unit.cell.row, unit.cell.col, unit) - player.units.append(unit) + was_played_this_turn=unit_msg("wasPlayedThisTurn"), + target_id=unit_msg["target"], + target_cell=Cell(row=unit_msg["targetCell"]["row"], col=unit_msg["targetCell"]["col"])) + if not is_dead_unit: + self.map.add_unit_in_cell(unit.cell.row, unit.cell.col, unit) + player.units.append(unit) + else: + player.dead_units.append(unit) def _handle_turn_cast_spells(self, msg): - cast_spell_list = [] + self.cast_spells = [] for cast_spell_msg in msg: cast_spell = self.get_spell_by_type_id(cast_spell_msg["typeId"]) cell = self.map.get_cell(cast_spell_msg["cell"]["row"], cast_spell_msg["cell"]["col"]) - if isinstance(cast_spell, AreaSpell): - cast_spell_list.append( - CastAreaSpell(type_id=cast_spell.type, caster_id=cast_spell_msg["casterId"], center=cell, - affected_units=[self.get_unit_by_id(affected_unit_id) for - affected_unit_id in - cast_spell_msg["affectedUnits"]] - )) - elif isinstance(cast_spell, UnitSpell): - cast_spell_list.append(CastUnitSpell(type_id=cast_spell.type, caster_id=cast_spell_msg["casterId"], - target_cell=cell, unit_id=cast_spell_msg["unitId"], - path_id=cast_spell_msg["pathId"], - )) - self.cast_spell = dict((cast_spell_i.type_id, cast_spell_i) for cast_spell_i in cast_spell_list) - - def get_cast_spell_by_type(self, type): - return self.cast_spell[type] + affected_units = [self.get_unit_by_id(affected_unit_id) for + affected_unit_id in + cast_spell_msg["affectedUnits"]] + if cast_spell.is_area_spell(): + self.cast_spells.append( + CastAreaSpell(type_id=cast_spell.type_id, caster_id=cast_spell_msg["casterId"], center=cell, + was_cast_this_turn=cast_spell_msg["wasCastThisTurn"], + remaining_turns=cast_spell_msg["remainingTurns"], + affected_units=affected_units)) + elif cast_spell.is_unit_spell(): + self.cast_spells.append(CastUnitSpell(type_id=cast_spell.type_id, caster_id=cast_spell_msg["casterId"], + target_cell=cell, unit_id=cast_spell_msg["unitId"], + path_id=cast_spell_msg["pathId"], + was_cast_this_turn=cast_spell_msg["wasCastThisTurn"], + remaining_turns=cast_spell_msg["remainingTurns"], + affected_units=affected_units)) + + def get_cast_spell_by_type_id(self, type_id): + for cast_spell in self.cast_spells: + if cast_spell.type_id == type_id: + return cast_spell + return None def _handle_turn_message(self, msg): self.current_turn = msg['currTurn'] - self.player.deck = [self.base_units[deck["typeId"]] for deck in msg["deck"]] - self.player.hand = [self.base_units[hand["typeId"]] for hand in msg["hand"]] + 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["diedUnits"], is_dead_unit=True) self._handle_turn_cast_spells(msg["castSpells"]) self.turn_updates = TurnUpdates(received_spell=msg["receivedSpell"], @@ -206,14 +231,14 @@ def _handle_turn_message(self, msg): self.start_time = self.get_current_time_millis() - def pre_process_shortest_path(self): + def _pre_process_shortest_path(self): def path_count(path): shortest_path_to_cell = [] shortest_path_to_cell_num = [] - for i in range(len(self.map.row_count)): + for i in range(self.map.row_count): l = [] s = [] - for j in range(len(self.map.column_count)): + for j in range(self.map.column_count): l.append(-1) s.append(-1) shortest_path_to_cell.append(l) @@ -233,207 +258,427 @@ def path_count(path): for p in self.players: paths = self.get_paths_from_player(p.player_id) for i in range(len(paths)): - self.shortest_path.update({p.player_id:path_count(paths[i])}) + self.shortest_path.update({p.player_id: path_count(paths[i])}) # 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): - pass + + 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_my_id(self): - pass + return self.player.player_id def get_friend_id(self): - pass + return self.player_friend.player_id + + 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_id(self): - pass + return self.player_first_enemy.player_id def get_second_enemy_id(self): - pass - - # returns a cell that is the fortress of player with player_id + return self.player_second_enemy.player_id + # returns a cell that is the fortress of player with player_id def get_player_position(self, player_id): - pass - - # return a list of paths starting from the fortress of player with player_id - # the beginning is from player_id fortress cell + player = self.get_player_by_id(player_id) + if player is not None: + return player.king.center + # return a list of paths starting from the fortress of player with player_id + # the beginning is from player_id fortress cell def get_paths_from_player(self, player_id): - pass - - # returns the path from player_id to its friend beginning from player_id's fortress - + paths = [] + player_king_cell = self.get_player_position(player_id) + for p in self.map.paths: + first_cell = p.cells[0] + last_cell = p.cells[len(p.cells) - 1] + if first_cell == player_king_cell: + paths.append(p) + continue + if last_cell == player_king_cell: + p.cells.reverse() + paths.append(p) + continue + return paths + + # returns the path from player_id to its friend beginning from player_id's fortress def get_path_to_friend(self, player_id): - pass - - def get_map_height(self): - pass - - def get_map_width(self): - pass - + player_king_cell = self.get_player_position(player_id) + friend_king_cell = self.get_friend_by_id(player_id).king.center + + for p in self.map.paths: + first_cell = p.cells[0] + last_cell = p.cells[len(p.cells) - 1] + if first_cell == player_king_cell and last_cell == friend_king_cell: + return p + if last_cell == player_king_cell and first_cell == friend_king_cell: + p.cells.reverse() + return p + + def get_map_row_num(self): + return self.map.row_count + + def get_map_col_num(self): + return self.map.column_count # return a list of paths crossing one cell - def get_paths_crossing_cell(self, cell): - pass + # 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) - # return units of player that are currently in map + paths = [] + for p in self.map.paths: + if cell in p.cells: + paths.append(p) + return paths + # return units of player that are currently in map def get_player_units(self, player_id): - pass - - # return a list of units in a cell - - def get_cell_units(self, cell): - pass - - # 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, player_id, cell): - pass - - # returns the limit of ap for each player - + player = self.get_player_by_id(player_id) + return player.units + + # return a list of units in a cell + def get_cell_units(self, cell=None, row=None, col=None): + if cell == None: + if row == None and col == 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, player_id, cell=None, row=None, col=None): + if len(list(self.shortest_path.values())) == 0: + self._pre_process_shortest_path() + + if cell is None: + if row is None or col is None: + return + cell = self.map.get_cell(row, col) + + shortest_path_to_cell = self.shortest_path.get(player_id) + if shortest_path_to_cell[cell.row][cell.col] == -1: + return None + + return shortest_path_to_cell[cell.row][cell.col] + + # returns the limit of ap for each player def get_max_ap(self): - pass - - # get remaining ap + return self.game_constants.max_ap + # get remaining ap def get_remaining_ap(self): - pass - - # returns a list of units in hand + return self.player.ap + # returns a list of units in hand def get_hand(self): - pass - - # returns a list of units in deck + return self.player.hand + # returns a list of units in deck def get_deck(self): - pass - - # place unit with type_id in path_id - - def put_unit(self, type_id, path_id): - - pass - - # return the number of turns passed - + return self.player.deck + + # 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.path_id + if path_id is None or type_id is None: + 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): - pass - - # return the limit of turns + return self.current_turn + # return the limit of turns def get_max_turns(self): - pass - - # return the time left to pick units and put in deck in the first turn + return self.game_constants.max_turns + # return the time left to pick units and put in deck in the first turn def get_pick_timeout(self): - pass - - # a constant limit for each turn + return self.game_constants.pick_timeout + # a constant limit for each turn def get_turn_timeout(self): - pass - - # returns the time left for turn (miliseconds) + return self.game_constants.turn_timeout + # returns the time left for turn (miliseconds) def get_remaining_time(self): - pass - - # returns the health point remaining for each player + return self.get_turn_timeout() - self.get_time_past() + # returns the health point remaining for each player def get_player_hp(self, player_id): - pass - - # put unit_id in path_id in position 'index' all spells of one kind have the same id + player = self.get_player_by_id(player_id) + return player.king.hp + # put unit_id in path_id in position 'index' all spells of one kind have the same id def cast_unit_spell(self, unit_id, path_id, index, spell=None, spell_id=None): - pass - - # cast spell in the cell 'center' - - def cast_area_spell(self, center, row=None, col=None, spell=None, spell_id=None): - pass - - # returns a list of units the spell casts effects on - - def get_area_spell_targets(self, center, row=None, col=None, spell=None, spell_id=None): - pass - - # every once in a while you can upgrade, this returns the remaining time for upgrade - + path = None + for p in self.map.paths: + if p.path_id == path_id: + path = p + break + cell = path.cells[index] + if spell is None: + spell = self.get_spell_by_type_id(spell_id) + message = Message(type="castSpell", turn=self.get_current_turn(), + info={ + "typeId": spell.type, + "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_type_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, + "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 + 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_type_id(type_id) + 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_count)): + for j in range(max(0, center.col - spell.range), min(center.col + spell.range, self.map.column_count)): + 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 + + def get_cast_spells_on_unit(self, unit=None, unit_id=None): + ls = [] + if unit_id is None: + unit_id = unit.unit_id + for cast_spell in self.cast_spells: + if cast_spell is isinstance(CastUnitSpell): + if unit_id == cast_spell.unit_id: + ls.append(unit_id) + return ls + + # every once in a while you can upgrade, this returns the remaining time for upgrade def get_remaining_turns_to_upgrade(self): - pass - - # every once in a while a spell is given this remains the remaining time to get new spell + return self.game_constants.turns_to_upgrade + # 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): - pass - - # returns area spells that are casted in last turn and returns other players spells also + return self.game_constants.turns_to_spell + # returns area spells that are casted in last turn and returns other players spells also def get_cast_area_spell(self, player_id): - pass - - # returns unit spells that are casted in last turn and returns other players spells also + return [cast_spell_i for cast_spell_i in self.cast_spells + if cast_spell_i.caster_id and isinstance(cast_spell_i, CastAreaSpell)] + # returns unit spells that are casted in last turn and returns other players spells also def get_cast_unit_spell(self, player_id): - pass - - def get_active_poisons_on_unit(self, unit_id=None, unit=None): - pass - - # returns a list of spells casted on a cell + return [cast_spell_i for cast_spell_i in self.cast_spells + if cast_spell_i.caster_id and isinstance(cast_spell_i, CastUnitSpell)] + # returns a list of spells casted on a cell def get_range_upgrade_number(self, player_id): - pass + return self.turn_updates.available_range_upgrade def get_damage_upgrade_number(self, player_id): - pass - - # returns the token of the upgrade you can do - - def get_upgrade_token_number(self): - pass + return self.turn_updates.available_damage_upgrade def get_spells_list(self): - pass - - # get current available spells + return self.player.spells + # get current available spells as a dictionary def get_spells(self): - pass - - # returns the spell given in that turn + return_dict = dict() + for spell in self.player.spells: + if spell in return_dict: + return_dict[spell] += 1 + else: + return_dict[spell] = 1 + return return_dict + # returns the spell given in that turn def get_received_spell(self): - pass - - # returns the spell given in that turn to friend + spell_type_id = self.turn_updates.received_spell + if spell_type_id == -1: + return None + else: + return self.get_spell_by_type_id(spell_type_id) + # returns the spell given in that turn to friend def get_friend_received_spell(self): - pass + spell_type_id = self.turn_updates.friend_received_spell + if spell_type_id == -1: + return None + else: + return self.get_spell_by_type_id(spell_type_id) def upgrade_unit_range(self, unit=None, unit_id=None): - pass + if unit is not None: + unit_id = unit.unit_id - def upgrade_unit_damage(self, unit=None, unit_id=None): - pass + elif unit_id is not None: + self.queue.put(Message(type="rangeUpgrade", + turn=self.get_current_turn(), + info={ + "unitId": unit_id + })) - def get_player_clone_units(self, player_id): - pass + def upgrade_unit_damage(self, unit=None, unit_id=None): + if unit is not None: + unit_id = unit.unit_id + + elif unit_id is not None: + self.queue.put(Message(type="damageUpgrade", + turn=self.get_current_turn(), + info={ + "unitId": unit_id + })) + + def get_player_duplicate_unit(self, player_id): + unit_list = [] + for u in self.get_player_by_id(player_id).units: + if u.is_clone: + unit_list.append(u) + return unit_list def get_player_hasted_units(self, player_id): - pass - - def get_player_poisoned_units(self, player_id): - pass + 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): - pass + return [unit for unit in self.get_player_by_id(player_id=player_id).units if unit.was_played_this_turn] + + def get_unit_target(self, unit=None, unit_id=None): + if unit_id is None: + if unit is None: + return None + unit_id = unit.unit_id + + target_id = self.get_unit_by_id(unit_id).target_id + unit = self.get_unit_by_id(target_id) + return unit + + def get_unit_target_cell(self, unit=None, unit_id=None): + if unit_id is None: + if unit is None: + return None + unit_id = unit.unit_id + + target_id = self.get_unit_by_id(unit_id).target_id + cell = self.get_unit_by_id(unit_id).target_cell + unit = self.get_unit_by_id(target_id) + if unit is None: + return None + + return cell + + def get_king_target(self, player_id): + king = self.get_player_by_id(player_id).king + return self.get_unit_by_id(king.target_id) + + def get_king_target_cell(self, player_id): + king = self.get_player_by_id(player_id).king + return king.target_cell + + def get_king_unit_is_attacking_to(self, unit=None, unit_id=None): + if unit is not None: + unit_id = unit.unit_id + unit = self.get_unit_by_id(unit_id) + for p in self.players: + if unit.target_id == p.player_id: + return p.player_id + return -1 + + def get_all_base_unit(self): + return copy.deepcopy(self.base_units) + + def get_all_spells(self): + return copy.deepcopy(self.spells) + + def get_spell_by_id(self, spell_id): + for i in self.spells: + if spell_id == i.type_id: + return i + + 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_player_died_units(self, player_id): + return self.get_player_by_id(player_id).dead_units + + def has_player_used_ranged_upgrade(self, player_id): + if self.turn_updates.got_range_upgrade is not None: + return True + return False + + def has_player_used_damage_upgrade(self, player_id): + if self.turn_updates.got_damage_upgrade is not None: + return True + return False