Stage 5 石を裏返す機能を実装する
5-2 石を裏返す機能を実装する
とりあえずコードを見ていただきましょうか。
                        
    def turn(self, player, row, col, logger=None):
        logger = logger or local_logger
        
        # out of the board
        if not (InBoard(row) and InBoard(col)):
            logger.info('OUT OF THE BOARD')
            return FAILED
        # there is already a piece
        if self.board[row][col] != EMPTY:
            logger.info('THERE IS ALREADY A PIECE')
            return FAILED
        turned = False
        # searching all the direction for available one
        for direction in WHOLE_DIRECTION:
            focused = [row + direction[ROW], col + direction[COL]]
            if not (InBoard(focused[ROW]) and InBoard(focused[COL])):
                continue
            next_piece = self.board[focused[ROW]][focused[COL]]
            logger.debug('direc = {}, next_piece = {}'.format(direction, next_piece))
            # in case available
            if next_piece == -player and self.turnjudge(player, focused[ROW], focused[COL], direction):
                while self.board[focused[ROW]][focused[COL]] == -player:
                    self.board[focused[ROW]][focused[COL]] = player
                    focused[ROW] += direction[ROW]
                    focused[COL] += direction[COL]
                    turned = True
                
        # in case a piece was turned
        if turned:
            self.board[row][col] = player
            return SUCCEEDED
        # in case any piece was not turned
        else:
            logger.info('THERE IS NO DIRECTION AVAILABLE')
            return FAILED
                        
                    
                もうなんかコード長くても驚かなくなったわ
いい兆候です。やっとプログラミングに慣れてきましたね。
~~~~~~~~~~~~~~~
まずは引数から見ていきましょう。とは言っても turnjudge とほとんど変わらないんですが。
| player | 石をおいたプレーヤー番号 | 
| row | 石をおいたマスの row 番号 | 
| col | 石をおいたマスの column 番号 | 
| logger | ロガー | 
ほんと見たような表やな
そりゃそうですよ、これ 4-2 の表のコピペみたいなもんですから。
引数入れたらいつも通りロガーを設定してあげてください。
                        
    def turn(self, player, row, col, logger=None):
        logger = logger or local_logger
                        
                    
                ほんと説明手抜くよなお前
だって前やってますから。
~~~~~~~~~~~~~~~
turnjudge で石を裏返せるか確認する前に、そんなの確認しなくても石をおけない場合を除外しましょう。指定のマス [row, col] が盤面外に出ている場合と、すでにそこに石が置かれている場合ですね。
                        
        # out of the board
        if not (InBoard(row) and InBoard(col)):
            logger.info('OUT OF THE BOARD')
            return FAILED
        # there is already a piece
        if self.board[row][col] != EMPTY:
            logger.info('THERE IS ALREADY A PIECE')
            return FAILED
                        
                    
                InBoard 関数は row か col かどちらかでも False を出したらアウトですから、「両方大丈夫な場合」以外は「石を置けない」FAILED をリターンします。
~~~~~~~~~~~~~~~
さて、ここからは turnjudge をしっかり使っていきますよ。
とりあえず turned = False と書いている部分は無視していただいて結構ですので、for ループの中身を見ていきましょう。
                        
        turned = False
        # searching all the direction for available one
        for direction in WHOLE_DIRECTION:
            focused = [row + direction[ROW], col + direction[COL]]
            if not (InBoard(focused[ROW]) and InBoard(focused[COL])):
                continue
            next_piece = self.board[focused[ROW]][focused[COL]]
            logger.debug('direc = {}, next_piece = {}'.format(direction, next_piece))
            # in case available
            if next_piece == -player and self.turnjudge(player, focused[ROW], focused[COL], direction):
                while self.board[focused[ROW]][focused[COL]] == -player:
                    self.board[focused[ROW]][focused[COL]] = player
                    focused[ROW] += direction[ROW]
                    focused[COL] += direction[COL]
                    turned = True
                        
                    
                for ループで direction に全方向を入れてそれぞれループの中を巡らせます。
まずは focused というマスを決めてあげます。「[row, col] の隣のマス」という意味です。
                        
        turned = False
        # searching all the direction for available one
        for direction in WHOLE_DIRECTION:
            focused = [row + direction[ROW], col + direction[COL]]
                        
                    
                この focused というマスを色々と弄るのですが、そもそも盤面外にあったらいじることができませんから、focused が盤面外の場合は再び方向選択させますので continue します。
                        
            focused = [row + direction[ROW], col + direction[COL]]
            if not (InBoard(focused[ROW]) and InBoard(focused[COL])):
                continue
            next_piece = self.board[focused[ROW]][focused[COL]]
                        
                    
                focused にある石を next_piece という変数に格納します。
                        
            if not (InBoard(focused[ROW]) and InBoard(focused[COL])):
                continue
            next_piece = self.board[focused[ROW]][focused[COL]]
            logger.debug('direc = {}, next_piece = {}'.format(direction, next_piece))
            # in case available
                        
                    
                裏返せるならこれは -player になっているはずです。とりあえずログをとっておきましょう。
~~~~~~~~~~~~~~~
さて、本格的に石を裏返します。石を裏返せる条件は
- next_piece が -player である
- turnjudge が True である
ですよね。
                        
            logger.debug('direc = {}, next_piece = {}'.format(direction, next_piece))
            # in case available
            if next_piece == -player and self.turnjudge(player, focused[ROW], focused[COL], direction):
                while self.board[focused[ROW]][focused[COL]] == -player:
                        
                    
                両方ともクリアしていれば次のステップに入りましょう。focused のマスにある石を裏返します。
でも focused って [row, col] の隣のマスやろ
ええ、ですから裏返すたびに focused を動かしていきます。
                        
            if next_piece == -player and self.turnjudge(player, focused[ROW], focused[COL], direction):
                while self.board[focused[ROW]][focused[COL]] == -player:
                    self.board[focused[ROW]][focused[COL]] = player
                    focused[ROW] += direction[ROW]
                    focused[COL] += direction[COL]
                    turned = True
                        
                    
                focused にあるのが相手の石なら自分の石にする、そして focused の位置を direction の方向にずらすと言うことを、自分の石にたどり着くまでやります。
最後の turned ってなんやねん
それについては今からご説明しましょう。
~~~~~~~~~~~~~~~
さて、ここまでコーディングしてきましたけれども、実際に「石を裏返した」ということをどうやって判別しましょうか?
それって調べないといけねーんか。
ええ、例えばこういう場合を考えてみてください。
 
                黒がこの状態で d6 に石を置こうとしたとしましょう。
待て待て待て、おめーそこに石おけねーよ
ええ、そうですよね。ではそれどうやってそこに「置けない」ことを判別します?
いや、判別って turnjudge でいいじゃねえか
でも turn の中で turnjudge をちゃんと使ってますから、「置けるか置けないか」を判断するメソッドを別に作ったら二度手間ですよね。
まあ、そうなるな
turn の中では実際に石を裏返してるんですから、「マジで石を裏返したら turned を True にする」みたいな変数ほしくないですか?
さっきの turned ってそう言うことだったのね
ええ、つまり
| turned == True | 裏返した | 
| turned == False | 裏返していない | 
という判別が効きますので、turned が True なら裏返し成功、False なら失敗としてリターンすることができます。
                        
        # in case a piece was turned
        if turned:
            self.board[row][col] = player
            return SUCCEEDED
        # in case any piece was not turned
        else:
            logger.info('THERE IS NO DIRECTION AVAILABLE')
            return FAILED
                        
                    
                これで石を裏返す機能は全て揃いました。あとはゲームを進めるだけです。
