前提・実現したいこと
Python3.6.4でリバーシのプログラムを作成しています。GUI部分はtkinterで実装し、Threadingとソケット通信を使用して非同期処理でAI同士で対局を行わせるプログラムを作成しております。
今回、新しい機能として「戻る」「進む」ボタンをクリックすることで対局中でもボードの状態を遡れるような機能を実装しようとしています。
ボードの状態は辞書型のrecordという変数で管理し、具体的なコードではサーバーの処理側で、以下のようにrecordに毎ターンボードの状態を追加していこうと考えております。
board.record[board.turn_count] = {'board':copy.deepcopy(board.discs), 'newest_place':board.newest_place}
しかし、毎回17手目でプログラムが停止してしまい例外もキャッチできないため、解決方法が分からず困っております。
以下のソースコードのBoardクラスのself.recordという変数で、BoardクラスのreverseDiscという関数内でrecordに要素を追加していっております。
該当のソースコード
サーバーのコード(クライアントであるAIx2とボードの状態、着手場所などをやり取りしております)
python
1# -*- coding:utf-8 -*- 2"""Script for Tkinter GUI VimReversi.""" 3from threading import Thread 4import tkinter as tk 5import socket 6import select 7import pickle 8import copy 9 10from vr_board import Board 11from vr_gui import GUI 12 13 14server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15readfds = set([server_sock]) 16host = '127.0.0.1' # server host 17port = 4000 # port number 18bufsize = 4096 # buffer size 19backlog = 2 # max queue number 20 21 22def server_core(board, gui,): 23 try: 24 server_sock.bind((host, port)) 25 server_sock.listen(backlog) 26 27 while True: 28 rready, wready, xready = select.select(readfds, [], []) 29 for sock in rready: 30 if sock is server_sock: 31 conn, address = server_sock.accept() 32 readfds.add(conn) 33 else: 34 """ receive """ 35 msg = sock.recv(bufsize) 36 msg = pickle.loads(msg) 37 player_turn = None 38 placeloc = None 39 cand_move = board.getCanPlace(board.turn) 40 41 print(msg) # print recv message 42 43 # if receive message is valid 44 player_turn = msg['turn'] 45 placeloc = msg['placeloc'] 46 47 # set player name 48 gui.setName(player_turn, msg['software_name']) 49 50 # place disc 51 if(player_turn == board.turn): 52 if(board.reverseDisc(player_turn, placeloc) == True): 53 board.newest_place = placeloc # last placed disc 54 55 board.record[board.turn_count] = {'board':copy.deepcopy(board.discs), 'newest_place':board.newest_place} 56 57 # draw game info on the listbox 58 gui.addList(player_turn, board.turn_count, placeloc) 59 board.turn_count += 1 60 61 board.switch_turn() 62 cand_move = board.getCanPlace(board.turn) 63 board.pass_count = 0 64 65 elif(msg['pass_flg'] == True): # player passes play 66 board.switch_turn() 67 cand_move = board.getCanPlace(board.turn) 68 board.pass_count += 1 69 """""""""""" # end receive 70 71 """ send """ 72 server_info = {} 73 server_info['clicked_index'] = gui.clicked_index 74 server_info['board'] = copy.deepcopy(board) 75 server_info['candidate_move'] = cand_move 76 77 # the game hasn't start yet 78 if(not gui.start_flg): 79 server_info['board'].turn = 'None' 80 server_info['candidate_move'] = [] 81 82 snd_msg = pickle.dumps(server_info) # dump pickle 83 sock.send(snd_msg) 84 """""""""""" # end send 85 86 # finish the game. 87 if(board.turn_count > 60 or board.pass_count >= 2): 88 print('game finished! gg!') 89 for rdd in readfds: 90 rdd.close() 91 return 92 93 # end the game and shutdown the server. 94 if(gui.end_flg): 95 print('server shutdown!') 96 for rdd in readfds: 97 rdd.close() 98 return 99 finally: 100 for sock in readfds: 101 sock.close() 102 103 104def main(): 105 root = tk.Tk() # create root window 106 root.title("VimRev") # window title 107 root.geometry("960x720") # window size 960x720 108 root.resizable(0, 0) # Prohibit change of window size 109 110 board = Board() 111 gui = GUI(root) 112 server_thread = Thread(target=server_core, name='server_thread', args=(board, gui,)) 113 server_thread.start() 114 115 # left click callback 116 root.bind("<Button-1>", gui.click) 117 118 # key press callback 119 root.bind("<Control-s>", gui.key) # start the game. 120 root.bind("<Control-q>", gui.key) # end the game. 121 root.bind("<Control-c>", gui.key) # end the game. 122 123 root.after(100, gui.draw, board) 124 root.mainloop() # Starts GUI execution. 125 126 127if __name__ == '__main__': 128 main()
ボードクラスやAIクラスも実装しておりますが、文字数の関係で記載することができなかったため、下記のGithubのリンクを参照していただければ幸いです。
補足情報(FW/ツールのバージョンなど)
プログラムはPython3.6.4で実装しており、今回の機能を実装していないバージョンをGithubで公開しております。
プログラムを実行するには、以下の方法に従ってください。
- サーバーを起動します。
python src/vr_server.py
- サーバーが起動している状態でプレーヤーx2をを起動します。
python src/vr_ai.py -n BlackPlayer -m Black <- 先手
python src/vr_ai.py -n WhitePlayer -m White <- 後手
- プレーヤーを2つ起動したら、ウィンドウをアクティブにした状態でCtrl-sで対局を開始できます。
また、対局中にCtrl-c or Ctrl-qを押すことで、サーバーを停止し、対局を終了することができます。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。