Last active
October 13, 2022 01:18
-
-
Save henryiii/9c04ee6378b1560abb7e to your computer and use it in GitHub Desktop.
base for card games
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Created on Sun Jul 20 17:27:33 2014 | |
@author: henryiii | |
""" | |
# http://en.wikipedia.org/wiki/Playing_cards_in_Unicode | |
from __future__ import unicode_literals, division | |
import random | |
from collections import Counter | |
from functools import total_ordering | |
import pickle | |
import socket | |
try: | |
input = raw_input | |
except NameError: | |
pass | |
SUITS = ('None','Clubs','Diamonds','Hearts','Spades') | |
SUITS_SIMPLE = 'xCDHS' | |
SUITS_UNICODE = 'x♣♦♥♠' | |
NAMES = ('None','A','2','3','4', | |
'5','6','7','8', | |
'9','10','J','Q','K','?') | |
POKERHANDS = ( | |
'High', | |
'One pair', | |
'Two pair', | |
'Three of a kind', | |
'Straight', | |
'Flush', | |
'Full house', | |
'Four of a kind', | |
'Straight flush', | |
'Royal flush', | |
'Five of a kind') | |
@total_ordering | |
class Card(object): | |
def __init__(self, rank, suit=None): | |
if suit is not None: | |
self._num = 0 | |
self.rank = rank | |
self.suit = suit | |
else: | |
if rank > 52 or rank < 0: | |
raise IndexError('Not valid card') | |
self._num = rank | |
@classmethod | |
def fromstr(cls, string): | |
self = cls(0) | |
string = string.upper() | |
for n in range(1,5): | |
if SUITS_UNICODE[n] in string or SUITS_SIMPLE[n] in string: | |
self.suit = n | |
string = string.replace(SUITS_UNICODE[n],'') | |
string = string.replace(SUITS_SIMPLE[n],'') | |
for n,rank in enumerate(NAMES): | |
if rank in string: | |
self.rank = n | |
return self | |
raise ValueError() | |
@property | |
def suit(self): | |
return self._num % 4 + 1 | |
@suit.setter | |
def suit(self,val): | |
assert 1 <= val <= 4 | |
self._num = (self._num//4)*4 + val - 1 | |
@property | |
def rank(self): | |
val = self._num // 4 + 1 | |
return val if val != 1 else 14 | |
@rank.setter | |
def rank(self,val): | |
assert 1 <= val <= 14 | |
val = val if val != 14 else 1 | |
self._num = self._num%4 + (val-1)*4 | |
@property | |
def lowrank(self): | |
val = self.rank | |
return val if val != 14 else 1 | |
@property | |
def color(self): | |
return int(1 < self.suit < 4) | |
def __str__(self): | |
return NAMES[self.lowrank] + SUITS_UNICODE[self.suit] | |
def __repr__(self): | |
return '{}({},{})'.format( | |
self.__class__.__name__, | |
self.rank, self.suit) | |
def __eq__(self, other): | |
return self._num == other._num | |
def __lt__(self, other): | |
return (self.rank < other.rank | |
if self.rank != other.rank | |
else self.suit < other.suit) | |
def __int__(self): | |
return self._num | |
class Deck(object): | |
def __init__(self): | |
self.cards = [Card(i) for i in range(52)] | |
self.shuffle() | |
def shuffle(self): | |
random.shuffle(self.cards) | |
def draw(self): | |
return self.cards.pop() | |
def reput(self, card): | |
self.cards.insert(0,card) | |
def __str__(self): | |
return ('[' + ' '.join(map(str,self.cards)) + ']') | |
class Hand (object): | |
def __init__(self, deck=None, handnum = 0): | |
self.cards = [] | |
self.deck = deck | |
self.handnum = handnum | |
def draw(self, num=5): | |
for i in range(num): | |
self.cards.append(self.deck.draw()) | |
self.cards.sort() | |
def add_cards(self, *cards): | |
for card in cards: | |
self.cards.append(card) | |
@classmethod | |
def fake_hand(cls, cardstr): | |
self = cls() | |
self.add_cards(*cards_from_string(cardstr)) | |
return self | |
def discard(self,*cards): | |
for card in cards: | |
if self.deck is not None: | |
self.deck.reput(card) | |
self.cards.remove(card) | |
def redraw(self, *cards): | |
self.discard(*cards) | |
self.draw(len(cards)) | |
def __str__(self): | |
return ('[' + ' '.join(map(str,self.cards)) + ']') | |
@total_ordering | |
class PokerHand (Hand): | |
def score(self): | |
return self.match()['score'] | |
def match(self): | |
return matchhand(self.cards) | |
def name(self): | |
return POKERHANDS[self.match()['type']-1] | |
def __lt__(self, other): | |
return self.score() < other.score() | |
def __eq__(self, other): | |
return self.score() == other.score() | |
def __str__(self): | |
return ('[' + ' '.join(map(str,self.match()['cards'])) + ']') | |
class PokerGame(object): | |
def __init__(self, hands=2, money=100): | |
self.deck = Deck() | |
self.hands = [None]*hands | |
self.restart() | |
self.moneys = [money]*hands | |
self.anti = 5 | |
def restart(self): | |
self.deck = Deck() | |
for n in range(len(self.hands)): | |
self.hands[n] = PokerHand(self.deck, n) | |
self.hands[n].draw() | |
def winner(self): | |
return [hand.handnum for hand in sorted(self.hands,reverse=True)] | |
def __str__(self): | |
return '\n'.join('Hand {}: {} {}'.format(hand.handnum + 1, str(hand), hand.name()) for hand in sorted(self.hands,reverse=True)) | |
def matchhand(cards): | |
values = dict() | |
cards = list(sorted(cards, reverse=True)) | |
# Counting groups | |
ranks = Counter(c.rank for c in cards).most_common() | |
suits = Counter(c.suit for c in cards).most_common() | |
# Ordering ranks | |
for rank, freq in ranks: | |
if freq > 1: | |
positions = [i for i in range(len(cards)) if cards[i].rank == rank] | |
for n,v in enumerate(positions): | |
cards.insert(n,cards.pop(v)) | |
values['cards'] = cards | |
# Straight checking vals | |
vals = set(c.lowrank for c in cards) | |
values['flush'] = len(suits) == 1 | |
values['runs'] = ranks | |
values['group'] = ranks[0][1] | |
values['twogroup'] = len(ranks)==3 and ranks[1][0]==2 | |
values['royal']=vals=={1,10,11,12,13} | |
values['straight'] = len(ranks) == 5 and (min(vals)+4 == max(vals) or values['royal']) | |
if values['flush']: | |
if values['straight']: | |
if values['royal']: | |
values['type']=10 | |
else: | |
values['type']=9 | |
else: | |
values['type']=6 | |
elif values['straight']: | |
values['type']=5 | |
elif values['twogroup']: | |
if ranks[0][1] == 3: | |
values['type'] = 7 | |
else: | |
values['type'] = 3 | |
else: | |
values['type'] = (1,2,4,8,11)[ranks[0][1]-1] | |
#Score: | |
# (type)(r1)(r2)...(s1)... | |
# where each digit is rank | |
# A is 14; vals are 1 hex digits each | |
# last five are suits | |
values['score'] = values['type'] * 16**10 | |
for n,card in enumerate(cards): | |
values['score'] += card.rank * 16**(9-n) | |
values['score'] += card.suit * 16**(4-n) | |
return values | |
def pprint_values(values): | |
print '''Hand: {v[cards][0]} {v[cards][1]} {v[cards][2]} {v[cards][3]} {v[cards][4]} | |
Runs: {v[runs]} | |
R: {v[royal]}, \ | |
F: {v[flush]}, \ | |
S: {v[straight]} | |
Group: {v[group]}, \ | |
Second group?: {v[twogroup]} | |
Type: {t} | |
Score: {v[score]:X}\ | |
'''.format(v=values,t=POKERHANDS[values['type']-1]) | |
def cards_from_string(strings): | |
return [Card.fromstr(cstr) for cstr in strings.split()] | |
def poker_play_console(): | |
players = int(input('How many players? ')) | |
game = PokerGame(players) | |
pot = 0 | |
bet = 0 | |
for player in range(players): | |
print "Player {}'s turn.".format(player + 1) | |
game.moneys[player] -= game.anti | |
pot += game.anti | |
print "Anti: ${}".format(game.anti, game.moneys[player]) | |
print 'Your cards: {} {}, ${}'.format(game.hands[player], game.hands[player].name(), game.moneys[player]) | |
betstr = input('What would you like to bet? 0 to call, f to fold') | |
if betstr.lower() != 'f': | |
if betstr!='': | |
bet += int(betstr) | |
game.moneys[player] -= bet | |
pot += bet | |
for player in range(players): | |
print "Player {}'s turn.".format(player + 1) | |
print 'Your cards: {} {}, ${}'.format(game.hands[player], game.hands[player].name(), game.moneys[player]) | |
cards = cards_from_string(input('What cards shall you discard? ')) | |
game.hands[player].redraw(*cards) | |
print 'Final hand: {} {}'.format(game.hands[player], game.hands[player].name()) | |
bet = int(input('What would you like to bet? ')) | |
game.moneys[player] -= bet | |
pot += bet | |
print "Winner: Player {}".format(game.winner()[0] + 1) | |
print game | |
game.moneys[game.winner()[0]] += pot | |
return game | |
if __name__ == '__main__': | |
game = poker_play_console() | |
def test_simple(): | |
deck = Deck() | |
hand1 = PokerHand(deck) | |
hand1.draw() | |
hand2 = PokerHand(deck) | |
hand2.draw() | |
print '-'*35 | |
print hand1 | |
pprint_values(hand1.match()) | |
print hand2 | |
pprint_values(hand2.match()) | |
print 'hand2 > hand1?', hand2 > hand1 | |
hand3 = PokerHand.fake_hand('4♥ 5♣ 6♣ 7♥ 8♠') | |
pprint_values(hand3.match()) | |
hand4 = PokerHand.fake_hand('A♥ q♣ K♣ 10♥ J♠') | |
pprint_values(hand4.match()) | |
hand5 = PokerHand.fake_hand('A♥ Q♥ K♥ 10♥ J♥') | |
pprint_values(hand5.match()) | |
hand5 = PokerHand.fake_hand('3♥ Q♥ K♥ 10♥ J♥') | |
pprint_values(hand5.match()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment