#apply
#include "../_include.txt"
#include "../../define/_vector2.txt"


cev[CEV_CHEST_SHOUGI] .name("mg_チェスト将棋") {

    def {
        NUM_OF_VAR = 64
        NUM_OF_STR = 0
        NUM_OF_PIC = 30

        BASE_LAYER = 6

        PATH_BOARD  = "ts\bo"
        PATH_PIECE  = "ts\pi"
        PATH_CURSOR = "ts\cu"
        PATH_SUB    = "ts\au"
        PATH_RESULT = "ts\re"

        PIC_HEAD   = 1
        PIC_BOARD  = 2
        PIC_PIECE  = 3//+0_+15
        PIC_CURSOR = 20
        PIC_AUTO   = 21
        PIC_GUARD  = 22
        PIC_B_TEXT = 23
        PIC_C_TEXT = 24
        PIC_RESULT = 25//+0_+2

        //実績
        ACHIEVE_WIN = 5

        //盤面
        FIELD_SIZE = 4//最大6

        //シーン
        SCENE_STATE_CTRL = 0
        SCENE_STATE_REPLAY
        SCENE_STATE_CHANGE
        SCENE_STATE_MOVE
        SCENE_STATE_RED_WIN
        SCENE_STATE_BLUE_WIN

        //ターン
        TEAM_BIT_BLUE = (1 << 0)
        TEAM_BIT_RED  = (1 << 1)

        //向き
        DIR_NUM = 8
        DIR_BIT_U  = (1 << 0)
        DIR_BIT_UR = (1 << 1)
        DIR_BIT_R  = (1 << 2)
        DIR_BIT_DR = (1 << 3)
        DIR_BIT_D  = (1 << 4)
        DIR_BIT_DL = (1 << 5)
        DIR_BIT_L  = (1 << 6)
        DIR_BIT_UL = (1 << 7)

        //駒を動かせるか
        MOVE_NO_PROBLEM = 0
        MOVE_WRONG_DIRECTION
        MOVE_CANT
        MOVE_GET_KING

        //駒
        PIECE_MAX = 16
        PIECE_BIT_NUM = 5
        PIECE_BIT_NUM_TURN = 2
        PIECE_BIT_NUM_TYPE = 3

        PIECE_MASK = 0x1f//11111
        PIECE_TURN_MASK = 0x03//00011bx
        PIECE_TYPE_MASK = 0x1c//11100

        PIECE_TYPE_KING = 0
        PIECE_TYPE_ZACK
        PIECE_TYPE_ALISA
        PIECE_TYPE_ALBERT
        PIECE_TYPE_MIA

        PIECE_BIT_NONE = 0x00//何もない
        //PIECE_BIT_SIDE = (1 << 0)//最初の2ビットで敵味方を識別する
        PIECE_BIT_KING   = (PIECE_TYPE_KING << PIECE_BIT_NUM_TURN)
        PIECE_BIT_ZACK   = (PIECE_TYPE_ZACK << PIECE_BIT_NUM_TURN)
        PIECE_BIT_ALISA  = (PIECE_TYPE_ALISA << PIECE_BIT_NUM_TURN)
        PIECE_BIT_ALBERT = (PIECE_TYPE_ALBERT << PIECE_BIT_NUM_TURN)
        PIECE_BIT_MIA    = (PIECE_TYPE_MIA << PIECE_BIT_NUM_TURN)

        //評価基準
        EVAL_WAIT_INTERVAL = 4
        EVAL_WAIT_MIN = 20
        EVAL_MAX =  9999999
        EVAL_MIN = -9999999
        EVAL_DIR = 1//動きやすい
        EVAL_DIR_ENEMY = -1//相手が動きやすい
        EVAL_MOVE = 0//移動量
        EVAL_MOVE_KING = -5
        EVAL_GET_KING  = 10000//取れる
        EVAL_GET_ENEMY = 50
        EVAL_DANGER_KING  = -1000//次に取られる
        EVAL_DANGER_ENEMY = -30

        //定数
        TURN_MAX = 50
        TURN_ROYAL_GUARD = 2
        RESULT_PIC_NUM = 2
        PIECE_WIDTH = 32
        REF_BOARD_X = 48
        REF_BOARD_Y = -16
        REF_PIECE_X = 96
        REF_PIECE_Y = 32
        AUTO_X = 266
        AUTO_Y = 112
        GUARD_X = 266
        GUARD_Y = 32
        UNDER_TEXT_X = 0
        UNDER_TEXT_Y = 240
        TURN_COUNTER_X = 320
        TURN_COUNTER_Y = 0

        //方向キーが入力されている
        enteredDirection = (ipt == KEY_UP || ipt == KEY_DOWN || ipt == KEY_LEFT || ipt == KEY_RIGHT)
    }

    //変数定義
    defv {
        varHead = TV_MINIGAME
        
        ipt
        pid
        cell
        ix
        iy
        tx
        ty
        vx
        vy

        selectedPiece
        capturedPiece
        checkedPiece
        pieceType
        amount
        tmRule
        tmDir

        sceneState
        aiSwitch
        turnCount
        waitCount
        aiCount
        maxEval
        curEval
        curTurn
        selectX
        selectY
        selectVx
        selectVy
        selectDir

        //行動
        actStartX
        actStartY
        actEndX
        actEndy

        //現在の状態
        field0//+0_+4
        field1
        field2
        field3
        field4

        //初期状態
        initField0//+0_+4
        initField1
        initField2
        initField3
        initField4

        //AI用
        ahField0//+0_+4
        ahField1
        ahField2
        ahField3
        ahField4
        ahPiece
        ahIx
        ahIy
        ahEx
        ahEy
        ahTurn
        ahTurnCount
        ahDir
        ahRule

        varFoot
    }

    commentRangeOfVariables(varFoot, TV_MINIGAME, NUM_OF_VAR, NUM_OF_STR, NUM_OF_PIC)

    //ピクチャの共通コマンド
    def {
        basePicCmd = {
            .chromakey(1)
            .mapLayer(BASE_LAYER)
            .eraseWhenTransfer
            .affectedByFlash
            .affectedByShake
        }

        boardPicCmd = {
            PATH_BOARD
            .topLeft
            basePicCmd
        }

        piecePicCmd = {
            PATH_PIECE
            .topLeft
            .grid(8, 2)
            basePicCmd
        }

        cursorPicCmd = {
            PATH_CURSOR
            .topLeft
            .grid(3, 3)
            basePicCmd
        }

        autoPicCmd = {
            PATH_SUB
            .topLeft
            .grid(2, 1)
            basePicCmd
        }

        resultPicCmd = {
            PATH_RESULT
            .grid(1, 2)
            basePicCmd
        }

        bottomTextPicCmd = {
            .size(320, 32)
            .font("", 12)
            .spacing(0, 4)
            .skin ""
            basePicCmd
        }

        turnTextPicCmd = {
            .size(56, 32)
            .font("", 12)
            .spacing(0, 4)
            .skin ""
            basePicCmd
        }
    }

    //盤上の駒を取得する
    __fn _getPieceOnField $d $head $pos bl {
        $id  = __id($head) + v[1 + __id($pos)]
        $mov = PIECE_BIT_NUM * v[0 + __id($pos)]
        v[__id($d)] = ( v[$id] >> ($mov) ) & PIECE_MASK
    }

    //盤上に駒を設置する
    __fn _setPieceOnField $s $head $pos bl {
        $x = v[0 + __id($pos)]
        $y = v[1 + __id($pos)]
        $id = __id($head) + ($y)
        $mask = (-1) ^ ( PIECE_MASK << ( PIECE_BIT_NUM * ($x) ) )
        $bit =  ($s) << ( PIECE_BIT_NUM * ($x) )
        v[$id] = v[$id] & ($mask) | ($bit)
    }

    //駒の種類を取得する
    __fn _getPieceType $d $p bl {
        v[__id($d)] = (($p) & PIECE_TYPE_MASK ) >> PIECE_BIT_NUM_TURN
    }

    //駒の所属を取得する
    __fn _getPieceTeam $d $p bl {
        v[__id($d)] = ($p) & PIECE_TURN_MASK
    }

    //駒の移動方向を取得する
    __fn _getPieceRule $d $p bl {
        //DIR_BIT_U | DIR_BIT_D | DIR_BIT_L | DIR_BIT_R | DIR_BIT_UL | DIR_BIT_UR | DIR_BIT_DL | DIR_BIT_DR
        v[__id($d)] = [DIR_BIT_U | DIR_BIT_D | DIR_BIT_L | DIR_BIT_R,
        DIR_BIT_U | DIR_BIT_DL | DIR_BIT_DR,
        DIR_BIT_U | DIR_BIT_R | DIR_BIT_D | DIR_BIT_L,
        DIR_BIT_D | DIR_BIT_UL | DIR_BIT_UR,
        DIR_BIT_UR | DIR_BIT_DR | DIR_BIT_UL | DIR_BIT_DL,
        0,
        0,
        0][ $p ]
    }

    //番号から向きビットを取得する
    __fn _getDirectionBit $d $s bl {
        v[__id($d)] = [DIR_BIT_U, DIR_BIT_UR, DIR_BIT_R, DIR_BIT_DR, DIR_BIT_D, DIR_BIT_DL, DIR_BIT_L, DIR_BIT_UL][ v[__id($s)] ]
    }

    //駒からピクチャIDを取得する
    __fn _getPiecePicture $d $s bl {
        v[__id($d)]  = ((($s) & PIECE_TYPE_MASK ) >> PIECE_BIT_NUM_TURN) + ((($s) & PIECE_TURN_MASK) - 1) * 8 + PIC_PIECE
    }

    //移動方向から移動量を取得する
    __fn _getVeclocity $d $dir bl {
        v[0 + __id($d)] = ( (($dir) & (DIR_BIT_UL | DIR_BIT_L | DIR_BIT_DL)) ? -1 : 0 ) + ( (($dir) & (DIR_BIT_UR | DIR_BIT_R | DIR_BIT_DR)) ? 1 : 0 )
        v[1 + __id($d)] = ( (($dir) & (DIR_BIT_UL | DIR_BIT_U | DIR_BIT_UR)) ? -1 : 0 ) + ( (($dir) & (DIR_BIT_DL | DIR_BIT_D | DIR_BIT_DR)) ? 1 : 0 )
    }

    //駒の設置位置を取得する
    __fn _getPiecePosition $d $s bl {
        v[0 + __id($d)] = REF_PIECE_X + v[0 + __id($s)] * PIECE_WIDTH
        v[1 + __id($d)] = REF_PIECE_Y + v[1 + __id($s)] * PIECE_WIDTH
    }

    //駒を動かして移動量と結果を得る
    //tx, vx, amount, capturedPiece, checkedPieceを使用する
    __fn _checkMovingPiece $field $turn $start $dir bl {
        //始点
        V2_copy(tx, $start)
        //向き
        _getVeclocity(vx, $dir)
        //一歩ずつ動かしながら見る
        amount = 0
        capturedPiece = 0
        @loop FIELD_SIZE bl {
            //一歩先の情報
            V2_asAdd(tx, vx)
            _getPieceOnField(checkedPiece, $field, tx)
            //範囲内にある
            @if `0 <= tx && tx < FIELD_SIZE && 0 <= ty && ty < FIELD_SIZE bl {
                //味方の駒がある
                @if `checkedPiece & ($turn) bl {
                    @break
                //そうでない駒がある
                } .elif `checkedPiece != PIECE_BIT_NONE bl {
                    capturedPiece = checkedPiece
                    amount += 1
                    @break
                //何もない
                } .else bl {
                    amount += 1
                }
            //画面端にぶつかった
            } .else bl {
                @break
            }
        }
    }

    //手番を交代する
    __fn _nextTurn $d $s bl {
        v[__id($d)] = (v[__id($s)] == TEAM_BIT_BLUE) ? TEAM_BIT_RED : TEAM_BIT_BLUE
    }

    //ウェイトを挟んで負荷を抑える
    __fn _reduceBurden bl {
        waitCount += 1
        @if `waitCount % EVAL_WAIT_INTERVAL == 0 bl {
            @wait(0)
        }
    }

    //カーソルを隠す
    __fn _hideCursor bl {
        @pic.move [PIC_CURSOR] .trans(100) 
    }

    //カーソルを動かす
    __fn _moveCursor $d $max $ax $ay bl {
        v[0 + __id($d)] = ( v[0 + __id($d)] + ($ax) + ($max) ) % ($max)
        v[1 + __id($d)] = ( v[1 + __id($d)] + ($ay) + ($max) ) % ($max)
    }

    //カーソルの移動量を取得する
    __fn _getCursorVelocity $d $input bl {
        v[0 + __id($d)] = (($input) == KEY_LEFT ? -1 : 0) + (($input) == KEY_RIGHT ? 1 : 0)
        v[1 + __id($d)] = (($input) == KEY_UP   ? -1 : 0) + (($input) == KEY_DOWN  ? 1 : 0)
    }

    //画面下にテキストを表示する
    __fn _showBottomText $str bl {
        @pic.strpic [PIC_B_TEXT] $str .pos(UNDER_TEXT_X, UNDER_TEXT_Y) .bottomLeft .scale(100) .trans(0) bottomTextPicCmd
    }

    //ターンを表示する
    __fn _showTurnCountText bl {
        @pic.strpic [PIC_C_TEXT] __str("Turn \c[2]\", turnCount) .pos(TURN_COUNTER_X, TURN_COUNTER_Y) .topRight .scale(100) .trans(0) turnTextPicCmd
    }

    //入力が無効だった時の効果音
    __fn _playBuzzerSound bl {
        @se.play "Buzzer1" .opt(100, 100, 50)
    }

    //入力を取り消した時の効果音
    __fn _playCancelSound bl {
        @se.play "Cancel2" .opt(100, 100, 50)
    }

    //入力した時の効果音
    __fn _playSelectSound bl {
        @se.play "Cursor1" .opt(80, 100, 50)
    }

    //------------------------------------------------------------------------------------
    //開始処理
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        msgBottom()
        
        //開始直後の状態
        //再配置を行う
        sceneState = SCENE_STATE_CHANGE
        //相手のみAI
        aiSwitch = TEAM_BIT_BLUE
        //ピクチャ
        @pic.show[PIC_BOARD] .pos(REF_BOARD_X, REF_BOARD_Y) boardPicCmd
        @pic.show[PIC_CURSOR] .pos(160, 320) .trans(0) .cell(1) cursorPicCmd
        @pic.show[PIC_AUTO] .trans(100) .cell(1) autoPicCmd
        @pic.show[PIC_GUARD] .trans(100) .cell(2) autoPicCmd
        //結果
        @loop RESULT_PIC_NUM .dst(ix) bl {
            pid = PIC_RESULT + ix
            @pic.show[pid] .trans(100) .cell(1) resultPicCmd
        }
        //駒
        @loop PIECE_MAX .dst(ix) bl {
            pid = PIC_PIECE + ix
            cell = 1 + ix
            @pic.show [pid] .trans(100) .cell(cell) piecePicCmd
        }
        //暗転
        @scr.tint .rgbs(50, 50, 50, 100) .time(1)

        @label.jump "gameLoop"
    }

    //------------------------------------------------------------------------------------
    //ゲーム処理
    @label.set "gameLoop"
    bl {
        //----------------------------
        //ゲームを再開したとき、ここから始まる
        @label.set "replay"

        //駒の初期配置
        @if sceneState == SCENE_STATE_CHANGE bl {
            v[__id(initField0)..__id(initField0) + FIELD_SIZE - 1] = 0x00
            //ahField0以下の変数を借りる
            //シャッフルの指定範囲が分かっていないので、一つ多めに確保する
            v[__id(ahField0)..__id(ahField0) + 6] = [ PIECE_BIT_KING, PIECE_BIT_ZACK, PIECE_BIT_ALISA, PIECE_BIT_ALBERT, PIECE_BIT_MIA, -1, -1  ]
            
            @loop 2 .dst(curTurn) bl {
                //基準位置
                vx = rnd(0, FIELD_SIZE - 3)
                vy = (curTurn == 0) ? (FIELD_SIZE - 2) : 0
                //シャッフル
                v[__id(ahField0)].shuffle(6 + 1)

                @loop 6 .dst(ix) bl {
                    //駒の種類
                    pieceType = v[__id(ahField0) + ix]
                    //未定義
                    @if `pieceType < 0 bl {
                        @continue

                    }

                    //設置座標
                    tx = vx + ix % 3
                    ty = vy + ix / 3
                    //設置する駒
                    selectedPiece = pieceType | [TEAM_BIT_RED, TEAM_BIT_Blue][curTurn]
                    //設置する
                    _setPieceOnField(selectedPiece, initField0, tx)
                }
            }
        }

        //盤の初期状態
        v[__id(initField0)].copy(v[__id(field0)], FIELD_SIZE)
        //状態
        sceneState = SCENE_STATE_CTRL
        //ターン数
        turnCount = 1
        //AIに頼った回数
        aiCount = 0
        //プレイヤーが先手となる
        curTurn = TEAM_BIT_RED
        //カーソルを初期化する
        //中心下
        V2_set(selectX, FIELD_SIZE / 2, FIELD_SIZE / 2)
        //向きは上
        selectDir = DIR_BIT_U
        V2_set(selectVx, 1, 0)
        //ターン数を表示する
        _showTurnCountText()

        //----------------------------
        //ピクチャを隠す
        @pic.move [PIC_CURSOR] .trans(100)
        @loop RESULT_PIC_NUM .dst(ix) bl {
            pid = PIC_RESULT + ix
            @pic.move[pid] .trans(100)
        }

        @loop PIECE_MAX .dst(ix) bl {
            pid = PIC_PIECE + ix
            @pic.move[pid] .pos(160 - 16, 240 + 64) .trans(100)
        }
        @wait(0)

        //----------------------------
        //護衛
        @pic.move[PIC_GUARD] .pos(GUARD_X + 64, GUARD_Y) .topLeft .scale(100) .trans(0)
        @wait(0)
        @pic.move[PIC_GUARD] .pos(GUARD_X, GUARD_Y) .topLeft .scale(100) .trans(0) .time(2)

        //----------------------------
        //駒を並べる
        @se.play "Escape" .opt(100, 100, 50)

        @loop FIELD_SIZE .dst(iy) bl {
            @loop FIELD_SIZE .dst(ix) bl {
                _getPieceOnField(selectedPiece, field0, ix)
                @if selectedPiece != PIECE_BIT_NONE bl {
                    _getPiecePicture(pid, selectedPiece)
                    _getPiecePosition(vx, ix)
                    @pic.move[pid] .pos(vx, vy) .topLeft .scale(100) .trans(0) .time(2)
                    @wait .frame(2)
                }
            }
        }
        @wait(2)

        //----------------------------
        //ループ
        @loop bl {
            //----------------------------
            //AI操作
            @if `aiSwitch & curTurn bl {
                //AI操作の解除
                //解除できるのは赤組だけ
                @if `aiSwitch & TEAM_BIT_RED bl {
                    @key.input .dst(ipt) bl {
                        .shift
                        .cancel
                    }

                    @if `ipt bl {
                        bitOff(aiSwitch, TEAM_BIT_RED)

                        @pic.move[PIC_AUTO] .pos(AUTO_X + 64, AUTO_Y) .topLeft .scale(100) .trans(0) .time(5)
                        @se.play "robotarm1" .opt(100, 120, 50)
                        @wait(2)

                        //最初に戻る
                        @continue
                    }
                }
                
                //説明を表示する
                //プレイヤー
                @if curTurn == TEAM_BIT_RED bl {
                    _showBottomText("\c[2]<代理の手番>\c[0] ShiftかXを押し続ける:AI操作を解除")
                //相手
                } .else bl {
                    _showBottomText("\c[2]<相手の手番>\c[0] ちょっと待ってね")
                }

                //カーソルを隠す
                _hideCursor()

                //----------------------------
                //AIの手数
                @if curTurn == TEAM_BIT_RED bl {
                    aiCount += 1
                }

                //----------------------------
                //思考開始
                //一手先しか読まない為か、よく勝ち筋を見逃す

                //初期化
                maxEval = EVAL_MIN
                curEval = 0
                waitCount = 0
                //取れる選択を考えてみる
                @loop FIELD_SIZE .dst(iy) bl {
                    @loop FIELD_SIZE .dst(ix) bl {
                        //駒を取得する
                        _getPieceOnField(selectedPiece, field0, ix)
                        //自分の駒でない
                        @if `!(selectedPiece & curTurn) bl {
                            @continue
                        }

                        //移動規則を取得
                        _getPieceType(pieceType, selectedPiece)
                        _getPieceRule(tmRule, pieceType)
                        //移動規則が無効
                        @if tmRule <= 0x00 bl {
                            @continue
                        }
                        //----------------------------
                        //全方向
                        @loop DIR_NUM .dst(tmDir) bl {
                            //移動方向をビットで取得する
                            _getDirectionBit(tmDir, tmDir)
                            //対応していない方向
                            @if `!(tmRule & tmDir) bl {
                                @continue
                            }
                            //負荷を減らす為に定期的にウェイトを挟む
                            _reduceBurden()
                            //評価変数を初期化
                            curEval = 0
                            //駒の移動量と結果を取得する
                            _checkMovingPiece(field0, curTurn, ix, tmDir)
                            //一歩も動けなかった
                            @if amount <= 0 bl {
                                @continue
                            }
                            //移動できる方向が多いと僅かに評価が増える
                            curEval += EVAL_DIR
                            //----------------------------
                            //移動量を評価に加える
                            _getPieceType(pieceType, selectedPiece)
                            curEval += amount * ( ( pieceType == PIECE_TYPE_KING ) ? (EVAL_MOVE_KING) : (EVAL_MOVE) )
                            //----------------------------
                            //取った駒の種類を評価に加える
                            @if `capturedPiece bl {
                                _getPieceType(pieceType, capturedPiece)
                                //王を取るには早い
                                @if `pieceType == PIECE_BIT_KING && turnCount <= TURN_ROYAL_GUARD bl {
                                    @continue
                                } .else bl {
                                    curEval += ( (pieceType == PIECE_TYPE_KING) ? (EVAL_GET_KING) : (EVAL_GET_ENEMY) )
                                }
                            }

                            //----------------------------
                            //次のターンの相手の動きについて考えてみる
                            //盤上をコピーする
                            v[__id(field0)].copy(v[__id(ahField0)], FIELD_SIZE)
                            //次のターン
                            _nextTurn(ahTurn, curTurn)
                            ahTurnCount = turnCount + 1
                            //移動後の座標
                            ahEx = ix + vx * amount
                            ahEy = iy + vy * amount
                            //駒を動かす
                            _setPieceOnField(PIECE_BIT_NONE, ahField0, ix)
                            _setPieceOnField(selectedPiece, ahField0, ahEx)
                            //相手の駒を探す
                            @loop FIELD_SIZE .dst(ahIy) bl {
                                @loop FIELD_SIZE .dst(ahIx) bl {
                                    //駒を取得する
                                    _getPieceOnField(ahPiece, ahField0, ahIx)
                                    //自分の駒でない
                                    @if `!(ahPiece & ahTurn) bl {
                                        @continue
                                    }
                                    //移動規則を取得
                                    _getPieceType(pieceType, ahPiece)
                                    _getPieceRule(ahRule, pieceType)
                                    //移動規則が無効
                                    @if ahRule <= 0x00 bl {
                                        @continue
                                    }

                                    //----------------------------
                                    //全方向
                                    @loop DIR_NUM .dst(ahDir) bl {
                                        //移動方向をビットで取得する
                                        _getDirectionBit(ahDir, ahDir)
                                        //対応していない方向
                                        @if `!(ahRule & ahDir) bl {
                                            @continue
                                        }
                                        //負荷を減らす為に定期的にウェイトを挟む
                                        _reduceBurden()
                                        //駒の移動量と結果を取得する
                                        _checkMovingPiece(ahField0, ahTurn, ahIx, ahDir)
                                        //一歩も動けなかった
                                        @if amount <= 0 bl {
                                            @continue
                                        }
                                        //相手が移動できる方向が多いと僅かに評価が減る
                                        curEval += EVAL_DIR_ENEMY
                                        //----------------------------
                                        //取った駒の種類
                                        @if `capturedPiece bl {
                                            _getPieceType(pieceType, capturedPiece)
                                            //相手は王が取れない
                                            @if `pieceType == PIECE_BIT_KING && ahTurnCount <= TURN_ROYAL_GUARD bl {
                                                @continue
                                            } .else bl {
                                                curEval += ( (pieceType == PIECE_TYPE_KING) ? (EVAL_DANGER_KING) : (EVAL_DANGER_ENEMY) )
                                            }
                                        }
                                    }
                                }
                            }

                            //----------------------------
                            //より評価の高い手を見つけた
                            //値が同じ場合は20％の確率で上書きする
                            @if `curEval > maxEval || ( curEval >= maxEval && rnd(0, 99) < 20 ) bl {
                                maxEval = curEval
                                V2_copy(actStartX, ix)
                                V2_copy(actEndX, ahEx)
                            }
                        }
                    }
                }

                //早すぎても困るので、思考にかかったフレーム数を引いた分だけ止まる
                waitCount = EVAL_WAIT_MIN - waitCount / EVAL_WAIT_INTERVAL
                @if `waitCount > 0 bl {
                    @wait .frame(waitCount)
                }

                //手が決まった
                @if maxEval > EVAL_MIN bl {
                    sceneState = SCENE_STATE_MOVE

                //動けなかった場合、投了する
                } .else bl {
                    _playBuzzerSound()
                    _showBottomText("\c[2]<投了>\c[0] 打てる手がない為、投了します")
                    @wait(10)

                    //対局終了
                    sceneState = (curTurn == TEAM_BIT_RED) ? SCENE_STATE_BLUE_WIN : SCENE_STATE_RED_WIN
                    @label.jump "result"
                }

            //手動操作
            } .else bl {
                //説明を表示する
                //プレイヤー
                @if curTurn == TEAM_BIT_RED bl {
                    _showBottomText("\c[2]<駒を選択>\c[0] Z:決定 X:終了 Shift:AIに任せる")
                //相手
                //ありえない状況だが一応表示する
                } .else bl {
                    _showBottomText("\c[2]上側 <駒を選択>\c[0] Z:決定 X:終了 Shift:AIに任せる")
                }
                //カーソルを表示する
                _getPiecePosition(vx, selectX)
                @pic.show[PIC_CURSOR] .pos(vx, vy) .topLeft .cell(5) cursorPicCmd
                //入力を取得する(同時押しは無効)
                @key.input .dst(ipt) .wait bl {
                    .right
                    .left
                    .up
                    .down
                    .decision
                    .cancel
                    .shift
                }

                //カーソル移動
                @if `enteredDirection bl {
                    _getCursorVelocity(ix, ipt)
                    _moveCursor( selectX, FIELD_SIZE, ix, iy )
                    _playSelectSound()

                //キャンセルキーで中断メニューを開く
                } .elif ipt == KEY_CANCEL bl {
                    _playCancelSound()
                    //----------------------------
                    @msg.choice bl {
                        .cancel(0)
                        .case "\>つづける" bl {
                        }
                        .case "\>\c[2]配置を変える\c[0]" bl {
                            sceneState = SCENE_STATE_CHANGE
                            @label.jump "replay"
                        }
                        .case "\>やりなおす" bl {
                            sceneState = SCENE_STATE_REPLAY
                            @label.jump "replay"
                        }
                        .case "\>やめる" bl {
                            @label.jump "gameEnd"
                        }
                    }
                //Shiftを押すと自動操作モードになる
                } .elif ipt == KEY_SHIFT bl {
                    @if `!(aiSwitch & TEAM_BIT_RED) bl {
                        bitOn(aiSwitch, TEAM_BIT_RED)

                        @pic.move[PIC_AUTO] .pos(AUTO_X + 64, AUTO_Y) .topLeft .scale(100) .trans(0)
                        @wait(0)
                        @pic.move[PIC_AUTO] .pos(AUTO_X, AUTO_Y) .topLeft .scale(100) .trans(0) .time(2)

                        @se.play "robotarm1" .opt(100, 150, 50)

                        //間を設ける
                        @wait(5)
                    }

                //駒を選択する
                } .elif ipt == KEY_DECISION bl {
                    //説明を表示する
                    _showBottomText("\c[2]<方向を選択>\c[0] Z:決定 X:戻る")
                    //駒を取得する
                    _getPieceOnField(selectedPiece, field0, selectX)
                    //味方の駒がある
                    @if `selectedPiece & curTurn bl {
                        _playSelectSound()
                        //----------------------------
                        //向きを選択する
                        @loop bl {
                            //カーソルを表示する
                            cell = 1 + selectVx + selectVy * 3
                            _getPiecePosition(vx, selectX)

                            //向きによってずれる
                            vx += [-1, 0, 1][selectVx] * 8
                            vy += [-1, 0, 1][selectVy] * 8
                            @pic.show[PIC_CURSOR] .pos(vx, vy) .topLeft .cell(cell) cursorPicCmd

                            //入力を取得する
                            @key.input .dst(ipt) .wait bl {
                                .right
                                .left
                                .up
                                .down
                                .decision
                                .cancel
                            }

                            //向きを指示する
                            @if `enteredDirection bl {
                                _getCursorVelocity(tx, ipt)
                                V2_asAdd(selectVx, tx)
                                //端を超えたり中心に来ると調節が入る
                                @if `selectVx == 1 && selectVy == 1 bl {
                                    V2_asAdd(selectVx, tx)
                                }

                                @if `selectVx < 0 bl {
                                    V2_set(selectVx, 0, 1)
                                }

                                @if `selectVx > 2 bl {
                                    V2_set(selectVx, 2, 1)
                                }

                                @if `selectVy < 0 bl {
                                    V2_set(selectVx, 1, 0)
                                }

                                @if `selectVy > 2 bl {
                                    V2_set(selectVx, 1, 2)
                                }

                                //座標を向きに変換する
                                selectDir = [DIR_BIT_UL, DIR_BIT_U, DIR_BIT_UR, DIR_BIT_L, DIR_BIT_U, DIR_BIT_R, DIR_BIT_DL, DIR_BIT_D, DIR_BIT_DR][selectVx + selectVy * 3]
                                _playSelectSound()

                            //戻る
                            } .elif ipt == KEY_CANCEL bl {
                                _playCancelSound()
                                @break

                            //向きを選択
                            } .elif ipt == KEY_DECISION bl {
                                //動かせるかどうか
                                curEval = MOVE_NO_PROBLEM
                                //駒の規則を取得する
                                _getPieceType(pieceType, selectedPiece)
                                _getPieceRule(tmRule, pieceType)
                                //規則に則っていない
                                @if `!(tmRule & selectDir) bl {
                                    curEval = MOVE_WRONG_DIRECTION

                                //規則に則っている
                                } .else bl {
                                    //動かすとどうなる？
                                    _checkMovingPiece(field0, curTurn, selectX, selectDir)
                                    //capturedPiece,amount,vxを使用する
                                    //一歩も動けなかった
                                    @if amount <= 0 bl {
                                        curEval = MOVE_CANT
                                    }

                                    //相手の駒を取れた
                                    @if `capturedPiece bl {
                                        //王を取れるが、ターン数が足りない
                                        _getPieceType(pieceType, capturedPiece)
                                        @if `pieceType == PIECE_TYPE_KING && turnCount <= TURN_ROYAL_GUARD bl {
                                            curEval = MOVE_GET_KING
                                        }
                                    }
                                }

                                //動かせる
                                @if `curEval == MOVE_NO_PROBLEM bl {
                                    //駒の始点と終点
                                    V2_copy(actStartX, selectX)
                                    actEndX = selectX + vx * amount
                                    actEndy = selectY + vy * amount
                                    //移動開始
                                    sceneState = SCENE_STATE_MOVE
                                    @break

                                //動かせない
                                } .else bl {
                                    //メッセージを表示する
                                    @if curEval == MOVE_GET_KING bl {
                                        _showBottomText( "\c[2]<ルール違反>\c[0] まだ王様を取っちゃダメです" )
                                    }
                                    _playBuzzerSound()
                                    @wait(0)
                                }
                            }
                        }

                    //空白か、相手の駒を選択している
                    } .else bl {
                        _playBuzzerSound()
                    }
                }
            }

            //----------------------------
            //移動開始
            @if `sceneState == SCENE_STATE_MOVE bl {
                //説明文を消去する
                _showBottomText("")
                //カーソルを隠す
                _hideCursor()
                //始点にある駒と終点にある駒を取得する
                _getPieceOnField(checkedPiece, field0, actStartX)
                _getPieceOnField(capturedPiece, field0, actEndX)
                //ピクチャを移動させる
                _getPiecePicture(pid, checkedPiece)
                _getPiecePosition(vx, actEndX)
                @pic.move[pid] .pos(vx, vy) .topLeft .scale(100) .trans(0) .time(1)
                //駒を動かす
                _setPieceOnField(PIECE_BIT_NONE, field0, actStartX)
                _setPieceOnField(checkedPiece, field0, actEndX)
                //相手を倒した
                @if `capturedPiece bl {
                    cell = rnd(8, 12) * 10
                    @se.play "voice_chest2" .opt(100, cell, 50)
                    @wait .frame(6)
                    //吹っ飛ぶ
                    _getPiecePicture(pid, capturedPiece)
                    @pic.move[pid] .relative .pos(320, -320) .scale(0) .trans(0) .time(2) 
                    //ヒット音
                    @if `rnd(0, 99) < 50 bl {
                        cell = rnd(8, 12) * 10
                        @se.play "hit_db" .opt(100, cell, 50)
                    } .else bl {
                        cell = rnd(10, 12) * 10
                        @se.play "Explosion2" .opt(100, cell, 50)
                    }

                    @wait .frame(4)
                    
                    //王を倒した
                    _getPieceType(pieceType, capturedPiece)
                    @if pieceType == PIECE_BIT_KING bl {
                        //対局終了
                        sceneState = (curTurn == TEAM_BIT_RED) ? SCENE_STATE_RED_WIN : SCENE_STATE_BLUE_WIN
                        @label.jump "result"
                    }

                //特になし
                } .else bl {
                    cell = rnd(9, 11) * 10
                    @se.play "jump_anim" .opt(100, cell, 50)
                    @wait(1)
                }

                //交代する
                _nextTurn(curTurn, curTurn)
                //全滅や詰み判定は省略する
                //カーソルの向きを初期化する
                selectDir = DIR_BIT_U
                V2_set(selectVx, 1, 0)
                //ターンカウントを進ませる
                turnCount += 1
                _showTurnCountText()
                //ターン数オーバー
                @if turnCount > TURN_MAX bl {
                    _playBuzzerSound()
                    _showBottomText("\c[2]<ターン数オーバー>\c[0] 対局をやり直します。何か入力して")
                    //対局終了
                    sceneState = SCENE_STATE_REPLAY
                    @label.jump "result"
                }

                //護衛解除
                @if `turnCount == TURN_ROYAL_GUARD + 1 bl {
                    @pic.move[PIC_GUARD] .pos(GUARD_X + 64, GUARD_Y) .topLeft .scale(100) .trans(0) .time(2)
                }

                //入力待ち状態へ
                sceneState = SCENE_STATE_CTRL
            }
        }
    }

    //----------------------------
    //勝負の結果
    @label.set "result"
    bl {
        //勝敗
        @if `sceneState == SCENE_STATE_RED_WIN ||
            sceneState == SCENE_STATE_BLUE_WIN bl {
            @wait(4)

            //無敵モード中は強制的に勝利する
            @if invincibleSwitch.isOn bl {
                sceneState = SCENE_STATE_RED_WIN
            }

            //勝ち
            @if sceneState == SCENE_STATE_RED_WIN bl {
                //一度でもAIに代わりに指してもらうと勝利数がカウントされない
                @if aiCount <= 0 bl {
                    chestShougiScore += 1
                    checkSetAchievement(achievedChest, chestShougiScore >= ACHIEVE_WIN)
                }

                @se.play "Holy7" .opt(100, 100, 50)

            //負け
            } .else bl {
                @se.play "Fall1" .opt(100, 100, 50)
            }

            //勝敗を表示する
            @loop RESULT_PIC_NUM .dst(ix) bl {
                pid = PIC_RESULT + ix
                cell = (sceneState == SCENE_STATE_RED_WIN) ? 1 : 2
                @pic.show[pid] .pos(160, 120 - 32) .center .scale(200) .trans(100) .cell(cell) resultPicCmd
                @pic.move[pid] .relative .pos(0, 0) .scale(-100) .trans(-100) .time(4)
                @wait(1)
            }
            @wait(5)
        }

        //入力を待つ
        getAnyKey(ipt, TRUE)

        //----------------------------
        //もう一度やる？
        @msg.choice bl {
            .cancel(2)
            .case "\>\c[2]配置を変える\c[0]" bl {
                sceneState = SCENE_STATE_CHANGE
                @label.jump "replay"
            }
            .case "\>やりなおす" bl {
                sceneState = SCENE_STATE_REPLAY
                @label.jump "replay"
            }
            .case "\>やめる" bl {
                @label.jump "gameEnd"
            }
        }
    }

    //------------------------------------------------------------------------------------
    //終了する
    @label.set "gameEnd"
    bl {
        initPicturesAndVariables(PIC_HEAD, NUM_OF_PIC, TV_MINIGAME, NUM_OF_VAR, 0, 0)
        @scr.tint .rgbs(100, 100, 100, 100) .time(1) .wait
    }
}