21点游戏python代码简单实现(含流程图和功能设计)

mac2022-06-30  26

21点游戏python简单实现

文章目录

21点游戏python简单实现规则简述游戏流程图设计功能设计代码实现总结OOA(分析)和OOD(设计)代码部分可改进部分

规则简述

玩家共两个角色:电脑和人类,电脑是庄家

游戏开始时,先给人类和电脑每个玩家分别发两张牌作为底牌,庄家底牌只漏一张

判断双方底牌是否直接为21点,如果其中一方为21点则直接判胜利,并在总分上加一分。如果双方都是21点,那就是平局,不得分。

当初始牌面上,没有直接出现21点,人类玩家根据自己的牌面大小决定是否继续要牌。如果要牌,那就在牌堆中抽一张,然后再次判断胜负。如果人类牌面的总点数超过了21点,那就直接判输

如果人类玩家停止要牌了,并且没有因为超过21点而被判输的情况下,则电脑要牌。电脑要牌这里,可以自己设计一个规则: 5.1 比如电脑一直要牌,直到比人类玩家大才停止要牌。 5.2 根据牌堆中剩余牌的数量,计算赢的概率,然后设置一个阈值,超过阈值就要,低于就不要。 5.3 …

循环4和5的步骤

完成一轮游戏的时候,可由人类玩家决定,是否继续玩下一轮

牌堆中剩余的牌数不够玩一轮游戏的时候,游戏自动结束。

计算规则: 2. 3. 4. 5. 6. 7. 8. 9. 10分别是正常的点数,J. Q. K都是10点

A比较特殊,首先把A当做1来计算,牌面总分数如果小于21,那么再把A当做11再计算一次,如果这个时候仍然小于21,那么A就当11算,如果这个时候牌面总分数大于了21,那么A就当1算。

游戏流程图设计

功能设计

class poke

class dealer

field: cards: 每一个荷官对应多副牌 function: give_one_card(): 发牌

class Player

field: name: 昵称score: 总比分points:计数器cards_in_hand->list: 手牌 function: who_win(player): 判断未提前结束下与其他玩家的胜负now_count(): 计算当前牌数字get(*cards): 将荷官发的牌加入手牌

代码实现

