Skip to content

Instantly share code, notes, and snippets.

@rbtcollins
Created April 7, 2016 08:05
Show Gist options
  • Save rbtcollins/16b6c9a447c564bab57e100d86f57c98 to your computer and use it in GitHub Desktop.
Save rbtcollins/16b6c9a447c564bab57e100d86f57c98 to your computer and use it in GitHub Desktop.
from operator import methodcaller
import random
import itertools
def card_values(card):
"""Get the possible values of a card in a blackjack game.
e.g. card_values(0) -> (1, 11)
:return: A tuple of the possible values.
"""
c = card % 13
if c == 0:
return (1, 11)
if c >= 9:
return (10,)
return (c + 1,)
def showcard(c):
suite = c // 13
card = c % 13
suites = {0: 'H', 1: 'D', 2:'S', 3:'C'}
cards = {0:'A', 1:'2', 2:'3', 3:'4', 4:'5', 5:'6', 6:'7', 7:'8', 8:'9', 9:'10', 10:'J', 11:'Q', 12:'K'}
return "%s%s" % (suites[suite], cards[card])
def shuffle():
"""Return a shuffled deck of 8 regular decks.
Each card is modelled by a number between 0 and 51.
"""
singledeck = list(range(52))
alldecks = singledeck * 8
random.shuffle(alldecks)
return iter(alldecks)
class Hand:
def __init__(self):
self.cards = []
self.held = False
def __repr__(self):
return "%s %s" % (list(map(showcard,self.cards)), self.held)
def _possible_values(self):
possible_values = set()
for combination in itertools.product(*map(card_values, self.cards)):
value = sum(combination)
possible_values.add(value)
return possible_values
def winning(self):
possible_values = self._possible_values()
if 21 in possible_values:
return True
if min(possible_values) > 21:
return False
return None
def best_value(self):
try:
return max(filter(lambda x:x<=21, self._possible_values()))
except ValueError:
return 0
def finished(self):
return self.held or self.winning() is not None
class Game:
def __init__(self, playercount):
self.dealer = Hand()
self.players = []
self.deck = shuffle()
self.nextplayer = 0
for pos in range(playercount):
self.players.append(Hand())
self.players[pos].cards.append(next(self.deck))
self.players[pos].cards.append(next(self.deck))
self.dealer.cards.append(next(self.deck))
self.dealer.cards.append(next(self.deck))
def __repr__(self):
return repr(self.__dict__)
def turn(self, take):
"""Take a turn.
:param take: True to take a card, False to hold.
"""
if not take:
self.players[self.nextplayer].held = True
self.players[self.nextplayer].cards.append(next(self.deck))
self.nextplayer = (self.nextplayer + 1) % len(self.players)
def finished(self):
return all(map(methodcaller(finished), self.players))
def dealer_turn(self):
to_beat = list(map(methodcaller("best_value"), self.players))
target = max(to_beat)
if target == 21:
print("someone won")
return
if self.dealer.best_value() > target:
print("dealer wins")
return
self.dealer.cards.append(next(self.deck))
from collections import defaultdict
from testtools import TestCase
from testtools.matchers import HasLength
from blackjack.deck import Hand, card_values, shuffle, Game
class TestDeck(TestCase):
def test_shuffle(self):
seq1 = list(shuffle())
seq2 = list(shuffle())
self.assertNotEqual(seq1, seq2)
self.expectThat(seq1, HasLength(52*8))
self.expectThat(seq2, HasLength(52*8))
seen = defaultdict(list)
for card in seq1:
seen[card].append(card)
for card, occurences in seen.items():
self.expectThat(occurences, HasLength(8))
def test_card_values(self):
# 0-> 12: H A, 2, ... K
# 13 -> 25: D A...
# 26 -> 38
# 39 -> 51
for offset in range(0, 52, 13):
self.assertEqual((1,11), card_values(0 + offset))
for c in range(1,10):
self.assertEqual((c + 1,), card_values(c + offset))
for c in range(11,13):
self.assertEqual((10,), card_values(c + offset))
class TestHand(TestCase):
def test_init(self):
h = Hand()
self.assertEqual([], h.cards)
def test_winning_state(self):
h = Hand()
hands = [[9, 0], [9, 10, 0]]
for hand in hands:
h = Hand()
h.cards = hand
self.assertEqual(True, h.winning())
def test_losing_state(self):
h = Hand()
hands = [[7, 8 ,9], [9, 8, 0, 1]]
for hand in hands:
h = Hand()
h.cards = hand
self.assertEqual(False, h.winning())
def test_neutral_state(self):
h = Hand()
hands = [[7, 8], [9, 8, 0]]
for hand in hands:
h = Hand()
h.cards = hand
self.assertEqual(None, h.winning(), "hand %r" % (hand, ))
class TestGame(TestCase):
def test_init(self):
g = Game(2)
self.expectThat(g.players, HasLength(2))
self.assertIsInstance(g.players[0], Hand)
self.assertIsInstance(g.players[1], Hand)
self.assertIsInstance(g.dealer, Hand)
def check_initial(hand):
self.expectThat(hand.cards, HasLength(2))
check_initial(g.dealer)
check_initial(g.players[0])
check_initial(g.players[1])
self.assertEqual(0, g.nextplayer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment