Skip to content

Commit 51757d9

Browse files
committed
WIP: Spec the prepare_bot dicts
1 parent 5eab556 commit 51757d9

File tree

3 files changed

+126
-80
lines changed

3 files changed

+126
-80
lines changed

pelita/game.py

Lines changed: 88 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .gamestate_filters import noiser, relocate_expired_food, update_food_age, in_homezone
1717
from .layout import get_legal_positions, initial_positions
1818
from .network import Controller, RemotePlayerFailure, RemotePlayerRecvTimeout, RemotePlayerSendError, ZMQPublisher
19-
from .spec import GameState, Layout, Pos
19+
from .spec import GameState, Layout, Pos, TeamInitial, TeamState, TeamStateFinished
2020
from .team import RemoteTeam, make_team
2121
from .viewer import (AsciiViewer, ProgressViewer, ReplayWriter, ReplyToViewer,
2222
ResultPrinter)
@@ -660,89 +660,98 @@ def request_new_position(game_state):
660660
return bot_reply
661661

662662

663-
def prepare_bot_state(game_state, team_idx=None):
663+
def prepare_bot_state(game_state: GameState, team_idx=None) -> TeamState | TeamInitial | TeamStateFinished:
664664
""" Prepares the bot’s game state for the current bot.
665665
666666
NB: This will update the game_state to store new noisy positions.
667667
"""
668-
if game_state['game_phase'] == 'INIT':
669-
# We assume that we are in get_initial phase
670-
turn = team_idx
671-
bot_turn = None
672-
seed = game_state['rng'].randint(0, sys.maxsize)
673-
elif game_state['game_phase'] == 'FINISHED':
674-
# Called for remote players in _exit
675-
turn = team_idx
676-
bot_turn = None
677-
seed = None
678-
elif game_state['game_phase'] == 'RUNNING':
679-
turn = game_state['turn']
680-
bot_turn = game_state['turn'] // 2
681-
seed = None
682-
else:
683-
_logger.warning("Got bad game_state in prepare_bot_state")
684-
return
685-
686-
bot_position = game_state['bots'][turn]
687-
own_team = turn % 2
688-
enemy_team = 1 - own_team
689-
enemy_positions = game_state['bots'][enemy_team::2]
690-
noised_positions = noiser(walls=game_state['walls'],
691-
shape=game_state['shape'],
692-
bot_position=bot_position,
693-
enemy_positions=enemy_positions,
694-
noise_radius=game_state['noise_radius'],
695-
sight_distance=game_state['sight_distance'],
696-
rng=game_state['rng'])
697-
698-
699-
# Update noisy_positions in the game_state
700-
# reset positions
701-
game_state['noisy_positions'] = [None] * 4
702-
noisy_or_none = [
703-
noisy_pos if is_noisy else None
704-
for is_noisy, noisy_pos in
705-
zip(noised_positions['is_noisy'], noised_positions['enemy_positions'])
706-
]
707-
game_state['noisy_positions'][enemy_team::2] = noisy_or_none
708-
709-
bots = game_state['bots'][:]
710-
bots[enemy_team::2] = noised_positions['enemy_positions']
711-
712-
is_noisy = [False for _ in range(4)]
713-
is_noisy[enemy_team::2] = noised_positions['is_noisy']
714-
715-
shaded_food_own = list(pos for pos, age in game_state['food_age'][own_team].items()
716-
if age > 0)
717-
shaded_food = [[], []]
718-
shaded_food[own_team] = shaded_food_own
719-
720-
bot_state = {
721-
'bots': bots,
722-
'score': game_state['score'][:],
723-
'kills': game_state['kills'][:],
724-
'deaths': game_state['deaths'][:],
725-
'bot_was_killed': game_state['bot_was_killed'][:],
726-
'error_count': [len(e) for e in game_state['timeouts'][:]],
727-
'food': [list(team_food) for team_food in game_state['food']],
728-
'shaded_food': shaded_food,
729-
'team_time': game_state['team_time'][:],
730-
'is_noisy': is_noisy,
731-
'round': game_state['round'],
732-
'turn': turn,
733-
'timeout_length': game_state['timeout_length'],
734-
}
668+
match game_state['game_phase']:
669+
case "INIT":
670+
turn = team_idx
671+
seed = game_state['rng'].randint(0, sys.maxsize)
672+
673+
team_state_initial: TeamInitial = {
674+
'walls': game_state['walls'],
675+
'shape': game_state['shape'],
676+
'seed': seed,
677+
'max_rounds': game_state['max_rounds'],
678+
'team_names': game_state['team_names'][:],
679+
'timeout_length': game_state['timeout_length'],
680+
}
681+
return team_state_initial
682+
case "RUNNING":
683+
684+
turn = game_state['turn']
685+
686+
bot_position = game_state['bots'][turn]
687+
own_team = turn % 2
688+
enemy_team = 1 - own_team
689+
enemy_positions = game_state['bots'][enemy_team::2]
690+
noised_positions = noiser(walls=game_state['walls'],
691+
shape=game_state['shape'],
692+
bot_position=bot_position,
693+
enemy_positions=enemy_positions,
694+
noise_radius=game_state['noise_radius'],
695+
sight_distance=game_state['sight_distance'],
696+
rng=game_state['rng'])
697+
698+
# Update noisy_positions in the game_state
699+
# reset positions
700+
game_state['noisy_positions'] = [None] * 4
701+
noisy_or_none = [
702+
noisy_pos if is_noisy else None
703+
for is_noisy, noisy_pos in
704+
zip(noised_positions['is_noisy'], noised_positions['enemy_positions'])
705+
]
706+
game_state['noisy_positions'][enemy_team::2] = noisy_or_none
707+
708+
bots = game_state['bots'][:]
709+
bots[enemy_team::2] = noised_positions['enemy_positions']
710+
711+
is_noisy = [False for _ in range(4)]
712+
is_noisy[enemy_team::2] = noised_positions['is_noisy']
713+
714+
shaded_food_own = list(pos for pos, age in game_state['food_age'][own_team].items()
715+
if age > 0)
716+
shaded_food = [[], []]
717+
shaded_food[own_team] = shaded_food_own
718+
719+
bot_state: TeamState = {
720+
'bots': bots,
721+
'score': game_state['score'][:],
722+
'kills': game_state['kills'][:],
723+
'deaths': game_state['deaths'][:],
724+
'bot_was_killed': game_state['bot_was_killed'][:],
725+
'error_count': [len(e) for e in game_state['timeouts'][:]],
726+
'food': [list(team_food) for team_food in game_state['food']],
727+
'shaded_food': shaded_food,
728+
'team_time': game_state['team_time'][:],
729+
'is_noisy': is_noisy,
730+
'round': game_state['round'],
731+
'turn': turn,
732+
}
733+
return bot_state
734+
735+
case "FINISHED":
736+
# Called for remote players in _exit
737+
turn = team_idx
738+
# TODO: is turn needed?
739+
740+
team_state_final: TeamStateFinished = {
741+
'bots': game_state['bots'][:],
742+
'score': game_state['score'][:],
743+
'kills': game_state['kills'][:],
744+
'deaths': game_state['deaths'][:],
745+
'bot_was_killed': game_state['bot_was_killed'][:],
746+
'error_count': [len(e) for e in game_state['timeouts'][:]],
747+
'food': [list(team_food) for team_food in game_state['food']],
748+
'team_time': game_state['team_time'][:],
749+
'round': game_state['round'],
750+
'turn': turn,
751+
}
752+
return team_state_final
735753

