Reference¶
Manipulation of strings¶
-
class
hanabython.
StringAnsi
[source]¶ An ANSI escape code that modifies the printing aspect.
-
BLUE
= '\x1b[94m'¶
-
BROWN
= '\x1b[33m'¶
-
CYAN
= '\x1b[96m'¶
-
GREEN
= '\x1b[32m'¶
-
MAGENTA
= '\x1b[35m'¶
-
RED
= '\x1b[31m'¶
-
RESET
= '\x1b[0;0m'¶ This escape code is special: it is used to return to default aspect.
-
STYLE_BOLD
= '\x1b[1m'¶
-
STYLE_REVERSE_VIDEO
= '\x1b[7m'¶
-
STYLE_UNDERLINE
= '\x1b[4m'¶
-
WHITE
= ''¶ This should be white on black background, and vice-versa.
-
YELLOW
= '\x1b[93m'¶
-
-
hanabython.
str_from_iterable
(l: Iterable[T_co]) → str[source]¶ Convert an iterable to a simple string.
There are two differences with the standard implementation of str:
- No brackets.
- For each
item
of the iterable,str_from_iterable
usesstr(item)
, whereasstr
usesrepr(item)
.
Parameters: l – an iterable. Returns: a simple string. >>> print(str_from_iterable(['a', 'b', 'c'])) a b c >>> print(['a', 'b', 'c']) ['a', 'b', 'c']
-
hanabython.
title
(s: str, width: int) → str[source]¶ Format a string as a title.
Parameters: - s – the string
- width – the total width of the final layout (in number of characters).
Returns: the string formatted as a title.
>>> title(s='Title', width=20) '****** Title *******' >>> title(s='A not-too-long title', width=20) 'A not-too-long title' >>> title(s='A title that is really too long', width=20) 'A title that is r...'
-
hanabython.
uncolor
(s: str) → str[source]¶ Remove ANSI escape codes from the string.
Parameters: s (string) – a string. Returns: the same string without its ANSI escape codes. >>> from hanabython import StringAnsi >>> s = (StringAnsi.RED + "Hanabi" + StringAnsi.RESET + ', a game by ' ... + StringAnsi.BLUE + 'Antoine Bauza' + StringAnsi.RESET) >>> uncolor(s) 'Hanabi, a game by Antoine Bauza'
-
class
hanabython.
Colored
[source]¶ An object with a colored string representation.
>>> from hanabython import StringAnsi >>> class MyClass(Colored): ... def colored(self): ... return StringAnsi.RED + 'some text' + StringAnsi.RESET >>> my_object = MyClass() >>> my_object.colored() '\x1b[31msome text\x1b[0;0m' >>> str(my_object) 'some text' >>> repr(my_object) '<MyClass: some text>'
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
Colors¶
-
class
hanabython.
Color
(name: str, symbol: str, print_color: str)[source]¶ A color in Hanabi.
Parameters: - name – The full name of the color. In a game, two distinct colors must have different names.
- symbol – The short name of the color. For standard colors
(defined as constants in
Colors
), it is always 1 character, and no two standard colors have the same symbol. For user-defined colors, it is recommended to do the same, but not necessary. - print_color – an ANSI escape code that modifies the printing
color. See
StringAnsi
.
>>> brown = Color(name='Brown', symbol='N', print_color=StringAnsi.BROWN) >>> brown.name 'Brown' >>> brown.symbol 'N' >>> brown.print_color '\x1b[33m'
-
color_str
(o: object) → str[source]¶ Convert an object to a colored string.
Parameters: o – any object. Returns: the __str__
of this object, with an ANSI color-modifying escape code at the beginning and its cancellation at the end.>>> brown = Color(name='Brown', symbol='N', ... print_color=StringAnsi.BROWN) >>> brown.color_str('some text') '\x1b[33msome text\x1b[0;0m' >>> brown.color_str(42) '\x1b[33m42\x1b[0;0m'
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
is_cluable
¶ Returns: whether this color can be used for clues. For a normal color, it is True. This is different in ColorMulticolor
andColorColorless
.
-
match
(clue_color: hanabython.Modules.Color.Color) → bool[source]¶ React to a color clue.
Parameters: clue_color – the color of the clue. Returns: whether a card of the current color should react to a clue of color clue_color
. A normal color matches simply if the color of the clue is the same. This is different inColorMulticolor
andColorColorless
.>>> brown = Color(name='Brown', symbol='N', ... print_color=StringAnsi.BROWN) >>> pink = Color(name='Pink', symbol='P', ... print_color=StringAnsi.MAGENTA) >>> brown.match(clue_color=brown) True >>> brown.match(clue_color=pink) False
-
class
hanabython.
ColorMulticolor
(name: str, symbol: str, print_color: str)[source]¶ -
is_cluable
¶ Returns: False. It is not allowed to give “multicolor” as a clue.
-
match
(clue_color: hanabython.Modules.Color.Color) → bool[source]¶ Multicolor matches any color clue.
>>> multicolor = ColorMulticolor(name='Multicolor', symbol='M', ... print_color=StringAnsi.MAGENTA) >>> brown = Color(name='Brown', symbol='N', ... print_color=StringAnsi.BROWN) >>> multicolor.match(clue_color=brown) True
-
-
class
hanabython.
ColorColorless
(name: str, symbol: str, print_color: str)[source]¶ -
is_cluable
¶ Returns: False. It is not allowed to give “colorless” as a clue.
-
match
(clue_color: hanabython.Modules.Color.Color) → bool[source]¶ Colorless matches no color clue.
>>> colorless = ColorColorless(name='Colorless', symbol='C', ... print_color=StringAnsi.MAGENTA) >>> brown = Color(name='Brown', symbol='N', ... print_color=StringAnsi.BROWN) >>> colorless.match(clue_color=brown) False
-
-
class
hanabython.
Colors
[source]¶ Standard colors in Hanabi.
-
BLUE
= <Color: B>¶
-
COLORLESS
= <ColorColorless: C>¶ Use this for the colorless cards. As of now, it is brown but the display color might change in future implementations.
-
GREEN
= <Color: G>¶
-
MULTICOLOR
= <ColorMulticolor: M>¶ Use this for multicolor cards. As of now, it is cyan but the display color might change in future implementations.
-
RED
= <Color: R>¶
-
SIXTH
= <Color: P>¶ Use this for the sixth color. As of now, it is pink but the display color might change in future implementations.
-
WHITE
= <Color: W>¶
-
YELLOW
= <Color: Y>¶
-
Configuration¶
-
class
hanabython.
ConfigurationColorContents
(contents: Iterable[int], name: str = None)[source]¶ The contents of a color in a deck of Hanabi.
This is essentially a list, stating the number of copies for each card. For example, [3, 2, 2, 2, 1] means there are 3 ones, 2 twos, etc. Each integer in this list must be strictly positive.
Parameters: - contents – an iterable used to create the list.
- name – the name of the configuration. Can be None (default value). Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”).
>>> cfg = ConfigurationColorContents.NORMAL >>> print(cfg.name) normal >>> print(cfg) normal >>> print(list(cfg)) [3, 2, 2, 2, 1] >>> cfg = ConfigurationColorContents([3, 2, 1]) >>> print(cfg.name) None >>> print(cfg) [3, 2, 1]
-
NORMAL
= <ConfigurationColorContents: normal>¶ Normal contents of a color (3 2 2 2 1).
-
SHORT
= <ConfigurationColorContents: short>¶ Contents of a short color (1 1 1 1 1).
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
class
hanabython.
ConfigurationDeck
(contents: Iterable[Tuple[hanabython.Modules.Color.Color, hanabython.Modules.ConfigurationColorContents.ConfigurationColorContents]], name: str = None)[source]¶ The contents of the deck for a game of Hanabi.
This is essentially an OrderedDict. To each
Color
in the deck, it associates the contents of the color, an object of classConfigurationColorContents
.The order of the colors is important: it will be used in many occasions (including for display).
Parameters: - contents – the iterable used to construct the ordered
dictionary. Typically it is an
OrderedDict
or a list of pairs (color, contents). - name – the name of the configuration. Can be None (default value). Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”).
>>> cfg = ConfigurationDeck.NORMAL >>> print(cfg.name) normal >>> print(cfg) normal >>> cfg = ConfigurationDeck( ... contents=[ ... (Colors.BLUE, ConfigurationColorContents.NORMAL), ... (Colors.RED, ConfigurationColorContents([3, 2, 1])) ... ] ... ) >>> print(cfg.name) None >>> print(cfg) B normal, R [3, 2, 1]
-
EIGHT_COLORS
= <ConfigurationDeck: with sixth color, multicolor and colorless (10 cards each)>¶ Deck with 8 colors (6 colors + multicolor + colorless, all of 10 cards).
-
NORMAL
= <ConfigurationDeck: normal>¶ Normal deck (5 colors of 10 cards).
-
W_MULTICOLOR
= <ConfigurationDeck: with normal multicolor (10 cards)>¶ Deck with long multicolor (5 colors of 10 cards + 1 multi of 10 cards).
-
W_MULTICOLOR_SHORT
= <ConfigurationDeck: with short multicolor (5 cards)>¶ Deck with short multicolor (5 colors of 10 cards + 1 multi of 5 cards).
-
W_SIXTH
= <ConfigurationDeck: with normal sixth color (10 cards)>¶ Deck with long sixth color (6 colors of 10 cards).
-
W_SIXTH_SHORT
= <ConfigurationDeck: with short sixth color (5 cards)>¶ Deck with short sixth color (5 colors of 10 cards + 1 color of 5 cards).
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
copy
() → hanabython.Modules.ConfigurationDeck.ConfigurationDeck[source]¶ Copy the deck configuration.
Returns: a copy of this deck configuration. You can modify the copy without modifying the original. However, it is not a deep copy, (most of time, it would not be useful). >>> cfg = ConfigurationDeck.NORMAL.copy() >>> cfg.name = None >>> del(cfg[Colors.WHITE], cfg[Colors.YELLOW]) >>> print(cfg) B normal, G normal, R normal >>> print(ConfigurationDeck.NORMAL[Colors.WHITE]) normal
-
static
normal_plus
(contents: Iterable[Tuple[hanabython.Modules.Color.Color, hanabython.Modules.ConfigurationColorContents.ConfigurationColorContents]], name: str = None) → hanabython.Modules.ConfigurationDeck.ConfigurationDeck[source]¶ Shortcut to define a deck configuration from the normal one.
Parameters: - contents – the additional contents (typically multicolor, etc.)
- name – the name of the configuration.
Returns: the new configuration.
>>> cfg = ConfigurationDeck.normal_plus(contents=[ ... (Colors.SIXTH, ConfigurationColorContents.NORMAL), ... (Colors.MULTICOLOR, ConfigurationColorContents.SHORT) ... ]) >>> print(cfg) B normal, G normal, R normal, W normal, Y normal, P normal, M short
- contents – the iterable used to construct the ordered
dictionary. Typically it is an
-
class
hanabython.
ConfigurationEmptyClueRule
(i: int, name: str)[source]¶ A rule for “empty clues” in Hanabi.
An empty clue is a clue that corresponds to 0 cards in the hand of the concerned partner.
This class does not implement the rules themselves: they are hardcoded in the class
Game
.Parameters: - i – a unique identifier of the rule.
- name – the name of the configuration. Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”).
>>> cfg = ConfigurationEmptyClueRule.FORBIDDEN >>> print(cfg) empty clues are forbidden >>> print(cfg==ConfigurationEmptyClueRule.FORBIDDEN) True >>> print(cfg==ConfigurationEmptyClueRule.ALLOWED) False
-
ALLOWED
= <ConfigurationEmptyClueRule: empty clues are allowed>¶
-
FORBIDDEN
= <ConfigurationEmptyClueRule: empty clues are forbidden>¶
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
class
hanabython.
ConfigurationEndRule
(i: int, name: str)[source]¶ A rule for the end of game in Hanabi.
This class does not implement the rules themselves: they are hardcoded in the class
Game
.Parameters: - i – a unique identifier of the rule.
- name – the name of the configuration. Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”), except if it is seen as a title (e.g. “Crowning Piece”).
>>> cfg = ConfigurationEndRule.NORMAL >>> print(cfg) normal >>> print(cfg==ConfigurationEndRule.NORMAL) True >>> print(cfg==ConfigurationEndRule.CROWNING_PIECE) False
-
CROWNING_PIECE
= <ConfigurationEndRule: Crowning Piece>¶ “Crowning piece” variant for the end of game. The game stops when a player starts her turn with no card in hand.
-
NORMAL
= <ConfigurationEndRule: normal>¶ Default rule for the end of game. When a player draws the last card, all players play one last time (her included).
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
class
hanabython.
ConfigurationHandSize
(f: Callable[[int], int], name: str = None)[source]¶ A rule for the initial size of the players’ hands.
Parameters: - f – a callable that, to a number of players, associates a number of cards.
- name – the name of the configuration. Can be None (default value). Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”).
>>> cfg = ConfigurationHandSize.NORMAL >>> print(cfg) normal >>> cfg = ConfigurationHandSize(f=lambda n: 9 - n) >>> print(cfg) 7 for 2p, 6 for 3p, 5 for 4p, 4 for 5p
-
NORMAL
= <ConfigurationHandSize: normal>¶ Normal rule for hand size (5 for 3- players, 4 for 4+ players).
-
VARIANT_6_3
= <ConfigurationHandSize: experimental (6 for 2 players, 3 for 5 players)>¶ Experimental variant for hand size (6 for 2 players, 3 for 5+ players).
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
class
hanabython.
Configuration
(deck: hanabython.Modules.ConfigurationDeck.ConfigurationDeck = <ConfigurationDeck: normal>, n_clues: int = 8, n_misfires: int = 3, hand_size_rule: hanabython.Modules.ConfigurationHandSize.ConfigurationHandSize = <ConfigurationHandSize: normal>, empty_clue_rule: hanabython.Modules.ConfigurationEmptyClueRule.ConfigurationEmptyClueRule = <ConfigurationEmptyClueRule: empty clues are forbidden>, end_rule: hanabython.Modules.ConfigurationEndRule.ConfigurationEndRule = <ConfigurationEndRule: normal>, name: str = None)[source]¶ A configuration for a game of Hanabi.
Parameters: - deck – the configuration of the deck.
- n_clues – the number of clue chips that players have.
- n_misfires – the number of misfire chips that players have.
If
n_misfires
misfire chips are used, then the game is lost immediately (it is not a final warning but really the end of the game). - hand_size_rule – the rule used for the initial size of the hands.
- empty_clue_rule – the rule used about empty clues.
- end_rule – the rule used to determine when then game is finished.
- name – the name of the configuration. Can be None (default value). Should not be capitalized (e.g. “my favorite configuration” and not “My favorite configuration”).
Variables: - colors (list) – a list of Color objects. It is the list of keys
of
deck
. - n_colors (int) – the number of colors.
- highest (OrderedDict) – For each color from
colors
, it gives the number on the highest card in that color. - n_values (int) – the number on the highest card in the whole deck.
- values (list) – the list of possible values (from 1 to
n_values
). - deck_array (np.array) – a numpy array of size
n_colors
*n_values
. Each row represents the distribution of cards in a color. Typically, a row is [3, 2, 2, 2, 1], meaning that there are 3 ones, 2 twos, etc. Please note that column 0 corresponds to card value 1, etc. - n_cards (int) – the total number of cards in the deck (50 in the standard configuration).
- max_score (int) – the maximum possible score (25 in the standard configuration).
>>> cfg = Configuration.W_MULTICOLOR_SHORT >>> print(cfg.name) with short multicolor (5 cards) >>> print(cfg) Deck: with short multicolor (5 cards). Number of clues: 8. Number of misfires: 3. Clues rule: empty clues are forbidden. End rule: normal. >>> print(cfg.hand_size_rule) normal >>> print(cfg.colors) [<Color: B>, <Color: G>, <Color: R>, <Color: W>, <Color: Y>, <ColorMulticolor: M>] >>> print(cfg.n_colors) 6 >>> print(cfg.highest) OrderedDict([(<Color: B>, 5), (<Color: G>, 5), (<Color: R>, 5), (<Color: W>, 5), (<Color: Y>, 5), (<ColorMulticolor: M>, 5)]) >>> print(cfg.n_values) 5 >>> print(cfg.values) [1, 2, 3, 4, 5] >>> print(cfg.deck_array) [[3 2 2 2 1] [3 2 2 2 1] [3 2 2 2 1] [3 2 2 2 1] [3 2 2 2 1] [1 1 1 1 1]] >>> print(cfg.n_cards) 55 >>> print(cfg.max_score) 30
Design a configuration manually:
>>> from hanabython import (ConfigurationDeck, ConfigurationColorContents, ... ConfigurationEmptyClueRule) >>> cfg = Configuration( ... deck=ConfigurationDeck(contents=[ ... (Colors.BLUE, ConfigurationColorContents([3, 2, 1, 1])), ... (Colors.RED, ConfigurationColorContents([2, 1])), ... ]), ... n_clues=4, ... n_misfires=1, ... hand_size_rule=ConfigurationHandSize.VARIANT_6_3, ... empty_clue_rule=ConfigurationEmptyClueRule.ALLOWED, ... end_rule=ConfigurationEndRule.CROWNING_PIECE ... ) >>> print(cfg) Deck: B [3, 2, 1, 1], R [2, 1]. Number of clues: 4. Number of misfires: 1. Clues rule: empty clues are allowed. End rule: Crowning Piece.
-
EIGHT_COLORS
= <Configuration: with sixth color, multicolor and colorless (10 cards each)>¶
-
STANDARD
= <Configuration: standard>¶
-
W_MULTICOLOR
= <Configuration: with normal multicolor (10 cards)>¶
-
W_MULTICOLOR_SHORT
= <Configuration: with short multicolor (5 cards)>¶
-
W_SIXTH
= <Configuration: with normal sixth color (10 cards)>¶
-
W_SIXTH_SHORT
= <Configuration: with short sixth color (5 cards)>¶
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
Clues¶
-
class
hanabython.
Clue
(x: Union[int, hanabython.Modules.Color.Color])[source]¶ A clue.
Parameters: x – the clue (value or color). Variables: category (int) – can be either Clue.VALUE or Clue.COLOR. >>> clue = Clue(1) >>> print(clue) 1 >>> clue.category == Clue.VALUE True >>> clue = Clue(Colors.RED) >>> print(clue) R >>> clue.category == Clue.COLOR True
-
COLOR
= 1¶ Category for a clue by color.
-
VALUE
= 0¶ Category for a clue by value.
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
Cards¶
-
class
hanabython.
Card
(*args, **kwargs)[source]¶ A card of Hanabi.
Parameters: - c (Color) – the color of the card.
- v (int) – the value of the card (usually between 1 and 5).
- s (str) – a short string representing the card. Must use one of the
standard colors, cf.
Color.from_symbol()
.
You can provide either
c
andv
, ors
. The constructor accepts several types of syntax, as illustrated below.>>> my_card = Card(c=Colors.BLUE, v=3) >>> print(my_card) B3 >>> my_card = Card(Colors.BLUE, 3) >>> print(my_card) B3 >>> my_card = Card(3, Colors.BLUE) >>> print(my_card) B3 >>> my_card = Card(s='B3') >>> print(my_card) B3 >>> my_card = Card('B3') >>> print(my_card) B3 >>> my_card = Card(s='3B') >>> print(my_card) B3 >>> my_card = Card('3B') >>> print(my_card) B3
N.B.: the string input works even if the v has several digits.
>>> my_card = Card('B42') >>> print(my_card) B42 >>> my_card = Card('51M') >>> print(my_card) M51
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
match
(clue: hanabython.Modules.Clue.Clue) → bool[source]¶ React to a clue.
Parameters: clue – the clue. Returns: whether the card should be pointed when giving this clue. >>> from hanabython import Colors >>> card_blue = Card('B3') >>> card_blue.match(Clue(Colors.BLUE)) True >>> card_blue.match(Clue(Colors.RED)) False >>> card_blue.match(Clue(3)) True >>> card_blue.match(Clue(4)) False >>> card_multi = Card('M3') >>> card_multi.match(Clue(Colors.BLUE)) True >>> card_colorless = Card('C3') >>> card_colorless.match(Clue(Colors.BLUE)) False
-
class
hanabython.
CardPublic
(cfg: hanabython.Modules.Configuration.Configuration)[source]¶ The “public” part of a card.
An object of this class represents what is known by all players, including the owner of the card.
Parameters: cfg – the configuration of the game.
Variables: - can_be_c (np.array) – a coefficient is True iff the card can be of the corresponding color.
- can_be_v (np.array) – a coefficient is True iff the card can be of the corresponding value.
- yes_clued_c (np.array) – a coefficient is True iff the card was explicitly clued as the corresponding color and it can be of this color (this precision is important for multicolor).
- yes_clued_v (np.array) – a coefficient is True iff the card was explicitly clued as value v.
>>> from hanabython import Configuration >>> card = CardPublic(Configuration.EIGHT_COLORS) >>> print(card) BGRWYPMC 12345
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
match
(clue: hanabython.Modules.Clue.Clue, b: bool) → None[source]¶ React to a clue.
Updates the internal variables of the card.
Parameters: - clue – the clue.
- b – whether the card matches or not.
>>> from hanabython import Configuration >>> cfg = Configuration.EIGHT_COLORS >>> card = CardPublic(cfg) >>> print(card) BGRWYPMC 12345 >>> card.match(clue=Clue(Colors.RED), b=False) >>> print(card) #doctest: +NORMALIZE_WHITESPACE BGWYPC 12345 >>> card.match(clue=Clue(Colors.BLUE), b=True) >>> print(card) #doctest: +NORMALIZE_WHITESPACE B 12345
Let us try with the clues in the opposite order:
>>> from hanabython import Configuration >>> card = CardPublic(Configuration.EIGHT_COLORS) >>> print(card) BGRWYPMC 12345 >>> card.match(clue=Clue(Colors.BLUE), b=True) >>> print(card) #doctest: +NORMALIZE_WHITESPACE BM 12345 >>> card.match(clue=Clue(Colors.RED), b=False) >>> print(card) #doctest: +NORMALIZE_WHITESPACE B 12345
Now with clues by value:
>>> from hanabython import Configuration >>> card = CardPublic(Configuration.EIGHT_COLORS) >>> print(card) BGRWYPMC 12345 >>> card.match(clue=Clue(3), b=False) >>> print(card) #doctest: +NORMALIZE_WHITESPACE BGRWYPMC 1245 >>> card.match(clue=Clue(5), b=True) >>> print(card) #doctest: +NORMALIZE_WHITESPACE BGRWYPMC 5
Hands¶
-
class
hanabython.
Hand
(source: Iterable[Union[hanabython.Modules.Card.Card, str]] = None)[source]¶ The hand of a player.
We use the same convention as in Board Game Arena: newest cards are on the left (i.e. at the beginning of the list) and oldest cards are on the right (i.e. at the end of the list).
Basically, a Hand is a list of Card objects. It can be constructed as such, or using a list of strings which will be automatically converted to cards.
Parameters: source – an iterable used to construct the hand. N.B.: this parameter is mostly used for examples and tests. In contrast, at the beginning of a game, the hand should be initialized with no cards, because cards will be given one by one to the players during the initial dealing of hands. >>> hand = Hand([Card('Y3'), Card('M1'), Card('B2'), Card('R4')]) >>> print(hand) Y3 M1 B2 R4 >>> hand = Hand(['Y3', 'M1', 'B2', 'R4']) >>> print(hand) Y3 M1 B2 R4
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
give
(k: int) → hanabython.Modules.Card.Card[source]¶ Give a card.
Parameters: k – the position of the card in the hand (0 = newest). Returns: the card given. >>> hand = Hand(['Y3', 'B1', 'M1', 'B2', 'R4']) >>> card = hand.give(1) >>> print(card) B1 >>> print(hand) Y3 M1 B2 R4
-
match
(clue: hanabython.Modules.Clue.Clue) → List[bool][source]¶ React to a clue.
Parameters: clue – the clue. Returns: a list of booleans. The i-th coefficient is True iff the i-th card of the hand matches the clue given. >>> hand = Hand(['G2', 'Y3', 'M1', 'B2', 'R4']) >>> hand.match(Clue(Colors.RED)) [False, False, True, False, True] >>> hand.match(Clue(2)) [True, False, False, True, False]
-
-
class
hanabython.
HandPublic
(cfg: hanabython.Modules.Configuration.Configuration, n_cards: int = 0)[source]¶ The “public” part of a hand.
An object of this class represents what is known by all players, including the owner of the hand.
We use the same convention as in Board Game Arena: newest cards are on the left (i.e. at the beginning of the list) and oldest cards are on the right (i.e. at the end of the list).
Basically, a HandPublic is a list of CardPublic objects.
Parameters: - cfg – the configuration of the game.
- n_cards – the number of cards in the hand. N.B.: this parameter is mostly used for examples and tests. In contrast, at the beginning of a game, the hand should be initialized with 0 cards, because cards will be given one by one to the players during the initial dealing of hands.
>>> hand = HandPublic(cfg=Configuration.STANDARD, n_cards=4) >>> print(hand) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
give
(k: int) → None[source]¶ Give a card.
Parameters: k – the position of the card in the hand (0 = newest). The card is simply suppressed from the hand.
>>> hand = HandPublic(cfg=Configuration.STANDARD, n_cards=4) >>> hand.match(clue=Clue(5), bool_list=[False, True, False, False]) >>> hand.match(clue=Clue(4), bool_list=[True, False, False, False]) >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGRWY 4 , BGRWY 5 , BGRWY 123 , BGRWY 123 >>> hand.give(1) >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGRWY 4 , BGRWY 123 , BGRWY 123
-
match
(clue: hanabython.Modules.Clue.Clue, bool_list: List[bool])[source]¶ React to a clue
Parameters: - clue – the clue.
- bool_list – a list of booleans. The i-th coefficient is True iff the i-th card of the hand matches the clue given.
Updates the internal variables of the hand.
>>> hand = HandPublic(cfg=Configuration.STANDARD, n_cards=4) >>> hand.match(clue=Clue(3), bool_list=[False, True, False, False]) >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGRWY 1245 , BGRWY 3 , BGRWY 1245 , BGRWY 1245 >>> hand.match(clue=Clue(Colors.RED), ... bool_list=[False, True, False, False]) >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGWY 1245 , R3 , BGWY 1245 , BGWY 1245
-
receive
() → None[source]¶ Receive a card.
An unknown card is added on the left, i.e. at the beginning of the list.
>>> hand = HandPublic(cfg=Configuration.STANDARD, n_cards=4) >>> hand.match(clue=Clue(5), bool_list=[True, True, False, False]) >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGRWY 5 , BGRWY 5 , BGRWY 1234 , BGRWY 1234 >>> hand.receive() >>> print(hand) #doctest: +NORMALIZE_WHITESPACE BGRWY 12345, BGRWY 5 , BGRWY 5 , BGRWY 1234 , BGRWY 1234
Draw Pile¶
-
class
hanabython.
DrawPile
(cfg: hanabython.Modules.Configuration.Configuration)[source]¶ The draw pile of a game of Hanabi.
Parameters: cfg – the configuration of the game. At initialization, the draw pile is generated with the parameters in
cfg
, then it is shuffled.Basically, a DrawPile is a list of cards. The top of the pile, where cards are drawn, is represented by the end of the list (not that we care much, but it could have an influence someday in some not-yet-implemented non-official variants).
>>> from hanabython import Configuration >>> draw_pile = DrawPile(Configuration.STANDARD)
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
give
() → Optional[hanabython.Modules.Card.Card][source]¶ Give the card from the top of pile.
Returns: the card drawn. If the pile is empty, return None. >>> from hanabython import Configuration >>> draw_pile = DrawPile(cfg=Configuration.STANDARD) >>> card = draw_pile.give() >>> type(card) <class 'hanabython.Modules.Card.Card'> >>> while draw_pile.n_cards >= 1: ... _ = draw_pile.give() >>> print(draw_pile.give()) None
-
n_cards
¶ Number of cards in the pile.
Returns: the number of cards. >>> from hanabython import Configuration >>> draw_pile = DrawPile(Configuration.STANDARD) >>> draw_pile.n_cards 50
-
-
class
hanabython.
DrawPilePublic
(cfg: hanabython.Modules.Configuration.Configuration)[source]¶ The public part of a draw pile.
An object of this class represents what is known by all players. In the normal version of the game and all official variants, it is only the number of cards left.
Parameters: cfg – the configuration of the game. >>> from hanabython import Configuration >>> draw_pile = DrawPilePublic(cfg=Configuration.STANDARD) >>> print(draw_pile) 50 cards left
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
give
() → None[source]¶ Give the card from the top of pile.
Updates the internal variables of the pile.
>>> from hanabython import Configuration >>> draw_pile = DrawPilePublic(cfg=Configuration.STANDARD) >>> print(draw_pile) 50 cards left >>> while draw_pile.n_cards >= 2: ... draw_pile.give() >>> print(draw_pile) 1 card left >>> draw_pile.give() >>> print(draw_pile) No card left
-
Discard Pile¶
-
class
hanabython.
DiscardPile
(cfg: hanabython.Modules.Configuration.Configuration)[source]¶ The discard pile in a game of Hanabi.
Parameters: cfg – the configuration of the game.
Variables: - chronological (list) – a list a cards discarded, by chronological order.
- array (np.array) – each row represents a color, each column a card value. The coefficient is the number of copies of this card in the discard pile.
- not_discarded (np.array) – is equal to
Configuration.deck_array
-array
. Number of copies left for each card (including everything except the discard pile: the draw pile, the players’ hand and the board). - scorable (np.array) – each row represents a color, each column a card value. The coefficient is True it is possible to have a such card on the board at the end of the game (whether it is already on the board or not). For example, if the two G4’s are discarded, then G4 and G5 are not “scorable”. Note that a 1 always is considered “scorable”, whether it is on the board or not.
>>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> print(discard_pile) No card discarded yet
Check that scorable cards are counted correctly with unusual configurations:
>>> from hanabython import (Configuration, ConfigurationDeck, ... Colors, ConfigurationColorContents) >>> discard_pile = DiscardPile(Configuration( ... deck=ConfigurationDeck(contents=[ ... (Colors.BLUE, ConfigurationColorContents([3, 2, 1, 1])), ... (Colors.RED, ConfigurationColorContents([2, 1])), ... ]) ... )) >>> print(discard_pile) No card discarded yet >>> print(discard_pile.array) [[0 0 0 0] [0 0 0 0]] >>> print(discard_pile.not_discarded) [[3 2 1 1] [2 1 0 0]] >>> print(discard_pile.scorable) [[ True True True True] [ True True False False]] >>> print(discard_pile.max_score_possible) 6
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
colored_as_array
() → str[source]¶ Colored version of
str_as_array()
.
-
colored_compact_chronological
() → str[source]¶ Colored version of
str_compact_chronological()
.
-
colored_compact_factorized
() → str[source]¶ Colored version of
str_multi_line_compact()
.
-
colored_compact_ordered
() → str[source]¶ Colored version of
str_compact_ordered()
.
-
colored_multi_line
() → str[source]¶ Colored version of
str_multi_line()
.
-
colored_multi_line_compact
() → str[source]¶ Colored version of
str_multi_line_compact()
.
-
list_reordered
¶ List of discarded cards, ordered by color and value.
Returns: the list of discarded cards, by lexicographic order. The order on the colors is the one specified in cfg
.>>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> discard_pile.list_reordered [<Card: B1>, <Card: B3>, <Card: R4>]
-
max_score_possible
¶ Maximum possible score, considering the discard pile.
Returns: the maximum score that is still possible.
-
receive
(card) → None[source]¶ Receive a card.
Parameters: card – the card discarded. Update the internal variables of the discard pile.
>>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('B2')) >>> discard_pile.receive(Card('B3')) >>> print(discard_pile) B2 B3 B3 >>> print(discard_pile.not_discarded) [[3 1 0 2 1] [3 2 2 2 1] [3 2 2 2 1] [3 2 2 2 1] [3 2 2 2 1]] >>> print(discard_pile.scorable) [[ True True False False False] [ True True True True True] [ True True True True True] [ True True True True True] [ True True True True True]] >>> print(discard_pile.max_score_possible) 22
-
str_as_array
() → str[source]¶ Convert to string in an array-style layout.
Returns: a representation of the discard pile. >>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_as_array()) 1 2 3 4 5 B [1 0 1 0 0] G [0 0 0 0 0] R [0 0 0 1 0] W [0 0 0 0 0] Y [0 0 0 0 0]
-
str_compact_chronological
() → str[source]¶ Convert to string in a list-style layout, by chronological order.
Returns: a representation of the discard pile. >>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_compact_chronological()) B3 R4 B1
-
str_compact_factorized
() → str[source]¶ Convert to nice string.
Returns: a representation of the discard pile. >>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_compact_factorized()) B 1 3 R 4
-
str_compact_ordered
() → str[source]¶ Convert to string in a list-style layout, ordered by color and value.
Returns: a representation of the discard pile. >>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_compact_ordered()) B1 B3 R4
-
str_multi_line
() → str[source]¶ Convert to nice string.
Returns: a representation of the discard pile. >>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_multi_line()) B1 B3 - R4 - -
-
str_multi_line_compact
() → str[source]¶ Convert to nice string.
Returns: a representation of the discard pile. As of now, it is the one used for the standard method __str__()
(this behavior might be modified in the future).>>> from hanabython import Configuration >>> discard_pile = DiscardPile(Configuration.STANDARD) >>> discard_pile.receive(Card('B3')) >>> discard_pile.receive(Card('R4')) >>> discard_pile.receive(Card('B1')) >>> print(discard_pile.str_multi_line_compact()) B1 B3 R4
Board¶
-
class
hanabython.
Board
(cfg: hanabython.Modules.Configuration.Configuration)[source]¶ The board (cards successfully played) in a game of Hanabi.
Parameters: cfg – the configuration of the game. Variables: altitude (np.array) – indicates the highest card played in each color. E.g. with color c
of indexi
,altitude[i]
is the value of the highest card played in colorc
. The correspondence between colors and indexes is the one provided bycfg
.>>> from hanabython import Configuration >>> board = Board(Configuration.STANDARD) >>> print(board.altitude) [0 0 0 0 0]
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
colored_compact
() → str[source]¶ Colored version of
str_compact()
.
-
colored_fixed_space
() → str[source]¶ Colored version of
str_fixed_space()
.
-
colored_multi_line
() → str[source]¶ Colored version of
str_multi_line()
.
-
colored_multi_line_compact
() → str[source]¶ Colored version of
str_multi_line_compact()
.
-
score
¶ The current score.
Returns: the sum of the altitudes reached in all colors. >>> from hanabython import Configuration >>> cfg = Configuration.STANDARD >>> board = Board(cfg) >>> for s in ['G1', 'G2', 'Y1', 'Y2', 'Y3', 'Y4', 'Y5']: ... _ = board.try_to_play(Card(s)) >>> print(board.score) 7
-
str_compact
() → str[source]¶ Convert to string in “compact” layout.
Returns: a representation of the board. >>> from hanabython import Configuration >>> board = Board(Configuration.STANDARD) >>> for s in ['G1', 'G2', 'Y1', 'Y2', 'Y3', 'Y4', 'Y5']: ... _ = board.try_to_play(Card(s)) >>> print(board.str_compact()) G1 G2 Y1 Y2 Y3 Y4 Y5
-
str_fixed_space
() → str[source]¶ Convert to string in “fixed-space” layout.
Returns: a representation of the board. >>> from hanabython import Configuration >>> board = Board(Configuration.STANDARD) >>> for s in ['G1', 'G2', 'Y1', 'Y2', 'Y3', 'Y4', 'Y5']: ... _ = board.try_to_play(Card(s)) >>> print(board.str_fixed_space()) B - G 1 2 R - W - Y 1 2 3 4 5
-
str_multi_line
() → str[source]¶ Convert to string in “multi-line” layout.
Returns: a representation of the board. >>> from hanabython import Configuration >>> board = Board(Configuration.STANDARD) >>> for s in ['G1', 'G2', 'Y1', 'Y2', 'Y3', 'Y4', 'Y5']: ... _ = board.try_to_play(Card(s)) >>> print(board.str_multi_line()) - G1 G2 - - Y1 Y2 Y3 Y4 Y5
-
str_multi_line_compact
() → str[source]¶ Convert to string in “compact multi-line” layout.
Returns: a representation of the board. >>> from hanabython import Configuration >>> board = Board(Configuration.STANDARD) >>> for s in ['G1', 'G2', 'Y1', 'Y2', 'Y3', 'Y4', 'Y5']: ... _ = board.try_to_play(Card(s)) >>> print(board.str_multi_line_compact()) G1 G2 Y1 Y2 Y3 Y4 Y5
-
try_to_play
(card: hanabython.Modules.Card.Card) → bool[source]¶ Try to play a card on the board.
Parameters: card – the card. Returns: True if the card is successfully played on the board, False otherwise (i.e. if it leads to a misfire). >>> from hanabython import Configuration, Card >>> board = Board(Configuration.STANDARD) >>> for s in ['B1', 'B2', 'Y1', 'Y3', 'B1']: ... board.try_to_play(Card(s)) True True True False False >>> print(board.str_compact()) B1 B2 Y1
-
Actions¶
-
class
hanabython.
Action
(category: int)[source]¶ An action performed by a player (Throw, Play a card, Clue or Forfeit).
In the end-user interfaces (including methods
colored
), “throw” should be called “discard” and “play a card” can be called “play” (to be consistent with the official rules). In the code however, we prefer to use “throw” (to distinguish from other forms of discards, for example after a misfire) and “play a card” (to distinguish from simply playing in general).Parameters: category – can be Action.THROW
,Action.PLAY_CARD
,Action.CLUE
orAction.FORFEIT
.Generally, only subclasses are instantiated. Cf.
ActionThrow
,ActionPlayCard
,ActionClue
andActionForfeit
.-
CATEGORIES
= {0, 1, 2, 3}¶ Possibles categories of action.
-
CLUE
= 2¶
-
FORFEIT
= 3¶
-
PLAY_CARD
= 1¶
-
THROW
= 0¶
-
-
class
hanabython.
ActionClue
(i: int, clue: hanabython.Modules.Clue.Clue)[source]¶ An action of a player: give a clue.
Parameters: - i – the relative position of the concerned player (i.e. 1 for next player, 2 for second next player, etc.).
- clue – the clue.
>>> from hanabython import Colors >>> action = ActionClue(i=1, clue=Clue(2)) >>> print(action) Clue 2 to player in relative position 1 >>> action = ActionClue(i=2, clue=Clue(Colors.BLUE)) >>> print(action) Clue B to player in relative position 2
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
class
hanabython.
ActionForfeit
[source]¶ An action of a player: forfeit (lose the game immediately).
>>> action = ActionForfeit() >>> print(action) Forfeit
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
Players¶
-
class
hanabython.
Player
(name: str)[source]¶ A player for Hanabi.
Parameters: name – the name of the player. To define a subclass, the only real requirement is to implement the function
choose_action()
.>>> antoine = Player('Antoine') >>> print(antoine) Antoine
-
choose_action
() → hanabython.Modules.Action.Action[source]¶ Choose an action.
Returns: the action chosen by the player.
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
receive_action_illegal
(s: str) → None[source]¶ Receive a message: the action chosen is illegal.
Parameters: s – a message explaining why the action is illegal.
-
receive_end_dealing
() → None[source]¶ Receive a message: the initial dealing of hands is over.
The hands themselves are not communicated in this message. Drawing cards, including for the initial hands, is always handled by
receive_i_draw()
orreceive_partner_draws()
.
-
receive_game_exhausted
(score: int) → None[source]¶ Receive a message: the game is over and is neither really lost (misfires, forfeit) nor a total victory (maximal score). Typically, this happens a bit after the deck ran out of cards (it depends on the end-of-game rule that is used).
Parameters: score – the final score.
-
receive_i_draw
() → None[source]¶ Receive a message: this player tries to draw a card.
A card is actually drawn only if the draw pile is not empty.
-
receive_init
(cfg: hanabython.Modules.Configuration.Configuration, player_names: List[str]) → None[source]¶ Receive a message: the game starts.
Parameters: - cfg – the configuration of the game.
- player_names – the names of the players, rotated so that this player corresponds to index 0.
-
receive_lose
(score: int) → None[source]¶ Receive a message: the game is lost (misfires or forfeit).
Parameters: score – the final score (0 in that case).
-
receive_partner_draws
(i_active: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: another player tries to draw a card.
A card is actually drawn only if the draw pile is not empty.
Parameters: - i_active – the position of the player who draws (relatively to this player).
- card – the card drawn.
-
receive_remaining_turns
(remaining_turns: int) → None[source]¶ Receive a message: the number of remaining turns is now known.
This happens with the normal rule for end of game: as soon as the discard pile is empty, we know how many turns are left. N.B.: the word “turn” means that one player gets to play (not all of them).
Parameters: remaining_turns – the number of turns left.
-
receive_someone_clues
(i_active: int, i_clued: int, clue: hanabython.Modules.Clue.Clue, bool_list: List[bool]) → None[source]¶ Receive a message: a player gives a clue to another one.
It is not necessary to check whether this action is legal: the
Game
will only send this message when it is the case.Parameters: - i_active – the position of the player who gives the clue (relatively to this player).
- i_clued – the position of the player who receives the clue (relatively to this player).
- clue – the clue.
- bool_list – a list of boolean that indicates what cards match the clue given.
-
receive_someone_forfeits
(i_active: int) → None[source]¶ Receive a message: a player forfeits.
Parameters: i_active – the position of the player who forfeits (relatively to this player).
-
receive_someone_plays_card
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: a player tries to play a card on the board.
This can be a success or a misfire.
Parameters: - i_active – the position of the player who plays the card (relatively to this player).
- k – position of the card in the hand.
- card – the card played.
-
receive_someone_throws
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: a player throws (discards a card willingly).
It is not necessary to check whether this action is legal: the
Game
will only send this message when it is the case.Parameters: - i_active – the position of the player who throws (relatively to this player).
- k – position of the card in the hand.
- card – the card thrown.
-
-
class
hanabython.
PlayerPuppet
(name, speak=False)[source]¶ A player for Hanabi that serves only for testing purposes.
Parameters: speak – if True, then each time this player receives a message, she prints a acknowledgement. Variables: next_action (Action) – this variable makes it possible to control this player’s action. >>> from hanabython import ActionThrow >>> antoine = PlayerPuppet('Antoine', speak=True) >>> antoine.next_action = ActionThrow(k=4) >>> _ = antoine.choose_action() Antoine: Choose an action Antoine: action = Discard card in position 5
-
receive_action_illegal
(s: str) → None[source]¶ Receive a message: the action chosen is illegal.
Parameters: s – a message explaining why the action is illegal.
-
receive_end_dealing
() → None[source]¶ Receive a message: the initial dealing of hands is over.
The hands themselves are not communicated in this message. Drawing cards, including for the initial hands, is always handled by
receive_i_draw()
orreceive_partner_draws()
.
-
receive_game_exhausted
(score: int) → None[source]¶ Receive a message: the game is over and is neither really lost (misfires, forfeit) nor a total victory (maximal score). Typically, this happens a bit after the deck ran out of cards (it depends on the end-of-game rule that is used).
Parameters: score – the final score.
-
receive_i_draw
() → None[source]¶ Receive a message: this player tries to draw a card.
A card is actually drawn only if the draw pile is not empty.
-
receive_init
(cfg: hanabython.Modules.Configuration.Configuration, player_names: List[str]) → None[source]¶ Receive a message: the game starts.
Parameters: - cfg – the configuration of the game.
- player_names – the names of the players, rotated so that this player corresponds to index 0.
-
receive_lose
(score: int) → None[source]¶ Receive a message: the game is lost (misfires or forfeit).
Parameters: score – the final score (0 in that case).
-
receive_partner_draws
(i_active: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: another player tries to draw a card.
A card is actually drawn only if the draw pile is not empty.
Parameters: - i_active – the position of the player who draws (relatively to this player).
- card – the card drawn.
-
receive_remaining_turns
(remaining_turns: int) → None[source]¶ Receive a message: the number of remaining turns is now known.
This happens with the normal rule for end of game: as soon as the discard pile is empty, we know how many turns are left. N.B.: the word “turn” means that one player gets to play (not all of them).
Parameters: remaining_turns – the number of turns left.
-
receive_someone_clues
(i_active: int, i_clued: int, clue: hanabython.Modules.Clue.Clue, bool_list: List[bool]) → None[source]¶ Receive a message: a player gives a clue to another one.
It is not necessary to check whether this action is legal: the
Game
will only send this message when it is the case.Parameters: - i_active – the position of the player who gives the clue (relatively to this player).
- i_clued – the position of the player who receives the clue (relatively to this player).
- clue – the clue.
- bool_list – a list of boolean that indicates what cards match the clue given.
-
receive_someone_forfeits
(i_active: int) → None[source]¶ Receive a message: a player forfeits.
Parameters: i_active – the position of the player who forfeits (relatively to this player).
-
receive_someone_plays_card
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: a player tries to play a card on the board.
This can be a success or a misfire.
Parameters: - i_active – the position of the player who plays the card (relatively to this player).
- k – position of the card in the hand.
- card – the card played.
-
receive_someone_throws
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ Receive a message: a player throws (discards a card willingly).
It is not necessary to check whether this action is legal: the
Game
will only send this message when it is the case.Parameters: - i_active – the position of the player who throws (relatively to this player).
- k – position of the card in the hand.
- card – the card thrown.
-
-
class
hanabython.
PlayerBase
(name: str)[source]¶ A player for Hanabi with basic features.
This class is meant to serve as a mother class for most AIs and interface for human players. It provides all basic features, such as keeping track of the number of cards in the draw pile, the cards in the other players’ hands, the clues given, etc.
Note that all the variables are “personal” to this player: the
Game
does not share access to its internal variables with the players.Note also that most methods are not supposed to work before
receive_init()
is run at least once, which initializes all the variables for a new game.Parameters: name (str) – the name of the player.
Variables: - player_names (list) – a list of strings, each with a player’s name. By convention, the list is always rotated to that this player has position 0, the next player has position 1, etc.
- n_players (int) – the number of players.
- cfg (Configuration) – the configuration of the game.
- board (Board) – the board.
- draw_pile (DrawPilePublic) – the draw pile.
- discard_pile (DiscardPile) – the discard pile.
- n_clues (int) – the number of clues left.
- n_misfires (int) – the number of misfires (initially 0).
- hand_size (int) – the initial hand size.
- hands (list) – a list of Hand objects. The hand in position 0, corresponding to this player, is never updated because the player does not know what she has.
- hands_public (list) – a list of HandPublic objects. This allow the player to keep track, not only of her own clues, but also of the clues received by her partners.
- remaining_turns (int) – the number of remaining turns (once the draw pile is empty, in the normal rule for end of game). As long as the draw pile contains cards, this variable is None.
- recent_events (str) – things that happened “recently” (typically, since
this player’s last turn). Subclasses may typically print and/or empty
this variable from time to time. Cf.
log()
. - dealing_is_ongoing (bool) – True only during the initial dealing of
hands. Avoid useless verbose messages in
recent events
. Cf.log()
. - display_width (int) – the width of the display on the terminal (in number of characters).
>>> antoine = PlayerBase(name='Antoine')
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
colored_hands
() → str[source]¶ A string used to display the hands of all players.
Returns: the string (whose width is usually display_width
, except maybe in the end of game when the hands are shorter).>>> antoine = PlayerBase('Antoine') >>> antoine.demo_game() >>> from hanabython import uncolor >>> print(uncolor(antoine.colored_hands())) #doctest: +NORMALIZE_WHITESPACE Antoine BGRWY 12345, BGRWY 2345 , BGRWY 1 , BGRWY 1 , BGRWY 2345 <BLANKLINE> Donald X Y2 , R1 , R3 , G3 , Y4 BGRWY 2345 , BGRWY 1 , BGRWY 2345 , BGRWY 2345 , BGRWY 2345 <BLANKLINE> Uwe G4 , B4 , W4 , G5 , W1 BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345
-
demo_game
() → None[source]¶ Mimic the beginning of a game.
This method is meant to be used for tests and examples.
>>> from hanabython import uncolor >>> antoine = PlayerBase('Antoine') >>> antoine.demo_game() >>> print(uncolor(antoine.recent_events)) Configuration ------------- Deck: normal. Number of clues: 8. Number of misfires: 3. Clues rule: empty clues are forbidden. End rule: normal. <BLANKLINE> First moves ----------- The game begins. Antoine clues Donald X about 1. Donald X clues Antoine about 1. Uwe discards R3. Uwe draws G4. Antoine plays W1. Antoine draws a card. <BLANKLINE>
-
log
(o: object) → None[source]¶ Log events for the player.
Parameters: o – an object. The method adds str(o) to the variable recent_events
, except during the initial dealing of cards (to avoid useless messages about each card dealt). Do not forget the end-of-line character when relevant (it is not added automatically).This is for the player herself: it is used, in particular, in the subclass
PlayerHumanText
to inform the player of the most recent events in a relatively user-friendly form.N.B.: this is totally different from the use of the standard package
logging
, which is essentially used for debugging purposes.>>> antoine = PlayerBase('Antoine') >>> antoine.log_init() >>> antoine.log('Something happens.\n') >>> antoine.dealing_is_ongoing = True >>> antoine.log('Many useless messages.\n') >>> antoine.dealing_is_ongoing = False >>> antoine.log('Something else happens.\n') >>> print(antoine.recent_events) Something happens. Something else happens. <BLANKLINE> >>> antoine.log_forget() >>> antoine.log('Something new happens.') >>> print(antoine.recent_events) Something new happens.
-
log_forget
() → None[source]¶ Forget old events (during the game).
Empties
recent_events
. In this base class, this method has the same implementation aslog_init()
, but it could be different in some subclasses.
-
log_init
() → None[source]¶ Initialize the log process (at the beginning of a game).
Empties
recent_events
.
-
receive_begin_dealing
() → None[source]¶ The log is turned off to avoid having a message for each card dealt. Cf.
log()
.>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.receive_begin_dealing() >>> antoine.dealing_is_ongoing True >>> antoine.receive_end_dealing() >>> antoine.dealing_is_ongoing False
-
receive_end_dealing
() → None[source]¶ The log is turned back on. Cf.
log()
andreceive_begin_dealing()
.
-
receive_game_exhausted
(score: int) → None[source]¶ We just log the event for the player.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_game_exhausted(score=23) >>> print(antoine.recent_events) Antoine's team has reached the end of the game. Score: 23. <BLANKLINE>
-
receive_i_draw
() → None[source]¶ If there are cards in the draw pile, a card is drawn. There is one card less in
drawpile
, and one more in this player’s hand inhands_public
.>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for _ in range(4): ... antoine.receive_i_draw() >>> print(antoine.draw_pile) 46 cards left >>> print(antoine.hands_public[0]) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345
If there are no cards in the draw pile, nothing happens.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for _ in range(50): ... antoine.receive_i_draw() >>> len(antoine.hands_public[0]) 50 >>> print(antoine.draw_pile) No card left >>> antoine.receive_i_draw() >>> len(antoine.hands_public[0]) 50 >>> print(antoine.draw_pile) No card left
-
receive_init
(cfg: hanabython.Modules.Configuration.Configuration, player_names: List[str]) → None[source]¶ Initialize all the instance variables for a new game.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> print(repr(antoine)) #doctest: +NORMALIZE_WHITESPACE <PlayerBase: ************************** board ************************** B - G - R - W - Y - *************************** cfg *************************** Deck: normal. Number of clues: 8. Number of misfires: 3. Clues rule: empty clues are forbidden. End rule: normal. ******************* dealing_is_ongoing ******************** False ********************** discard_pile *********************** No card discarded yet ********************** display_width ********************** 63 ************************ draw_pile ************************ 50 cards left ************************ hand_size ************************ 5 ************************** hands ************************** [<Hand: >, <Hand: >] ********************** hands_public *********************** [<HandPublic: >, <HandPublic: >] ************************* n_clues ************************* 8 *********************** n_misfires ************************ 0 ************************ n_players ************************ 2 ************************** name *************************** Antoine ********************** player_names *********************** ['Antoine', 'Donald X'] ********************** recent_events ********************** Configuration ------------- Deck: normal. Number of clues: 8. Number of misfires: 3. Clues rule: empty clues are forbidden. End rule: normal. <BLANKLINE> ********************* remaining_turns ********************* None >
-
receive_lose
(score: int) → None[source]¶ We just log the event for the player.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_lose(score=0) >>> print(antoine.recent_events) Antoine's team loses. Score: 0. <BLANKLINE>
-
receive_partner_draws
(i_active: int, card: hanabython.Modules.Card.Card) → None[source]¶ If there are cards in the draw pile, a card is drawn. There is one card less in
drawpile
, one more in the partner’s hand inhands_public
, and the actual card is added in the partner’s hand inhands
.>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for s in ['B1', 'G3', 'Y1', 'W1', 'R5']: ... antoine.receive_partner_draws(i_active=1, card=Card(s)) >>> print(antoine.draw_pile) 45 cards left >>> print(antoine.hands[1]) R5 W1 Y1 G3 B1 >>> print(antoine.hands_public[1]) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345
If there are no cards in the draw pile, nothing happens.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for _ in range(50): ... antoine.receive_partner_draws(i_active=1, card=Card('B1')) >>> len(antoine.hands[1]) 50 >>> len(antoine.hands_public[1]) 50 >>> print(antoine.draw_pile) No card left >>> antoine.receive_i_draw() >>> len(antoine.hands[1]) 50 >>> len(antoine.hands_public[1]) 50 >>> print(antoine.draw_pile) No card left
-
receive_remaining_turns
(remaining_turns: int) → None[source]¶ We update
remaining_turns
and log the event for the player.>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_remaining_turns(remaining_turns=2) >>> antoine.remaining_turns 2 >>> print(antoine.recent_events) 2 turns remaining! <BLANKLINE>
-
receive_someone_clues
(i_active: int, i_clued: int, clue: hanabython.Modules.Clue.Clue, bool_list: List[bool]) → None[source]¶ We remove a clue chip, and we update the clued player’s hand in
hands_public
.>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for s in ['B1', 'G3', 'Y1', 'W1', 'R5']: ... antoine.receive_partner_draws(i_active=1, card=Card(s)) >>> print(antoine.hands[1]) R5 W1 Y1 G3 B1 >>> antoine.n_clues 8 >>> antoine.receive_someone_clues( ... i_active=0, i_clued=1, clue=Clue(1), ... bool_list=[False, True, True, False, True]) >>> print(antoine.hands_public[1]) #doctest: +NORMALIZE_WHITESPACE BGRWY 2345 , BGRWY 1 , BGRWY 1 , BGRWY 2345 , BGRWY 1 >>> antoine.n_clues 7
-
receive_someone_forfeits
(i_active: int) → None[source]¶ We just log the event for the player.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_someone_forfeits(i_active=1) >>> print(antoine.recent_events) Donald X forfeits. <BLANKLINE>
-
receive_someone_plays_card
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ If the action succeeds, the card goes on the board.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for s in ['B1', 'G3', 'Y1', 'W1', 'R5']: ... antoine.receive_partner_draws(i_active=1, card=Card(s)) >>> print(antoine.hands[1]) R5 W1 Y1 G3 B1 >>> antoine.receive_someone_plays_card(i_active=1, k=1, card=Card('W1')) >>> print(antoine.hands[1]) R5 Y1 G3 B1 >>> print(antoine.hands_public[1]) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345 >>> print(antoine.board) #doctest: +NORMALIZE_WHITESPACE B - G - R - W 1 Y -
If the action fails, the card goes in the discard pile and players get a misfire.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> for s in ['B1', 'G3', 'Y1', 'W1', 'R5']: ... antoine.receive_partner_draws(i_active=1, card=Card(s)) >>> print(antoine.hands[1]) R5 W1 Y1 G3 B1 >>> antoine.receive_someone_plays_card(i_active=1, k=0, card=Card('R5')) >>> print(antoine.hands[1]) W1 Y1 G3 B1 >>> print(antoine.hands_public[1]) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345 >>> print(antoine.board) #doctest: +NORMALIZE_WHITESPACE B - G - R - W - Y - >>> print(antoine.discard_pile) R5 >>> antoine.n_misfires 1
-
receive_someone_throws
(i_active: int, k: int, card: hanabython.Modules.Card.Card) → None[source]¶ The card goes in the discard pile, and players regain a clue chip.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.n_clues = 3 >>> for s in ['B1', 'G3', 'Y1', 'W1', 'R5']: ... antoine.receive_partner_draws(i_active=1, card=Card(s)) >>> print(antoine.hands[1]) R5 W1 Y1 G3 B1 >>> antoine.receive_someone_throws(i_active=1, k=4, card=Card('B1')) >>> print(antoine.hands[1]) R5 W1 Y1 G3 >>> print(antoine.hands_public[1]) BGRWY 12345, BGRWY 12345, BGRWY 12345, BGRWY 12345 >>> print(antoine.discard_pile) B1 >>> antoine.n_clues 4
-
receive_win
(score: int) → None[source]¶ We just log the event for the player.
>>> antoine = PlayerBase('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_win(score=25) >>> print(antoine.recent_events) Antoine's team wins! Score: 25. <BLANKLINE>
-
class
hanabython.
PlayerHumanText
(name: str, ipython=False)[source]¶ User interface for a human player in text mode (terminal or notebook).
Parameters: ipython – use True when using the player in a notebook. This fixes a problem between clear_output
andinput
.>>> antoine = PlayerHumanText('Antoine', ipython=True)
-
choose_action
() → hanabython.Modules.Action.Action[source]¶ The human player gets to choose an action.
-
receive_action_illegal
(s: str) → None[source]¶ Receive a message: the action chosen is illegal.
Parameters: s – a message explaining why the action is illegal.
-
receive_action_legal
() → None[source]¶ We forget the previous events.
>>> from hanabython import Configuration >>> antoine = PlayerHumanText('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.log('Donald does something.') >>> antoine.recent_events 'Donald does something.' >>> # Here, Antoine would choose his own action. Then... >>> antoine.receive_action_legal() >>> antoine.log("Antoine's action has such and such consequences.") >>> antoine.recent_events "Antoine's action has such and such consequences."
-
receive_game_exhausted
(score: int) → None[source]¶ We print and forget the recent events.
>>> from hanabython import Configuration >>> antoine = PlayerHumanText('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_game_exhausted(score=23) Antoine's team has reached the end of the game. Score: 23. <BLANKLINE> >>> antoine.recent_events ''
-
receive_lose
(score: int) → None[source]¶ We print and forget the recent (unfortunate) events.
>>> from hanabython import Configuration >>> antoine = PlayerHumanText('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_lose(score=0) Antoine's team loses. Score: 0. <BLANKLINE> >>> antoine.recent_events ''
-
receive_turn_finished
() → None[source]¶ We inform the player of the most recent events, i.e. the consequences of her actions. Then we pause (unless this string was empty). Finally, we forget these recent events.
-
receive_win
(score: int) → None[source]¶ We print and forget the recent (cheerful) events.
>>> from hanabython import Configuration >>> antoine = PlayerHumanText('Antoine') >>> antoine.receive_init(Configuration.STANDARD, ... player_names=['Antoine', 'Donald X']) >>> antoine.log_forget() >>> antoine.receive_win(score=25) Antoine's team wins! Score: 25. <BLANKLINE> >>> antoine.recent_events ''
-
Game¶
-
class
hanabython.
Game
(players: List[hanabython.Modules.Player.Player], cfg: hanabython.Modules.Configuration.Configuration = <Configuration: standard>)[source]¶ A game of Hanabi.
Parameters: - cfg – the configuration.
- players – the list of players. They will play in this order, starting with the first player in this list.
Variables: - n_players (int) – the number of players.
- board (Board) – the board.
- draw_pile (DrawPile) – the draw pile.
- discard_pile (DiscardPile) – the discard pile.
- n_clues (int) – the number of clue chips that players currently have.
- n_misfires (int) – the number of misfires chips that players currently have.
- hand_size (int) – the initial size of the hands.
- hands (list) – a list of
Hand
objects (in the same order asplayers
). - remaining_turns (int) – the number of remaining turns (once the draw pile is empty, in the normal rule for end of game). As long as the draw pile contains cards, this variable is None.
- b_lose (bool) – the game is lost.
- b_win (bool) – the game is won.
- i_active (int) – the index of the active player.
- active (Player) – the active player. It is automatically updated when
i_active
is updated.
>>> game = Game(players=[PlayerHumanText('Antoine'), ... PlayerHumanText('Donald X')])
-
ATTEMPTS_BEFORE_FORFEIT
= 100¶ Number of attempts that a player has to choose her action. If she provides illegal actions as many times, she is automatically considered to forfeit (and this issues a warning).
-
check_game_exhausted
() → bool[source]¶ Check if the game is exhausted.
Typically, the game end by exhaustion a bit after the deck ran out of cards (the exact moment depends on the end-of-game rule that is used).
This method is called at the beginning of each player’s turn.
We do not check here whether the current score is equal to the maximum score still possible (considering what is discarded), which would also end the game. This verification is done in
play()
.Returns: True iff the game must end. If the normal end-of-game rule is used, and
remaining_turns
is an integer: it is updated, then the end-of-game condition is checked.>>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.players[1].speak = True >>> game.remaining_turns = 1 >>> # Here, previous player would play her turn.. Then... >>> game.check_game_exhausted() Donald X: The number of remaining turns is now known. Donald X: remaining_turns = 0 True >>> print(game.remaining_turns) 0
If the normal end-of-game rule is used, and
remaining_turns
is None: it is not updated (the final countdown has not started).>>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.players[1].speak = True >>> game.check_game_exhausted() False >>> print(game.remaining_turns) None
If “Crowning piece” rule is used: if the active player has no card in hand, the game is over.
>>> game = Game( ... players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')], ... cfg=Configuration(end_rule=ConfigurationEndRule.CROWNING_PIECE) ... ) >>> game.players[1].speak = True >>> game.i_active = 1 >>> game.check_game_exhausted() True >>> game.hands[1].receive(Card('B1')) >>> game.check_game_exhausted() False
-
colored
() → str[source]¶ Colored version of
__str__()
.In the subclasses, the principle is to override only this method.
__str__()
is automatically defined as the uncolored version of the same string, and__repr__()
as the same with the class name added.Of course, it is also possible to override
__str__()
and/or__repr__()
if a different behavior is desired.Returns: a string representing the object, possibly with ANSI escape codes to add colors and style. Return type: str
-
deal
() → None[source]¶ Deal the initial hands.
i_active
should be -1 before dealing and will be -1 at the end (modulo the number of players).>>> game = Game(players=[PlayerHumanText('Antoine'), ... PlayerHumanText('Donald X'), ... PlayerHumanText('Uwe')]) >>> game.i_active = -1 >>> game.deal() >>> [len(hand) for hand in game.hands] [5, 5, 5] >>> game.i_active 2
-
draw
() → None[source]¶ The active player draws a card.
- Draw a card and put it in hand (unless the discard pile is empty).
- If the discard pile becomes empty, launch countdown for end of game
by setting variable
remaining_turns
to valuen_players
+ 1. It will be decremented at the beginning of next player’s turn (before testing the end-of-game condition). Cf.check_game_exhausted()
.
>>> game = Game(players=[PlayerHumanText('Antoine'), ... PlayerHumanText('Donald X'), ... PlayerHumanText('Uwe')]) >>> game.i_active = -1 >>> for _ in range(50): ... game.i_active += 1 ... game.draw() >>> [len(hand) for hand in game.hands] [17, 17, 16] >>> game.i_active += 1 >>> print(game.draw()) None >>> game.remaining_turns 4
-
execute_action
(action: hanabython.Modules.Action.Action) → bool[source]¶ Execute the action (by the active player).
Parameters: action – the action. Returns: True iff the action is legal. If not, it will be necessary to choose another action. This method dispatches to the auxiliary methods
execute_clue()
,execute_forfeit()
,execute_play_card()
andexecute_throw()
. Each of these methods has the responsability to:- Check if the action is legal,
- Inform the active player whether it is the case or not,
- Perform the action,
- Update the relevant variables, in particular
b_lose
andb_win
. - Inform all players of the result of the action,
- Make the active player draw a new card if necessary,
- Return the boolean stating whether the action is legal.
-
execute_clue
(i_clued: int, clue: hanabython.Modules.Clue.Clue) → bool[source]¶ Execute the action: give a clue.
Parameters: - i_clued – the index of the player who receives the clue.
- clue – the clue.
Returns: True iff the action is legal.
>>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')], ... cfg=Configuration.W_MULTICOLOR) >>> game.i_active = -1 >>> game.deal() >>> print(game.hands[2]) G2 W1 W1 B1 Y4 >>> game.players[1].speak = True >>> game.i_active = 1 >>> game.n_clues = 0 >>> game.execute_clue(2, Clue(1)) Donald X: The action chosen is illegal. Donald X: You cannot give a clue because you have do not have any clue chip. False >>> game.n_clues = 3 >>> game.execute_clue(1, Clue(1)) Donald X: The action chosen is illegal. Donald X: You cannot give a clue to yourself. False >>> game.execute_clue(2, Clue(6)) Donald X: The action chosen is illegal. Donald X: This value does not exist: 6. False >>> game.execute_clue(2, Clue(Colors.COLORLESS)) Donald X: The action chosen is illegal. Donald X: This color is not in the deck: C. False >>> game.execute_clue(2, Clue(Colors.MULTICOLOR)) Donald X: The action chosen is illegal. Donald X: You cannot clue this color: M. False >>> game.execute_clue(2, Clue(3)) Donald X: The action chosen is illegal. Donald X: You cannot give this clue because it does not correspond to any card. False >>> game.execute_clue(2, Clue(1)) Donald X: The action chosen is legal. Donald X: A player gives a clue to another one. Donald X: i_active = 0 Donald X: i_clued = 1 Donald X: clue = 1 Donald X: bool_list = [False, True, True, True, False] True >>> game.n_clues 2
-
execute_forfeit
() → bool[source]¶ Execute the action: forfeit.
Returns: True (meaning that this action is always legal). >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.players[1].speak = True >>> game.i_active = 1 >>> is_legal = game.execute_forfeit() Donald X: The action chosen is legal. Donald X: A player forfeits. Donald X: i_active = 0 >>> is_legal True >>> game.b_lose True >>> game.i_active = 2 >>> is_legal = game.execute_forfeit() Donald X: A player forfeits. Donald X: i_active = 1 >>> is_legal True >>> game.b_lose True
-
execute_play_card
(k: int) → bool[source]¶ Execute the action: try to play a card.
Parameters: k – the index of the card in the active player’s hand. Returns: True (meaning that this action is always legal). The action can fail, in the sense that it leads to a misfire, but it is legal anyway. If it leads to the last misfire, then the players lose:
>>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.i_active = -1 >>> game.deal() >>> game.i_active = 2 >>> game.n_misfires = 2 >>> print(game.hands[2]) B4 W4 G5 W1 R3 >>> game.players[1].speak = True >>> is_legal = game.execute_play_card(2) Donald X: A player tries to play a card on the board. Donald X: i_active = 1 Donald X: k = 2 Donald X: card = G5 >>> is_legal True >>> print(game.board) #doctest: +NORMALIZE_WHITESPACE B - G - R - W - Y - >>> print(game.discard_pile) G5 >>> game.n_misfires 3 >>> game.b_lose True
If the highest card in a color is played, then the players gain a clue:
>>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.i_active = -1 >>> game.deal() >>> for s in ['G1', 'G2', 'G3', 'G4']: ... _ = game.board.try_to_play(card=Card(s)) >>> game.n_clues = 3 >>> game.i_active = 2 >>> print(game.hands[2]) B4 W4 G5 W1 R3 >>> game.players[1].speak = True >>> is_legal = game.execute_play_card(2) Donald X: A player tries to play a card on the board. Donald X: i_active = 1 Donald X: k = 2 Donald X: card = G5 Donald X: Another player tries to draw a card. Donald X: i_active = 1 Donald X: card = G4 >>> is_legal True >>> print(game.board) #doctest: +NORMALIZE_WHITESPACE B - G 1 2 3 4 5 R - W - Y - >>> game.n_clues 4
But players cannot gain a clue if they already have the maximum number of clues:
>>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.i_active = -1 >>> game.deal() >>> for s in ['G1', 'G2', 'G3', 'G4']: ... _ = game.board.try_to_play(card=Card(s)) >>> game.n_clues 8 >>> game.i_active = 2 >>> print(game.hands[2]) B4 W4 G5 W1 R3 >>> game.players[1].speak = True >>> is_legal = game.execute_play_card(2) Donald X: A player tries to play a card on the board. Donald X: i_active = 1 Donald X: k = 2 Donald X: card = G5 Donald X: Another player tries to draw a card. Donald X: i_active = 1 Donald X: card = G4 >>> is_legal True >>> print(game.board) #doctest: +NORMALIZE_WHITESPACE B - G 1 2 3 4 5 R - W - Y - >>> game.n_clues 8
If the card completes the board, then the players win the game.
>>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.i_active = -1 >>> game.deal() >>> for c in ['B', 'R', 'W', 'Y']: ... for v in range(1, 6): ... _ = game.board.try_to_play(card=Card(c + str(v))) >>> for s in ['G1', 'G2', 'G3', 'G4']: ... _ = game.board.try_to_play(card=Card(s)) >>> game.i_active = 2 >>> print(game.hands[2]) B4 W4 G5 W1 R3 >>> game.players[1].speak = True >>> _ = game.execute_play_card(2) Donald X: A player tries to play a card on the board. Donald X: i_active = 1 Donald X: k = 2 Donald X: card = G5 >>> print(game.board) #doctest: +NORMALIZE_WHITESPACE B 1 2 3 4 5 G 1 2 3 4 5 R 1 2 3 4 5 W 1 2 3 4 5 Y 1 2 3 4 5 >>> game.b_win True
-
execute_throw
(k: int) → bool[source]¶ Execute the action: throw (= discard willingly).
Parameters: k – the index of the card in the active player’s hand. Returns: True iff the action is legal, i.e. except if players have all the clue chips. >>> import random >>> random.seed(0) >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.players[1].speak = True >>> game.i_active = 1 >>> game.draw() Donald X: This player tries to draw a card. >>> is_legal = game.execute_throw(0) Donald X: The action chosen is illegal. Donald X: You cannot discard because you have all the clue chips. >>> is_legal False >>> game.n_clues = 3 >>> game.i_active = 2 >>> game.draw() Donald X: Another player tries to draw a card. Donald X: i_active = 1 Donald X: card = Y4 >>> is_legal = game.execute_throw(0) Donald X: A player throws (discards a card willingly). Donald X: i_active = 1 Donald X: k = 0 Donald X: card = Y4 Donald X: Another player tries to draw a card. Donald X: i_active = 1 Donald X: card = R3 >>> is_legal True >>> game.n_clues 4 >>> print(game.discard_pile) Y4 >>> print(game.hands[2]) R3
-
game_exhausted
() → int[source]¶ The game is exhausted.
Inform the players. The game is over and is neither really lost (misfires, forfeit) nor a total victory (maximal score). Typically, this happens a bit after the deck ran out of cards (it depends on the end-of-game rule that is used).
Returns: the final score. >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> _ = game.board.try_to_play(Card('B1')) >>> game.players[1].speak = True >>> score = game.game_exhausted() Donald X: The game is exhausted. Donald X: score = 1 >>> score 1
-
i_active
¶ Index of the active player.
Returns: this index is automatically set modulo the number of players. >>> game = Game(players=[PlayerHumanText('Antoine'), ... PlayerHumanText('Donald X'), ... PlayerHumanText('Uwe')]) >>> game.i_active = 2 >>> game.i_active += 1 >>> print(game.i_active) 0
-
lose
() → int[source]¶ Lose the game (forfeit or too many misfires).
Inform the players.
Returns: the final score, i.e. 0. >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> game.players[1].speak = True >>> score = game.lose() Donald X: The game is lost. Donald X: score = 0 >>> score 0
-
play
() → int[source]¶ Main method: play the game.
Note: it is only possible to “play” once with a
Game
object. If you want to launch a game with the same player, it is necessary to define a newGame
.Returns: the final score of the game.
-
rel
(who: int, fro: int) → int[source]¶ Relative position of a player from the point of view of another one.
Parameters: - who – the player we talk about.
- fro – the player to whom we talk.
Returns: the relative position of
who
from the point of view offro
, i.e.who
-fro
(modulon_players
).>>> game = Game(players=[PlayerHumanText('Antoine'), ... PlayerHumanText('Donald X'), ... PlayerHumanText('Uwe')]) >>> game.rel(who=1, fro=2) 2
-
win
() → int[source]¶ Win the game (maximum score).
Inform the players.
Returns: the final score. >>> game = Game(players=[PlayerPuppet('Antoine'), ... PlayerPuppet('Donald X'), ... PlayerPuppet('Uwe')]) >>> for c in ['B', 'G', 'R', 'W', 'Y']: ... for v in range(1, 6): ... _ = game.board.try_to_play(card=Card(c + str(v))) >>> game.players[1].speak = True >>> score = game.win() Donald X: The game is won. Donald X: score = 25 >>> score 25