桌游“德国心脏病”的python代码实现

        没错!C语言小白又开始学习python啦,现在光荣晋升一位python小白,于是我又用python重新编了一次之前的游戏,具体规则请参见我的上一篇文章。

        遗憾的是,下面200行代码并没有涉及到面向对象的思想,重新编这个游戏只是为了熟悉python基础语法用来练手的。代码如下:

import random
from time import time, sleep

def input_name(): #输入每位玩家姓名(为了显示的美观性,字符长度不要超过7,1个汉字当做2个字符计算)
    for i in range(4):
        card_P[i] = input("请输入第{}位玩家的名字:".format(i+1))
    print("\n", end = '')
    sleep(0.5)

def shuffle(cards, card_num): #洗牌
    random.seed(time)
    for i in range(200):
        swap_x = random.randint(0,card_num)
        swap_y = random.randint(0,card_num)
        cards[swap_x],cards[swap_y] = cards[swap_y],cards[swap_x]

def give_card(): #发牌
    for i in range(56):
        card[i//14].append(init_card[i])
    for i in range(4): #用空字符填充每位玩家手牌至56张
        card[i] += ['']*42

def count_cards(cards): #计算传入列表中最后一个非空字符位置
    temp = -1 #用反向递减序号递减至非空字符位置,数字处理后返回
    while cards[temp] == '':
        temp -= 1
        if len(cards) == abs(temp)-1: #处理列表所有元素均为空字符的情况
            return 0
    return len(cards)-abs(temp)+1

def print_card(): #在窗体中打印每位玩家的姓名及已经打出的手牌
    global playernum
    cnt = count_cards(card_P)
    for i in range(cnt):
        print(card_P[i]+'\t\t', end = '')
        if i % playernum == playernum - 1 and i != cnt-1: #断行
            print('\n')
    print('\n')

def judge(): #判断是否满足奖励条件
    global fruits_num, playernum
    fruits_num = [0, 0, 0, 0] #表示明牌区不同种类水果牌对应水果个数
    for i in range(playernum, count_cards(card_P)):
        d = {'香蕉':0, '草莓':1, '樱桃':2, '柠檬':3}
        if card_P[i] != '': #处理空字符索引越界情况
            fruits_num[d[card_P[i][0:2]]] += int(card_P[i][2]) #水果个数累加
    print("{:*^54}".format("水果个数"))
    print("{:13}{:13}{:13}{:13}\n".format('香蕉'+str(fruits_num[0])+'个','草莓'+str(fruits_num[1])\
          +'个','樱桃'+str(fruits_num[2])+'个','柠檬'+str(fruits_num[3])+'个')+'*'*58+"\n")
    ls_back = [] #表示满足奖励条件的水果牌种类
    for i in range(4):
        if fruits_num[i]%5 == 0 and fruits_num[i] != 0:
            ls_back.append(i)
    return ls_back #返回满足奖励条件的水果牌种类

def punish(n): #罚牌
    rec_player = [0, 1, 2, 3]
    rec_player.remove(n) #在罚牌过程中获得牌的玩家列表
    for i in rec_player:
        if out_flag[i] == 0: #已出局的玩家不能获得牌
            card[i][card[i].index('')] = card[n].pop(0)
            card[n].append('')

def reward(n, fruit_kinds): #奖励牌
    d = {0:'香蕉', 1:'草莓', 2:'樱桃', 3:'柠檬'}
    i = playernum
    for kind in fruit_kinds:
        while i < count_cards(card_P):
            if card_P[i] != '' and card_P[i][0:2] == d[kind]: #明牌区符合条件的水果牌交给第n位玩家
                card[n][card[n].index('')] = card_P[i]
                for j in range(15):
                    if j*playernum+i < 155: #将待删除的牌用下一位置的牌覆盖
                        card_P[j*playernum+i] = card_P[(j+1)*playernum+i]
                i -= 1
            i += 1
        shuffle(card[n], card[n].index('')-1) #玩家得到牌之后洗牌
        for i in range(4): #同时清除另一明牌区符合条件的牌(明牌区有两个:card_P,show_card,暗牌区是card)
            for j in range(56):
                if show_card[i][j] != '' and show_card[i][j][0:2] == d[kind]:
                    show_card[i][j] = ''

def del_empty_string(): #删除列表中某些元素
    global playernum, counts, card_P
    i = 0
    while i < counts-playernum + 2: #删除card_P列表中counts位置之前连续的playernum个空字符
        if card_P[i:i+playernum] == ['']*playernum:
            del card_P[i:i+playernum]
            card_P += ['']*playernum #此行代码使card_P变成局部变量!!!
            i -= 1; counts -= playernum
        i += 1
    for i in range(4): #删除show_card[i]列表中非空字符之前的空字符
        while show_card[i].index('') < count_cards(show_card[i]):
            del show_card[i][show_card[i].index('')]
            show_card[i].append('')

def ring_bell(): #按铃阶段
    bell = input('请按铃:')
    print("\n", end = '')
    if bell[0] == '0':
        return None
    elif bell[0] in ['q', 'p', 'z', 'm']:
        d = {'q':0, 'p':1, 'z':2, 'm':3} #将输入的按键转化为明确代表玩家身份的数字0,1,2,3
        fruit_kinds = judge() #接收满足条件的水果牌(可能是空列表,没有满足条件的牌)
        sleep(1)
        if len(fruit_kinds) == 0: #判断是否有水果牌满足条件
            if card[d[bell[0]]].index('') == 0:
                print("判断错误!您手上没有牌可以惩罚。\n")
            else:
                print("判断错误!已惩罚。\n")
            punish(d[bell[0]])
        else:
            reward(d[bell[0]], fruit_kinds)
            del_empty_string() #执行reward之后,show_card和card_P列表中出现可以被删除的空字符
            print("判断正确!已奖励。\n")
        print_surplus_cards(cal_cards())
    else:
        print("请输入正确的按键!\n")
        ring_bell()

def judge_out(): #判断是否有人出局
    global playernum, counts
    temp = 0 #用于指示第temp个出局标志为0的玩家(当玩家数小于4时提供正确的card_P索引)
    for i in range(4): #遍历四个玩家以判断是否满足出局条件
        if out_flag[i] == 0:
            if card[i].index('')+count_cards(show_card[i]) == 0:
                sleep(1)
                print("{:=^54}".format(card_P[temp]+"出局")+"\n")
                out_flag[i] += 1 #该玩家出局标志置为1
                del card_P[temp:counts+1:playernum] #清除该出局玩家对应的牌
                counts -= counts//playernum + 1 #明牌区索引变量随之改变
                playernum -= 1
            temp += 1

def print_surplus_cards(cards): #打印场上玩家剩余牌数
    global playernum
    sleep(1)
    temp = 16*playernum-14
    print('-'*(temp//2)+"剩余牌数"+'-'*(temp//2))
    for i in range(len(cards)):
        print("{:4}:{:>2}张\t".format(card_P[i], cards[i]), end = '')
    print('\n'+'-'*(temp+8)+"\n\n\n")

def cal_cards(): #计算储存场上玩家牌数的列表
    cards = []
    for i in range(4):
        if out_flag[i] == 0:
            cards.append(card[i].index('')+show_card[i].index(''))
    return cards

def judge_over(playernum): #判断游戏是否结束
    cards = cal_cards()
    isTrue = card[0].index('') == 0 and card[1].index('') == 0 and card[2].index('') == 0 and card[3].index('') == 0
    if playernum == 2 or isTrue: #玩家只剩下两人或者所有人的牌出完时游戏结束
        print_surplus_cards(cards)
        for i in range(len(cards)):
            if cards[i] == max(cards):
                break
        sleep(3)
        print("{:=^54}".format("游戏结束")+"\n")
        if isTrue:
            print("所有人的牌出完了,", end = '')
        print("{}胜利!\n".format(card_P[i]))
        return 1
    return 0

def play(): #游戏正式开始
    print("{:=^54}".format("游戏开始")+"\n")
    sleep(1)
    global playernum, counts
    i = 0 #用于指示出牌局数
    while i < 1000:
        if out_flag[i % 4] == 1: #玩家出局时跳过该玩家出牌局
            i += 1
        cnt1 = i % 4
        cnt2 = i // 4
        if input("请{}输入0出牌:".format(card_P[counts%playernum])) == '0':
            sleep(1)
            if card[cnt1][0] != '': #处理无牌可出情况
                card[cnt1].append('')
                show_card[cnt1][cnt2] = card[cnt1].pop(0) #show_card列表中将出现可以被删除的空字符
                cnt_temp = counts
                if out_flag[cnt1] == 0:
                    while card_P[cnt_temp] == '':
                        cnt_temp -= playernum
                    card_P[cnt_temp+playernum] = show_card[cnt1][cnt2]
                del_empty_string() #删除上述空字符
                print_card()
                ring_bell()
                judge_out()
                sleep(1)
                if judge_over(playernum):
                    break
            else:
                print("\n嘿嘿!您手上没牌了哦。\n")
                sleep(1)
            i += 1; counts += 1
        else:
            print("\n请输入正确的按键!\n")

init_card = ['香蕉1']*5+['香蕉2']*3+['香蕉3']*3+['香蕉4']*2+['香蕉5']+\
            ['草莓1']*5+['草莓2']*3+['草莓3']*3+['草莓4']*2+['草莓5']+\
            ['樱桃1']*5+['樱桃2']*3+['樱桃3']*3+['樱桃4']*2+['樱桃5']+\
            ['柠檬1']*5+['柠檬2']*3+['柠檬3']*3+['柠檬4']*2+['柠檬5']
card = [[], [], [], []] #card的0,1,2,3四个位置分别代表四个玩家的手牌(暗牌区)
show_card = [['']*56, ['']*56, ['']*56, ['']*56] #show_card的0,1,2,3四个位置分别代表四个玩家已经打出的手牌(明牌区)
playernum = 4 #记录场上玩家数目,当有玩家出局时更新此变量,不同函数的执行过程和结果随该变量发生改变
card_P = ['']*160 #储存用于在窗体打印的玩家姓名和打出的手牌
out_flag = [0, 0, 0, 0] #玩家是否出局的标志,0,1,2,3四个位置分别代表四个玩家
fruits_num = [0, 0, 0, 0] #记录场上不同种类水果牌对应水果数目,0,1,2,3四个位置分别代表香蕉、草莓、樱桃、柠檬
counts = 4 #用于指示card_P列表下标索引
input_name()
print("…………发牌中…………\n")
sleep(3)
shuffle(init_card, 55)
give_card()
play()

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值