736-
if game_state['game_phase'] == 'INIT':
737-
bot_state.update({
738-
'walls': game_state['walls'], # only in initial round
739-
'shape': game_state['shape'], # only in initial round
740-
'seed': seed, # only used in set_initial phase
741-
'max_rounds': game_state['max_rounds'],
742-
'team_names': game_state['team_names'][:],
743-
})
744-
745-
return bot_state
754+
raise PelitaIllegalGameState("Got bad game_state in prepare_bot_state")
746755

747756

748757
def update_viewers(game_state):

pelita/spec.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,38 @@ class GameState(TypedDict):
4949
error_limit: int
5050
viewers: list[Any]
5151
controller: None|Any
52+
53+
class TeamInitial(TypedDict):
54+
walls: set[Pos]
55+
shape: Shape
56+
seed: int
57+
max_rounds: int
58+
team_names: list[str]
59+
timeout_length: float
60+
61+
class TeamState(TypedDict):
62+
bots: list[Pos]
63+
score: list[int]
64+
kills: list[int]
65+
deaths: list[int]
66+
bot_was_killed: list[bool]
67+
error_count: list[int]
68+
food: list[list[Pos]]
69+
shaded_food: list[list[Pos]]
70+
team_time: list[float]
71+
is_noisy: list[bool]
72+
round: int|None
73+
turn: int
74+
75+
class TeamStateFinished(TypedDict):
76+
bots: list[Pos]
77+
score: list[int]
78+
kills: list[int]
79+
deaths: list[int]
80+
bot_was_killed: list[bool]
81+
error_count: list[bool]
82+
food: list[list[Pos]]
83+
team_time: list[float]
84+
round: int|None
85+
turn: int
86+

pelita/team.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,9 @@ def wait_ready(self, timeout):
391391
raise RemotePlayerRecvTimeout("", "") from None
392392

393393
def set_initial(self, team_id, game_state):
394+
# TODO: timeout length should be set when object is created
394395
timeout_length = game_state['timeout_length']
396+
self.request_timeout = timeout_length
395397

396398
msg_id = self.conn.send_req("set_initial", {"team_id": team_id,
397399
"game_state": game_state})
@@ -401,7 +403,7 @@ def set_initial(self, team_id, game_state):
401403
return reply
402404

403405
def get_move(self, game_state):
404-
timeout_length = game_state['timeout_length']
406+
timeout_length = self.request_timeout
405407

406408
msg_id = self.conn.send_req("get_move", {"game_state": game_state})
407409
reply = self.conn.recv_reply(msg_id, timeout_length)

0 commit comments

Comments
 (0)