def test_scorePairs(self): scorer = HandScorer() # each row is [[cards in hand],turn, score] cases = [ [[0, 1, 2, 3], 4, 0], # A, 2, 3, 4, 5 - No pairs [[0, 13, 26, 39], 1, 12], # A, A, A, A, 2 - 4 of a kind [[1, 0, 13, 26], 39, 12], # 2, A, A, A, A - 4 of a kind, checks that sorting works [ [0, 2, 2 + 13, 2 + 13 * 2], 2 + 13 * 3, 12 ], # A, 3, 3, 3, 3 # 4 of a kind, check when last card matches previous [[1, 2, 3, 3], 4, 2], # 2,3,4,4,5 -1 pair [[1, 1, 2, 10], 10, 4], # 2,2,3,J,J - 2 pairs of 2 [[9, 10, 11, 12], 0, 0], # 10,J,Q,K,A - no pairs - checks that it uses face values [[15, 15 + 13, 15 + 13 * 2, 22], 22 + 13, 8], # 3,3,3,10,10 - 3 of a kind and a pair [[0, 2, 2 + 13, 3], None, 2], # 3,3 - pair for 2 [[2, 2 + 13, 2 + 13 * 2, 3], None, 6], # 3,3,3,4 - 3 of a kind for 6 ] for case in cases: cardsInHand, turn, scoreCorrect = case score = scorer.scorePairs(cardsInHand, turn) self.assertEqual( score, scoreCorrect, "predicted {} Correct: {} for hand {} with turn {}".format( score, scoreCorrect, cardsInHand, turn))
def test_scorer(self): ''' Test scoring of all the functions together ''' scorer = HandScorer() # Each row is [[cardsInHand], turn, score] cases = [ [[0, 1, 2, 3], 4, 12], # 15-2 5flush, 5straight [ [8, 10, 11 + 13 * 3, 12], 36, 8 ], # pair of Q, 2x straight JQK, heels but it doesn't get counted here [[8, 9, 10, 11], 12, 11], # test_Game.test_playHand, Hand #1, player 1 hand [[4, 5, 6, 7], 12, 13], # test_Game.test_playHand, Hand #1, player 2 hand [[0, 1, 2, 3], 12, 13], # test_Game.test_playHand, Hand #1, player 1 crib [[2, 9, 18, 3], 23, 0], # test_Game.test_playHand, Hand #2, player 1 hand [[1, 10, 5, 4], 23, 10], # test_Game.test_playHand, Hand #2, player 2 hand [[12, 24, 9, 0], 23, 4], # test_Game.test_playHand, Hand #2, player 2 crib [ [26, 51, 49, 20], 47, 1 ], # A clubs, K spades,J spades, 8 diamonds turn 9 spades - 1 for knees ] for case in cases: cardsInHand, turn, scoreCorrect = case score = scorer(cardsInHand, turn) self.assertEqual(score, scoreCorrect)
def test_potentialScoreMap(self): ''' ''' scorer = HandScorer() # hand of A, 2, 4, 6 ( drop idx 2,4) # Best turn would be a 3 for a score of 10: # 15-2 (2,3,4,6), straight (A,2,3,4) for 6, flush (A,2,4,6) for 10 hand = [0, 1, 2, 3, 4, 5] # A, 2, 3, 4, 5, 6 result = scorer.potentialScoreMap(hand) self.assertTrue(np.isnan( result[2, 4, 2])) # card is in hand, so should be NaN self.assertEqual(result[2, 4, 2 + 13 * 1], 10) # all other versions should be 10 self.assertEqual(result[2, 4, 2 + 13 * 2], 10) self.assertEqual(result[2, 4, 2 + 13 * 3], 10)
def test_scoreStraight(self): scorer = HandScorer() # each row is [[cards in hand],turn, score] cases = [ [[0, 1, 2, 3], 4, 5], # A, 2, 3, 4, 5 - 5 card straight [[0, 13, 1, 2], 5, 6], # A, A, 2,3, 6 - 2x 3 card straights for 6 [[9, 27, 29, 23], 24, 3], # 10, 2, 4, J, Q - run of 3 [[9, 10, 11, 12], None, 4], # 10, J, Q, K - run of 4 [[0, 2, 4, 6], None, 0] # no points ] for case in cases: cardsInHand, turn, scoreCorrect = case score = scorer.scoreStraight(cardsInHand, turn) self.assertEqual(score, scoreCorrect)
def test_scoreKnobs(self): scorer = HandScorer() # each row is [[cardsInHand],turnCard,score] cases = [ [[0, 1, 2, 3, 4, 5], 6, 0], [[0, 1, 2, 3, 10], 1, 1], # has jack, suite matches [[0, 1, 2, 3, 10 + 13 * 3], 4, 0], # has jack, suit does not match [[0, 10 + 13 * 2, 2, 3, 1], 3 + 13 * 2, 1], # has jack does match [[0, 1, 2, 3, 4], 10, 0], # is his heels, no points [[0, 3, 3, 5], None, 0], # not possible to calculate without turn ] for case in cases: hand, turn, scoreCorrect = case score = scorer.scoreKnobs(hand, turn) self.assertEqual(score, scoreCorrect)
def test_score15s(self): ''' Test the calculation of the score for cards totaling 15 ''' scorer = HandScorer() # each row is [[cardsInHand],turnCard,score] cases = [ [[0, 1, 2, 3], 4, 2], # A, 2, 3, 4, 5 = 15x2 [[0, 4, 9, 10], 11, 6], # A, 5,10, J, Q = 15x6 [[5, 8, 5 + 13, 8 + 2 * 13], 0, 8], # 6, 9, 6, 9, A = 15x8 [[5, 7 + 3 * 13, 3 + 13, 3 + 2 * 13], 0, 4], # 6,8,4,4,A = 15x4 [[4, 9, 10, 11], None, 6], #5,10 + 5,J + 5,Q + 5,K ] for case in cases: cardsInHand, turn, scoreCorrect = case score = scorer.score15s(cardsInHand, turn) self.assertEqual(score, scoreCorrect)
def test_scoreFlush(self): ''' Test cases for flush ''' scorer = HandScorer() # [[cards in hand], turn card, score] cases = [[[0, 1, 2, 3], 4, 5], [[0, 1, 2, 3], 51, 4], [[0, 1, 2, 51], 4, 0], [[0, 1, 2, 3], None, 4], [[0, 1, 2, 50], None, 0]] for case in cases: cardsInHand, turn, scoreCorrect = case score = scorer.scoreFlush(cardsInHand, turn) self.assertEqual( score, scoreCorrect, msg="predicted {} correct {} with hand {} and turn {}".format( score, scoreCorrect, cardsInHand, turn))
def test_scorePossible4CardHand(self): ''' A player is dealt 6 cards, this mechanism finds the scores of every combination of cards put to the crib. ''' scorer = HandScorer() # [[cards in hand], score] cases = [ [[6, 39, 47, 24, 13, 14], 2], # 7 H, A S, 9 S, Q D, A D, 2 D - pair of A for 2 ] for case in cases: cardsDealt, maxScoreCorrect = case result = scorer.scorePossible4CardHand(cardsDealt) scoreMap = result['scoreMap'] maxScore = scoreMap.max() self.assertEqual( maxScore, maxScoreCorrect, msg="predicted max {} correct max {} with hand {}".format( maxScore, maxScoreCorrect, cardsDealt))
def test_Cache(self): ''' Verify that items are cached in the correct location ''' scorer = HandScorer() score = scorer([0, 1, 2, 3], 4) # verify order independent self.assertEqual(score, 12) self.assertEqual(scorer.scores_15s[1, 2, 3, 4, 5], 2) # uses count value as idx self.assertEqual(scorer.scores_pairs[1, 2, 3, 4, 5], 0) # uses face value as idx self.assertEqual(scorer.scores_straight[1, 2, 3, 4, 5], 5) # uses face value as idx score = scorer([0, 1, 2, 3], None) # verify order independent self.assertEqual(score, 8) self.assertEqual(scorer.scores_15s_4card[1, 2, 3, 4], 0) # uses count value as idx self.assertEqual(scorer.scores_pairs_4card[1, 2, 3, 4], 0) # uses face value as idx self.assertEqual(scorer.scores_straight_4card[1, 2, 3, 4], 4) # uses face value as idx
def __init__(self, player1Type, player2Type, player1Name="Player1", player2Name="Player2", scorer=None, verbose=True): ''' player<1,2>Type is the type of player, options are: * 'random' * 'HighestAverageHandPlayer' scorer: Instance of a Scorer class. Can pass in one so the cache is primed ''' if player1Type.lower() == "random": self.player1 = RandomPlayer(name=player1Name) elif player1Type.lower() == 'bestminimalscore': self.player1 = BestMinimalScorePlayer(name=player1Name) elif player1Type.lower() == 'best4cardhand': self.player1 = Best4CardHandPlayer(name=player1Name) elif player1Type.lower() == 'besthandandcrib': self.player1 = BestHandAndCribPlayer(name=player1Name) elif player1Type.lower() == 'scorepegging': self.player1 = ScorePeggingPlayer(name=player1Name) elif player1Type.lower() == 'besthandandcribandscorepegging': self.player1 = BestHandAndCribAndScorePeggingPlayer( name=player1Name) elif player1Type.lower() == 'bestminimalhandandscorepegging': self.player1 = BestMinimalHandAndScorePeggingPlayer( name=player1Name) else: raise ValueError( "Invalid player type {} for player1".format(player1Type)) if player2Type.lower() == "random": self.player2 = RandomPlayer(name=player2Name) elif player2Type.lower() == 'bestminimalscore': self.player2 = BestMinimalScorePlayer(name=player2Name) elif player2Type.lower() == 'best4cardhand': self.player2 = Best4CardHandPlayer(name=player2Name) elif player2Type.lower() == 'besthandandcrib': self.player2 = BestHandAndCribPlayer(name=player2Name) elif player2Type.lower() == 'scorepegging': self.player2 = ScorePeggingPlayer(name=player2Name) elif player2Type.lower() == 'besthandandcribandscorepegging': self.player2 = BestHandAndCribAndScorePeggingPlayer( name=player2Name) elif player2Type.lower() == 'bestminimalhandandscorepegging': self.player2 = BestMinimalHandAndScorePeggingPlayer( name=player2Name) else: raise ValueError( "Invalid player type {} for player2".format(player2Type)) if type(scorer) is HandScorer: self.handScorer = scorer elif type(scorer) is str: # check the testing case, prevents from allocating/deallocating 100's of MB of RAM # when running tests # As of 20200608, using this takes test time from 2.5s to 1.7s if scorer.lower() == "do-not-create": self.handScorer = None else: self.handScorer = HandScorer() else: self.handScorer = HandScorer() self.verbose = verbose self.deck = Deck.Deck() self.player1Score = 0 self.player2Score = 0 # Flag to control who deals. True means player 1, False means player 2 # Is inverted at the start of self.playHand() self.player1Dealer = False # Flag for signaling the end of the game. # This is set by calling self._checkGameOver() self.gameOver = False
from Cribbage import Game,HandScorer import time if __name__ == "__main__": scorer = HandScorer() gamesToPlay = 100 printEvery = int(gamesToPlay//10) startTime = time.time() player1Wins = 0 for ii in range(gamesToPlay): handTime = time.time() game = Game("random","BestMinimalHandAndScorePegging",scorer=scorer,verbose=False) game.playGame() if game.player1Score > game.player2Score: player1Wins += 1 handTime = time.time() - handTime elapsedTime = time.time() - startTime handTimeAvg = elapsedTime/(ii+1) remaining = (gamesToPlay - ii) / handTimeAvg p1WinRate = float(player1Wins)/(ii+1)*100 if not ii%printEvery: print("Game {} Player1 win rate: {:.1f} Elapsed: {:.1f} Remaining: {:.1f} Average per hand: {:.3f}".format(ii, p1WinRate, elapsedTime, remaining, handTimeAvg)) print("Player 1 won {}/{} games, {:.1f}%".format(player1Wins,gamesToPlay,float(player1Wins)/gamesToPlay*100.))