贪心学院 Demo3 - 豪赌21点

导读:
demo内容来源网课贪心科技AI学社的网课《人工智能Python编程特训营》
本篇博客的主要内容是写一个21点(blackjack)的python程序。

作业

构建《豪赌21点》游戏,完成开发。

先说一下这次demo完成的情况,可以支持玩家和一名电脑进行PK。电脑提供两种要牌模式,一种是点数比玩家小就要牌,一种是设定一个阈值,小于阈值就要牌。
缺点:没有可视化、不是用面向对象写的代码的可扩展性比较差难以拓展到多个玩家

21点游戏规则与流程

  1. 玩家共两个角色:电脑和人类,电脑是庄家
  2. 游戏开始时,先给人类和电脑每个玩家分别发两张牌作为底牌,庄家底牌只漏一张
  3. 判断双方底牌是否直接为21点,如果其中一方为21点则直接判胜利,并在总分上加一分。如果双方都是21点,那就是平局,不得分。
  4. 当初始牌面上,没有直接出现21点,人类玩家根据自己的牌面大小决定是否继续要牌。如果要牌,那就在牌堆中抽一张,再次询问是否要牌。
    如果人类牌面的总点数超过了21点,那就直接判输
  5. 如果人类玩家停止要牌了,并且没有因为超过21点而被判输的情况下,则电脑要牌。电脑要牌这里,可以自己设计一个规则:
    5.1 比如电脑一直要牌,直到比人类玩家大才停止要牌。
    5.2 根据牌堆中剩余牌的数量,计算赢的概率,然后设置一个阈值,超过阈值就要,低于就不要。
  6. 电脑要完牌之后,直接判断人类玩家和电脑玩家的牌面大小判断胜负。
  7. 完成一轮游戏的时候,可由人类玩家决定,是否继续玩下一轮
  8. 牌堆中剩余的牌数不够玩一轮游戏的时候,游戏自动结束。
  9. 计算规则: 2、3、4、5、6、7、8、9、10分别是正常的点数,J、Q、K都是10点
  10. A比较特殊,首先把A当做1来计算,牌面总分数如果小于21,那么再把A当做11再计算一次,如果这个时候仍然小于21,
    那么A就当11算,如果这个时候牌面总分数大于了21,那么A就当1算。

代码部分

我们首先得理清我们的程序需要哪一些函数

"""
程序的功能模块:
洗牌:将排进行随机排列  random_card
发牌:1.初始化时发牌,一下发两张 start_game_init_two_poker
      2.要牌,一下发一张 get_one_poker
计分:2-10就是正常点数,JQK都是10,要考虑A的特殊性 score_count
胜负判断:比较电脑和玩家手中的分数谁大,并记录 who_win
是否要牌 if_get_next_poker
继续还是退出 continue_or_quit
每一轮 every_round
"""

接着引用相关的包及定义一些需要用到的变量

# 洗牌函数 shuffle 作用是随机打乱列表
from random import shuffle
import random

# 为什么要用numpy ,原因是numpy数组提供对应位置相加,不用我们自己计算
# 用于多轮游戏的分数统计
import numpy as np

# exit 函数就是退出程序
from sys import exit

# 初始化扑克牌
playing_cards = {
    "♠ A": 1, "♠ 2": 2, "♠ 3": 3, "♠ 4": 4, "♠ 5": 5, "♠ 6": 6, "♠ 7": 7,
    "♠ 8": 8, "♠ 9": 9, "♠10": 10, "♠ J": 10, "♠ Q": 10, "♠ K": 10,
    "♥ A": 1, "♥ 2": 2, "♥ 3": 3, "♥ 4": 4, "♥ 5": 5, "♥ 6": 6, "♥ 7": 7,
    "♥ 8": 8, "♥ 9": 9, "♥ 10": 10, "♥ J": 10, "♥ Q": 10, "♥ K": 10,
    "♦ A": 1, "♦ 2": 2, "♦ 3": 3, "♦ 4": 4, "♦ 5": 5, "♦ 6": 6, "♦ 7": 7,
    "♦ 8": 8, "♦ 9": 9, "♦ 10": 10, "♦ J": 10, "♦ Q": 10, "♦ K": 10,
    "♣ A": 1, "♣ 2": 2, "♣ 3": 3, "♣ 4": 4, "♣ 5": 5, "♣ 6": 6, "♣ 7": 7,
    "♣ 8": 8, "♣ 9": 9, "♣ 10": 10, "♣ J": 10, "♣ Q": 10, "♣ K": 10,
}

