diff --git a/klient/play.py b/klient/play.py index 0fef742..3efe2dc 100755 --- a/klient/play.py +++ b/klient/play.py @@ -7,36 +7,42 @@ import json import sys -class Action(enum.Enum): - UP = enum.auto() - DOWN = enum.auto() - LEFT = enum.auto() - RIGHT = enum.auto() - STAY = enum.auto() - - def invert(self) -> Action: - INVERSIONS = { - Action.UP: Action.DOWN, - Action.DOWN: Action.UP, - Action.LEFT: Action.RIGHT, - Action.RIGHT: Action.LEFT, - Action.STAY: Action.STAY, - } - return INVERSIONS[self] +# Třídy reprezentující hru + +class Direction(enum.Enum): + UP = 0 + LEFT = 1 + DOWN = 2 + RIGHT = 3 + STAY = None + + def combine(self, other) -> Direction: + return Direction((self.value + other.value)%4) + + def invert(self) -> Direction: + if self == Direction.STAY: + return self + return self.combine(Direction.DOWN) def __str__(self) -> str: return self.name.lower() -class State: - def __init__(self, state: dict) -> None: - self.world = parse_world(state["state"]["world"]) - self.my_team_id: int = state["team_id"] - self.round_number: int = state["round"] - self.time_to_response: Optional[int] = state["time_to_response"] +class Team: + home: 'Field' + def __init__(self, id: int, is_me: bool) -> None: + self.id: int = id + self.is_me = is_me + self.protected_fields: List[Field] = [] + self.occupied: List[Field] = [] + self.members: List[Member] = [] -state: State + def __eq__(self, other: Field) -> bool: + return (self.id) == (other.id) + + def __hash__(self) -> int: + return hash(self.id) class Member: @@ -44,22 +50,22 @@ class Member: self.field = field self.team = team self.id = id - self.action = Action.STAY + self.action = Direction.STAY class Field: members: List[Member] def __init__(self, i: int, j: int, hill: bool, - home_for_team: Optional[int], - occupied_by_team: Optional[int], - protected_for_team: Optional[int],) -> None: - self.i = i - self.j = j - self.hill = hill - self.home_for_team = home_for_team - self.occupied_by_team = occupied_by_team - self.protected_for_team = protected_for_team + home_for_team: Optional[Team], + occupied_by_team: Optional[Team], + protected_for_team: Optional[Team],) -> None: + self.i: int = i + self.j: int = j + self.hill: bool = hill + self.home_for_team: Optional[Team] = home_for_team + self.occupied_by_team: Optional[Team] = occupied_by_team + self.protected_for_team: Optional[Team] = protected_for_team def __eq__(self, other: Field) -> bool: return (self.i, self.j) == (other.i, other.j) @@ -67,17 +73,17 @@ class Field: def __hash__(self) -> int: return hash((self.i, self.j)) - def get_neighbour_field(self, action: Action) -> Field: - if action == Action.UP: + def get_neighbour_field(self, action: Direction) -> Field: + if action == Direction.UP: neighbour_i = self.i - 1 neighbour_j = self.j - elif action == Action.DOWN: + elif action == Direction.DOWN: neighbour_i = self.i + 1 neighbour_j = self.j - elif action == Action.LEFT: + elif action == Direction.LEFT: neighbour_i = self.i neighbour_j = self.j - 1 - elif action == Action.RIGHT: + elif action == Direction.RIGHT: neighbour_i = self.i neighbour_j = self.j + 1 else: @@ -88,7 +94,7 @@ class Field: neighbour_j %= len(state.world[0]) return state.world[neighbour_i][neighbour_j] - def is_accessible(self, team: int) -> bool: + def is_accessible(self, team: Team) -> bool: """If this field is accessible for the given team.""" if self.hill: @@ -98,19 +104,69 @@ class Field: return False return True +# Celý stav hry včetně parsování a vypisování -def main() -> None: - global state - state = State(json.loads(sys.stdin.read())) - my_members = find_team_members(state.my_team_id) +class State: + def __init__(self, state: dict) -> None: + self.teams = [Team(i, i==state["team_id"]) for i in range(state["teams_count"])] + self.world = self._parse_world(state["state"]["world"]) + self.my_team: Team = self.teams[state["team_id"]] + self.round_number: int = state["round"] + self.time_to_response: Optional[int] = state["time_to_response"] - # TODO: set actions for all members - # example: all members go up - for member in my_members: - member.action = Action.UP + def _parse_world(self, world: dict) -> List[List[Field]]: + def get_team(team_id): + return None if team_id is None else self.teams[team_id] + + fields = [] + for i, row in enumerate(world): + fields_row = [] + for j, field in enumerate(row): + parsed_field = Field( + i, j, + field["hill"], + get_team(field["home_for_team"]), + get_team(field["occupied_by_team"]), + get_team(field["protected_for_team"]), + ) + if parsed_field.home_for_team: + parsed_field.home_for_team.home = parsed_field + if parsed_field.occupied_by_team: + parsed_field.occupied_by_team.occupied.append(parsed_field) + if parsed_field.protected_for_team: + parsed_field.protected_for_team.protected_fields.append(parsed_field) + members = [] + for member in field["members"]: + m = Member( + parsed_field, + self.teams[member["team"]], + member["id"], + ) + members.append(m) + m.team.members.append(m) + parsed_field.members = members + fields_row.append(parsed_field) + + fields.append(fields_row) + return fields + + + def build_turn(self) -> dict: + for team in self.teams: + if not team.is_me: + for member in team.members: + if member.action is not Direction.STAY: + raise Exception("Akce přiřazena cizímu týmu") + return { + "members": [ + {"id": member.id, "action": str(member.action)} + for member in self.my_team.members + ] + } - print(json.dumps(build_turn(my_members))) +state: State +# Algoritmy def find_fields(predicate: Callable[[Field], bool]) -> List[Field]: """Find all fields that satisfy the given predicate.""" @@ -123,19 +179,7 @@ def find_fields(predicate: Callable[[Field], bool]) -> List[Field]: return result -def find_team_members(team_id: int) -> List[Member]: - """Find all members that belong to the given team.""" - - result = [] - for row in state.world: - for field in row: - for member in field.members: - if member.team == team_id: - result.append((member)) - return result - - -def pathfind(member: Member, goal: Field) -> Action: +def pathfind(member: Member, goal: Field) -> Direction: """Find the shortest path from member position to goal. Returns the first action to take. @@ -148,7 +192,7 @@ def pathfind(member: Member, goal: Field) -> Action: queue = collections.deque([goal]) while queue: field = queue.popleft() - for action in Action: + for action in Direction: neighbour = field.get_neighbour_field(action) if (neighbour in explored or not neighbour.is_accessible(member.team)): @@ -157,43 +201,20 @@ def pathfind(member: Member, goal: Field) -> Action: return action.invert() queue.append(neighbour) explored.add(neighbour) - return Action.STAY - - -def build_turn(members: Iterable[Member]) -> dict: - return { - "members": [ - {"id": member.id, "action": str(member.action)} - for member in members - ] - } - - -def parse_world(world: dict) -> List[List[Field]]: - fields = [] - for i, row in enumerate(world): - fields_row = [] - for j, field in enumerate(row): - parsed_field = Field( - i, j, - field["hill"], - field["home_for_team"], - field["occupied_by_team"], - field["protected_for_team"], - ) - members = [] - for member in field["members"]: - members.append(Member( - parsed_field, - member["team"], - member["id"], - )) - parsed_field.members = members - fields_row.append(parsed_field) - - fields.append(fields_row) - return fields + return Direction.STAY + +# main (zde doplňte kód) + +def main() -> None: + global state + state = State(json.loads(sys.stdin.read())) + + # TODO: set actions for all yours members + # example: all members go up + for member in state.teams[1].members: + member.action = Direction.UP + print(json.dumps(state.build_turn())) if __name__ == '__main__': main()