python小游戏——Crazy Eights(纸牌游戏)

Crazy Eights

一、游戏规则

Crazy Eights是脱落型 卡片游戏二至七名球员。游戏的目标是成为第一个丢弃所有牌的玩家。游戏类似于SwitchMau Mau[1]

原文:Crazy Eights is a shedding-type card game for two to seven players. The object of the game is to be the first player to discard all of their cards. The game is similar to Switch and Mau Mau.[1] ——来自维基百科

规则介绍:

  • 是有两个玩家参与的游戏。
  • 每个玩家有 5 张 牌,其他的牌都面朝下扣着。翻开一张牌,开始出牌。
  • 这个游戏的目标是要在另一 个人之前而且在取完一副牌之前出光所有牌

二、开发环境

  • GUI工具:   PyQt5
  • python:Python 3.9.2
  • 该游戏基于文本的版本

三、详细介绍

1) 每一轮,玩家必须做下面的操作之一:

         出一张牌,要与翻开的牌花色相同;

         出一张牌,要与翻开的牌点数相同;

         出一张 8。

2) 如果玩家出了一张 8,他可以“叫花色”,这说明他可以选择花色,下一个玩家要根据这个花色出牌。

3) 如果玩家无法出牌,必须从这副牌中选择一张牌,增加到自己手中。

4) 如果玩家出光了手中的所有牌,他就赢了,根据另一个玩家手中剩余的牌计 算得分:

         每个 8 得 50 分;

         每个花牌(J、Q 和 K)得 10 分;

         每个其他的牌按分值得分;

         每个 A 得 1 分。

5) 如果一副牌发光时仍没有人获胜,游戏结束。在这种情况下,每个玩家会根 据对方剩余的牌计算得分。

6) 可以一直玩到达到某个总分,或者直到你累了,得分最高的获胜。

四、程序工作

  •   跟踪面朝上的牌。
  •   得到玩家的下一步选择(出牌还是抽牌)。
  •  如果玩家想出牌,要确保出牌是合法的:

         ■ 这张牌必须是合法的牌;

         ■ 这张牌必须在玩家的手里;

         ■ 这张牌要与面朝上的牌花色或点数一致,或者是一个 8。

  • 如果玩家出一张 8,叫一个新的花色(并确保选择的是一个合法的花色)。
  • 轮到计算机选择(稍后介绍)。
  • 确定游戏何时结束。
  • 统计得分。

五、代码部分

5.1 创建一副牌

需要了解:

例如:开始时是一整副牌, 抽出红桃4的机会是1/52,或者大约2%。这是因为副牌里有52张牌,而只有一张红桃4。

如果继续抽牌(还没有抽到红桃4),整副牌只剩下一-半时,得到红桃4的机会就是1/26,或者大约4%。

剩下最后一张牌时,如果还没有抽到红桃4,说明抽出红桃4的机会就是1/1,或者100%。可以肯定下个肯定会抽到红桃4,因为只剩下这一-张牌了。

体现了一副牌在抽中时,剩下的牌越来越少,这会改变抽出剩余各纸牌的概率。

得出:如果要创建一个利用一副纸牌实现的计算机游戏,需要在整个过程中跟踪已经从这副牌中取走了哪些牌

🍿创建纸牌对象:

 🍿创建Card类定义:

class Card:
    def __init__(self, suit_id, rank_id):
        self.rank_id = rank_id
        self.suit_id = suit_id

        if self.rank_id == 1:
            self.rank = "Ace"
            self.value = 1
        elif self.rank_id == 11:
            self.rank = "Jack"
            self.value = 10
        elif self.rank_id == 12:
            self.rank = "Queen"
            self.value = 10
        elif self.rank_id == 13:
            self.rank = "King"
            self.value = 10
        elif 2 <= self.rank_id <= 10:
            self.rank = str(self.rank_id)
            self.value = self.rank_id
        else:
            self.rank = "RankError"
            self.value = -1

        if self.suit_id == 1:
            self.suit = "Diamonds"
        elif self.suit_id == 2:
            self.suit = "Hearts"
        elif self.suit_id == 3:
            self.suit = "Spades"
        elif self.suit_id == 4:
            self.suit = "Clubs"
        else:
            self.suit = "SuitError"
            
        self.short_name = self.rank[0] + self.suit[0]
        if self.rank == '10':
            self.short_name = self.rank + self.suit[0]

        self.long_name = self.rank + " of " + self.suit
         

🍿 创建52张牌,随机选5张并显示其属性

import random
from card import Card

#使用嵌套for循环建立一副牌
deck = []
for suit_id in range(1, 5):
    for rank_id in range(1, 14):
        deck.append(Card(suit_id, rank_id))

#从一副牌中选5张牌作为一手牌
hand = []
for cards in range(0, 5):
    a = random.choice(deck)
    hand.append(a)
    deck.remove(a)

print
for card in hand:
    print(card.short_name, "=", card.long_name, "Value:", card.value)

 

 5.2 将8号牌分值改为 50 分,要防止修改到Card类

