Add Blackjack game: rules, card rendering, game loop and tests
Implement the playable console game for gateway MIL-002. - rules.py: deal_card, calculate_score (blackjack = 0, aces drop 11 -> 1) and compare with an Outcome enum; no console I/O - display.py: hand rendering as plain-text rank plus suit emoji (keycap emoji rendered as boxes in common terminals), score formatting and outcome messages - art.py: course logo shown at the start of every game - game.py: play_game (hit/stand, dealer draws below 17), play (restart loop, console clear, logo) and ask_yes_no with re-prompt; read, write and draw are injected so games can be scripted - __main__.py: python -m blackjack entry point, exits cleanly on Ctrl+C/Ctrl+D - constants.py: card ranks and suits, prompts and messages - tests: 32 new unit and scripted end-to-end tests (35 in total) - README: run instructions for python -m blackjack Closes #7 Closes #8 Closes #9 Closes #10 Closes #11 Closes #12 Closes #13 Closes #14 Task: MIL-002#1 Task: MIL-002#2 Task: MIL-002#3 Task: MIL-002#4 Task: MIL-002#5 Task: MIL-002#6 Task: MIL-002#7 Task: MIL-002#8
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""!
|
||||
@file display.py
|
||||
@brief Turns cards, scores and outcomes into text for the console.
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from blackjack.constants import (
|
||||
BLACKJACK_MARKER,
|
||||
CARD_RANKS,
|
||||
CARD_SUITS,
|
||||
LABEL_BLACKJACK,
|
||||
MESSAGE_DRAW,
|
||||
MESSAGE_LOSE,
|
||||
MESSAGE_LOSE_BUST,
|
||||
MESSAGE_LOSE_DEALER_BLACKJACK,
|
||||
MESSAGE_WIN,
|
||||
MESSAGE_WIN_BLACKJACK,
|
||||
MESSAGE_WIN_DEALER_BUST,
|
||||
)
|
||||
from blackjack.rules import Outcome
|
||||
|
||||
_OUTCOME_MESSAGES: dict[Outcome, str] = {
|
||||
Outcome.DRAW: MESSAGE_DRAW,
|
||||
Outcome.WIN: MESSAGE_WIN,
|
||||
Outcome.WIN_BLACKJACK: MESSAGE_WIN_BLACKJACK,
|
||||
Outcome.WIN_DEALER_BUST: MESSAGE_WIN_DEALER_BUST,
|
||||
Outcome.LOSE: MESSAGE_LOSE,
|
||||
Outcome.LOSE_DEALER_BLACKJACK: MESSAGE_LOSE_DEALER_BLACKJACK,
|
||||
Outcome.LOSE_BUST: MESSAGE_LOSE_BUST,
|
||||
}
|
||||
|
||||
|
||||
def render_hand(cards: Sequence[int]) -> str:
|
||||
"""!
|
||||
@brief Show a hand as emoji cards.
|
||||
@param cards The card values in the hand.
|
||||
@return The emoji faces separated by spaces.
|
||||
"""
|
||||
return " ".join(
|
||||
f"{CARD_RANKS[card]}{CARD_SUITS[index % len(CARD_SUITS)]}"
|
||||
for index, card in enumerate(cards)
|
||||
)
|
||||
|
||||
|
||||
def format_score(score: int) -> str:
|
||||
"""!
|
||||
@brief Show a score for the player.
|
||||
@param score A score from calculate_score (0 means blackjack).
|
||||
@return The number, or the blackjack label.
|
||||
"""
|
||||
return LABEL_BLACKJACK if score == BLACKJACK_MARKER else str(score)
|
||||
|
||||
|
||||
def outcome_message(outcome: Outcome) -> str:
|
||||
"""!
|
||||
@brief Message announcing how the game ended.
|
||||
@param outcome The outcome seen from the player.
|
||||
@return The text to show.
|
||||
"""
|
||||
return _OUTCOME_MESSAGES[outcome]
|
||||
Reference in New Issue
Block a user