600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > python实现井字棋人机对战(图形窗口 博弈论)

python实现井字棋人机对战(图形窗口 博弈论)

时间:2020-04-15 17:34:20

相关推荐

python实现井字棋人机对战(图形窗口 博弈论)

本程序实现了井字棋人机对战小游戏,先选择玩家先手,电脑先手,再开始游戏,点击重玩会重置游戏界面,鼠标移动上去变成能点击样式的才能点

代码如下:

import tkinter as tkimport numpy as npimport copy# 游戏结束def game_over(B1, B2, B3, ):global Bfor i in range(3):for j in range(3):B[i][j]['state'] = 'disabled' # 设置为禁用B[i][j]['cursor'] = 'arrow' # 鼠标样式更改if B1['text'] == 'x':B1['text'] = '玩'B2['text'] = '家'B3['text'] = '胜'elif B1['text'] == 'o' or B2['text'] == 'o':B1['text'] = '电'B2['text'] = '脑'B3['text'] = '胜'else:global b2b2['text'] = '和棋'# 绝杀点/关键点def Key_points(M, t):x = []s_r = M.sum(axis=1) # 各行的和s_c = M.sum(axis=0) # 各列的和m_d = M[0, 0] + M[1, 1] + M[2, 2] # 主对角线b_d = M[0, 2] + M[1, 1] + M[2, 0] # 反对角线for i in range(3):for j in range(3):if M[i][j] == 0: # 这是个空位c = 0 # 行,列,或对角和为1的个数if i == j and m_d == t: c += 1 # 如果是对角线或反对角线if i + j == 2 and b_d == t: c += 1if s_r[i] == t: c += 1if s_c[j] == t: c += 1if c >= 2:x.append([i, j]) # 能绝杀,放置return x# 电脑下棋+判断输赢def aiplay():global B, b1, b2, b3mark = [] # 记号,储存棋盘t = 0 # 记录空位个数for i in range(3):mark.append([])for j in range(3):if B[i][j]['text'] == 'o':mark[i].append(1)elif B[i][j]['text'] == 'x':mark[i].append(-1)else:mark[i].append(0)t += 1if sum(mark[i]) == -3: # 如果某一排有三个x玩家赢game_over(B[i][0], B[i][1], B[i][2])returnif not t: # 没有空位,和棋game_over(b1, b2, b3)mark = np.array(mark)sum_row = mark.sum(axis=1) # 各行的和sum_column = mark.sum(axis=0) # 各列的和main_diagonal = mark[0, 0] + mark[1, 1] + mark[2, 2] # 主对角线back_diagonal = mark[0, 2] + mark[1, 1] + mark[2, 0] # 反对角线for j in range(3):if sum_column[j] == -3: # 如果某一列有三个x玩家赢game_over(B[0][j], B[1][j], B[2][j])returnif main_diagonal == -3: # 单独判断对角线game_over(B[0][0], B[1][1], B[2][2])returnif back_diagonal == -3: # 单独判断反对角线game_over(B[0][2], B[1][1], B[2][0])return# 电脑胜判断======================================================for i in range(3): # 有2个o电脑再下一个,电脑胜if sum_row[i] == 2:game_over(B[i][0], B[i][1], B[i][2])returnif sum_column[i] == 2:game_over(B[0][i], B[1][i], B[2][i])returnif main_diagonal == 2: # 单独判断对角线game_over(B[0][0], B[1][1], B[2][2])returnif back_diagonal == 2: # 单独判断反对角线game_over(B[0][2], B[1][1], B[2][0])return# 没法直接赢,看看有没有能堵住的==================================for i in range(3): # 有2个x电脑堵一下if sum_row[i] == -2:aiplace(B[i][0]), aiplace(B[i][1]), aiplace(B[i][2])returnif sum_column[i] == -2:aiplace(B[0][i]), aiplace(B[1][i]), aiplace(B[2][i])returnif main_diagonal == -2: # 单独判断对角线aiplace(B[0][0]), aiplace(B[1][1]), aiplace(B[2][2])returnif back_diagonal == -2: # 单独判断反对角线aiplace(B[0][2]), aiplace(B[1][1]), aiplace(B[2][0])return# 多想一步,如果有地方下了能有两个值为2的地方,就能绝杀================================K = Key_points(mark, 1)for i in K:aiplace(B[i[0]][i[1]]) # 能绝杀,放置return# 再多想一步,如果对方有能把自己绝杀的点,抢先堵住=======================================K = Key_points(mark, -1)for i in K:aiplace(B[i[0]][i[1]]) # 能绝杀,放置return# 多想两步,看有没有位置放了之后可以出现两个绝杀点for i in range(3):for j in range(3):if mark[i][j] == 0: # 这是个空位mark_new = copy.deepcopy(mark) # 深拷贝mark_new[i][j] = 1K = Key_points(mark_new, 1)if len(K) >= 2:aiplace(B[i][j]) # 或许能绝杀,放置return# 再多想两步,看对面有没有位置放了之后可以出现两个绝杀点for i in range(3):for j in range(3):if mark[i][j] == 0: # 这是个空位mark_new = copy.deepcopy(mark) # 深拷贝mark_new[i][j] = -1K = Key_points(mark_new, -1)if len(K) >= 2:aiplace(B[i][j]) # 或许能绝杀,放置return# 这还没办法,看哪有空位下在哪for i in range(3):for j in range(3):if mark[i][j] == 0: # 这是个空位aiplace(B[i][j]) # 放置return# 没有空位了,平局game_over(b1, b2, b3)# 电脑放置def aiplace(Bu):if not Bu['text'] == 'x':Bu['text'] = 'o' # 打上oBu['state'] = 'disabled' # 设置为禁用Bu['cursor'] = 'arrow' # 鼠标样式更改# 玩家放置def place(Bu):Bu['text'] = 'x' # 打上xBu['state'] = 'disabled' # 设置为禁用Bu['cursor'] = 'arrow' # 鼠标样式更改aiplay()# 重玩def restart():global b1, b2, b3, Bfor i in range(3):for j in range(3):B[i][j]['text'] = '' # 棋盘重置B[i][j]['state'] = 'disabled' # 设置为禁用B[i][j]['cursor'] = 'arrow' # 鼠标样式更改b1['state'] = 'disabled' # 设置为禁用b1['cursor'] = 'arrow' # 鼠标样式更改b2['text'] = '开始' # 和棋时需要重置b2['state'] = 'normal' # 设置为启用b2['cursor'] = 'hand2' # 鼠标样式更改b3['state'] = 'normal' # 设置为启用b3['cursor'] = 'hand2' # 鼠标样式更改# 开始def play():global b1, b2, b3, B, player_firstfor i in range(3):for j in range(3):B[i][j]['text'] = '' # 棋盘重置B[i][j]['state'] = 'normal' # 设置为启用B[i][j]['cursor'] = 'hand2' # 鼠标样式更改b1['state'] = 'normal' # 设置为启用b1['cursor'] = 'hand2' # 鼠标样式更改b2['state'] = 'disabled' # 设置为禁用b2['cursor'] = 'arrow' # 鼠标样式更改b3['state'] = 'disabled' # 设置为禁用b3['cursor'] = 'arrow' # 鼠标样式更改if not player_first:aiplay() # AI先下# 先手判断def Go_first():global player_firstif player_first:b3['text'] = '电脑先手'else:b3['text'] = '玩家先手'player_first = not player_firstglobal player_first, B, b1, b2, b3player_first = True # 玩家先手main_window = tk.Tk() # 调用Tk()创建主窗口main_window.title("井字棋") # 给主窗口起一个名字main_window.geometry("450x450") # 大小# main_window.resizable(0,0) # 不允许拉伸改变大小# 按钮 text:按钮文本,width、height:按钮大小,cursor:鼠标样式,command:调用函数B = [] # 棋盘按钮组for i in range(3):B.append([])main_window.grid_rowconfigure(i, weight=1) # row为i,缩放比为1for j in range(3):main_window.grid_columnconfigure(j, weight=1) # column为i,缩放比为1B[i].append(tk.Button(main_window, text="", width=15, height=5, )) # 添加按钮B[i][j]['command'] = lambda i=i, j=j: place(B[i][j]) # 增加点击函数B[i][j]['state'] = 'disabled' # 初始禁用B[i][j].grid(row=i, column=j, sticky=tk.N + tk.S + tk.W + tk.E) # 添加到主窗口显示b1 = tk.Button(main_window, text="重玩", width=15, height=5, command=restart) # 添加按钮,点击调用重启函数b2 = tk.Button(main_window, text="开始", width=15, height=5, cursor='hand2', command=play) # 添加按钮,点击调用开始函数b3 = tk.Button(main_window, text='玩家先手', width=15, height=5, cursor='hand2', command=Go_first) # 添加按钮,点击调用先手函数b1['state'] = 'disabled' # 初始为禁用b1.grid(row=3, column=0, sticky=tk.N + tk.S + tk.W + tk.E)b2.grid(row=3, column=1, sticky=tk.N + tk.S + tk.W + tk.E)b3.grid(row=3, column=2, sticky=tk.N + tk.S + tk.W + tk.E)main_window.mainloop() # 开启主循环,让窗口处于显示状态

结果示例:

拉伸不错位

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。