十点半纸牌游戏设计与实现

十点半是一种流行的纸牌游戏,本文将详细介绍如何使用Python实现一个四人十点半游戏,包括游戏规则、核心功能和完整代码实现。

游戏规则

  1. 参与人数:4人游戏,1号为庄家,其余三人为闲家
  2. 初始筹码:每人开局100个筹码
  3. 发牌规则
    • 开局每人发一张牌
    • 闲家根据情况选择是否要牌
    • 点数大的玩家获胜
  4. 点数计算
    • J/Q/K称为"人牌",代表0.5点
    • A代表1点
    • 其他牌按面值计算
    • 点数超过10.5就输,称为"爆牌"
  5. 胜负判定
    • 某玩家点数最大且全场没有相同点数:单人获胜
    • 某玩家点数最大但存在相同点数:所有持最大点数的玩家都获胜
    • 所有玩家都爆牌:下注金额全部归庄家

游戏特色功能

  1. 特殊牌型奖励
    牌型 条件 奖励倍数
    大天王 9张牌正好10.5点 下注×10
    九小 9张牌小于10.5点 下注×9
    八小 8张牌小于10.5点 下注×8
    七小 7张牌小于10.5点 下注×7
    六小 6张牌小于10.5点 下注×6
    天王 5张牌正好10.5点 下注×5
    人五小 5张牌且包含3张人牌 下注×4
    五小 5张牌小于10.5点 下注×3
  2. 多轮游戏:支持连续多轮游戏,直到有玩家选择退出

代码实现

1. 初始化游戏

import random  # 导入随机函数库

# 定义函数,功能:分行打印玩家
def print_player(player):
    for i in range(len(player)):
        print(player[i][:-1])

# 定义初始化玩家
def create_player(player):
    for number in range(4):
        if number == 0:
            player_name = input("请输入庄家的姓名:")
            player[number].append(player_name)  # 给玩家添加姓名
        else:
            player_name = input("请输入第" + str(number) + "个闲家的姓名:")
            player[number].append(player_name)  # 给玩家添加姓名
        player_money = 100
        player[number].append(player_money)  # 初始化玩家的筹码为100
        player_flag = True
        player[number].append(player_flag)  # 初始化玩家要牌标志符为Ture
        player_cards = []
        player[number].append(player_cards)  # 初始化玩家的牌列表为空
        player_pointSum = 0
        player[number].append(player_pointSum)  # 初始玩家的牌点数位0
        player_bet = 0
        player[number].append(player_bet)  # 初始玩家的下注点数位0
        player_against = True
        player[number].append(player_against)  # 初始化玩家的再玩一局为True
    return player

2. 洗牌和下注功能

# 定义模拟洗牌
def create_cards():
    # 生成一副扑克牌
    RANKS = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
    SUITS = ["", "", "", ""]
    
    # 模拟生成一副牌
    cards = []
    for i in RANKS:
        for j in SUITS:
            cards.append(i + j)
    
    # 洗牌
    random.shuffle(cards)
    return cards

# 定义模拟下注函数
def bet(player):
    # 模拟用户下注
    i = 1  # 只有闲家才需要下注
    while i <= 3:
        while True:
            try:
                player_bet = input(player[i][0] + ":请下注(0-20)")
                while int(player_bet) > 20 or int(player_bet) < 1 or int(
                        player_bet) > int(player[i][1]):
                    player_bet = input(player[i][0] + ":下注超过了极限,请重新下注")
            except BaseException:
                player_bet = input(player[i][0] + ":下注输入不正确,请重新下注")
            else:
                player[i][5] = int(player_bet)
                i = i + 1
                if i == 4:
                    print("三个闲家下注完成")
                    break
    return(player)

3. 点数计算和特殊牌型判断

# 计算牌点数
def calculate_card(card):
    if card[0] == "J" or card[0] == "Q" or card[0] == "K":
        cardpoint = 0.5
    elif card[0] == "A":
        cardpoint = 1
    elif len(card) > 2:
        cardpoint = 10
    else:
        cardpoint = int(card[0])
    return cardpoint