# usr/bin/env python3; #-*-coding: utf-8-* import random from sys import exit class Poke: ''' Poke类用来初始化一个牌堆 ''' def __init__(self): self.cards = [[face, suite] for face in "♠♥♦♣" for suite in [1,2,3,4,5,6,7,8,9,10,'J','Q','K']] random.shuffle(self.cards) class Dealer: ''' Dealer类初始化一个荷官 主要用来实现取牌和发牌的作用 ''' def __init__(self): self.cards = Poke().cards def give_one_card(self): ''' 给玩家发牌 return: list ''' if not self.cards: # 重新取一副牌并洗牌 self.cards.extend(Poke().cards) return self.cards.pop() class Player: def __init__(self, name): ''' 初始化实例属性 ''' self.name = name self.score = 0 self.points = 0 self.cards_in_hand = [] def init(self): ''' 重置计数器和牌列表 ''' self.cards_in_hand = [] self.points = 0 def now_count(self): ''' 更新计数器 ''' point = 0 for face, suite in self.cards_in_hand: if suite in ['J', 'Q', 'K']: suite = 10 point += suite # 判断是否有A,如果有A再判断是否大于11,如果是的话A当做1,否的话当做11 for card in self.cards_in_hand: if card[1] == 1 and point + 10 < 21: self.points = point + 10 else: self.points = point def is_win(self, player): ''' 未提前结束回合时,判断玩家输赢 param: player 进行比较的玩家 ''' s1 = self.points s2 = player.points if s1 > s2: print(f"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 玩家{self.name}赢了!") self.score += 1 elif s1 == s2: print(f"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 平局!") else: print(f"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 电脑{player.name}赢了!") player.score += 1 def get(self, *cards): ''' 玩家取荷官发的牌,并更新计数器 param: *cards 一个或多个list类型表示的牌 ''' for card in cards: self.cards_in_hand.append(card) self.now_count() # 重置分数 def main(dealer: Dealer, computer: Player, human: Player): ''' 游戏控制主函数 ''' # 回合数 count = 0 try: while True: count += 1 print(f"第{count}轮比赛开始:") # 设置提前结束标志 flag = False # 新回合初始化计数器和牌 human.init() computer.init() # 准备发牌,两张牌给human, 两张牌给电脑{computer.name} human.get(dealer.give_one_card(), dealer.give_one_card()) computer.get(dealer.give_one_card(), dealer.give_one_card()) print(f"玩家{human.name}手中的牌是{human.cards_in_hand[-2]}, {human.cards_in_hand[-1]}") print(f"电脑{computer.name}手中的牌是{computer.cards_in_hand[-2]}, ?") # 判断是否21点 if human.points == 21 == computer.points: print("玩家{human.name}和电脑{computer.name}都为21点,平局!") elif human.points == 21: print("玩家{human.name}的点数为21点,恭喜玩家{human.name}赢了!") human.score += 1 else: # 玩家要牌 while True: if_next_card = input("是否继续要牌:(Y/N)") if if_next_card in ['N', 'n']: break elif if_next_card in ['Y', 'y']: human.get(dealer.give_one_card()) print(f"玩家{human.name}得到一张{human.cards_in_hand[-1]}, 玩家{human.name}手中的牌是{human.cards_in_hand}") # 判断玩家是否超过21点,如果是提前结束标志设置为True if human.points > 21: print(f"玩家{human.name}的点数{human.points}超过了21点,玩家{human.name}输了!") computer.score += 1 flag = True break # 电脑要牌 if not flag: # 电脑要牌逻辑,只要小于玩家分数就要牌 while computer.points < human.points: computer.get(dealer.give_one_card()) print(f"电脑{computer.name}得到一张{computer.cards_in_hand[-1]}, 电脑{computer.name}手中的牌是{computer.cards_in_hand}") # 先判断电脑是否大于21点,如果大于21点提前结束 if computer.points > 21: print(f"电脑{computer.name}的点数为{computer.points}超过21点,恭喜玩家{human.name}赢了!") human.score += 1 else: # 没有提前结束也就是都小于21点的情况下,判断大小输赢 human.is_win(computer) print("-" * 30) # 是否进行下一局 if_play_again = input("是否进行下一局:(Y/N)") # 如果继续,先打印总比分,再重新开始 if if_play_again in ['Y', 'y']: print(f"玩家{human.name},电脑{computer.name}总比分为{human.score}:{computer.score}") # 如果停止,打印总比分并判处胜者后退出 elif if_play_again in ['N', 'n']: print(f"玩家{human.name},电脑{computer.name}总比分为{human.score}:{computer.score}") if human.score > computer.score: print(f"{human.name}胜出!") elif human.score < computer.score: print(f"{computer.name}胜出!") else: print("战况激烈,你们打平了!") print("游戏结束") exit(0) else: print("输入有误,请重新输入:") except Exception: print("有bug,游戏结束!") if __name__ == '__main__': computer = Player('Robot') human = Player('Lihaoer') dealer = Dealer() main(dealer, computer, human)

总结

OOA(分析)和OOD(设计)

制作流程图时,主流程尽量保持在一个方向上,每遇到选择分支,就在垂直方向上继续分析,尽量保证各个分支的同一层次和主流程保持平行,这样的话如果有提前结束的分支,也非常清楚。流程图不要过于复杂,过于复杂的话很容易混乱也不利于再次阅读,并且不要着急去考虑方法。本例中需要抽象的类、属性和方法都不多。对于多类多方法的情况,考虑增加类图;多对象的交互行为考虑增加顺序图;而对于像本例这样的游戏属于单对象跨用例行为,可以考虑状态机图。

代码部分

python的类属性和实例属性。与Java有static静态来表示属性的归属不同,python的实例属性定义在__init()__中,类属性仍然直接表示在类中。如果实例属性需要定期重置,可能需要重新定义一个init函数。类之间的关系有至少三种,包括关联,泛化和依赖,如果类之间互相有对象的参数调用,需要先搞清楚类之间的关系,否则类方法可能有重复等不合理的地方。提前结束的代码逻辑一般是由多层并列循环的跳出来实现的,但具体实现提出设计到goto的思想,一般代码中是通过设置提前结束标志来实现。本例中至少两处需用到,一是是否重复获取输入标志,一是是否提前结束本局标志。random类和sys.exit()方法python支持多重判断a==b==c两种输出格式化字符串方法。 print(f"%format", args) print("%format".format(args))

可改进部分

改进系统输入的代码部分,抛出异常或抓获checked exception,或是直接改进bug。游戏逻辑可改进,包括电脑要牌逻辑,以及游戏规则等。类属性和方法的访问安全问题。
最新回复(0)