Py-Hanabi/hanab_live.py

82 lines
3.5 KiB
Python

from typing import List, Optional
import hanabi
import constants
from variants import Variant
class HanabLiveInstance(hanabi.HanabiInstance):
def __init__(
self,
deck: List[hanabi.DeckCard],
num_players: int,
variant_id: int,
one_extra_card: bool = False,
one_less_card: bool = False,
*args, **kwargs
):
assert 2 <= num_players <= 6
hand_size = constants.HAND_SIZES[num_players]
if one_less_card:
hand_size -= 1
if one_extra_card:
hand_size += 1
super().__init__(deck, num_players, hand_size=hand_size, *args, **kwargs)
self.variant_id = variant_id
self.variant = Variant.from_db(self.variant_id)
@staticmethod
def select_standard_variant_id(instance: hanabi.HanabiInstance):
err_msg = "Hanabi instance not supported by hanab.live, cannot convert to HanabLiveInstance: "
assert 3 <= instance.num_suits <= 6, \
err_msg + "Illegal number of suits ({}) found, must be in range [3,6]".format(instance.num_suits)
assert 0 <= instance.num_dark_suits <= 2, \
err_msg + "Illegal number of dark suits ({}) found, must be in range [0,2]".format(instance.num_dark_suits)
assert 4 <= instance.num_suits - instance.num_dark_suits, \
err_msg + "Illegal ratio of dark suits to suits, can have at most {} dark suits with {} total suits".format(
max(instance.num_suits - 4, 0), instance.num_suits
)
return constants.VARIANT_IDS_STANDARD_DISTRIBUTIONS[instance.num_suits][instance.num_dark_suits]
class HanabLiveGameState(hanabi.GameState):
def __init__(self, instance: HanabLiveInstance, starting_player: int = 0):
super().__init__(instance, starting_player)
self.instance: HanabLiveInstance = instance
def make_action(self, action):
match action.type:
case hanabi.ActionType.ColorClue | hanabi.ActionType.RankClue:
assert(self.clues > 0)
self.actions.append(action)
self.clues -= self.instance.clue_increment
self._make_turn()
# TODO: could check that the clue specified is in fact legal
case hanabi.ActionType.Play:
self.play(action.target)
case hanabi.ActionType.Discard:
self.discard(action.target)
case hanabi.ActionType.EndGame | hanabi.ActionType.VoteTerminate:
self.over = True
def _waste_clue(self) -> hanabi.Action:
for player in range(self.turn + 1, self.turn + self.num_players):
for card in self.hands[player % self.num_players]:
for rank in self.instance.variant.ranks:
if self.instance.variant.rank_touches(card, rank):
return hanabi.Action(
hanabi.ActionType.RankClue,
player % self.num_players,
rank
)
for color in range(self.instance.variant.num_colors):
if self.instance.variant.color_touches(card, color):
return hanabi.Action(
hanabi.ActionType.ColorClue,
player % self.num_players,
color
)
raise RuntimeError("Current game state did not permit any legal clue."
"This case is incredibly rare and currently not handled.")