hanabi.py: implement taking arbitrary actions, support striking out

This commit is contained in:
Maximilian Keßler 2023-05-06 17:41:33 +02:00
parent 9cd87445f2
commit 3a00879e03
Signed by: max
GPG key ID: BCC5A619923C0BA5

View file

@ -166,18 +166,25 @@ class GameState():
# can be set to true if game is known to be in a lost state # can be set to true if game is known to be in a lost state
self.in_lost_state = False self.in_lost_state = False
# automatically set upon third strike, when extar round is over or when explicitly taking EndGame or VoteTerminate actions
self.over = False
# will track replay as game progresses # will track replay as game progresses
self.actions = [] self.actions = []
## Methods to control game state change ## Methods to control game state change
def make_action(self, Action): def make_action(self, action):
match Action.ActionType: match action.type:
case ActionType.clue: case ActionType.ColorClue | ActionType.RankClue:
self.clue() self.clue()
case ActionType.Play: case ActionType.Play:
self.play(action.target) self.play(action.target)
case ActionType.Discard:
self.discard(action.target)
case ActionType.EndGame | ActionType.VoteTerminate:
self.over = True
def play(self, card_idx): def play(self, card_idx):
card = self.instance.deck[card_idx] card = self.instance.deck[card_idx]
@ -187,11 +194,12 @@ class GameState():
self.clues += 1 self.clues += 1
else: else:
self.strikes += 1 self.strikes += 1
assert (self.strikes < self.instance.num_strikes)
self.trash.append(self.instance.deck[card_idx]) self.trash.append(self.instance.deck[card_idx])
self.actions.append(Action(ActionType.Play, target=card_idx)) self.actions.append(Action(ActionType.Play, target=card_idx))
self.__replace(card_idx) self.__replace(card_idx)
self.__make_turn() self.__make_turn()
if all(s == 5 for s in self.stacks) or self.strikes >= self.instance.num_strikes:
self.over = True
def discard(self, card_idx): def discard(self, card_idx):
assert(self.clues < 8) assert(self.clues < 8)
@ -245,7 +253,7 @@ class GameState():
# Properties of GameState # Properties of GameState
def is_over(self): def is_over(self):
return all(s == 5 for s in self.stacks) or (self.remaining_extra_turns == 0) or (self.is_known_lost()) return self.over or self.is_known_lost()
def is_won(self): def is_won(self):
return self.score == 5 * instance.num_suits return self.score == 5 * instance.num_suits
@ -255,6 +263,8 @@ class GameState():
@property @property
def score(self): def score(self):
if self.strikes >= self.instance.num_strikes:
return 0
return sum(self.stacks) return sum(self.stacks)
@property @property
@ -292,10 +302,12 @@ class GameState():
# increments turn counter and tracks extra round # increments turn counter and tracks extra round
def __make_turn(self): def __make_turn(self):
assert(self.remaining_extra_turns > 0) assert(not self.over)
self.turn = (self.turn + 1) % self.instance.num_players self.turn = (self.turn + 1) % self.instance.num_players
if self.progress == self.instance.deck_size: if self.progress == self.instance.deck_size:
self.remaining_extra_turns -= 1 self.remaining_extra_turns -= 1
if self.remaining_extra_turns == 0:
self.over = True
# replaces the specified card (has to be in current player's hand) with the next card of the deck (if nonempty) # replaces the specified card (has to be in current player's hand) with the next card of the deck (if nonempty)
def __replace(self, card_idx): def __replace(self, card_idx):