# 特殊牌型判断
def special(flag):
    # 闲家爆了
    if flag:
        if len(player[0][3]) == 9 and player[0][4] == 10.5:
            player[0][5] *= 10
            print('大天王')
        elif len(player[0][3]) == 9 and player[0][4] < 10.5:
            player[0][5] *= 9
            print('九小')
        elif len(player[0][3]) == 8 and player[0][4] < 10.5:
            player[0][5] *= 8
            print('八小')
        elif len(player[0][3]) == 7 and player[0][4] < 10.5:
            player[0][5] *= 7
            print('七小')
        elif len(player[0][3]) == 6 and player[0][4] < 10.5:
            player[0][5] *= 6
            print('六小')
        elif len(player[0][3]) == 5 and player[0][4] == 10.5:
            player[0][5] *= 5
            print('天王')
        elif len(player[0][3]) == 5 and set(player[0][3]) | {'J','Q','K'} == 3:
            player[0][5] *= 4
            print('人五小')
        elif len(player[0][3]) == 5 and player[0][4] < 10.5:
            player[0][5] *= 3
            print('五小')
    # 庄家爆了
    else:
        for i in range(1,4):
            if len(player[i][3]) == 9 and player[i][4] == 10.5:
                player[i][5] *= 10
                print('大天王')
            elif len(player[i][3]) == 9 and player[i][4] < 10.5:
                player[i][5] *= 9
                print('九小')
            elif len(player[i][3]) == 8 and player[i][4] < 10.5:
                player[i][5] *= 8
                print('八小')
            elif len(player[i][3]) == 7 and player[i][4] < 10.5:
                player[i][5] *= 7
                print('七小')
            elif len(player[i][3]) == 6 and player[i][4] < 10.5:
                player[i][5] *= 6
                print('六小')
            elif len(player[i][3]) == 5 and player[i][4] == 10.5:
                player[i][5] *= 5
                print('天王')
            elif len(player[i][3]) == 5 and set(player[i][3]) | {'J', 'Q', 'K'} == 3:
                player[i][5] *= 4
                print('人五小')
            elif len(player[i][3]) == 5 and player[i][4] < 10.5:
                player[i][5] *= 3
                print('五小')

4. 胜负判定

def win(player):
    i = 1  # 定义变量i来记录第i个闲家与庄家比大小
    while i <= 3:
        if player[i][4] > 0:  # 如果闲家没有爆牌,则与庄家进行比较大小
            # 如果闲家和庄家都是五龙,或者都不是五龙
            if (len(player[i][3]) == 5 and (len(player[0][3]) == 5 and player[0][4] != 0)) or (
                    len(player[i][3]) <= 4 and len(player[0][3]) <= 4):
                if float(player[i][4]) > float(player[0][4]):
                    player[0][1] = int(
                        player[0][1] - int(player[i][5]))  # 庄家支付筹码给赢了的闲家
                    player[i][1] = int(player[i][1]) + int(player[i][5])
                    print(player[i][0] + "你本局赢了")
                    player[i][5] = 0
                    i = i + 1  # 轮到下一个闲家
                elif float(player[i][4]) < float(player[0][4]):
                    player[0][1] = int(
                        player[0][1] + int(player[i][5]))  # 闲家输了,支付筹码给庄家
                    player[i][1] = int(player[i][1]) - int(player[i][5])
                    print(player[i][0] + "你本局输了")
                    player[i][5] = 0
                    i = i + 1  # 轮到下一个玩家
                 # 庄家第5张牌爆牌,闲家赢
                elif len(player[0][3]) == 5 and player[0][4] == 0:
                    player[0][1] = int(player[0][1]) - int(player[i][5])
                    player[i][1] = int(player[i][1]) + int(player[i][5])
                    print(player[i][0] + "你本局赢了")
                    player[i][5] = 0
                    i = i + 1  # 轮到下一个闲家
            else:
                print(player[i][0] + "你本局输了")
                i = i + 1  # 轮到下一个闲家
        else:
            print(player[i][0] + "你本局输了")
            i = i + 1  # 轮到下一个闲家
    return player  # 返回玩家列表

