[0][1][2] [3][4][5] [6][7][8]
best_way = [4,0,2,6,8,1,3,5,7]
python
win_chess = [[0,4,8],[2,4,6],[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8]]
多線程
人(X)點擊某個格子,觸發綁定事件app
1
線程的使用:dom
id = 1 th = [] for i in range(50): id = id * -1 try: th.append(threading.Thread(target=run,args=(i,id))) th[i].start() except Exception as e: print(e) i = i - 1
tkinter的mianloop作爲主線程儘可能避免被阻塞,以避免界面卡死ide
建立窗口:函數
top = tk.Tk()#建立窗口 top.title('井字棋 -> Fighting')#標題 top.geometry("300x300")#大小 top.resizable()#可改變大小
建立Frame:oop
frame_top = tk.Frame(top)#top是上層
建立按鈕:佈局
tk.Button(frame_top,text='人機對決',command=but1).pack(side=tk.LEFT)
建立labe:學習
label1 = tk.Label(frame_cont,justify=tk.CENTER,textvariable=show_str,font=("幼圓",30))
顯示可刷新變量:測試
tips = tk.StringVar(top) #提示信息 tips.set("")#設置顯示內容 label_bottom = tk.Label(frame_bot,justify=tk.CENTER,textvariable=tips,font=("幼圓",20),padx=0)#設置顯示的值爲tips
綁定事件及解綁:
l0.bind("<Button-1>", touch_l0)#綁定 l0.unbind("<Button-1>")#解綁
佈局:
l0.pack(side=tk.LEFT) frame_top.pack()
開啓消息循環:
top.mainloop()
X _ O O O _ X X X
補充:以前之因此會卡,是由於在計算下一步時,若是隻剩下3或2個格子時,沒法返回下一步的值,致使棋沒有下,外層循環又是
while True
,便致使死循環。針對這個問題我添加了具體的改進,已修復。
運行
gui.py
便可
chess.py
內核部分#coding=utf-8 """ [0,1,2] [3,4,5] [6,7,8] """ #勝利的走法 win_chess = [[0,4,8],[2,4,6],[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8]] #最佳下棋順序 best_way = [4,0,2,6,8,1,3,5,7] #棋盤 chess = [0,0,0,0,0,0,0,0,0] def is_win(now_chess,who): """ 判斷遊戲方(who)是否贏局 """ temp = now_chess[:] for w_c in win_chess: if temp[w_c[0]] == who and temp[w_c[1]] == who and temp[w_c[2]] == who : return who return 0 def count_zero(now_chess): """ 統計剩餘格子 返回個數 """ temp = now_chess[:] count = 0 for te in temp: if te == 0: count = count + 1 return count def evaluation(now_chess): """ 估價函數(以X爲對象) 能夠贏的行數 +1 能夠贏的行數上有本身的棋子 +2 可致使本身贏 +2 可致使對手贏 -2 """ temp = now_chess[:] count = 0 for w_c in win_chess: if temp[w_c[0]] >= 0 and temp[w_c[1]] >= 0 and temp[w_c[2]] >= 0 : if temp[w_c[0]] == 1 or temp[w_c[1]] == 1 or temp[w_c[2]] == 1 : count += 1 count += 1 if is_win(temp,1) == 1: count = count + 2 if is_win(temp,-1) == -1: count = count - 2 return count def all_go(now_chess,who): """ 遍歷全部走法 """ temp = now_chess[:] tempp = [] for i in best_way: if temp[i] == 0: temppp = temp[:] temppp[i]=who tempp.append([temppp,i]) return tempp def get_next_x(now_chess,who): """ x獲取下一個位置 """ temp = now_chess[:] best_list = None best_one = -1 if count_zero(temp) <= 3 : for te in all_go(temp,who): if best_one == -1: best_list = te[0] best_one = te[1] else : if evaluation(te[0]) > evaluation(best_list): best_list = te[0] best_one = te[1] return best_one for te in all_go(temp,who): for tee in all_go(te[0],who*-1): for teee in all_go(tee[0],who): if best_list is None: best_list = teee[0] best_one = te[1] else: if evaluation(teee[0]) > evaluation(best_list) : best_list = teee[0] best_one = te[1] return best_one def get_next_o(now_chess,who): """ o獲取下一個位置 """ temp = now_chess[:] best_list = None best_one = -1 if count_zero(temp) <= 2 : for te in all_go(temp,who): if best_one == -1: best_list = te[0] best_one = te[1] else : if evaluation(te[0]) < evaluation(best_list): best_list = te[0] best_one = te[1] return best_one for te in all_go(temp,who): for tee in all_go(te[0],who*-1): if best_list is None: best_list = tee[0] best_one = te[1] else: if evaluation(tee[0]) < evaluation(best_list) : best_list = tee[0] best_one = te[1] return best_one def is_danger(now_chess,who=0): """ 判斷本身是否處於危險狀態(即 對手可能已經差一子贏局) """ temp = now_chess[:] for te in all_go(temp,who*-1): if is_win(te[0],who*-1) == who*-1: return te[1] return -1 if __name__ == "__main__": """ 測試用 """ chess = [0,0,0,\ 0,1,0,\ 0,0,0] #print(get_next_old(chess,-1,1)) #print(all_go(chess,1)) print(get_next_o(chess,-1))
gui.py
圖形及控制 部分#coding=utf-8 """ """ import tkinter as tk import time import threading import random import chess init_chess = [0,0,0,0,0,0,0,0,0] #原始棋盤 the_chess = [0,0,0,0,0,0,0,0,0] #記錄棋盤 show_chess = '' flag = True who = 1 count_x = 0 count_y = 0 count_z = 0 top = tk.Tk() top.title('井字棋 -> Fighting') top.geometry("300x300") top.resizable() show_str = tk.StringVar(top) tips = tk.StringVar(top) #提示信息 #初始化棋盤信息 ch = [] for i in range(9): ch.append(tk.StringVar(top)) #初始化提示信息 tips.set("") frame_top = tk.Frame(top) frame_cont = tk.Frame(top) frame_bot = tk.Frame(top) frame_cont1 = tk.Frame(frame_cont) frame_cont2 = tk.Frame(frame_cont) frame_cont3 = tk.Frame(frame_cont) label1 = tk.Label(frame_cont,justify=tk.CENTER,textvariable=show_str,font=("幼圓",30)) # 棋盤顯示label 0~9 l0 = tk.Label(frame_cont1,textvariable=ch[0],font=("幼圓",30),padx=0) l1 = tk.Label(frame_cont1,textvariable=ch[1],font=("幼圓",30),padx=0) l2 = tk.Label(frame_cont1,textvariable=ch[2],font=("幼圓",30),padx=0) l3 = tk.Label(frame_cont2,textvariable=ch[3],font=("幼圓",30),padx=0) l4 = tk.Label(frame_cont2,textvariable=ch[4],font=("幼圓",30),padx=0) l5 = tk.Label(frame_cont2,textvariable=ch[5],font=("幼圓",30),padx=0) l6 = tk.Label(frame_cont3,textvariable=ch[6],font=("幼圓",30),padx=0) l7 = tk.Label(frame_cont3,textvariable=ch[7],font=("幼圓",30),padx=0) l8 = tk.Label(frame_cont3,textvariable=ch[8],font=("幼圓",30),padx=0) label_bottom = tk.Label(frame_bot,justify=tk.CENTER,textvariable=tips,font=("幼圓",20),padx=0) def update_chess(): """ 更新棋盤 """ for i in range(9): if the_chess[i] == 1 : ch[i].set('|X|') elif the_chess[i] == -1 : ch[i].set('|O|') else : ch[i].set('| |') #print(i) def init_ch(): """ 初始化棋盤 """ for i in range(9): the_chess[i] = init_chess[i] update_chess() return the_chess def ai_go_first(): if chess.count_zero(the_chess) == 9: the_chess[random.randint(0,8)] = -1 update_chess() forget() ai_go_fir_b = tk.Button(frame_cont,text='機器先下',command=ai_go_first) def forget(): ai_go_fir_b.pack_forget() def but1(): """ 人機對戰 """ flag = True init_ch() tips.set("人機對戰模式") l0.bind("<Button-1>", touch_l0) l1.bind("<Button-1>", touch_l1) l2.bind("<Button-1>", touch_l2) l3.bind("<Button-1>", touch_l3) l4.bind("<Button-1>", touch_l4) l5.bind("<Button-1>", touch_l5) l6.bind("<Button-1>", touch_l6) l7.bind("<Button-1>", touch_l7) l8.bind("<Button-1>", touch_l8) ai_go_fir_b.pack(side=tk.TOP) def run(i,id): """ 建立一個機器對打局 """ new_chess = init_chess[:] global count_x global count_y global count_z if id == 1 : new_chess[random.randint(0,8)] = -1 else : new_chess[random.randint(0,8)] = 1 x = 0 for x in range(10): if chess.count_zero(new_chess) > 0 : #print(chess.count_zero(new_chess)) if id == 1: #print('*****') #print(chess.get_next_x(new_chess,id)) pos = chess.get_next_x(new_chess,id) if pos != -1 : new_chess[int(chess.get_next_x(new_chess,id))] = id else : for xx in range(9): if new_chess[xx] == 0 : new_chess[xx] = id else : pos = chess.get_next_o(new_chess,id) if pos != -1 : new_chess[int(chess.get_next_o(new_chess,id))] = id else : for xx in range(9): if new_chess[xx] == 0 : new_chess[xx] = id id = id * -1 if chess.is_win(new_chess,id) == id : name = '' if id == 1 : name = 'X' update_chess() print("第 {} 局 : {} 贏了!".format(i+1,name) + ' ' + str(new_chess)) tips.set("第 {} 局 : {} 贏了!".format(i+1,name)) threading.Lock() count_x = count_x + 1 threading.RLock() time.sleep(3) break else : name = 'O' update_chess() print("第 {} 局 : {} 贏了!".format(i+1,name) + ' ' + str(new_chess)) tips.set("第 {} 局 : {} 贏了!".format(i+1,name)) threading.Lock() count_y = count_y + 1 threading.RLock() time.sleep(3) break elif chess.is_win(new_chess,id*-1) == id*-1 : id = id * -1 name = '' if id == 1 : name = 'X' print("第 {} 局 : {} 贏了!".format(i+1,name) + ' ' + str(new_chess)) tips.set("第 {} 局 : {} 贏了!".format(i+1,name)) threading.Lock() count_x = count_x + 1 threading.RLock() break else : name = 'O' print("第 {} 局 : {} 贏了!".format(i+1,name) + ' ' + str(new_chess)) tips.set("第 {} 局 : {} 贏了!".format(i+1,name)) threading.Lock() count_y = count_y + 1 threading.RLock() break elif chess.count_zero(new_chess) == 0: print("第 {} 局 : 平局".format(i+1) + ' ' + str(new_chess)) tips.set("第 {} 局 : 平局".format(i+1)) threading.Lock() count_z = count_z + 1 threading.RLock() break else : pass else : print("第 {} 局 : 平局".format(i+1) + ' ' + str(new_chess)) tips.set("第 {} 局 : 平局".format(i+1)) threading.Lock() count_z = count_z + 1 threading.RLock() break #print(str(i + 1) + ' ' + str(new_chess)) '''if i == 9: print("第 {} 局 : 平局".format(i+1) + ' ' + str(new_chess)) tips.set("第 {} 局 : 平局".format(i+1)) threading.Lock() count_z = count_z + 1 threading.RLock()''' time.sleep(3) for i in range(9): the_chess[i] = new_chess[i] update_chess() threading.Lock() tips.set("50局已經結束!\nX 雙贏 {}次\nO 雙贏 {}次\n平局 {} 次".format(count_x,count_y,count_z)) threading.RLock() def but2(): """ 機器對戰 """ print(" ") ai_go_fir_b.pack_forget() flag = False global count_x global count_y global count_z count_x = 0 count_y = 0 count_z = 0 init_ch() tips.set("機器對戰模式") l0.unbind("<Button-1>") l1.unbind("<Button-1>") l2.unbind("<Button-1>") l3.unbind("<Button-1>") l4.unbind("<Button-1>") l5.unbind("<Button-1>") l6.unbind("<Button-1>") l7.unbind("<Button-1>") l8.unbind("<Button-1>") id = 1 th = [] for i in range(50): id = id * -1 try: th.append(threading.Thread(target=run,args=(i,id))) th[i].start() except Exception as e: print(e) i = i - 1 #tips.set("50 局已經結束! X 雙贏 {}次, O 雙贏 {}次, 平局 {} 次".format(count_x,count_y,count_z)) def ai_go(w): """ 機器走棋 O """ if chess.count_zero(the_chess) < 9: po = chess.is_danger(the_chess,1) if po != -1 : the_chess[po] = w update_chess() elif constraint(w) == False: pass else : the_chess[chess.get_next_o(the_chess,-1)] = w update_chess() if chess.is_win(the_chess,-1) == -1: tips.set("你輸了!") if chess.count_zero(the_chess) == 0: tips.set("平局!") def constraint(w): """ 判斷是否處於危險狀態 """ po = chess.is_danger(the_chess,-1) if po != -1: the_chess[po] = w update_chess() return False return True def peo_go(po): """ 獲取人們按鍵,並下棋 """ if the_chess[po] == 0 : the_chess[po] = who update_chess() if chess.is_win(the_chess,who) == who: tips.set('你贏了!') elif chess.count_zero(the_chess) == 0: tips.set("平局!") else : ai_go(who*-1) def touch_l0(e): peo_go(0) def touch_l1(e): peo_go(1) def touch_l2(e): peo_go(2) def touch_l3(e): peo_go(3) def touch_l4(e): peo_go(4) def touch_l5(e): peo_go(5) def touch_l6(e): peo_go(6) def touch_l7(e): peo_go(7) def touch_l8(e): peo_go(8) tk.Button(frame_top,text='人機對決',command=but1).pack(side=tk.LEFT) tk.Button(frame_top,text='機器對決',command=but2).pack(side=tk.RIGHT) update_chess() l0.pack(side=tk.LEFT) l1.pack(side=tk.LEFT) l2.pack(side=tk.LEFT) l3.pack(side=tk.LEFT) l4.pack(side=tk.LEFT) l5.pack(side=tk.LEFT) l6.pack(side=tk.LEFT) l7.pack(side=tk.LEFT) l8.pack(side=tk.LEFT) label_bottom.pack() frame_cont1.pack() frame_cont2.pack() frame_cont3.pack() frame_top.pack() frame_cont.pack() frame_bot.pack() top.mainloop()