Thonnyを使ってPythonでChessを作ってみる#01 駒の移動と今更ながらのクラス化

## 始めに
前回のが最初で最後のQiitaの投稿になると思ってたけど、「ふと書かないとな」と思い、溜まってた作業の進捗を記述する。Python初心者なので先輩等が引っかかってきた数々のトラップに引っかかってきました。番外編でまとめる予定なので「あ～これ俺もひっかかったな～」なんて気持ちで見てあげてください。同じ初学者の人たちは参考にするなり煮るなりしてうまく活用してくれ。

[ここにいつか番外編リンクを貼る]()

 　前回の投稿から間が空いたのは大3の就活生だから色々とすべきことが多くてなかなか時間作れなかったから。続けているだけ偉いぞおいら。

　タイトルにあるように今更ながらにプログラムをクラス化してみる。
 　なんかプログラム組むとき、最初に一通りの流れで書いちゃうからクラス化あと回しになって苦しむことになる。今回も例に漏れずそのパターン。クラス化なんかしなくても幸せにいられたかもしれないと思えたのも若いうちまでだったのね。

 ### クラス化しようと思ったきっかけ
 * 棋譜を記録するときとかに駒ひとつひとつのムーブを記録していく必要を感じたため
 * 白駒動かしたあとに黒駒動かすと白駒のときのデータ残っちゃうから？
 * 
 クラス化したけど、後々考えたら別にいらなくね？ってなった。社会勉強だ馬鹿野郎。

## 開発環境
* Windows 10 Home 22H2 OSBuild:19045.4046
* Thonny version 4.1.4
* py --version : Python 3.9.13
* python --version : Python 3.8.10

　大学の研究でPython扱っていて、pyのバージョンだのPythonのバージョンだのに振り回されて、ライブラリのインポートに苦戦してきた。一応ちゃんとpython内のバージョンを書いてあげよっと
 pyとpythonの違いも番外編に書きたいね

[ここにいつか番外編リンクを貼る]()

## 改めて今回実装した機能等
* 駒の移動情報 movData{}に情報追加
    * movStatus2(chackmate,take等の情報)
     ↑相手の駒をテイクしながらチェックかけたりすることもあるから
    * movDire
     ↑移動元が複数箇所ある場合、どの方向から移動してきたかの情報
     
* ポーン、ルークの前進
* 入力した棋譜のスペルチェック機能
* プログラムのクラス化

```Main.py
import numpy as np
import os

from Piece import Piece
from Move import Move
from Board import Board
from Display import Display

def main():
    
    #クラスのインスタンス生成
    piece = Piece()
    mov = Move()
    board = Board()
    display = Display()
    
    BWflg = 1 #1:white 0:black
    spellflg = 1 #1:spellOK #0:
    
    while(True):
        try:
            
            #スペルチェックOKのとき
            if spellflg :
                
                #入力待ち 白マス　黒マスを交互に指すため、黒マスの棋譜入力後に＊をつける
                if BWflg:
                    print('White:Enter piece move')
                    dist = input()
                else:
                    print('Black:Enter piece move')
                    dist = input()
                    dist += '*'
                
                #入力された棋譜が正しいかのチェック
                spellflg = mov.spellcheck(dist)
                
                #distを翻訳する関数
                #    return movData{movPiece:'x',movStatus:'y',movDist:'z'}
                mov.translate(dist,BWflg)

                #コマを動かす(交換する)関数 movPiece()
                ###取ったコマを記憶する関数
                
                #白黒反転(交互に手を指すため)
                BWflg = BWflg ^ 1 #反転

                #盤の表示
                display.dispBoard()
                
        except IndexError :
            spellflg = 1
            
            #コンソールのクリア
            os.system('cls')

#def movPiece():

#def research():

if __name__ == "__main__":
#if __name__ == "__main__":
    main()
    

```

