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()
    

 

 

 

 
posted @ 2020-02-27 16:56  吴立文的学习笔记  阅读(1060)  评论(0编辑  收藏  举报