poker_name = list(playing_cards.keys())  # 扑克牌名
poker_count = 1  # 几副扑克
poker_list = poker_name * poker_count  # 参与游戏的所有扑克牌

# 用于判断手中的牌是否有A,根据分数来进行选择A的分值是0还是1
four_a = {"♠ A", "♥ A", "♦ A", "♣ A"}
# 计分器, 玩家:电脑 初始的分数都是0
total_score = np.array([0, 0])
# 记录游戏是第几个回合
game_round = 1

洗牌函数:只需要调用shuffle函数即可

"""
洗牌:重新对扑克牌进行随机排列
不需要return,因为传入的值是引用
"""
def random_card(poker_name_temp):
    shuffle(poker_name_temp)

计分函数:计算手里牌的分数

"""
计分:计算手里牌的分数
传进来的参数是一个列表
"""
def score_count(hand_poker):
    # 声明一个变量,这个变量用来记录牌的总分数
    poker_score = 0
    # 标记 是否有A的标记,默认没有
    have_a = False
    # 计算手中牌的分数
    for k in hand_poker:
        poker_score += playing_cards[k]
    # 判断手中的牌是否有A,然后再根据A的规则进行分数计算
    # 有A就结束循环,没有A就继续循环直到遍历完成
    for i in hand_poker:
        if i in four_a:
            have_a = True
            break
        else:
            continue
    if have_a:  # 如果有A,且总分不超过21,则A记为11
        if poker_score + 10 <= 21:
            poker_score = poker_score + 10
    return poker_score

判断输赢函数:

"""
判断输赢的函数
"""
def who_win(your_score, pc_score):
    if your_score > 21 and pc_score > 21:
        print("平局了")
        return np.array([1, 1])
    elif your_score > 21 and pc_score <= 21:
        print("对不起,玩家输了")
        return np.array([0, 1])
    elif your_score <= 21 and pc_score > 21:
        print("恭喜,玩家赢了")
        return np.array([1, 0])
    elif your_score <= 21 and pc_score <= 21:
        if your_score < pc_score:
            print("对不起,玩家输了")
            return np.array([0, 1])
        elif your_score > pc_score:
            print("恭喜你,玩家赢了")
            return np.array([1, 0])
        else:
            print("平局了")
            return np.array([1, 1])

决定是否继续要牌:

"""
是否继续要牌
"""
def if_get_next_poker():
    if_continue = input("是否继续要下一张牌?(Y/N)>>>>>:")
    if if_continue.upper() == "Y":
        return get_one_poker()  # 返回一张牌
    elif if_continue.upper() == "N":
        print("玩家停止叫牌")
        return False  # 返回False
    else:
        print("输入错误,请重新输入")
        return if_get_next_poker()  # 递归调用,也可以用while True

发牌函数:包括发一张牌和初始化

"""
发牌:要牌的时候需要从牌堆随机抽取一张牌
"""
def get_one_poker():
    # 发一张牌,必须要在牌堆里面删掉这张牌 pop 删除并且返回
    return poker_list.pop(random.randint(0, len(poker_list) - 1))

"""
开局初始化牌,自动给电脑和玩家发两张牌
"""
def start_game_init_two_poker(poker_database):
    return [poker_database.pop(random.randint(0, len(poker_database) - 1)),
            poker_database.pop(random.randint(0, len(poker_database) - 1))]

继续游戏或结束游戏:

