Projects/Gin_Rummy_Card_Game.py

139 lines
3.4 KiB
Python

import random
from collections import defaultdict
RANK_ORDER = {str(n): n for n in range(2, 11)}
RANK_ORDER.update({"A": 1, "J": 11, "Q": 12, "K": 13})
class Card:
suits = ['', '', '', '']
ranks = list(range(1, 11)) + ['J', 'Q', 'K']
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
@property
def value(self):
if isinstance(self.rank, int):
return self.rank
return 10 if self.rank in ['J', 'Q', 'K'] else 1 # Ace low
def __repr__(self):
return f"{self.rank}{self.suit}"
class Deck:
def __init__(self):
self.cards = [Card(rank, suit) for suit in Card.suits for rank in Card.ranks]
random.shuffle(self.cards)
def draw(self):
return self.cards.pop() if self.cards else None
class DiscardPile:
def __init__(self):
self.cards = []
def top(self):
return self.cards[-1] if self.cards else None
def discard(self, card):
self.cards.append(card)
class Hand:
def __init__(self):
self.cards = []
def add(self, card):
self.cards.append(card)
def remove(self, card):
self.cards.remove(card)
def melds(self):
return find_sets(self.cards) + find_runs(self.cards)
def deadwood_points(self):
return sum(c.value for c in self.cards) # placeholder
def __repr__(self):
return f"Hand({self.cards})"
class Player:
def __init__(self, name):
self.name = name
self.hand = Hand()
def draw(self, deck, discard_pile, from_discard=False):
card = discard_pile.top() if from_discard else deck.draw()
if card:
self.hand.add(card)
if from_discard:
discard_pile.cards.pop()
return card
def discard(self, discard_pile, card):
self.hand.remove(card)
discard_pile.discard(card)
class Game:
def __init__(self, players):
self.deck = Deck()
self.discard_pile = DiscardPile()
self.players = players
def deal(self):
for _ in range(10):
for player in self.players:
player.hand.add(self.deck.draw())
self.discard_pile.discard(self.deck.draw())
def play_round(self):
# placeholder loop
self.deal()
print("Initial hands:")
for p in self.players:
print(p.name, p.hand)
# Function to detect sets
def find_sets(cards):
groups = defaultdict(list)
for c in cards:
groups[c.rank].append(c)
return [group for group in groups.values() if len(group) >= 3]
# Function to detect runs
def find_runs(cards):
runs = []
# group by suit
suits = defaultdict(list)
for c in cards:
suits[c.suit].append(c)
for suit, suited_cards in suits.items():
# sort by rank order
sorted_cards = sorted(suited_cards, key=lambda c: RANK_ORDER[str(c.rank)])
# scan for consecutive sequences
temp = [sorted_cards[0]]
for i in range(1, len(sorted_cards)):
prev = RANK_ORDER[str(sorted_cards[i-1].rank)]
curr = RANK_ORDER[str(sorted_cards[i].rank)]
if curr == prev + 1:
temp.append(sorted_cards[i])
else:
if len(temp) >= 3:
runs.append(temp)
temp = [sorted_cards[i]]
if len(temp) >= 3:
runs.append(temp)
return runs