#使用嵌套for循环建立一副牌
deck = []
for suit_id in range(1, 5):
    for rank_id in range(1, 14):
        new_card = Card(suit_id, rank_id)

        if new_card.rank_id == 8:
            new_card.value = 50

        deck.append(new_card)

 5.3  主循环

玩家和计算机必须轮流选择(出牌或者抽牌),直到有人获胜或双方都无法继续。

程序主循环部分要确定游戏何时结束。可能在玩家或计算机出完手上所有牌时结束,也可能双方手上都有牌却无法继续,游戏结束。

如果计算机无法继续,会在相应代码中设置blocked,轮到计算机出牌时,如果计算机无法继续,同样会在相应代码在设置blocked变量,直到blocked = 2 确保玩家和计算机都无法继续。

done = False
p_total = c_total = 0

while not done:
    init_cards()
    while not game_done:
        blocked = 0;
        player_turn()           #轮到玩家

        if len(p_hand) == 0:    #玩家手中,已经没有牌,玩家获胜
            game_done = True
            print
            print("You Won!")

        if not game_done:       #轮到计算机
            computer_turn()

        if len(c_hand) == 0:    #计算机手中,已经没有牌,计算机获胜
            game_done = True
            print
            print("Computer Won!")

        if blocked >= 2:        #双方都无法继续,游戏结束
            game_done = True
            print("Both players blocked, GAME OVER")
    play_again = input("Play again(Y/N)")
    if play_again.lower().startswith('y'):
        done = False
    else:
        done = True
    

5.4 明牌和当前花色

明牌:最开始发牌时,要从一副牌中选一张牌翻过来,作为不要的一堆牌中的第一张。弃牌中显示的牌叫明牌(up_card).

#第一张明牌
up_card = random.choice(deck)
deck.remove(up_card)

玩家或计算机出牌:

hand.remove(chosen_card)
up_card = chosen_card

当前花色:当前明牌的花色,玩家或计算机出牌时要与这个花色一致,只有出一张8时,玩家可以更新当前花色花色,如:出一张方块8,可能叫花色黑桃,意味这下一张牌必须是黑桃,

 #当前花色
    active_suit = up_card.suit

5.5 初始化部分 

#初始卡牌
def init_cards():
    global deck, p_hand, c_hand, up_card, active_suit, active_rank
    #使用嵌套for循环建立一副牌
    deck = []
    for suit_id in range(1, 5):
        for rank_id in range(1, 14):
            new_card = Card(suit_id, rank_id)
            if new_card.rank_id == 8:
                new_card.value = 50
            deck.append(new_card)

    p_hand = [] #人
    c_hand = [] #计算机
    
    #从一副牌中选5张牌作为一手牌
    hand = []
    for cards in range(0, 5):
        p_card = random.choice(deck)
        deck.remove(p_card)
        p_hand.append(p_card)
        c_card = random.choice(deck)
        deck.remove(c_card)
        c_hand.append(c_card)
    #第一张明牌    
    up_card = random.choice(deck)
    deck.remove(up_card)
    
    #当前花色
    active_suit = up_card.suit
    active_rank = up_card.rank

5.6 显示手中的牌

询问玩家想要做什么之前,应当显示他手中的牌有什么,以及明牌是什么?如果出了一张8,要更新当前花色

print("\nYour hand:")
    for card in p_hand:
        print(card.short_name + ', ')
    print("Up card: " , up_card.short_name)

    if up_card.rank == '8':
        print("Suit is ", active_suit)

5.7 得到玩家的选择

玩家

  ■ 出一张牌

             出的牌合法?

             牌在他手上?

             选择的这张牌能合法出牌?(是否与明牌的点或花色一致,或是不是一张8?)

  ■ 抽一张牌

def player_turn():
    global deck, p_hand, blocked, up_card, active_suit
    valid_play = False
    is_eight = False
    
    print("\nYour hand:")
    for card in p_hand:
        print(card.short_name + ', ')
    print("Up card: " , up_card.short_name)

    if up_card.rank == '8':
        print("Suit is ", active_suit)

    print("what would you like to do?")
    response = input("Type a card to play or 'Draw' to take a card :")
    valid_play = False

    while not valid_play:
        selected_card = None

        while selected_card == None:
            if response.lower() == 'draw':  #玩家没有牌出,要抽牌
                valid_play = True
                if len(deck) > 0:           #查看桌上还有无牌
                    card = random.choice(deck)
                    p_hand.append(card)
                    deck.remove(card)
                    print("You drew", card.short_name)
                else:
                    print("There are no cards left in the deck")
                    blocked += 1
                return
            else:#玩家要出牌,需要判断牌有没有在玩家手中
                for card in p_hand:
                    if response.upper() == card.short_name:
                        selected_card = card

                if selected_card == None:
                    response = input("You dont't have that card. Try again:")

        if selected_card.rank == '8':
            valid_play =True
            is_eight =True
        elif selected_card.suit == active_suit:
            valid_play = True
        elif selected_card.rank == up_card.rank:
            valid_play = True

        if not valid_play:
            response = input("That's not a legal play. Try again:")
    #如果玩家出一张牌,要从玩家手中删除这张牌
    p_hand.remove(selected_card)
    up_card = selected_card
    active_suit = up_card.suit
    print("You played", selected_card.short_name)

