Each game in Python Arcade Suite implements distinct algorithms and game mechanics. This guide examines the core logic, explaining how game rules are translated into Python code.
def deck_of_cards(): DoC = [] numbers = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"] suits = ["♣", "♠", "♥", "♦"] for suit in suits: for number in numbers: card = f"{number}{suit}" DoC.append(card) return DoC
Algorithm:
Define 13 ranks (A through K)
Define 4 suits (clubs, spades, hearts, diamonds)
Create cartesian product: 13 × 4 = 52 cards
Each card is a string combining rank and suit (e.g., “A♠”, “10♥”)
Design Decision:
Cards are represented as strings rather than objects. This simplifies serialization for session state and makes debugging easier (you can print a hand directly).
The deck is generated fresh for each new game, ensuring a full 52-card deck with no duplicates.
The most complex logic in Blackjack is calculating hand value with flexible Ace handling:
def hand_value(hand): value = sum(card_value(card) for card in hand) num_aces = sum(1 for card in hand if card[0] == 'A') while value > 21 and num_aces: value -= 10 num_aces -= 1 return value
Algorithm Breakdown:
Step 1: Calculate Total
Step 2: Count Aces
Step 3: Adjust for Bust
value = sum(card_value(card) for card in hand)
Calculate the sum treating all Aces as 11. For example:
Hand: [“A♠”, “A♥”, “9♣”]
Initial value: 11 + 11 + 9 = 31
num_aces = sum(1 for card in hand if card[0] == 'A')
Count how many Aces are in the hand:
Hand: [“A♠”, “A♥”, “9♣”]
num_aces: 2
while value > 21 and num_aces: value -= 10 num_aces -= 1
If over 21 and Aces remain, convert Aces from 11 to 1 (by subtracting 10):
Iteration 1: value = 31 - 10 = 21, num_aces = 1
Loop exits (21 is not > 21)
Final value: 21
Why This Works:
Aces start as 11 (soft)
If bust, convert to 1 (hard) by subtracting 10
Process one Ace at a time until under 22 or no more Aces
def read_words_from_file(filepath): try: with open(filepath, 'r', encoding='utf-8') as file: words = [line.strip().upper() for line in file if line.strip()] return words except FileNotFoundError: return ["PYTHON", "STREAMLIT", "DEVELOPER", "AHORCADO"]
Error Handling Strategy:
Primary: Load from external file
Fallback: Use hardcoded list if file not found
Normalization: Convert all words to uppercase for consistent comparison
List Comprehension Breakdown:
[line.strip().upper() for line in file if line.strip()]# │ │ │ │# │ │ │ └─ Filter: only non-empty lines# │ │ └─ Iterate through file lines# │ └─ Convert to uppercase# └─ Remove whitespace
display_word = []won = Truefor char in st.session_state.hangman_word: if char in st.session_state.hangman_guessed: display_word.append(char) else: display_word.append("_") won = Falsest.markdown(f"## {' '.join(display_word)}")
Algorithm:
Iterate through each character in the secret word
If letter has been guessed, display it
If not guessed, show underscore
If any letter is not guessed, won = False
Join with spaces for readable display
Example:
word = "PYTHON"guessed = {'P', 'O', 'N', 'X', 'Z'}# Result: "P _ _ O N" (won = False)
if cols[i % 7].button(letter, key=f"btn_{letter}"): st.session_state.hangman_guessed.add(letter) if letter not in st.session_state.hangman_word: st.session_state.hangman_attempts -= 1 st.rerun()
Logic:
User clicks a letter button
Add letter to guessed set
Check if letter exists in word
If not, decrement attempts (wrong guess)
Re-run to update display
Important: Correct guesses don’t reduce attempts, only wrong ones.
if won and not st.session_state.hangman_game_over: st.session_state.hangman_result = "¡Felicidades! Ganaste." st.session_state.hangman_game_over = Trueif st.session_state.hangman_attempts <= 0 and not st.session_state.hangman_game_over: st.session_state.hangman_result = f"Perdiste. La palabra era: {st.session_state.hangman_word}" st.session_state.hangman_game_over = True
Two Win Conditions:
Win: All letters guessed (won = True)
Loss: Zero attempts remaining
Guard Condition: not st.session_state.hangman_game_over prevents these from running multiple times.
alphabet = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"cols = st.columns(7)for i, letter in enumerate(alphabet): if letter not in st.session_state.hangman_guessed: if cols[i % 7].button(letter, key=f"btn_{letter}"): st.session_state.hangman_guessed.add(letter) if letter not in st.session_state.hangman_word: st.session_state.hangman_attempts -= 1 st.rerun() else: cols[i % 7].button(" ", disabled=True, key=f"btn_{letter}_dis")
Grid Layout:
Create 7 columns
Use modulo operator (i % 7) to wrap letters across columns
27 letters ÷ 7 columns = ~4 rows
Dynamic Buttons:
Not guessed: Active button with letter label
Guessed: Disabled button with blank label
Each button needs a unique key to avoid Streamlit key conflicts
The Spanish alphabet includes “Ñ”, which is why there are 27 letters instead of 26.
def get_winner(user, computer): if user == computer: return "Empate" elif (user == "Piedra" and computer == "Tijera") or \ (user == "Papel" and computer == "Piedra") or \ (user == "Tijera" and computer == "Papel"): return "Usuario" else: return "Computadora"
Logic Table:
User
Computer
Winner
Piedra
Tijera
Usuario (rock crushes scissors)
Papel
Piedra
Usuario (paper covers rock)
Tijera
Papel
Usuario (scissors cut paper)
Same
Same
Empate (tie)
Other
Other
Computadora (all other combos)
Algorithm:
Check for tie first (simplest case)
Check all three winning conditions for user
Everything else is a computer win
Approach 1: Explicit Conditions
Approach 2: Dictionary Lookup
Approach 3: Modular Arithmetic
The current implementation explicitly lists winning conditions:
if user == computer: return "Empate"elif (user == "Piedra" and computer == "Tijera") or \ (user == "Papel" and computer == "Piedra") or \ (user == "Tijera" and computer == "Papel"): return "Usuario"else: return "Computadora"
Pros: Clear, readable, easy to understand
Cons: Verbose, not easily extensible
An alternative using a rules dictionary:
def get_winner(user, computer): if user == computer: return "Empate" wins = { "Piedra": "Tijera", "Papel": "Piedra", "Tijera": "Papel" } return "Usuario" if wins[user] == computer else "Computadora"
Pros: More concise, easier to extend with new options
Cons: Less immediately obvious what beats what
Using numeric values and modulo:
def get_winner(user, computer): choices = {"Piedra": 0, "Papel": 1, "Tijera": 2} u, c = choices[user], choices[computer] if u == c: return "Empate" elif (u - c) % 3 == 1: return "Usuario" else: return "Computadora"
Pros: Mathematical, elegant
Cons: Harder to understand, overkill for 3 options
These pure functions can be tested without mocking Streamlit or session state.The game logic implementations demonstrate fundamental programming concepts: algorithms, data structures, state machines, and user interaction handling. Each game showcases different approaches to solving classic problems in an interactive web environment.