"""
一轮游戏结束后,询问玩家是继续还是结束
"""
def continue_or_quit():
    if_next_round = input("你还想要玩下一局吗?(Y/N)>>>>>:")
    if if_next_round.upper() == "Y":
        if len(poker_list) < 15:
            print("剩余扑克牌太少了,不能玩了,游戏结束")
            exit(1)
        else:
            return True
    elif if_next_round.upper() == "N":
        print("游戏结束,玩家不玩了")
        exit(1)
    else:
        print("输入错误,请再输入一次")
        continue_or_quit()

每一轮游戏函数:在注释部分提供了两种电脑叫牌的规则,一种感受比玩家小就叫牌,一种是取某个阈值,小于阈值就叫牌

"""
每一次游戏的流程
"""
def every_round(poker_list):
    # 声明一个变量,代表我们手里的变量
    your_hand_poker = []
    # 声明一个变量,代表电脑手里的变量
    computer_hand_poker = []
    # 一个回合的游戏,首先要自动的在牌堆里抽取两张牌
    your_init_poker = start_game_init_two_poker(poker_list)
    computer_init_poker = start_game_init_two_poker(poker_list)
    print("玩家所获得的扑克牌是{}和{}".format(your_init_poker[0], your_init_poker[1]))
    print(f"电脑所获得的的扑克牌是{computer_init_poker[0]},?\n")
    # 荷官同志把牌放到我们手里
    # extend是添加一个序列,append是添加一个对象
    your_hand_poker.extend(your_init_poker)
    computer_hand_poker.extend(computer_init_poker)
    # 计算初始牌面的分数
    score = np.array([score_count(your_hand_poker), score_count(computer_hand_poker)])
    # 首先判断一下初始化牌面分数的大小,如果有等于21 ,那么直接调用判断输赢函数
    if score[0] == 21 or score[1] == 21:
        print("初始化牌面分数有21点")
        return who_win(score[0], score[1])
    # 否则,判断自己手里的分数是否小于21点,如果小于21点,那么询问是否要下一张牌
    else:
        while score[0] <= 21:
            get_new_poker = if_get_next_poker()
            if get_new_poker:
                # 把新的扑克牌放到我的手里
                your_hand_poker.append(get_new_poker)
                print("你手里的扑克牌是:{}".format(your_hand_poker))

                score[0] = score_count(your_hand_poker)
                # 判断分数大小
                if score[0] > 21:
                    print("你手里的扑克牌已经超过了21点")
                    print("电脑手里的扑克牌是:{}".format(computer_hand_poker))
                    return who_win(score[0], score[1])
                else:
                    continue
            # 玩家不要牌了,电脑开始叫牌
            elif not get_new_poker:
                # # 电脑叫牌的规则1:只要分数比玩家低就一直叫,直到大于等于玩家的分数才停止
                # while score[1] < score[0]:
                #     computer_poker = get_one_poker()
                #     computer_hand_poker.append(computer_poker)
                #     pc_score = score_count(computer_hand_poker)
                #     score[1] = pc_score
                # 电脑叫牌的规则2:只要分数低于阈值18就继续叫牌
                threshold = 18
                while score[1] < threshold:
                    computer_poker = get_one_poker()
                    computer_hand_poker.append(computer_poker)
                    pc_score = score_count(computer_hand_poker)
                    score[1] = pc_score

                print("电脑手里的扑克牌是:{}".format(computer_hand_poker))
                return who_win(score[0], score[1])
            else:
                continue

开始游戏:先选择扑克牌数,然后进入游戏

# 开始玩游戏
input("游戏开始,祝你好运。按'回车'游戏正式开始 ")
while True:
    poker_count = input("请输入要几副牌?(1-6)>>>>>")
    if poker_count.isdigit() and 1 <= int(poker_count) <= 6:
        poker_list = poker_name * int(poker_count)
        break
else:
    print("输入错误,请重新输入!")
while True:
    print("游戏是第{}轮".format(game_round))
    # 洗牌
    random_card(poker_list)
    # 开始游戏
    every_score = every_round(poker_list)
    # 计算总分数
    total_score = np.add(total_score, every_score)
    print("本轮结束,总比分是玩家{}:电脑{}".format(total_score[0], total_score[1]))
    # 轮数+1
    game_round += 1
    # 判断继续或退出
    continue_or_quit()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容