added demo game in chris_demo

You had some really clear planning in your commit message--
In the "chris_demo" folder I implemented a bunch of what
you planned. I suggest playing the game I built
(go into chris_demo and run python game.py), and then
carefully reading all the source code. Then, if you like
the patterns I used, copy or move whatever you want
to use into your main project folder. Also, if there
are parts of my code you don't understand, please let
me know (in a commit message or in person next time
I'm in class) and I'll be happy to explain it.
This commit is contained in:
Chris Proctor
2025-12-19 15:38:03 -05:00
parent 95ae6740d3
commit b8e92eedcf
7 changed files with 265 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

146
chris_demo/card.py Normal file
View File

@@ -0,0 +1,146 @@
suits = ['', '', '', '']
colors = ['black', 'red', 'red', 'black']
ranks = "A23456789TJQK"
class Card:
"""A card is not an agent itself, but it manages two agents
which are always next to each other, representing
the card as something like '♠A'.
"""
display = False
def __init__(self, position, index, hidden=False, selected=False):
"""When creating a card, you pass an index, which should be a number between
0 and 51. If you imagine a deck of playing cards in order (all the spades from A-K,
then all the hearts from A-K, etc.), then the index is all we need to identify which
card this is. See the CardSuit and CardRank classes below for the math we can use
to convert an index value to a suit or a rank.
"""
self.index = index
self.name = str(index)
self.agents = [CardSuit(index, hidden, selected), CardRank(index, hidden, selected)]
self.set_position(position)
def __str__(self):
return ''.join(a.character for a in self.agents)
def __repr__(self):
return f"<Card {self.index} {self}>"
def value(self):
"""Returns how many points this card is worth. Currently treats aces as worth 1.
Later we might need a way of considering that an ace could be worth 1 or 11 in
blackjack.
"""
rank_index = self.index % 13
return rank_index + 1
def set_position(self, position):
"""When the Card's position gets set, it updates
the position of its suit and rank. In this way, we have one
agent (Card) which manages the positions of two agents on the
screen.
"""
x, y = position
suit, rank = self.agents
self.position = position
suit.position = position
rank.position = (x+1, y)
def set_z(self, z):
suit, rank = self.agents
suit.z = z
rank.z = z
def hide(self):
for agent in self.agents:
agent.hide()
def show(self):
for agent in self.agents:
agent.show()
def select(self):
for agent in self.agents:
agent.select()
def deselect(self):
for agent in self.agents:
agent.deselect()
class CardSuit:
def __init__(self, index, hidden=False, selected=False):
self.name = f"{index}_suit"
self.index = index
self.suit_color = colors[index // 13]
self.hidden = hidden
self.selected = selected
self.update_display()
def select(self):
self.selected = True
self.update_display()
def deselect(self):
self.selected = False
self.update_display()
def show(self):
self.hidden = False
self.update_display()
def hide(self):
self.hidden = True
self.update_display()
def update_display(self):
if self.hidden:
self.character = ""
fg = "blue"
else:
self.character = suits[self.index //13]
fg = self.suit_color
if self.selected:
bg = "yellow"
else:
bg = "gray"
self.color = fg + "_on_" + bg
class CardRank:
def __init__(self, index, hidden=False, selected=False):
self.name = f"{index}_rank"
self.index = index
self.suit_color = colors[index // 13]
self.hidden = hidden
self.selected = selected
self.update_display()
def select(self):
self.selected = True
self.update_display()
def deselect(self):
self.selected = False
self.update_display()
def show(self):
self.hidden = False
self.update_display()
def hide(self):
self.hidden = True
self.update_display()
def update_display(self):
if self.hidden:
self.character = ""
fg = "blue"
else:
self.character = ranks[self.index % 13]
fg = self.suit_color
if self.selected:
bg = "yellow"
else:
bg = "gray"
self.color = fg + "_on_" + bg

88
chris_demo/dealer.py Normal file
View File

@@ -0,0 +1,88 @@
from deck import Deck
class Dealer:
"""The Dealer runs the game, following these rules:
I have a card class that returns a card value
I have a dealer file that has a function that deals the first two cards
I'm still a little lost on how this works into the Game class
and how to organize the play.
I want to:
1. deal two cards to each dealer and player
2. hide one of the dealers cards
3. present the user with their cards and let them
choose * hit me OR * stay.
4. If they hit, deal another card to them and calculate if they
went over 21. If they went over 21 end the game with BUST Dealer WINS!.
If they didn't go over 21, calculate their score and allow the dealer
their turn.
5. If they stay, calculate their score and let the dealer have their turn.
6. Dealer - checks their cards and compares them to the player. Then
chooses to hit or stay. Print choice to screen. If they hit, show the card
to the player.
"""
display = False
playing = False
dealer_origin = (1, 3)
player_origin = (1, 5)
def __init__(self, position):
self.position = position
self.dealer_cards = []
self.player_cards = []
def play_turn(self, game):
if not self.playing:
self.set_up_new_round(game)
self.playing = True
def handle_keystroke(self, keystroke, game):
game.log(keystroke)
if keystroke == "h":
self.deal_card_to_player()
game.state["score"] = self.get_player_score()
def set_up_new_round(self, game):
self.deck = Deck(self.position)
for agent in self.deck.get_agents():
game.add_agent(agent)
self.deal_card_to_dealer(hidden=True)
self.deal_card_to_dealer(hidden=False)
self.deal_card_to_player()
self.deal_card_to_player()
game.state["score"] = self.get_player_score()
def deal_card_to_dealer(self, hidden=True):
card = self.deck.draw()
if hidden:
card.hide()
else:
card.show()
card.set_position(self.get_position_of_next_dealer_card())
self.dealer_cards.append(card)
def deal_card_to_player(self, hidden=False):
card = self.deck.draw()
if hidden:
card.hide()
else:
card.show()
card.set_position(self.get_position_of_next_player_card())
self.player_cards.append(card)
def get_position_of_next_player_card(self):
x, y = self.player_origin
return (x + 4 * len(self.player_cards), y)
def get_position_of_next_dealer_card(self):
x, y = self.dealer_origin
return (x + 4 * len(self.dealer_cards), y)
def get_player_score(self):
return sum([card.value() for card in self.player_cards])
def end_round(self, game):
for agent in self.deck.get_agents():
game.remove_agent(agent)

20
chris_demo/deck.py Normal file
View File

@@ -0,0 +1,20 @@
from card import Card
from random import shuffle
class Deck:
def __init__(self, position, hidden=True, shuffled=True):
self.position = position
self.cards = [Card(position, i, hidden=hidden) for i in range(52)]
if shuffled:
shuffle(self.cards)
def draw(self):
return self.cards.pop()
def get_agents(self):
agents = []
for card in self.cards:
agents.append(card)
agents += card.agents
return agents

11
chris_demo/game.py Normal file
View File

@@ -0,0 +1,11 @@
from retro.game import Game
from dealer import Dealer
dealer = Dealer((1, 1))
state = {
"score": 0,
"options": "h to hit or s to stay",
}
game = Game([dealer], state)
game.play()