Example
The following is a simple example of how to use the library to simulate a round of whist with some very basic bots (the source code for example_strategy.py and printing_event_listener.py is also included further below).
print_one_round.py
1"""Use the `whist_backend` module to make 5 simple bots play a round of whist."""
2
3from __future__ import annotations
4
5from typing import TYPE_CHECKING
6
7from example_strategy import NoThinkingStrategy
8from printing_event_listener import PrinterEventListener
9
10from whist_backend import RoundSimulator
11
12if TYPE_CHECKING:
13 from whist_backend.player_strategy_protocol import PlayerStrategy
14
15if __name__ == "__main__":
16 strategies: list[PlayerStrategy] = [
17 NoThinkingStrategy("Player 1"),
18 NoThinkingStrategy("Player 2"),
19 NoThinkingStrategy("Player 3"),
20 NoThinkingStrategy("Player 4"),
21 NoThinkingStrategy("Player 5"),
22 ]
23 round_simulator = RoundSimulator(
24 strategies, event_listeners=[PrinterEventListener()]
25 )
26 results = round_simulator.play_round()
27 for result in results:
28 print(f"{result[0].name} won {result[1]} points.")
Sample output for this script would look something like:
Sample output
REVEALED CARD: 4♥ (trump suit ♥, hand size 6)
PLAYERS:
Player 1: hand 8♠, 3♥,10♣, 7♣, K♣, 5♠
Player 2: hand Q♣, 5♥, 9♦, 9♥, J♦, 5♦
Player 3: hand K♠, A♣, K♦, 6♥, 2♥, 8♦
Player 4: hand Q♠, A♦, 4♦, Q♦, 2♣,10♥
Player 5: hand 6♦, 5♣, 7♥, 6♣,10♠, 3♠
BETS:
Player 1: 0
Player 2: 0
Player 3: 0
Player 4: 0
Player 5: 7
A new trick is starting with 0
Player 1 played 8♠ (remaining cards 3♥,10♣, 7♣, K♣, 5♠).
Player 2 played Q♣ (remaining cards 5♥, 9♦, 9♥, J♦, 5♦).
Player 3 played K♠ (remaining cards A♣, K♦, 6♥, 2♥, 8♦).
Player 4 played Q♠ (remaining cards A♦, 4♦, Q♦, 2♣,10♥).
Player 5 played 10♠ (remaining cards 6♦, 5♣, 7♥, 6♣, 3♠).
Player 3 won the trick!
A new trick is starting with 2
Player 3 played A♣ (remaining cards K♦, 6♥, 2♥, 8♦).
Player 4 played 2♣ (remaining cards A♦, 4♦, Q♦,10♥).
Player 5 played 5♣ (remaining cards 6♦, 7♥, 6♣, 3♠).
Player 1 played 10♣ (remaining cards 3♥, 7♣, K♣, 5♠).
Player 2 played 5♥ (remaining cards 9♦, 9♥, J♦, 5♦).
Player 2 won the trick!
A new trick is starting with 1
Player 2 played 9♦ (remaining cards 9♥, J♦, 5♦).
Player 3 played K♦ (remaining cards 6♥, 2♥, 8♦).
Player 4 played A♦ (remaining cards 4♦, Q♦,10♥).
Player 5 played 6♦ (remaining cards 7♥, 6♣, 3♠).
Player 1 played 3♥ (remaining cards 7♣, K♣, 5♠).
Player 1 won the trick!
A new trick is starting with 0
Player 1 played 7♣ (remaining cards K♣, 5♠).
Player 2 played 9♥ (remaining cards J♦, 5♦).
Player 3 played 6♥ (remaining cards 2♥, 8♦).
Player 4 played 4♦ (remaining cards Q♦,10♥).
Player 5 played 6♣ (remaining cards 7♥, 3♠).
Player 2 won the trick!
A new trick is starting with 1
Player 2 played J♦ (remaining cards 5♦).
Player 3 played 8♦ (remaining cards 2♥).
Player 4 played Q♦ (remaining cards 10♥).
Player 5 played 7♥ (remaining cards 3♠).
Player 1 played K♣ (remaining cards 5♠).
Player 5 won the trick!
A new trick is starting with 4
Player 5 played 3♠ (remaining cards ).
Player 1 played 5♠ (remaining cards ).
Player 2 played 5♦ (remaining cards ).
Player 3 played 2♥ (remaining cards ).
Player 4 played 10♥ (remaining cards ).
Player 4 won the trick!
Player 1 won -1 points.
Player 2 won -2 points.
Player 3 won -1 points.
Player 4 won -1 points.
Player 5 won -6 points.
example_strategy.py
1from __future__ import annotations
2
3from typing import TYPE_CHECKING, Optional
4
5from whist_backend import Bet, PlayerStrategy
6
7if TYPE_CHECKING:
8 from whist_backend.cards import Card
9
10
11class NoThinkingStrategy(PlayerStrategy):
12 def __init__(self, name: str) -> None:
13 self.name = name
14
15 def make_move(self, allowed_cards: list[Card]) -> Card:
16 return allowed_cards[0]
17
18 def make_bet(self, disallowed_bet: Optional[int] = None) -> Bet:
19 return Bet(disallowed_bet + 1 if disallowed_bet is not None else 0, False)
printing_event_listener.py
1from __future__ import annotations
2
3from typing import TYPE_CHECKING, Iterator
4
5from whist_backend import WhistEventListener
6
7if TYPE_CHECKING:
8 from whist_backend import Bet, Card, Suit
9 from whist_backend.round_simulator import _Player
10
11
12class PrinterEventListener(WhistEventListener):
13 """A simple example WhistEventListener that prints information about game events."""
14
15 def notify_round_start(
16 self,
17 revealed_card: Card,
18 trump_suit: Suit,
19 hand_size: int,
20 players: list[_Player],
21 ) -> None:
22 print(
23 f"REVEALED CARD: {revealed_card} "
24 + f"(trump suit {trump_suit}, hand size {hand_size})"
25 )
26 print("PLAYERS:")
27 for player in players:
28 print(player)
29 print()
30
31 def notify_card_played(self, player: _Player, played_card: Card) -> None:
32 print(
33 f"{player.strategy.name} played {played_card} "
34 f"(remaining cards {','.join(map(str, player.hand))})."
35 )
36
37 def notify_trick_won(self, player: _Player) -> None:
38 print(f"{player.strategy.name} won the trick!")
39 print()
40
41 def notify_bets_made(self, bets: Iterator[tuple[_Player, Bet]]) -> None:
42 print("BETS:")
43 for player, bet in bets:
44 print(f"{player.strategy.name}: {bet}")
45 print()
46
47 def notify_new_trick(self, player_id: int) -> None:
48 print(f"A new trick is starting with {player_id}")