5.8 玩家出一张8得到新花色

def get_new_suit():
    global active_suit
    got_suit = False

    while not got_suit:
        suit = input("Pick a suit:")
        if suit.lower() == 'd':
            active_suit = "Diamonds"
            got_suit =True
        elif suit.lower() == 's':
            active_suit = "Spades"
            got_suit =True
        elif suit.lower() == 'h':
            active_suit = "Hearts"
            got_suit =True
        elif suit.lower() == 'c':
            active_suit = "Clubs"
            got_suit =True
        else:
            print("Not a valid suit.Try again")
    print("You picked", active_suit )

5.9 轮到计算机选择

玩家选择完,就轮到计算机,其出牌的情况,和玩家相同:

■ 出一张8 (并挑选一个新花色)

■出另外一张牌

■抽牌

  • 如果计算机出了一张8,它必须挑选新花色。最简单的方法就是统计计算机手中每种花色各有多少张牌,并选择牌数最多的花色。同样,这也不是最完美的策略,不过这样编写代码最为简单。
  • 如果计算机手中没有8,程序就必须检查所有牌,查看哪些牌可以出。在这些牌中,它会选择出分值最大的牌。
  • 如果根本无法出牌,计算机会抽牌。倘若计算机想要抽牌,但这副牌中已经没有任何牌了,计算机就无法继续,这和人类玩家是一样的。
def computer_turn():
    global c_hand, deck, up_card, active_suit, blocked
    options = []

    for card in c_hand:
        if card.rank == '8':
            c_hand.remove(card)
            up_card = card
            print("Computer played", card.short_name)

            #suit total:[do=iamonds, hearts, spades, clubs]
            suit_totals = [0, 0, 0, 0]

            for suit in range(1, 5):
                for card in c_hand:
                    if card.suit_id == suit:
                        suit_totals[suit - 1] +=1
            long_suit = 0

            for i in range(4):
                if suit_totals[i] > long_suit:
                    long_suit = i

            if long_suit == 0:
                active_suit = "Diamonds"

            if long_suit == 1:
                active_suit = "Hearts"

            if long_suit == 2:
                active_suit = "Spades"

            if long_suit == 3:
                active_suit = "Clubs"

            print("Computer changed suit to", active_suit)
            return
        else:
            if card.suit == active_suit:
                options.append(card)
            elif card.rank == up_card.rank:
                options.append(card)

    if len(options) >0:
        best_play = options[0]

        for card in options:
            if card.value > best_play.value:
                best_play = card

        c_hand.remove(best_play)
        up_card = best_play
        active_siut = up_card.suit
        print("Computer played", best_play.short_name)

    else:
        if len(deck)>0:
            next_card = random.choice(deck)
            c_hand.append(next_card)
            deck.remove(next_card)
            print("Computer drew a card")
        else:
            print("Computer is blocked")
            blocked += 1

    print("Computer has %i cards left" %(len(c_hand)))

5.10 记录分数

要完成这个游戏,还需要最后一点:这就是记录得分。游戏结束时,需要得到赢家的得分,这要根据输家剩余的牌来计算。还要显示所有游戏的总分。
 

done = False
p_total = c_total = 0

while not done:
    game_done = False
    blocked = 0
    init_cards()
    
    while not game_done:
        blocked = 0;
        player_turn()           #轮到玩家

        if len(p_hand) == 0:    #玩家手中,已经没有牌,玩家获胜
            game_done = True
            print
            print("You Won!")
            
            #display game score here
            p_points = 0
            for card in c_hand:
                p_points += card.value

            p_total += p_points
            print("You got %i points for computer 'shand" %p_points)

        if not game_done:       #轮到计算机
            computer_turn()

        if len(c_hand) == 0:    #计算机手中,已经没有牌,计算机获胜
            game_done = True
            print
            print("Computer Won!")
            
            #display game score here
            c_points = 0
            for card in p_hand:
                c_points += card.value

            c_total += c_points
            print("You got %i points for computer 'shand" %c_points)

        if blocked >= 2:        #双方都无法继续,游戏结束
            game_done = True
            print("Both players blocked, GAME OVER")

            played_points = 0
            for card in c_card:
                p_pionts += card.value
            p_total += p_points
            
            c_points = 0
            for card in p_card:
                c_pionts += card.value
            c_total += c_points

            print("You got %i points for computer 's hand" %p_points)
            print("Computer got %i points for your 's hand" %c_points)
            
    play_again = input("Play again(Y/N)")
    if play_again.lower().startswith('y'):
        done = False
        print("\n So far, you have %i points" %p_total)
        print("\n and the computer has  %i points" %c_total)
    else:
        done = True

print("\n Final Score:" )
print("\n You %i   cOMPUTER :%i" %(p_total, c_total))

六、运行:

 计划:后面将其以gui界面形式显示出来

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值