I'm trying to make a cribbage game in python, and I have a pretty good things going except for when I'm trying to find combinations of cards that add up to 15 after the player discards 2 cards to the crib, it doesn't work for combinations of 3 or greater. My code is below.
import math
import random
from itertools import *
deck = ['dA','d2','d3','d4','d5','d6','d7','d8','d9','dT','dJ','dQ','dK',
'hA','h2','h3','h4','h5','h6','h7','h8','h9','hT','hJ','hQ','hK',
'sA','s2','s3','s4','s5','s6','s7','s8','s9','sT','sJ','sQ','sK',
'cA','c2','c3','c4','c5','c6','c7','c8','c9','cT','cJ','cQ','cK']
newHand = []
CARD_SYMBOLS = {"d": "♦", "h": "♥", "s": "♠", "c": "♣"}
def show_hand(cards):
print("┌─────┐\t"*len(cards))
print( "\t".join([f"| {card[1]} |" for card in cards]))
print( "\t".join([f"| {CARD_SYMBOLS[card[0]]} |" for card in cards]))
print("└─────┘\t"*len(cards))
hand = []
handPoints = []
computerHand = []
crib = []
separator = ''
def cutCard():
CD = random.choice(deck)
newHand.append(CD)
deck.remove(CD)
def dealCards():
for x in range(6):
card_dealt = random.choice(deck)
hand.append(card_dealt)
deck.remove(card_dealt)
compCard_dealt = random.choice(deck)
computerHand.append(compCard_dealt)
deck.remove(compCard_dealt)
AtoK = {'2','3','4','5','6','7','8','9'}
tens = {'T','J','Q','K'}
twoCard15s = {'T5','J5','Q5','K5','78','96'}
threeCard15s = {'K4A','K32','Q4A','Q32','T4A','T32','95A','942','933','86A','852','843','77A','762','753','744','662','654','555'}
fourCard15s = {'K3AA','K22A','Q3AA','Q22A','J3AA','J22A','T3AA','T22A','94AA','932A','9222','85AA','842A','833A','8322','76AA','752A','7244','743A','7332','662A','6522','653A','6432','6441','6333','5433','5442','554A','555A','5532','4443'}
def countPoints():
def count15s():
#------2 card----this all works
for num1 in range(0,4):
for num2 in range(0,4):
if(num1 != num2):
combo = ''.join(newHand[num1][1] newHand[num2][1])
if(combo in twoCard15s):
handPoints.append(combo)
#-------3 card---works for about 3 combinations and I can't figure out why
for numX in range(0,4):
for numY in range(0,4):
for numZ in range(0,4):
if(numX != numY and numY != numZ and numX != numZ):
combThree = ''.join(newHand[numX-1][1] newHand[numY-1][1] newHand[numZ-1][1])
if(combThree in threeCard15s):
if(combThree not in handPoints):
handPoints.append(combThree)
#---------4 card---also doesn't work
for numX in range(0,4):
for numY in range(0,4):
for numZ in range(0,4):
for numA in range(0,4):
if(numX != numY != numZ != numA):
combFour = ''.join(newHand[numX][1] newHand[numY][1] newHand[numZ][1] newHand[numA][1])
if(combFour in fourCard15s ):
if(combFour not in handPoints):
handPoints.append(combFour)
count15s() #actually makes the function run
print(handPoints) #prints the array of card combinations--I'm going to change this later so it actually counts points instead
def makeCrib():
whichCards = input("Which cards do you want to put in the crib? (1-6) : ")
if(whichCards[0] != whichCards[1]):
if(len(whichCards) == 2):
value1 = hand[int(whichCards[0]) - 1]
value2 = hand[int(whichCards[1]) - 1]
#chooses the inputed cards from the player's hand, subtracts 1 so it's more appealing to the eye, then adds the new cards to a separate array.
both = []
both.append(value1)
both.append(value2)
# for each card in the hand, if the card selected isn't in the array of selected cards, push the card to the newHand (scored)
for x in range(0,6):
if(hand[x] not in both):
newHand.append(hand[x])
#makes it appealing to the eye
print('Your Hand: \n 1 2 3 4 5 6')
dealCards() #randomizes the cards and deals them
show_hand(hand) #prints the card art for the hand
makeCrib()
cutCard()
show_hand(newHand)
countPoints()
I guess my main question is why does this work for 2 card combinations, and how can I make it so it works for 3-5?
What it ends up printing is something like this: The combination of 8 6 and A should be printed in the array at the very bottom but it doesn't.
Also is there an easier/more efficient way to check every combination other than a quad nested for
loop? Thank you in advance to anyone who can help!
CodePudding user response:
You should use a dictionary to map cards to their numeric value and compute the sum of values for combinations (rather than searching for pre-defined combinations).
Also, you should use the combinations function from itertools instead of nested loops. (your loops are combining the some cards with themselves and also repeating permutations of the same combinations which requires extra work to compensate)
from itertools import combinations
kinds = "dhsc"
faces = "A23456789TJQK"
cardValues = {kind face:min(10,value) for kind in kinds
for value,face in enumerate(faces,1)}
def count15s(cards):
points = 0
combos = []
for size in (2,3,4,5):
for combo in combinations(cards,size):
if sum(map(cardValues.get,combo)) == 15:
points = 2
combos.append(combo)
return points,combos
print(*count15s(['s7','dA','h6','h8','d5']))
# 4 [('s7', 'h8'), ('dA', 'h6', 'h8')]
print(*count15s(['s2','d7','h3','h5','dK']))
# 6 [('h5', 'dK'), ('s2', 'h3', 'dK'), ('d7', 'h3', 'h5')]
print(*count15s(['s2','d5','h3','h5','dK']))
# 8 [('d5', 'dK'), ('h5', 'dK'), ('s2', 'h3', 'dK'), ('s2', 'd5', 'h3', 'h5')]
print(*count15s(['s5','d5','h5','c5','dK']))
# 16 [('s5', 'dK'), ('d5', 'dK'), ('h5', 'dK'), ('c5', 'dK'),
('s5', 'd5', 'h5'), ('s5', 'd5', 'c5'), ('s5', 'h5', 'c5'),
('d5', 'h5', 'c5')]
The same approach can be used to count sequences:
cardOrder = {kind face:order for kind in kinds
for order,face in enumerate(faces)}
def countSeq(cards):
cards = sorted(cards,key=cardOrder.get)
points = 0
combos = []
for size in (5,4,3):
for combo in combinations(cards,size):
sequence = "".join(card[1] for card in combo)
if sequence in faces:
points = size
combos.append(combo)
if points: break
return points,combos
print(*countSeq(['s7','d8','h8','h9','d9']))
# 12 [('s7', 'd8', 'h9'), ('s7', 'd8', 'd9'),
('s7', 'h8', 'h9'), ('s7', 'h8', 'd9')]
print(*countSeq(['sA','d2','h2','c2','d3']))
# 9 [('sA', 'd2', 'd3'), ('sA', 'h2', 'd3'), ('sA', 'c2', 'd3')]
print(*countSeq(['sT','dJ','hQ','cK','dK']))
# 8 [('sT', 'dJ', 'hQ', 'cK'), ('sT', 'dJ', 'hQ', 'dK')]
print(*countSeq(['sT','d9','hQ','cJ','dK']))
# 5 [('d9', 'sT', 'cJ', 'hQ', 'dK')]