Skip to content

Instantly share code, notes, and snippets.

@SegFaultAX
Last active December 10, 2015 04:58
Show Gist options
  • Save SegFaultAX/4384790 to your computer and use it in GitHub Desktop.
Save SegFaultAX/4384790 to your computer and use it in GitHub Desktop.
Simple blackjack implementation
#!/usr/bin/env python
import sys
from random import shuffle
from pprint import pformat
def group_by(keyfn, l):
groups = {}
for e in l:
key = keyfn(e)
groups.setdefault(key, [])
groups[key].append(e)
return groups
### Cards ###
SUITS = { s[0]: s for s in ["spades", "hearts", "clubs", "diamonds"] }
RANKS = { 1: "ace", 11: "jack", 12: "queen", 13: "king" }
SCORES = { 1: 11, 11: 10, 12: 10, 13: 10 }
STATES = {
"busted": "You've busted!",
"blackjack": "You hit blackjack!",
"twentyone": "You hit 21!",
}
def new_deck():
ranks = range(1, 14)
return [(suit, rank) for suit in SUITS.keys() for rank in ranks]
def shuffle_deck(deck=None, times=1):
if deck is None:
deck = new_deck()
for _ in range(times):
shuffle(deck)
return deck
def format_card(card):
suit, rank = card
suit_name = str(SUITS.get(suit))
rank_name = str(RANKS.get(rank, rank))
return "%s of %s" % (rank_name.capitalize(), suit_name.capitalize())
def format_hand(hand, sep="\n"):
return sep.join(format_card(card) for card in hand)
### Blackjack ###
DEALER = "_dealer_"
def deal_cards(game, per_player):
deck = game["deck"]
hands = game["hands"]
for _ in range(per_player):
for player in game["players"]:
hands[player].append(deck.pop(0))
game["dealer"].append(deck.pop(0))
game.update({"deck": deck, "hands": hands})
return game
def score_card(card):
suit, rank = card
return SCORES.get(rank, rank)
def is_ace(card):
suit, rank = card
return rank == 1
def score_hand(hand):
aces = len([c for c in hand if is_ace(c)])
score = sum(score_card(card) for card in hand)
while score > 21 and aces:
score -= 10
aces -= 1
return score
def new_game(players):
game = { "deck": shuffle_deck(times=7), "players": players, "hands": {},
"dealer": [] }
for player in players:
game["hands"][player] = []
return game
def hand_type(hand):
score = score_hand(hand)
cards = len(hand)
if score == 21 and cards == 2:
return "blackjack"
elif score == 21:
return "twentyone"
elif score > 21:
return "busted"
return "normal"
WINNING = ["twentyone", "blackjack"]
LOSING = ["busted"]
COMPLETED = WINNING + LOSING
def normalize_hand(hand):
scoring = {"blackjack": 100, "twentyone": 50, "busted": 0}
return scoring.get(hand_type(hand), score_hand(hand))
def compare_hands(hand1, hand2):
return cmp(normalize_hand(hand1), normalize_hand(hand2))
def determine_winners(game):
dealer, players = game["dealer"], game["hands"].items()
comp = lambda p: compare_hands(p[1], dealer)
stats = group_by(comp, players)
winners = stats.get(1, [])
losers = stats.get(-1, [])
pushes = stats.get(0, [])
if hand_type(dealer) == "busted":
losers += pushes
pushes = []
return (winners, losers, pushes)
### UI ###
def get_input(prompt, options=None):
while True:
val = raw_input(prompt)
if options is None or val in options:
return val
def print_menu(player):
print "It's %s's turn" % player
print "Press 'h' to hit"
print "Press 's' to stay"
print "Press 'q' to quit"
def print_hand(player, hand):
print "\n%s's hand:" % player
print format_hand(hand)
def player_turn(player, game):
deck, hand = game["deck"], game["hands"][player]
print_menu(player)
print_hand(player, hand)
while True:
print "\nScore: %d" % score_hand(hand)
htype = hand_type(hand)
if htype in COMPLETED:
print STATES.get(htype)
break
move = get_input("> ", ["h", "s", "q"])
if move == "h":
card = deck.pop(0)
hand.append(card)
print "Hit: %s" % format_card(card)
elif move == "s":
print "Staying"
break
elif move == "q":
print "Goodbye!"
sys.exit()
print
return htype
def dealer_turn(game):
deck, hand = game["deck"], game["dealer"]
print "It's the dealers turn"
print "\nDealer's hand:"
print format_hand(hand)
while score_hand(hand) < 17:
card = deck.pop(0)
hand.append(card)
print "Dealer hits: %s" % format_card(card)
score = score_hand(hand)
print "\nScore: %d" % score
return score
def print_scores(game):
print "\nScore\n"
print "Dealer has:"
print format_hand(game["dealer"])
print "with a score of %d\n" % score_hand(game["dealer"])
print
winners, losers, pushes = determine_winners(game)
print "Winners: "
for winner in winners:
name, hand = winner
print " %s - %d" % (name, score_hand(hand))
print
print "Losers: "
for loser in losers:
name, hand = loser
print " %s - %d" % (name, score_hand(hand))
print
print "Pushes: "
for push in pushes:
name, hand = push
print " %s - %d" % (name, score_hand(hand))
print
def main():
game = new_game([chr(n) for n in range(65, 75)])
deal_cards(game, 2)
for player in game["players"]:
player_turn(player, game)
dealer_turn(game)
print_scores(game)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment