普通人都能看懂的德州扑克-python版

德州扑克

德州扑克不使用鬼牌,只使用52张扑克牌,是一种不换牌扑克游戏。

牌局进行流程
第一轮前先决定座位及起始发牌位置。
1、洗牌并切牌。
2、本次轮到担任盲注的牌手下盲注。
3、为每位牌手发两张底牌。
4、翻牌前(preflop)喊注。
5、消一张牌后发出三张公共牌。
6、翻牌圈(flop)喊注。
7、消一张牌后发出一张公共牌(转牌)。
8、转牌圈(turn)喊注。
9、消一张牌后发出一张公共牌(河牌)。
10、河牌圈(river)喊注。
11、若有两家或以上未盖牌则斗牌比大小,依胜负分配总彩金。
12、结束本回合,庄家位置依顺时钟次序移动至下一家进行下一轮。

牌型大小规则

  • 牌型大小依序为:同花大顺 > 同花顺 > 四条 > 葫芦 > 同花 > 顺子 > 三条 > 两对 > 一对 > 散牌
  • 同花大顺/皇家同花顺:同花色的A,K,Q,J和10
  • 同花顺:五张同花色的连续数字牌
  • 四条:其中四张是相同数字的扑克牌,第五张是剩下牌组中最大的一张牌
  • 满堂红:由三张相同数字及任何两张其他相同数字的扑克牌组成
  • 同花:同一花色的任意五张牌
  • 顺子:由五张连续数字扑克牌组成
  • 三条:由三张相同数字和两张不同数字的扑克牌组成
  • 两对:两对数字相同但两两不同的扑克和一张杂牌组成
  • 一对:由两张相同数字的扑克牌和另三张无法组成牌型的杂牌组成
  • 散牌:无法组成以上任一牌型的杂牌

概要需求分析

  1. 首先,要模拟出一副不含鬼牌扑克牌并进行洗牌
  2. 接着我们要为玩家分发扑克牌
  3. 最后我们要判断玩家手中的牌的类型

编码实现

模拟扑克牌(文件:card.py)

需求分析:
我们需要模拟出52张扑克牌,涵盖了四种花色、13个数字,其中A、J、Q、K四个数字比较特殊,我们需要对其进行特殊处理。
因此,该类需要有两个成员属性——花色和数字(即color和value)并对其进行封装(@property、@color.setter、@value.setter)
在实例化Card对象时,数字为1-13,其中1为A,11、12、13分别为J、Q、K,为了将扑克牌更直观的展现给用户,我们可以通过复写__str__方法来实现这种效果。在__str__方法内,我们将1、11、12、13分别转换为A、J、Q、K进行输出。

class Card:
    """
    Card类:用于模拟与描述单张扑克牌的类
    """
    def __init__(self):
        """
        构造方法
        两个成员变量分别表示该张扑克牌的花色和数字
        """
        self.__color = ''
        self.__value = 1

    @property
    def color(self):
        """
        相当于java中的color的getter方法
        :return:
        """
        return self.__color

    @color.setter
    def color(self, value):
        """
        相当于java中的color的setter方法
        :param value:
        :return:
        """
        self.__color = value

    @property
    def value(self):
        """
        相当于java中的value的getter方法
        :return: 
        """
        return self. __value

    @value.setter
    def value(self, v):
        """
        相当于java中的value的setter方法
        :param v: 
        :return: 
        """
        # 防止非法扑克牌的出现
        if v < 1 or v >= 14:
            self.__value = 1
        else:
            self.__value = v

    def __str__(self):
        """
        相当于java中的toString()方法
        :return: 
        """
        # 定义特殊点数字典
        special_value = {1: 'A', 11: 'J', 12: 'Q', 13: 'K'}
        # 如果赋值的点数在特殊的点数中,那么我们需要处理一下
        if self.value in special_value:
            # 将特殊点数key对应的value取出来
            real_value = special_value[self.value]
        else:
            # 如果不是特殊的点数,那么转成字符串即可
            real_value = str(self.__value)
        #拼接输出对象信息 花色+点数
        return self.__color + real_value+" "

测试:

from card import Card

card1 = Card()
card1.color = '♥'
card1.value = 1

print('card1', card1)
print('card1\'s color', card1.color)
print('card1\'s value', card1.value)
------------------------------------------------------------------------
结果:
card1 ♥A 
card1's color ♥
card1's value 1

模拟发牌(文件:poke.py)

需求分析:
在发牌前我们需要有一副扑克牌,所以我们需要提供生成一副扑克牌的方法,而最好的实现方式就是在实例化时就已经生成了一副,所以我们可以将生成一副扑克牌的方法写在构造函数里。
显然,在发牌前我们必须保证这副扑克牌不是按照顺序摆放的,我们需要保证他是乱序的,我们可以通过random模块中的shuffle方法来进行乱序排序。
我们知道,德州扑克每个玩家的手牌是五张,所以我们只要抽取五张牌给玩家即可,可以通过切片的方式将扑克牌列表分割。通过字典的方式绑定玩家与其手牌,手牌使用列表,在发完牌后将此字典返回。

from card import Card
from random import shuffle

class Poke:
    def __init__(self):
        """
        构造方法
        在Poke类被实例化时就生成一副有序扑克牌(没有鬼牌)
        """
        colors = ["♥", "♠", "♣", "♦"]
        values = [i for i in range(1, 14)]

        # 装牌列表
        self.poke = []

        # 生产牌
        for color in colors:
            for value in values:
                # 生产card
                c = Card()
                # 赋值花色
                c.color = color
                # 赋值点数
                c.value = value
                # 拼接
                self.poke.append(c)
    
    def __show(self):
        """显示所有的扑克牌"""
        index = 0
        for card in self.poke:
            if index % 13 == 0:
                print("")
            print(card, end='')
            index += 1

    def shuffle(self):
        """洗牌"""
        shuffle(self.poke)

    def deal_poke(self, playerNum):
        """发牌"""
        players = dict()
        for i in range(0, playerNum):
            cards = self.poke[i * 5:i * 5 + 5]
            players['player' + str(i + 1)] = cards
        return players

判断类型(文件:play.py)

需求分析:
由于玩家人数不确定,所以需要进行排错处理,德州扑克的玩家数是2-9,所以当用户输入错误玩家数时,会给予提示,无法开始游戏。
判断玩家手牌类型是一个比较难的地方。根据惯性思维,只要这个玩家满足了高等级的牌型,就不许用再去判断他是否满足低等级的牌型了,因此我们直接从最大的牌型来判断,并依次降低,即判断的顺序为同花大顺 > 同花顺 > 四条 > 葫芦 > 同花 > 顺子 > 三条 > 两对 > 一对 > 散牌。
皇家同花顺: 首先必须是同色花,即花色的种类只有一种;其数值类型只有一种选择(1、10、11、12、13),因此我们可以直接使用暴力比较,将列表[1, 10, 11, 12, 13]与排序后的values进行比较。
同花顺: 首先判断同色花;然后判断是否是连续的五张牌,五张连续的牌必然是五种类型,并且极差是4
四条: 首先,具有两种类型的数值;其次数值数量多的牌的个数与数值数量少的牌的个数相差3;并且要求单独的那一张牌是最大的。分析后两个需求,即小的数的个数要比大的数的个数多3个,因此我们可以获取小的数的个数和大的数的个数来进行做差。【那么事实上,在第二种思路下我们就没有必要去考虑数值种类了,因为相差是,相加是5,只能有一种结果,就是4-1,即只会有两种类型的数值。也就是我们将valuesLen == 2条件删掉也不会影响结果】
满堂红: 首先,有两种类型的数值;其次,一种数值有三个,另一种数值有两个,即较多数值类型的个数与较少数值类型的个数之差是1。【这个时候必须要判断数值类型种类数,因为3-2等于1,2-1也等于1,例2、2、5、5、6】
同花: 很简单,只有一种花色即可
顺子: 不需要考虑花色。五种数值类型、极差为4
三条: 首先,三种数值类型;其次较多数值类型的个数与较少数值类型的个数之差是2。
两对: 首先,三种数值类型;其次较多数值类型的个数与较少数值类型的个数之差是1。
一对: 首先,四种数值类型;其次较多数值类型的个数与较少数值类型的个数之差是1。
散牌: 除以上内容即是散牌。

from poke import Poke

class Play:
    def __init__(self, number=5):
        """
        初始化扑克堆并进行发牌
        :param number: 参与人数
        """
        self.poke = Poke()
        self.poke.shuffle()
        if number < 2 or number > 10:
            print('玩家数错误,无法开始游戏')
        self.players = self.poke.deal_poke(number)

    def showPlayers(self):
        """展示所有玩家"""
        print(self.players.keys())

    def showPlayerCard(self, player):
        """展示指定玩家的牌"""
        cards = self.players[player]
        print(player + '\'s cards: ', end='')
        for card in cards:
            print(card, end='')
        print()

    def showAllPlayersCard(self):
        """展示所有玩家的牌"""
        for player in self.players.keys():
            self.showPlayerCard(player)

    def showPlayerCardsType(self, player):
        """
        展示指定玩家的牌型
        :param player:
        :return:
        """
        # 获取该玩家的手牌
        cards = self.players[player]
        # 将该玩家的手牌的花色和数值分开
        colors = []
        values = []
        for card in cards:
            colors.append(card.color)
            values.append(card.value)
        # 获取该玩家手牌的花色和数值的种类数
        # set()集合不允许重复,通过set()强制转型并取其长度,即可获得种类数
        colorsLen = len(set(colors))
        valuesLen = len(set(values))

        # 获取该玩家手牌中 数值数量最多的牌的数量 与 数值数量最少的牌的数量 之差,最终结果为sameCardNum
        # result,统计每种数值类型的个数的字典
        # 例对于 3, 4, 4, 5, 5 数值数量分别为3:一个,4:两个,5:两个,所以...之差为2-1 = 1,result={3: 1, 4: 2, 5: 2}
        # 例对于 4, 4, 4, 4, 5 数值数量分别4:四个,5:一个,所以...之差为4-1 = 3,result={4: 4, 5: 1}
        result = dict()
        for i in values:
            if i not in result.keys():
                result[i] = 1
            else:
                result[i] += 1
        sameCardNum = max(result.values()) - min(result.values())

        print('玩家' + player + '的牌型是')
        if colorsLen == 1 and [1, 10, 11, 12, 13] == sorted(values):
            print('大同花顺')
        elif colorsLen == 1 and valuesLen == 5 and max(values) - min(values) == 4:
            print('同花顺')
        elif valuesLen == 2 and result[min(result.keys())] - result[max(result.keys())] == 3:
            print('四条')
        elif valuesLen == 2 and sameCardNum == 1:
            print('满堂红')
        elif colorsLen == 1:
            print('同花')
        elif valuesLen == 5 and max(values) - min(values) == 4:
            print('顺子')
        elif valuesLen == 3 and sameCardNum == 2:
            print('三条')
        elif valuesLen == 3 and sameCardNum == 1:
            print('两队')
        elif valuesLen == 4 and sameCardNum == 1:
            print('一对')
        else:
            print('散牌')

    def showAllPlayersCardsType(self):
        """
        展示所有玩家的牌型
        :return:
        """
        for i in self.players.keys():
            self.showPlayerCardsType(i)

开始游戏(文件:game.py)

需求分析: 开始游戏的程序千变万化,不做分析
代码分析: 玩家人数需要用户输入,因此加入了排错的代码;选择2和选择4需要用户输入,加入排错代码,此处排错直接使用异常处理,当在字典中查询不到数据时,会报出异常,直接在此处进行捕获处理即可;选择6直接结束本循环即可;选择7除了需要结束本循环以外,还要将外循环的flag修改为False

from play import Play

if __name__ == '__main__':
    print('欢迎进入德州扑克游戏!')
    flag = True
    while flag:
        number = int(input('请输入玩家人数(2-9):'))
        if number < 2 or number > 10:
            print('玩家人数有误,请重新输入:')
            continue
        play = Play(number)
        print('扑克牌已为您分发完成')
        while True:
            choice = int(input('''请输入您的选择:
1、查看所有玩家            2、查看指定玩家的手牌
3、查看所有玩家的手牌       4、查看指定玩家的手牌类型
5、查看所有玩家的手牌类型   6、重新开始游戏    7、退出游戏

'''))
            if choice == 1:
                play.showPlayers()
            elif choice == 2:
                player = input('请输入您要查看的玩家:')
                try:
                    play.showPlayerCard(player)
                except:
                    print('没有该玩家!')
            elif choice == 3:
                play.showAllPlayersCard()
            elif choice == 4:
                player = input('请输入您要查看的玩家:')
                try:
                    play.showPlayerCardsType(player)
                except:
                    print('没有该玩家!')
            elif choice == 5:
                play.showAllPlayersCardsType()
            elif choice == 6:
                break
            elif choice == 7:
                flag = False
                break
            else:
                print('您输入的数字有误!')
    print('欢迎您下次再来')


致读者:打牌不在笔者的爱好之内且不善python,游戏规则有误或需补充、代码如有不当之处,请及时指出,笔者感激不尽。

  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
下面是一个简单的Java代码实现德州扑克的基本规则: ```java import java.util.ArrayList; import java.util.Collections; public class TexasHoldem { private ArrayList<Card> deck; private ArrayList<Card> flop; private Card turn; private Card river; private ArrayList<Player> players; private int dealerIndex; private int smallBlindIndex; private int bigBlindIndex; private int pot; private int currentBet; public TexasHoldem() { deck = new ArrayList<Card>(); flop = new ArrayList<Card>(); players = new ArrayList<Player>(); // 初始化扑克牌 for (int i = 2; i <= 14; i++) { deck.add(new Card(i, "spades")); deck.add(new Card(i, "hearts")); deck.add(new Card(i, "clubs")); deck.add(new Card(i, "diamonds")); } // 随机洗牌 Collections.shuffle(deck); dealerIndex = 0; smallBlindIndex = (dealerIndex + 1) % players.size(); bigBlindIndex = (dealerIndex + 2) % players.size(); pot = 0; currentBet = 0; } public void play() { deal(); bettingRound(); flop(); bettingRound(); turn(); bettingRound(); river(); bettingRound(); showdown(); } public void deal() { // 发两张手牌给每个玩家 for (Player player : players) { for (int i = 0; i < 2; i++) { player.addCard(deck.remove(0)); } } } public void flop() { // 翻开三张公共牌 for (int i = 0; i < 3; i++) { flop.add(deck.remove(0)); } } public void turn() { // 翻开转牌 turn = deck.remove(0); } public void river() { // 翻开河牌 river = deck.remove(0); } public void bettingRound() { int currentPos = bigBlindIndex; int lastRaisePos = -1; while (true) { Player currentPlayer = players.get(currentPos); int bet = currentPlayer.getBet(currentBet); if (bet == -1) { // 弃牌 players.remove(currentPlayer); if (players.size() == 1) { // 游戏结束,只剩下一个玩家 break; } } else if (bet > currentBet) { // 加注 pot += (bet - currentBet); currentBet = bet; lastRaisePos = currentPos; } else if (bet < currentBet) { // 不能下注低于当前的赌注 continue; } else if (currentPos == lastRaisePos) { // 所有玩家都跟注或弃牌,进入下一轮 break; } currentPos = (currentPos + 1) % players.size(); } } public void showdown() { Player winner = null; Hand bestHand = null; for (Player player : players) { Hand hand = player.getHand(flop, turn, river); if (bestHand == null || hand.compareTo(bestHand) > 0) { winner = player; bestHand = hand; } } winner.winPot(pot); } public void addPlayer(Player player) { players.add(player); } public void nextDealer() { dealerIndex = (dealerIndex + 1) % players.size(); smallBlindIndex = (dealerIndex + 1) % players.size(); bigBlindIndex = (dealerIndex + 2) % players.size(); } public static void main(String[] args) { TexasHoldem game = new TexasHoldem(); game.addPlayer(new Player("Alice")); game.addPlayer(new Player("Bob")); game.addPlayer(new Player("Charlie")); while (game.players.size() > 1) { game.play(); game.nextDealer(); } Player winner = game.players.get(0); System.out.println("Winner: " + winner.getName()); } } class Player { private String name; private ArrayList<Card> hand; private int chips; public Player(String name) { this.name = name; hand = new ArrayList<Card>(); chips = 1000; } public void addCard(Card card) { hand.add(card); } public int getBet(int currentBet) { // 玩家决定下注的策略 return 0; } public Hand getHand(ArrayList<Card> flop, Card turn, Card river) { ArrayList<Card> allCards = new ArrayList<Card>(); allCards.addAll(hand); allCards.addAll(flop); allCards.add(turn); allCards.add(river); return new Hand(allCards); } public void winPot(int pot) { chips += pot; } public String getName() { return name; } } class Card { private int rank; private String suit; public Card(int rank, String suit) { this.rank = rank; this.suit = suit; } public int getRank() { return rank; } public String getSuit() { return suit; } } class Hand implements Comparable<Hand> { private ArrayList<Card> cards; private int rank; public Hand(ArrayList<Card> cards) { this.cards = cards; rank = calculateRank(); } private int calculateRank() { // 计算牌型的排名 return 0; } public int getRank() { return rank; } public int compareTo(Hand other) { return rank - other.getRank(); } } ``` 这个代码实现了德州扑克的基本规则,包括发牌、下注、翻牌、比牌等操作。其中,玩家可以通过实现`getBet`方法来决定下注的策略。这个方法的参数`currentBet`表示当前的赌注,玩家可以选择下注、跟注、加注或弃牌。在比牌时,利用`Hand`类来计算玩家的最好牌型,并比较各个玩家的牌型大小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值