```Move.py
from Piece import Piece
from Board import Board

import numpy as np
class Move:
    
    def __init__(self):   
        
        #moveの移動に関わるデータ
        self.movData = {'movPiece':'P','movStatus1': 'Nomal','movStatus2': 'Nomal','movDist':'','movPre':'','movDire':''}

        #インスタンス生成
        self.piece = Piece()
        self.board = Board()
        
        #インスタンス変数
        self.movlst = []
        
        #関数定義
        #self.translate(self.mov,self.BWflg)
        #self.movement(BWflg)

        
    def translate(self,mov,BWflg):
        
        #インスタンス変数
        self.mov = mov
        self.BWflg = BWflg
        
        #棋譜で入力された文字列をリストに配分する　
        self.movlst = list(mov)
        
        #mov判定式
        for s in self.movlst:
            
            if s in self.piece.pieceLst :
                movData['movPiece'] = s
            elif s in self.piece.statusDic:
                if self.movData['movStatus1'] != 'Nomal' : self.movData['movStatus2'] = self.piece.statusDic[s]
                if self.movData['movStatus1'] == 'Nomal' : self.movData['movStatus1'] = self.piece.statusDic[s]

        #mov末尾2桁から移動先を取得
        dstatus = 0
        
        #黒マス判定
        if not BWflg == 1:
            dstatus += -1
           
        #効果の有無
        if mov[-1+dstatus] in self.piece.statusDic:
            dstatus  += -1
        

        #moveの移動先:movData['movDist']の取得
        self.movData['movDist']= mov[-2 + dstatus]
        self.movData['movDist'] += mov[-1 + dstatus]
        
        ####move前位置:self.movData['movPre']の取得
        dislst = list(self.movData['movDist'])
        directlst = []
#         if self.movlst[0]  == 'x' :
#         
#         
#         elif distlst[1] == 'x':
#                 directlst.remove(dislst[1])
#                 directlst.remove(dislst[2])
      
        
#         if char(directlst[0]) => 97 and char(directlst[0]) != 120:
#             print('directlst:'+str(directlst[0]))
#             self.movData['movDire'] = directlst[0]
        
    #     for i in range(0,8):
    #         if  row[i] in  :
    #             self.movData['movPre'] = row
    #         elif column[i] in  self.movlst - self.movData['movDist'] :
    #             self.movData['movDist'] = column   


            #移動先から元々その駒があった場所を逆探知する必要がある
            #そのマスに移動できる駒を探索する
            #そのため駒の動きを定義している関数Movement():を呼び出す
        self.movement(BWflg)

            #関数research(piece,dest)
           
           
           
           #if(movlst == [s for s in self.piece.pieceLst])
        return self.movData

    def movement(self,BWflg):
        #self.movData['movPiece'],self.movData['movDest']
        
        #インスタンス変数
        self.BWflg = BWflg
        
        #移動元位置の候補をリストに追加していく
        candicate = []

        #移動先movDistが存在するpositionの要素番号
        disidx = np.argwhere(self.board.position == self.movData['movDist'])
                
        #status nomal=>移動,空いた場所には'…' take=>上書き、空いた場所には'…' 　動きは一緒
        if self.movData['movPiece'] == 'P':
            
            #進行先のマスにピースがあった場合 return0 でなにもしない
            if self.board.board[disidx[0,0],disidx[0,1]] != "・・・":
                return 0
            
            #ポーンが相手の駒をテイクするとき
            if (self.movData['movStatus1'] == 'x'):
                
                #ポーンの斜め前に相手のピースがいるとき
                if self.board.board[disidx[0,0],disidx[0,1]-1] != "・・・":
                    preidx = [disidx[0,0],disidx[0,1]-1]
                    pass
                elif self.board.board[disidx[0,0],disidx[0,1]+1] != "・・・":
                    preidx = [disidx[0,0],disidx[0,1]+1]
                    print('take')
                    pass
                
            #ポーンが前進するとき
            else:
                self.movData['movPre'] = self.board.position[disidx[0,0]-1+(2*BWflg),disidx[0,1]]
                #移動元movPreが存在するpositionの要素番号
                preidx = np.argwhere(self.board.position == self.movData['movPre'])

            #移動先⇐現位置
            self.board.board[disidx[0,0],disidx[0,1]] = self.board.board[preidx[0,0],preidx[0,1]]
            #現位置⇐'・・・'
            self.board.board[preidx[0,0],preidx[0,1]] = '・・・'

        if self.movData['movPiece'] == 'R':
            for file in range(0,8):
                
                #移動先を基準にして、ファイル(縦行)にRが存在するとき、positionをリストに追加
                if 'R' in self.board.board[file,disidx[0,1]]:
                    candicate.append(self.board.position[file,disidx[0,1]])
                
                #移動先を基準にして、ランク(横列)にRが存在するとき、positionをリストに追加
                if file == disidx[0,0]:
                    for rank in range(0,8):
                        if 'R' in self.board.board[disidx[0,0],rank]:
                            candicate.append(position[disidx[0,0],rank])
                            
            preidx = np.argwhere(self.board.position == candicate[0])
                
            #移動元の候補が2箇所以上あったとき
            if len(candicate) > 1:
                for x in candicate:
                    if self.movData['movPre'] in x:
                        #from here
                        preidx = np.argwhere(self.board.position == x)
            else:        
                self.board.board[disidx[0,0],disidx[0,1]] = self.board.board[preidx[0,0],preidx[0,1]]
                self.board.board[preidx[0,0],preidx[0,1]] = '・・・'
        
            #board[disidx[0,0],disidx[0,1]] = board[disidx[0,0]-1+(2*BWflg),disidx[0,1]]
            #board[disidx[0,0]-1+(2*BWflg),disidx[0,1]] = '・・・'
            
    def spellcheck(self,mov):
        
        #スペルチェックリスト asciiコードを比較し判定する
        #ここもっとおりこうに作れそう
        #spellchecklst = ["1","2","3","4","5","6","7","8", "a","b","c","d","e","f","g","h", "R","N","B","Q","K", "*","+","#","-","O"]
        spellchecklst = [49,50,51,52,53,54,55,56, 97,98,99,100,101,102,103,104, 82,66,78,81,75, 120,42,43,35,45,79]

        self.movlst = list(mov)
        
        #文字数チェック
        if int(len(self.movlst)) < 6:
            #movが棋譜に使われている文字だけで構成されているかのチェック
            for i in range(int(len(self.movlst))):
                if not ord(self.movlst[i]) in spellchecklst:
                    return 0
            return 1
```

