Pythonプログラミングで

チェスを作る

Stage 10 記録からゲームを進める

10-4 棋譜からゲームを再現する機能を実装する

次は readmode.py へ行ってもらいます。

                        
#! /usr/bin/env python3
# readmode.py
# programmed by Saito-Saito-Saito
# explained on https://Saito-Saito-Saito.github.io/chess
# last updated: 16 August 2020


import sys

from config import *
import board

local_logger = setLogger(__name__)


def readmode(turnmode=False, reverse=False, logger=None):
    ### LOGGER SETTING
    logger = logger or local_logger
    
    # initializing the board
    main_board = board.Board()
    main_board.print()
    print('ENTER TO START')
    input()
    
    while True:
        ### DISPLAYING TURN NO. AND PLAYER
        if main_board.player == WHITE:
            print('\n{}\tWHITE'.format(main_board.turn), end='\t')
            new_board = main_board.tracefile(main_board.turn, BLACK, False)
        elif main_board.player == BLACK:
            print('\n{}\tBLACK'.format(main_board.turn), end='\t')
            new_board = main_board.tracefile(main_board.turn + 1, WHITE, False)
        else:
            logger.error('UNEXPECTED VALUE of PLAYER in readmode')
            print('SYSTEM ERROR')
            sys.exit('SYSTEM ERROR')

        ### DISPLAYING THE RESULT
        if type(new_board) is int:
            if new_board == EMPTY:
                print('1/2-1/2\n\nDRAW')
                return
            elif new_board == WHITE:
                print('1-0\n\nWHITE WINS')
                return
            elif new_board == BLACK:
                print('0-1\n\nBLACK WINS')
                return
            else:
                logger.error('UNEXPECTED VALUE of new_board in readmode')
                print('SYSTEM ERROR')
                sys.exit('SYSTEM ERROR')
        # moving a piece
        else:
            main_board = new_board
            print(main_board.s)
            main_board.print(turnmode=turnmode, reverse=reverse)

        ### EXIT CODE
        print('ENTER TO NEXT / X TO QUIT ', end='')
        if input() in ['X', 'x']:
            print('QUITTED')
            return


if __name__=="__main__":
    readmode()
                        
                    

sys, config, board をインポートして、local_logger を設定します。もちろん config.py の中身は config. を付けなくてもいいようにしてください。

                        
import sys

from config import *
import board

local_logger = setLogger(__name__)
                        
                    

では readmode 関数へ入りましょう。

まずはいつも通り引数の確認です。

                        
def readmode(turnmode=False, reverse=False, logger=None):
    ### LOGGER SETTING
    logger = logger or local_logger
                        
                    

turnmode や reverse は Board クラスの print インスタンスに入れる引数です。

UNAVAILABLE

なんで reverse を一緒に使うんだ?

詳しくは後述しますけれども、tracefile メソッドが指定のターン・プレイヤーの手番

直前

までしか再現しないことに原因がありますね。

~~~~~~~~~~~~~~~

main_board インスタンスを宣言して盤面を初期化したら、まずは読み取りモードを使うユーザーに心の準備をする時間をあげます。それが "ENTER TO START" の部分。

                        
    # initializing the board
    main_board = board.Board()
    main_board.print()
    print('ENTER TO START')
    input()
                        
                    

これあったほうがいいですよ。

UNAVAILABLE

え?なんでもう駒動いてんの??

ってなりますから。

while ループに入ります。

                        
    while True:
                        
                    

~~~~~~~~~~~~~~~

ループの最初では「第何ターンのどちらの番か」を明記してあげます。

                        
        ### DISPLAYING TURN NO. & PLAYER
        if main_board.player == WHITE:
            print('\n{}\tWHITE'.format(main_board.turn), end='\t')
            new_board = main_board.tracefile(main_board.turn, BLACK, False)
        elif main_board.player == BLACK:
            print('\n{}\tBLACK'.format(main_board.turn), end='\t') 
            new_board = main_board.tracefile(main_board.turn + 1, WHITE, False)
        else:
            logger.error('UNEXPECTED VALUE of PLAYER in readmode')
            print('SYSTEM ERROR')
            sys.exit('SYSTEM ERROR')
                        
                    

また new_board には手番が終わった後の状況を tracefile を使って代入します。

                        
        ### DISPLAYING TURN NO. & PLAYER
        if main_board.player == WHITE:
            print('\n{}\tWHITE'.format(main_board.turn), end='\t')
            new_board = main_board.tracefile(main_board.turn, BLACK, False)
        elif main_board.player == BLACK:
            print('\n{}\tBLACK'.format(main_board.turn), end='\t')
            new_board = main_board.tracefile(main_board.turn + 1, WHITE, False) 
        else:
            logger.error('UNEXPECTED VALUE of PLAYER in readmode')
            print('SYSTEM ERROR')
            sys.exit('SYSTEM ERROR')
                        
                    
UNAVAILABLE

でもターン番号とかプレーヤーの値とかおかしくねえか?

あくまで「プレーヤーの手番が終わった後の盤面」を代入する点に注意してください。tracefile は

destination の直前の状態にする

メソッドですよ。

白が手番を終えたところまで tracefile で遡りたければ、引数は main_board.turn, BLACK ですし、黒が終えたところまで遡りたければ引数は main_board.turn + 1, WHITE です。しっかり確認してください。

UNAVAILABLE

~~~~~~~~~~~~~~~

プレーヤーまで表示し終わったら new_board の型によって場合分けします。

new_board が int 型なら WHITE/BLACK/EMPTY のいずれかがリターンされていて、勝敗がついています。勝者に応じて "1-0", "0-1" などと、ユーザーに勝敗を見せましょう。

                        
        if type(new_board) is int:
            if new_board == EMPTY:
                print('1/2-1/2\n\nDRAW')
                return
            elif new_board == WHITE:
                print('1-0\n\nWHITE WINS')
                return
            elif new_board == BLACK:
                print('0-1\n\nBLACK WINS')
                return
            else:
                logger.error('UNEXPECTED VALUE of new_board in readmode')
                print('SYSTEM ERROR')
                sys.exit('SYSTEM ERROR')
                        
                    

それ以外では駒を動かしている場合です。new_board を main_board に突っ込んでください。

                        
        # moving a piece
        else:
            main_board = new_board
            print(main_board.s)
            main_board.print(turnmode=turnmode, reverse=reverse)
                        
                    

そして print もお忘れなく。特に turnmode が True のときは reverse も True にとなるように引数を調整した方がいいかと思われます。

もしこれを逆にしてしまうと、main_board.player と盤面の向きが逆転してしまいますから。

~~~~~~~~~~~~~~~

これで 1 手です。エンターキーで次に進めるようにします。ユーザーが

UNAVAILABLE

ちょいとトイレ行ってくるわ

とかいろんな理由をつけて途中退室することも考えられますので、終了コード "X" を用意してあげます。

                        
        ### EXIT CODE
        print('ENTER TO NEXT / X TO QUIT ', end='')
        if input() in ['X', 'x']:
            print('QUITTED')
            return
                        
                    

NEXT Stage 11 全体の機能を統括する