From 0961d4161c72334c905facc27494224a78adf9de Mon Sep 17 00:00:00 2001 From: kulisak12 Date: Sun, 18 Sep 2022 11:10:04 +0200 Subject: [PATCH] =?UTF-8?q?Strategick=C3=A1:=20Pathfinding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- klient/play.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/klient/play.py b/klient/play.py index c9c0ace..97246e2 100755 --- a/klient/play.py +++ b/klient/play.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 from __future__ import annotations from enum import Enum -from typing import Callable, Iterable, List, Optional +from typing import Callable, Iterable, Optional, List, Set +import collections import json import sys @@ -13,6 +14,17 @@ class Action(Enum): RIGHT = "right" STAY = None + def invert(self) -> Action: + if self == Action.UP: + return Action.DOWN + if self == Action.DOWN: + return Action.UP + if self == Action.LEFT: + return Action.RIGHT + if self == Action.RIGHT: + return Action.LEFT + return Action.STAY + class State: def __init__(self, state: dict) -> None: @@ -44,6 +56,12 @@ class Field: self.home_for_team = home_for_team self.occupied_by_team = occupied_by_team + def __eq__(self, other: Field) -> bool: + return (self.i, self.j) == (other.i, other.j) + + def __hash__(self) -> int: + return hash((self.i, self.j)) + def get_neighbour_field(self, action: Action) -> Field: if action == Action.UP: neighbour_i = self.i - 1 @@ -111,6 +129,31 @@ def find_team_members(team_id: int) -> List[Member]: return result +def pathfind(member: Member, goal: Field) -> Action: + """Find the shortest path from member position to goal. + + Returns the first action to take. + If there is no path, returns Action.STAY. + """ + + # BFS from goal to member + # this direction makes it easier to realize that no path exists + explored: Set[Field] = set() + queue = collections.deque([goal]) + while queue: + field = queue.popleft() + for action in Action: + neighbour = field.get_neighbour_field(action) + if (neighbour in explored or + not neighbour.is_accessible(member.team)): + continue + if field == member.field: + return action.invert() + queue.append(neighbour) + explored.add(field) + return Action.STAY + + def build_turn(members: Iterable[Member]) -> dict: return { "members": [