haha - this is a lot of fun! I was trying to think of an example for pattern matching callback for the Dash Example Index and this topic inspired me.
By using pattern matching callbacks, you can avoid having 52 inputs in the callback.
I’ll probably turn this into some type of simple game for the Example Index, but in the meantime, here’s my version:
import random
from dash import Dash, html, Input, Output, ALL, ctx
import dash_bootstrap_components as dbc
from dash_iconify import DashIconify
app = Dash(__name__, external_stylesheets=[dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP])
SUITS = ["spades", "clubs", "diamonds", "hearts"]
RANKS = ["ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king"]
def create_deck(shuffle=False):
"""Create a deck of 52 cards"""
deck = [(s, r) for s in SUITS for r in RANKS]
if shuffle:
random.shuffle(deck)
return deck
def make_card(card):
"""format the card as a button"""
suit, rank = card
color = "black" if suit in ["spades", "clubs"] else "red"
card_icon = DashIconify(
icon=f"game-icons:card-{rank}-{suit}", color=color, height=60
)
return dbc.Button(
[card_icon], color="white", className="p-0", id={"index": f"{suit}-{rank}"}
)
def deck_layout(deck):
"""make card layout"""
return [dbc.Row(dbc.Col([make_card(c) for c in deck if s in c])) for s in SUITS]
deck = create_deck()
app.layout = dbc.Container(
[
html.H1("Select a Card"),
html.Div(deck_layout(deck)),
html.H2("You Selected:"),
html.Div(id="card-selected"),
]
)
@app.callback(
Output("card-selected", "children"),
Input({"index": ALL}, "n_clicks"),
prevent_initial_call=True,
)
def selected(_):
selected_card = ctx.triggered_id.index
suit, _, rank = selected_card.partition("-")
color = "black" if suit in ["spades", "clubs"] else "red"
return DashIconify(icon=f"game-icons:card-{rank}-{suit}", color=color, height=60)
if __name__ == "__main__":
app.run_server(debug=True)