from itepifanio_deck.utils import Hand
from itepifanio_deck.core import FrenchDeck
import ipywidgets as widgets
from fastcore.basics import patchUI
This nb designs a UI for the blackjack game
You may need to execute jupyter nbextension enable --py widgetsnbextension and restart the nb to output the widgets.
# !jupyter nbextension enable --py widgetsnbextensionDeck and cards UI
The card and deck are represented as buttons in the UI
def card_button_factory(name: str):
return widgets.Button(
disable=True,
description=name,
layout=widgets.Layout(height="auto", width="auto"),
)card_button = card_button_factory("test")
card_buttonSince the deck is a single button we can define them in a Layout
class GameLayout(widgets.TwoByTwoLayout):
def __init__(self, *args, **kwargs):
self.deck_button = widgets.Button(
description="Deck (52)",
tooltip="click me to draw a card!",
layout=widgets.Layout(height="100%", width="auto"),
)
self.reset_button = widgets.Button(
description="Reset",
layout=widgets.Layout(height="auto", width="auto")
)
self.displayer = widgets.Text(
value="Pull a card",
disabled=True,
layout=widgets.Layout(width="50%")
)
super().__init__(
top_left=self.deck_button,
top_right=widgets.HBox([self.reset_button, self.displayer]),
bottom_right=widgets.HBox([]),
justify_items="center",
width="50%",
align_items="center",
)GameLayout()@patch
def on_deck_click(self: GameLayout, callback):
self.top_left.on_click(callback)@patch
def on_reset_click(self: GameLayout, callback):
reset_button = self.top_right.children[0]
reset_button.on_click(callback)@patch
def update_num_cards(self: GameLayout, number: int):
self.top_left.description = f"Deck ({number})"@patch
def clear_hand(self: GameLayout):
self.bottom_right = widgets.HBox([])@patch
def update_hand(self: GameLayout, hand: Hand):
suits = {
'diamonds': '♢',
'hearts': '♡',
'spades': '♤',
'clubs': '♧'
}
self.bottom_right = widgets.HBox(
[card_button_factory(f'{card.rank} {suits[card.suit]}')
for card in hand]
)
self.update_num_cards(52 - len(hand))
value = hand.value() # type: ignore
if value > 21:
self.displayer.value = f"Game over ({value})"
elif value == 21:
self.displayer.value = "You won!"
else:
self.displayer.value = str(value)class BlackJack:
def __init__(self):
self.view = GameLayout()
self.view.on_deck_click(self.on_deck_clicked)
self.view.on_reset_click(self.on_reset_clicked)
self._start()
def _start(self):
self.deck = FrenchDeck()
self.deck.shuffle()
self.hand = Hand()
def on_deck_clicked(self, event):
card = self.deck.draw()
self.hand.draw(card)
self.view.update_hand(self.hand)
def on_reset_clicked(self, event):
self._start()
self.view.update_hand(self.hand)
def __repr__(self):
display(self.view)
return ""blackjack = BlackJack()
blackjack