主游戏循环

# 主游戏循环
player = [[], [], [], []]  # 二维的列表
player = create_player(player)  # 调用函数初始化玩家
print_player(player)  # 调用print_player实现分行打印
cards = create_cards()  # 调用函数洗牌
print(cards)

# 添加循环实现再玩一局
while len(set([i[6] for i in player])) == 1:
    # 初始化每局游戏状态
    for i in range(4):
        player[i][2] = True
        player[i][3] = []
    
    # 检查牌组剩余牌数
    if len(cards) < 20:
        print('牌数不足20 重新洗牌')
        cards = create_cards()
    
    # 下注阶段
    player = bet(player)
    print_player(player)
    
    # 发牌阶段
    j = 0  # 牌索引
    if j > 31:
        cards = create_cards()
        j = 0
    
    # 第一轮发牌
    print("从庄家开始发第一轮牌,每人一张牌")
    for i in range(4):
        player[i][3].append(cards[j])
        player[i][4] = calculate_card(cards[j])
        j += 1
    print("第一轮发牌完毕")
    print_player(player)
    
    # 闲家要牌阶段(最多4轮)
    for loop in range(2, 6):
        if any(p[2] for p in player[1:4]):
            for i in range(1, 4):
                if player[i][2]:
                    print(player[i][0] + "还要牌吗")
                    yesorno = input("请输入Y或者N").upper()
                    while yesorno not in ["Y", "N"]:
                        yesorno = input("请输入Y或N").upper()
                    
                    if yesorno == "Y":
                        player[i][3].append(cards[j])
                        player[i][4] += calculate_card(cards[j])
                        j += 1
                        
                        if player[i][4] > 10.5:
                            special(True)
                            print(f"{player[i][0]}你爆牌了,扣你{player[i][5]}筹码")
                            player[i][2] = False
                            player[i][1] -= player[i][5]
                            player[0][1] += player[i][5]
                            player[i][4] = 0
                            player[i][5] = 0
                    else:
                        player[i][2] = False
            print(f"第{loop}轮发牌结果")
            print_player(player)
        else:
            print("没有闲家要牌了")
            break
    
    # 庄家要牌阶段
    while player[0][2] and loop <= 10:
        print(player[0][0] + "还要牌吗,")
        yesorno = input("请输入Y或者N").upper()
        while yesorno not in ["Y", "N"]:
            yesorno = input("请输入Y或N").upper()
        
        if yesorno == "Y":
            player[0][3].append(cards[j])
            player[0][4] += calculate_card(cards[j])
            j += 1
            
            if player[0][4] > 10.5:
                special(False)
                total_bet = sum(p[5] for p in player[1:4])
                print(f"{player[0][0]}你爆牌了,扣你{total_bet}筹码")
                player[0][2] = False
                player[0][1] -= total_bet
                for i in range(1, 4):
                    player[i][1] += player[i][5]
                player[0][4] = 0
        else:
            player[0][2] = False
        loop += 1
        print(f"第{loop}轮发牌结果")
        print_player(player)
    
    # 胜负判定
    player = win(player)
    print_player(player)
    
    # 检查筹码
    if min(p[1] for p in player) < 0:
        print('有玩家的筹码为负数 退出游戏')
        break
    
    # 是否继续游戏
    for i in range(4):
        if input(f"{player[i][0]}是否继续玩(Y/N)").upper() != "Y":
            player[i][6] = False
            print("有人不玩了,游戏结束!")
            break

游戏特色与改进建议

当前实现特点

可能的改进方向

这个十点半游戏实现涵盖了从初始化、发牌、要牌到下注和胜负判定的完整流程,通过合理的函数划分使代码结构清晰,易于理解和扩展。游戏支持多轮进行,直到有玩家选择退出或筹码不足为止。