```Board.py
import numpy as np

class Board:
    board  = np.array([['R1*','N1*','B1*','Q*・','K*・','B2*','N2*','R2*'],
                       ['Pa*','Pb*','Pc*','Pd*','Pe*','Pf*','Ph*','Ph*'],
                       ['・・・','・・・','・・・','・・・','・・・','・・・','・・・','・・・'],
                       ['・・・','・・・','・・・','・・・','・・・','・・・','・・・','・・・'],
                       ['・・・','・・・','・・・','・・・','・・・','・・・','・・・','・・・'],
                       ['・・・','・・・','・・・','・・・','・・・','・・・','・・・','・・・'],
                       ['Pa・','Pb・','Pc・','Pd・','Pe・','Pf・','Ph・','Ph・'],
                       ['R1・','N1・','B1・','・Q・','・K・','B2・','N2・','R2・']])

    position = np.array([['a8','b8','c8','d8','e8','f8','g8','h8'],
                        ['a7','b7','c7','d7','e7','f7','g7','h7'],
                        ['a6','b6','c6','d6','e6','f6','g6','h6'],
                        ['a5','b5','c5','d5','e5','f5','g5','h5'],
                        ['a4','b4','c4','d4','e4','f4','g4','h4'],
                        ['a3','b3','c3','d3','e3','f3','g3','h3'],
                        ['a2','b2','c2','d2','e2','f2','g2','h2'],
                        ['a1','b1','c1','d1','e1','f1','g1','h1']])
                
    row = ['1','2','3','4','5','6','7','8']
    column = ['a','b','c','d','e','f','g','h']

```

```Display.py
from Board import  Board

class Display:
    #インスタンス生成
    def __init__(self):  
        self.board = Board()
    
    
    def dispBoard(self):
        #盤の表示
        for i in range(8):
            for j in range(8):
                print(self.board.board[i][j],end='|')
            print()

```


```Piece.py
#pieceが持っている属性値の定義
class Piece:

    def __init__(self):
        self.pieceLst = ['R','N','B','K','Q']
        self.statusDic = {'x':'take','+':'check','#':'checkmate','=':'promotion'}

```