NIM游戏的Python实现
可执行程序下载:
链接:https://pan.baidu.com/s/1n1lPpsI_y53wp6vONWbF-A
提取码:nxgy
Nim游戏是博弈论中最经典的模型(之一),它又有着十分简单的规则和无比优美的结论 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”(以下简称ICG)。
条件
满足以下条件的游戏是ICG(可能不太严谨):1、有两名选手;2、两名选手交替对游戏进行移动(move),每次一步,选手可以在(一般而言)有限的合法移动集合中任选一种进行移动;3、对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其它什么因素; 4、如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负。根据这个定义,很多日常的游戏并非ICG。例如象棋就不满足条件3,因为红方只能移动红子,黑方只能移动黑子,合法的移动集合取决于轮到哪名选手操作。
定义
通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。
实现
我用Pygame实现了一个简单的NIM游戏(这也是我编写的第一个游戏/小有成就感)
#NIM import pygame import random import time #pygame的初始化####################################### pygame.init() screen = pygame.display.set_mode([815,600]) pygame.display.set_caption("NIM V1.1 2020/2/27") #变量的声明########################################## WHITE = (255,255,255) PINK = (255,146,154) BLUE = (180,209,217) BLACK = (10,10,10) width = 120 lengh = 50 num = [random.randint(1,10),random.randint(1,10),random.randint(1,10)] LEFT = [10-num[0],10-num[1],10-num[2]] #字样的声明########################################### font = pygame.font.SysFont("Times",24) text1 = font.render("Congratulaton! You win!",True,BLACK) text1_rect=text1.get_rect() text1_rect.centerx=screen.get_rect().centerx text1_rect.y=550 text2 = font.render("GAME OVER!",True,BLACK) text2_rect=text2.get_rect() text2_rect.centerx=screen.get_rect().centerx text2_rect.y=550 text3 = font.render("Press F1 to play again",True,BLACK) text3_rect=text3.get_rect() text3_rect.x=50 text3_rect.y=550 #初始化地图################################# def draw_the_map(): screen.fill((255,255,255)) for y in range(3): for i in range(num[y]): pygame.draw.rect(screen,BLACK,((9-i)*85,y*200,lengh,width)) pic = pygame.image.load("exit.png") screen.blit(pic,(750,540)) pygame.display.update() #更新地图#################################### def refresh_the_map(a,b,color): global LEFT,num for i in range(a-LEFT[b]+1): pygame.draw.rect(screen,color,((LEFT[b]+i)*85,b*200,lengh,width)) pygame.display.update() time.sleep(0.05) LEFT[b]=a+1 if(LEFT[b]>10): LEFT[b]=10 num[b]=9-a # if(num[b]<0): # num[b]=0 # print(num) #玩家取子#################################### def player_draw(): global LEFT,num player_done = True while(player_done): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if event.type == pygame.MOUSEBUTTONDOWN: x, y = event.pos if(x>=760 and y>=550): pygame.quit() exit() a=x//85 b=y//200 if(x>=LEFT[b]*85): if(x<=(a*85+50) and y<=(b*200+120)): refresh_the_map(a,b,PINK) return #获取二进制下的最高位################################ def get_high(a): flag = True k=1 while(flag): if(a>>1==0): break a=a>>1 k=k+1 return k #检测二进制下a在b位上是否为1########################## def check_high(b,a): if(len(bin(a))<b): return False if (bin(a)[len(bin(a))-b]=='1'): return True else: return False #电脑取子############################################# def machine_draw(): global LEFT,num k=random.randint(0,2) while(num[k]==0): k=random.randint(0,2) result = num[0]^num[1]^num[2] if(result==0): refresh_the_map(LEFT[k]-1+random.randint(1,num[k]),k,BLUE) return high=get_high(result) if(check_high(high,num[0])): k=0 elif(check_high(high,num[1])): k=1 else: k=2 answer=num[k]-(num[k]^result) refresh_the_map(LEFT[k]+answer-1,k,BLUE) def win_judge(): if(num[0]==0 and num[1]==0 and num[2]==0): return True else:return False def replay(): global LEFT,num flag = True while(flag): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() if event.type == pygame.MOUSEBUTTONDOWN: x, y = event.pos if(x>=760 and y>=550): pygame.quit() exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_F1: num = [random.randint(1,10),random.randint(1,10),random.randint(1,10)] LEFT = [10-num[0],10-num[1],10-num[2]] draw_the_map() flag= False return def main(): draw_the_map() keep_going =True while(keep_going): player_draw() if(win_judge()): screen.blit(text1,text1_rect) screen.blit(text3,text3_rect) pygame.display.update() break machine_draw() if(win_judge()): screen.blit(text2,text2_rect) screen.blit(text3,text3_rect) pygame.display.update() break replay() if __name__ == '__main__': while(1): main()