Python之十点半小游戏
源码(详细注释):
1 # -*- coding: utf-8 -*- 2 3 #游戏类 4 class Game: 5 #一般游戏进程,从读取存档开始 6 def Process(self): 7 #初始回合数为0 8 self.rounds = 0 9 #初始Continue标记为True 10 self.Continue = True 11 #读取游戏 12 self.Read(self) 13 #当Continue标记为True时循环进行游戏 14 while self.Continue: 15 #创建一个玩家集合 16 self.player_set = set() 17 #初始化扑克牌 18 self.Card.InitCard(self) 19 #每轮的开始都将重置每名玩家的部分信息 20 for i in range(self.player_amount): 21 self.player_set.add(i) 22 self.player_list[i].banker = False 23 self.player_list[i].want = True 24 self.player_list[i].inboom = True 25 self.player_list[i].bet = 0 26 #下面两句是加牌操作,每名玩家1张 27 self.player_list[i].hand = [self.cards[0]] 28 del self.cards[0] 29 #进入叫庄环节 30 self.Banker(self,self.player_amount,self.player_set) 31 #游戏进程,从零开始 32 def Start(self): 33 #初始化扑克牌 34 self.Card.InitCard(self) 35 #初始化玩家 36 self.PlayerInit(self) 37 #牌点计算器,用于在创建扑克牌对象时提供每张牌的点数 38 #输入参数:{牌号} 39 def Calculate(rank): 40 #字典,数据来源 41 dictionary = {"A":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"J":0.5,"Q":0.5,"K":0.5} 42 #约定点数并返回 43 value = dictionary[rank] 44 return value 45 #玩家初始化 46 def PlayerInit(self): 47 while True: 48 try: 49 #输入玩家数量 50 self.player_amount = int(input(">>>欢迎来到全新的十点半Lite!\n>>>请您设定玩家数量,最低2人,最高4人:")) 51 #当玩家数量正确时执行子程序 52 if self.player_amount in (2,3,4): 53 self.__PlayerInit(self,self.player_amount) 54 break 55 #否则提示错误 56 else: 57 print("\n>>>不支持该数量的玩家哟,换个数试试吧!<<<") 58 #输入非数字时报错 59 except: 60 print("\n>>>系统监测到了错误,但是系统不知道怎么解决") 61 #玩家初始化子程序 62 #输入参数:{玩家数量} 63 def __PlayerInit(self,player_amount): 64 #创建空列表,用于放置玩家名 65 player_name = [] 66 print("\n>>>本局游戏共有{}名玩家~!<<<".format(self.player_amount)) 67 #输入玩家名并添加到列表 68 for i in range(self.player_amount): 69 player_name.append(input("您好,{}号玩家!\n-请输入您的大名:".format(i + 1))) 70 #初始化游戏 71 self.InitGame(self,player_name,self.player_amount,2) 72 #初始化游戏,有三种初始化方法 73 #输入参数:{玩家名称列表,玩家数量,初始化方式} 74 def InitGame(self,player_name,player_amount,Action): 75 #Action参数小于3时执行游戏初始化 76 if Action < 3: 77 #创建玩家列表,玩家集合 78 self.player_list = [] 79 self.player_set = set() 80 #给每位玩家添加初始数据 81 for i in range(self.player_amount): 82 self.player_list.append(self.Players(i,player_name[i],[self.cards[0]],False,True,True,0,100,0)) 83 self.player_set.add(i) 84 #因为中间涉及到了发牌,所以要从牌堆删除发给玩家的牌 85 del self.cards[0] 86 #若Action等于2追加执行,进入叫庄环节 87 if Action == 2: 88 self.Banker(self,self.player_amount,self.player_set) 89 #Action参数等于3时不进行初始化,直接进入叫庄环节(成功读取到游戏数据) 90 if Action == 3: 91 self.Banker(self,self.player_amount,self.player_set) 92 #叫庄环节 93 #输入参数:{玩家数量,玩家集合} 94 def Banker(self,player_amount,player_set): 95 #进入叫庄意味着游戏正式开始,回合数将加1 96 self.rounds += 1 97 while True: 98 try: 99 #输入庄家的玩家序号 100 banker_number = int(input("第{}局游戏开始,请您选出一名庄家,庄家不需要下注哟!\n>>>请指定庄家的序号,1-{}号都可以:".format(self.rounds,self.player_amount))) - 1 101 #若玩家序号没有错误将执行子程序 102 if banker_number in range(self.player_amount): 103 self.__Banker(self,self.player_amount,banker_number,self.player_set) 104 break 105 #玩家序号输入错误则报错 106 else: 107 print(">>>请输入正确的玩家序号哟,再试一次吧!<<<") 108 #若输入非数字将报出此错 109 except: 110 print("\n>>>系统监测到了错误,但是系统不知道怎么解决") 111 #叫庄子程序 112 #输入参数:{玩家数量,庄家编号,玩家集合} 113 def __Banker(self,player_amount,banker_number,player_set): 114 #修改该名玩家的庄家标识符 115 self.player_list[banker_number].banker = True 116 #从玩家集合中除去这名庄家,将其变为闲家集合 117 self.player_set -= {banker_number} 118 print("\n>>>{}号玩家:[{}]通过选举成为了庄家!".format(banker_number + 1,self.player_list[banker_number].name)) 119 #进入下注环节 120 self.Bet(self,self.player_amount,banker_number,self.player_set) 121 #下注环节 122 #输入参数:{玩家数量,庄家编号,闲家集合} 123 def Bet(self,player_amount,banker_number,player_set): 124 #对于每名闲家 125 for i in self.player_set: 126 while True: 127 try: 128 #输入下注值 129 bet = int(input("-闲家{}:[{}],轮到你下注了!\n>>>最低下1$,最高可以下20$:".format(i + 1,self.player_list[i].name))) 130 #限制下注值在1-20范围之间 131 if bet in range(1,21): 132 #进入下注子程序 133 if self.__Bet(self,i,bet): 134 break 135 #若下注不符合范围规定则报错 136 else: 137 print(">>>下注区间是1-20$,请注意下呢!<<<") 138 #若输入非整数将报此错 139 except: 140 print("\n>>>系统监测到了错误,但是系统不知道怎么解决") 141 #进入补牌环节 142 self.AugmentCard(self,self.player_amount,banker_number,self.player_set) 143 #补牌环节 144 #输入参数:{玩家数量,庄家编号,闲家集合} 145 def AugmentCard(self,player_amount,banker_number,player_set): 146 #初始化补牌轮数为0 147 count = 0 148 #完成补牌的玩家数为0 149 success = 0 150 #设定补牌未完成标识为True 151 insuccess = True 152 print("\n>>>补牌阶段开始,闲家优先!<<<\n") 153 #若补牌未完成标识为True 154 while insuccess: 155 #补牌轮数加1 156 count += 1 157 print("-第{}轮补牌开始!".format(count)) 158 #对于每名闲家 159 for i in self.player_set: 160 #若该名闲家的要牌标记为True且不爆牌标记为True 161 if self.player_list[i].want and self.player_list[i].inboom: 162 #玩家可决定是否补牌,若输入为Y、y将进入补牌子程序 163 if input(">>>闲家{}:[{}]轮到你选择了!\n-目前牌点为{},若要补牌请输入y:".format(i + 1,self.player_list[i].name,self.__calculate(self,i))) in ("Y","y"): 164 self.__AugmentCard(self,i) 165 #玩家选择不补牌则将玩家的要牌标记设为False 166 else: 167 print("\n>闲家{}不敢补了。".format(i + 1)) 168 self.player_list[i].want = False 169 #补牌完成了,完成补牌的玩家数量加1 170 else: 171 success += 1 172 #若所有闲家均完成补牌,则将未完成标识符设为False,循环将停止 173 if success == self.player_amount - 1: 174 insuccess = False 175 #接下来轮到庄家补牌了 176 i = banker_number 177 while True: 178 #循环条件为庄家要牌标记为True且不爆牌标记为True 179 if self.player_list[i].want and self.player_list[i].inboom: 180 #玩家可决定是否补牌,若输入为Y、y将进入补牌子程序 181 if input("\n>>>庄家{}:[{}]请注意!现在轮到你选择了!\n-目前牌点为{},若要补牌请输入y:".format(i + 1,self.player_list[i].name,self.__calculate(self,i))) in ("Y","y"): 182 self.__AugmentCard(self,i) 183 #玩家选择不补牌则将玩家的要牌标记设为False 184 else: 185 print("\n>庄家{}不敢补了。".format(i + 1)) 186 self.player_list[i].want = False 187 #所有玩家完成补牌,结束循环 188 else: 189 break 190 #进入决胜环节 191 self.Fight(self,self.player_amount,banker_number) 192 #决胜环节 193 #输入参数:{玩家数量,庄家编号} 194 def Fight(self,player_amount,banker_number): 195 #为了方便决出胜负,创建点数列表用于存放所有玩家的牌点 196 point_list = [] 197 #创建奖金,初始值为0 198 bouns = 0 199 #对所有玩家进行操作 200 for i in range(self.player_amount): 201 #奖金为玩家下注总和 202 bouns += self.player_list[i].bet 203 #若玩家未爆牌(手牌点数和小于10.5) 204 if self.player_list[i].point <= 10.5: 205 #则在点数列表中添加相应玩家的手牌点数 206 point_list.append(self.player_list[i].point) 207 else: 208 #否则为这名玩家添加大小为"-1"的点数 209 point_list.append(-1) 210 #判断玩家是否全爆,判断依据为:"-1"数量是否小于玩家的总数 211 if point_list.count(-1) < self.player_amount: 212 #玩家未全爆,则找出点数最大值 213 biggest = max(point_list) 214 #若点数最大值出现重复现象 215 if point_list.count(biggest) > 1: 216 #创建获胜玩家列表,重复且最高的玩家都将获胜 217 winner = [i for i,repeat in enumerate(point_list) if repeat == biggest] 218 print("\n>>>本轮游戏共有{}名玩家获胜:".format(len(winner))) 219 #对于每名获胜玩家,进入发奖子程序 220 for i in winner: 221 self.__Bouns(self,i,bouns/len(winner),banker_number) 222 #若点数最大值未出现重复现象 223 else: 224 #获胜者为该最大点数的所有者 225 i = point_list.index(biggest) 226 print("\n>>>恭喜玩家{}:[{}]获得本轮的胜利!<<<".format(i + 1,self.player_list[i].name)) 227 #进入发奖子程序 228 self.__Bouns(self,i,bouns,banker_number) 229 #若所有玩家都爆牌将不进行任何发奖 230 else: 231 print(">>>\n你们都爆了,这里的{}$谁也拿不走!".format(bouns),banker_number) 232 #程序将在此停顿,接到回车键命令后继续进行 233 input("\n>>>戳回车键展示所有玩家的数据<<<\n") 234 #保存游戏数据 235 self.Save(self,self.player_amount) 236 #进入Show程序,程序在展示玩家数据的同时将判断是否有玩家输光,若未出现输光情况则可以继续进行下一轮游戏 237 if self.Show(self,self.player_amount): 238 if input("\n>>>还来一把?\n-输入n可以结束游戏,不输n继续游戏:") in ("n","N"): 239 #若玩家选择不继续,将结束游戏 240 self.GameExit(self) 241 #若Show程序发现有玩家已经输光 242 else: 243 print(">>>啊哦,好像有人输光了!<<<") 244 #结束游戏 245 self.GameExit(self) 246 #结束游戏的程序 247 def GameExit(self): 248 self.Continue = False 249 input("\n>>>十点半游戏到此结束!!๑乛◡乛๑\n\n-请按回车键结束程序") 250 #保存游戏的程序 251 #输入参数:{玩家数量} 252 def Save(self,player_amount): 253 #首先进入保存游戏的子程序,子程序将判断系统是否能够保存游戏数据 254 if self.__Save(self): 255 #引入时间库,记录存档时间 256 import datetime as date 257 #重新格式化时间文本 258 time = date.datetime.now().strftime("%Y.%m.%d-%H:%M:%S") 259 #保存数据 260 with open("save.txt","w+") as data: 261 #游戏数据:保存时间、游戏回合、玩家数量 262 data.writelines("{}[Savetime]\n{}[Rounds]{}[Players]\n".format(time,self.rounds,self.player_amount)) 263 #玩家数据:玩家序号、玩家名称、玩家金钱 264 for i in range(self.player_amount): 265 data.writelines("{}[Num]{}[Name]{}[Money]\n".format(self.player_list[i].number,self.player_list[i].name,int(self.player_list[i].money))) 266 #保存游戏的子程序,用于判断能否保存游戏数据 267 def __Save(self): 268 try: 269 with open("save.txt","w+"): 270 #若执行成功程序将返回True 271 return True 272 #执行失败将报错 273 except: 274 print("\n>>>不知为何,系统无法保存游戏数据<<<") 275 #读取游戏的程序 276 def Read(self): 277 #首先进入读取游戏的子程序,子程序将判断系统是否能够读取游戏数据 278 if self.__Read(self): 279 #读取游戏存档 280 with open("save.txt","r") as data: 281 save = data.readlines() 282 #让玩家选择是开始新游戏还是继续上一局 283 if input(">>>系统检测到您已存在游戏数据:\n{}\n{}\n>>>是否要接着玩呢?输y继续玩,输其它开始新游戏:".format((save[0])[0:save[0].find("[Savetime]")],save[1])) in ("y","Y"): 284 player_name = [] 285 #读取玩家数量信息 286 self.player_amount = int((save[1])[save[1].find("[Rounds]")+8:save[1].find("[Players]")]) 287 #读取游戏回合信息 288 self.rounds = int((save[1])[0:save[1].find("[Rounds]")]) 289 #读取玩家名称信息 290 for i in range(self.player_amount): 291 player_name.append((save[i+2])[save[i+2].find("[Num]")+5:save[i+2].find("[Name]")]) 292 #初始化扑克牌 293 self.Card.InitCard(self) 294 #初始化游戏,初始化方法为1 295 self.InitGame(self,player_name,self.player_amount,1) 296 #读取玩家金钱信息 297 for i in range(self.player_amount): 298 self.player_list[i].money = int((save[i+2])[save[i+2].find("[Name]")+6:save[i+2].find("[Money]")]) 299 #清除读取的save,释放内存 300 del save 301 input(">>>已恢复上局游戏数据~<<<\n\n-戳回车键查看玩家信息并继续游戏") 302 #展示所有玩家信息 303 self.Show(self,self.player_amount) 304 #初始化游戏,初始化方法为3 305 self.InitGame(self,player_name,self.player_amount,3) 306 #若玩家选择不读取,则开始新游戏 307 else: 308 self.Start(self) 309 #读取游戏的子程序 310 def __Read(self): 311 try: 312 #检验是否能正常读取游戏数据,若能读取则返回True 313 with open("save.txt","r"): 314 return True 315 #否则将直接开始新游戏 316 except: 317 print(">>>系统未检测到游戏数据喔,新游戏将开始<<<") 318 self.Start(self) 319 #展示所有玩家信息的程序 320 #输入参数:{玩家数量} 321 def Show(self,player_amount): 322 #此Flag用于记录玩家金钱是否不足以进行下一局游戏,初始值为True 323 Flag = True 324 #对于所有玩家 325 for i in range(self.player_amount): 326 #展示玩家信息 327 print("\n>>>玩家{}:[{}]\n>>>庄家:{}\n>>>手牌:".format(i + 1,self.player_list[i].name,self.player_list[i].banker),end = "") 328 #若此玩家金钱不足,Flag将设定为False,游戏将结束 329 if int(self.player_list[i].money) <= 0: 330 Flag = False 331 #展示玩家信息 332 for n in range(len(self.player_list[i].hand)): 333 print(self.player_list[i].hand[n].suit + self.player_list[i].hand[n].rank,end = " ") 334 print("\n>>>手牌点数:{}\n>>>本轮下注:{}$\n>>>钱包余额:{}$".format(self.player_list[i].point,self.player_list[i].bet,self.player_list[i].money)) 335 return Flag 336 #发奖子程序 337 #输入参数:{获奖者玩家编号,奖金,庄家编号} 338 def __Bouns(self,i,bouns,banker_number): 339 #若该名获奖者不是庄家 340 if not self.player_list[i].banker: 341 #从庄家的钱包中扣除该名获奖者在本轮中的下注金额,并将其加入奖池 342 self.player_list[banker_number].money -= self.player_list[i].bet 343 bouns += self.player_list[i].bet 344 print("\n>>>闲家获胜,庄家要额外付给他与他下注同样多的钱,总共{}$!".format(self.player_list[i].bet)) 345 #发奖给获奖者 346 self.player_list[i].money += bouns 347 print(">>>玩家{}:[{}]共获得{}$奖金,钱包余额为{}$!".format(i + 1,self.player_list[i].name,bouns,self.player_list[i].money)) 348 #补牌子程序 349 #输入参数:{要牌者玩家编号} 350 def __AugmentCard(self,i): 351 print("\n-玩家{}:[{}]抽到了{}{}:{}点!".format(i + 1,self.player_list[i].name,self.cards[0].suit,self.cards[0].rank,self.cards[0].value)) 352 #从牌堆顶摸一张牌给玩家 353 self.player_list[i].hand.append(self.cards[0]) 354 del self.cards[0] 355 #玩家得牌后计算该名玩家的手牌点数,若大于10.5则爆牌 356 if self.__calculate(self,i) > 10.5: 357 print(">>>目前的点数为{}!您爆了,神仙也救不了您!".format(self.player_list[i].point)) 358 #修改不爆牌标记 359 self.player_list[i].inboom = False 360 #若未爆则对赌徒进行鼓励,增加赌场的预期收入 361 else: 362 print(">>>目前的点数为{}!再接再励哟!".format(self.player_list[i].point)) 363 #玩家牌点计算器 364 #输入参数:{被计算牌点的玩家编号} 365 def __calculate(self,i): 366 #计算前先将记录玩家牌点的属性归零,因为稍后将给予新的数值 367 self.player_list[i].point = 0 368 #将玩家手中每张牌的点数加起来 369 for n in range(len(self.player_list[i].hand)): 370 self.player_list[i].point += self.player_list[i].hand[n].value 371 #返回该名玩家的牌点 372 return self.player_list[i].point 373 #下注子程序 374 #输入参数:{下注者编号,下注金额} 375 def __Bet(self,i,bet): 376 #判断该名玩家是否下假注(钱包里根本没那么多钱) 377 if (self.player_list[i].money - bet) >= 0: 378 #未超额,正常下注 379 self.player_list[i].money -= bet 380 self.player_list[i].bet = bet 381 print("\n>>>闲家{}:[{}]下了{}$,钱包还剩{}$!".format(i + 1,self.player_list[i].name,bet,self.player_list[i].money)) 382 return True 383 #超额了,返回False给主程序,主程序将给予回应 384 else: 385 print(">>>您的钱不够,您只有{}$!请重新下注!".format(self.player_list[i].money)) 386 return False 387 #玩家类 388 class Players: 389 #初始化方法,包含了玩家对象的9个属性 390 #9个属性:{序号,名称,手牌,庄家标记,要牌标记,不爆牌标记,下注,金钱,牌点} 391 def __init__(self,number,name,hand,banker,want,inboom,bet,money,point): 392 self.number = number 393 self.name = name 394 self.hand = hand 395 self.banker = banker 396 self.want = want 397 self.inboom = inboom 398 self.bet = bet 399 self.money = money 400 self.point = point 401 #扑克牌类 402 class Card: 403 #初始化方法,包含了扑克牌对象的3个属性 404 #3个属性:{花色,牌号,所代表的点数} 405 def __init__(self,suit,rank,value): 406 self.suit = suit 407 self.rank = rank 408 self.value = value 409 #创建一副全新的扑克牌 410 def InitCard(self): 411 #创建扑克牌盒子 412 self.cards = [] 413 #创建花色 414 for suit in ["♠","♥","♣","♦"]: 415 #创建牌号 416 for rank in ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]: 417 #实例化扑克牌对象,并赋予属性,然后装进扑克牌盒子 418 self.cards.append(self.Card(suit,rank,self.Calculate(rank))) 419 #引入随机模块 420 from random import shuffle as refresh 421 #洗牌 422 refresh(self.cards) 423 #游戏开始运行 424 Game.Process(Game)