如何使用动态编程解决二十一点?

时间:2019-05-19 20:59:48

标签: python dynamic-programming memoization blackjack

这个问题来自Daily Coding Problem这本书,是对this MIT视频中描述的问题的稍作修改。问题如下:

  

二十一点是一款两人制纸牌游戏,规则如下:

     
      
  • 分别给玩家和发牌者两张牌。
  •   
  • 然后玩家可以“击中”或任意要求额外的卡,以使他或她的总数不超过21。
  •   
  • 如果发牌者的总分小于等于16,则必须命中,否则通过。
  •   
  • 最后,两个比较总数,而总和不超过21的是获胜者。
  •   
     

对于此问题,我们将卡值简化为:   介于2到10之间的纸牌将被视为其面值,将面部纸牌被视为   10,ace数为1。

     

完全了解甲板上纸牌的顺序,   实施二十一点求解器以最大化玩家的得分(即   是,胜利减去损失)。

这本书具有以下代码:

import random


class Deck:
    def __init__(self, seed=None):
        self.cards = [i for i in range(1, 10)] * 4 + [10] * 16
        random.seed(seed)
        random.shuffle(self.cards)

    def deal(self, start, n):
        return self.cards[start:start + n]


class Player:
    def __init__(self, hand):
        self.hand = hand
        self.total = 0

    def deal(self, cards):
        self.hand.extend(cards)
        self.total = sum(self.hand)


def cmp(x, y):
    return (x > y) - (x < y)


def play(deck, start, scores):
    player = Player(deck.deal(start, 2))
    dealer = Player(deck.deal(start + 2, 2))
    results = []

    for i in range(49 - start):
        count = start + 4
        player.deal(deck.deal(count, i))
        count += i

        if player.total > 21:
            results.append((-1, count))
            break

        while dealer.total < 17 and count < 52:
            dealer.deal(deck.deal(count, 1))
            count += 1
        if dealer.total > 21:
            results.append((1, count))
        else:
            results.append((cmp(player.total, dealer.total), count))

    options = []
    for score, next_start in results:
        options.append(score +
                       scores[next_start] if next_start <= 48 else score)
    scores[start] = max(options)


def blackjack(seed=None):
    deck = Deck(seed)
    scores = [0 for _ in range(52)]

    for start in range(48, -1, -1):
        play(deck, start, scores)

    return scores[0]

基本上,对于从卡牌n开始的副牌后缀(1 <= n <= 52),代码尝试了玩家将0带到52 - n的所有可能性命中,直到他们破产,然后经销商只要分数为<= 16,就接受命中。

对于循环for i in range(49 - start)的每次迭代,count =“已使用的卡数”被重置为start + 4,这是有道理的,因为我们正在模拟玩家采用不同的数字的点击次数比上次高。但是,困扰我的是玩家,发牌者的手未重置。在我看来,对于该循环的每次迭代,我们都应该从发给玩家和发牌人的两张牌开始,而不要保留最后一手。

我了解这个权利吗?

0 个答案:

没有答案