Laravelで将棋アプリを作りたい（第二回）

[第一回：プロジェクト作成 ~ 盤面作成](https://qiita.com/motoshi_cocoa/items/4397885d12185b9adb5b)

今回は、駒移動

#目次
[0.前回からの修正](#0-前回からの修正)
[1.駒を押したら、移動可能マスを選択できるようにする。](#1-駒を押したら、移動可能マスを選択できるようにする。)
[2.移動可能マスを押したら移動できるようにする。](#2-移動可能マスを押したら移動できるようにする。)

#0. 前回からの修正

ビューに渡していた`$appName`は必要ないので削除した。
駒の画像が読み込めないことが起こったため、画像ではなくテキストにした。
`$r(列)`と`$c(行)`をくっつけた変数(`$r . $c`)を新たに`$square(マス)`と定義した

#1. 駒を押したら、移動可能マスを選択できるようにする。

細かい要件は以下。今回は王将のみの実装

- 駒を押したら、その駒の移動可能マスを探す。
 - 1.1. 駒をリンクにして、現在いるマス目を引数で渡す。
 - 1.2. そのマス目を元に、移動可能マスを割り出す。

- 移動可能マスに色を付けてボタンにする。
 - 1.3. 移動可能マスでは表示を変える。

###1.1. 駒をリンクにして、現在いるマス目を引数で渡す。

`index`ページの駒を`select`ページへの引数を持ったリンクにする。

引数には駒名、列、行を「:」でつなげた文字列が入るようにする。

リンク部分

```html
<a style="text-decoration:none" href="' . action('App\Http\Controllers\ShogiController@select', 'myKing:' . $r . ':' . $c) . '">王</a>
```

修正後のindexページ

```php:resources/views/index.blade.php
<!DOCTYPE html>
<html>
<head>
    <title>将棋アプリ</title>
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>
<body>
    <div class="board">
        <?php
        for ($c = 1; $c < 10; $c++) {
            echo '<div class="column column' . $c . '" id="column' . $c . '">';
            for ($r = 9; $r > 0; $r--) {
                $square = $r . $c;
                if ($square == $MyKing) {
                    echo '<p class="piece row square' . $square . '" id="square' . $square . '"><a style="text-decoration:none" href="' . action('App\Http\Controllers\ShogiController@select', 'myKing:' . $r . ':' . $c) . '">王</a></p>';
                } else {
                    echo '<p class="row square' . $square . '" id="square' . $square . '">' . $square . '</p>';
                }
            }
            echo '</div>';
        }
        ?>
    </div>
</body>
</html>
```

`select`ビューを新たに作成

```php:resources/views/shogi/select.blade.php
// 新規作成
<!DOCTYPE html>
<html>
<head>
    <title>将棋アプリ</title>
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>
<body>
    <div class="board">
        <?php 
        for ($c = 1; $c < 10; $c++) {
            echo '<div class="column column' . $c . '" id="column' . $c . '">';
            for ($r = 9; $r > 0; $r--) {
                $square = $r . $c;
                if ($square == $MyKing) {
                    // 駒のあるマスには piece というクラスを追加
                    echo '<p class="piece row square' . $square . ' selected" id="square' . $square . '">王</p>';
                } else {
                    echo '<p class="row square' . $square . '" id="square' . $square . '">' . $square . '</p>';
                }
            }
            echo '</div>';
        } 
        ?>
    </div>
</body>
</html>
```

###1.2. そのマス目を元に、移動可能マスを割り出す。

コントローラーに`select`メソッドを追加

```php:app/Http/Controllers/ShogiController
    // 追加
    public function select($piece)
    {
        // $pieceには King:5:9 のように駒名、列、行が「:」でくっついた形が入る。
        $select = explode(":", $piece);
        $pieceName = $select[0];
        $row = $select[1];
        $column = $select[2];
        $MyKing = $row . $column;
        $ways = array();
        // 王将の移動可能マスを割り出して、$waysに追加する。
        for ($c = $column-1; $c < $column+2 ; $c++) {
            for ($r = $row-1; $r < $row+2 ; $r++) {
                $ways[] = $r . $c;
            }
        }
        // 重複削除
        $way = array_unique($ways);
        // 移動可能マスを $way という配列に入れてselectページに渡す
        return view('shogi/select', compact('MyKing', 'way'));
    }
```

`select`メソッドへの引数つきのルートを追加

```php:routes/web.php
// 追加
Route::get('shogi/select/{piece}', 'App\Http\Controllers\ShogiController@select');
```

###1.3. 移動可能マスでは表示を変える。

コントローラーから渡された引数を元に`select`ページの表示を条件分岐する。

マス目が`$way`に含まれるときは`class`に`way`を追加して、さらにgoボタンを表示させる。

```php:resources/views/select.blade.php
<!DOCTYPE html>
<html>
<head>
    <title>将棋アプリ</title>
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>
<body>
    <div class="board">
        <?php 
        for ($c = 1; $c < 10; $c++) {
            echo '<div class="column column' . $c . '" id="column' . $c . '">';
            for ($r = 9; $r > 0; $r--) {
                $square = $r . $c;
                if ($square == $MyKing) {
                    // 駒のあるマス selectedクラスを追加
                    echo '<p class="piece row square' . $square . ' selected" id="square' . $square . '">王</p>';
                } elseif (in_array($square, $way)) {
                    // 移動可能マス
                    echo '<p class="row square' . $square . ' way" id="square' . $square . '"><input type="button" value="go"/></p>';
                } else {
                    // それ以外のマス
                    echo '<p class="row square' . $square . '" id="square' . $square . '">' . $square . '</p>';
                }
            }
            echo '</div>';
        } 
        ?>
    </div>
</body>
</html>
```

追加したクラスを元にCSSを追加

```css:public/css/style.css
// 追加
.selected {
    background-color: yellow;
}

.way {
    background-color: red;
}

.piece {
    font-size: 30px;
    font-weight: bold;
}
```

これで、`index`で駒のリンクを踏むと、`select`では移動可能マスを選択できるようになった。

![移動可能マスが表示されたselectページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594194/72f2035e-24a0-b419-c361-de56e8c8dff2.png)


#2. 移動可能マスを押したら移動できるようにする。

細かい要件は以下。POST送信で移動先を教えるという流れにする。

- どのgoボタンを押したか判別する。
  - 2.1.  select ページに index 宛のフォームを作成する。
  - 2.2. どのボタンが押されたか区別できるように、押されたボタンには新たに「move」という名前をつける（JavaScript使用）

-  押したボタンの位置にコマを移動する。
 - 2.3. 「move」と名前のついたボタンの情報から、移動先を決定する。


###2.1.  select ページに index 宛のフォームを作成する。

moveformという名前のフォームを追加。csrf対策のために`{{ csrf_field() }}`も記述する必要がある。

```html
<form action="/shogi" method="POST" name="moveform">
    {{ csrf_field() }}
```

hiddenタイプで $square の値を送る。
送信ボタンは、クリック時に movePiece という関数（後で作成）を実行するようにする。

```php
echo '<input type="hidden" value="' . $square . '" name="square" id="data' . $square . '"></input>';
echo '<p class="row square' . $square . ' way" id="square' . $square . '"><input type="button" value="go" onclick="movePiece(' . $square . ')"/></p>';
```

別のJSファイルで記述する movePiece 関数を使えるようにするために、head内でJSを読み込む。

```html
<script type="text/javascript" src="{{ asset('js/shogi.js') }}"></script>
```

以上によって修正した`select`ビュー

```php:resources/views/select.blade.php
<!DOCTYPE html>
<html>
<head>
    <title>将棋アプリ</title>
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
    <script type="text/javascript" src="{{ asset('js/shogi.js') }}"></script>
</head>
<body>
    <div class="board">
        <form action="/shogi" method="POST" name="moveform">
            {{ csrf_field() }}
            <?php
            for ($c = 1; $c < 10; $c++) {
                echo '<div class="column column' . $c . '" id="column' . $c . '">';
                for ($r = 9; $r > 0; $r--) {
                    $square = $r . $c;
                    if ($square == $MyKing) {
                        // 駒マス
                        echo '<p class="piece row square' . $square . ' selected" id="square' . $square . '">王</p>';
                    } elseif (in_array($square, $way)) {
                        // 移動可能マス 送信されるデータはここにしかない
                        echo '<input type="hidden" value="' . $square . '" name="square" id="data' . $square . '"></input>';
                        echo '<p class="row square' . $square . ' way" id="square' . $square . '"><input type="button" value="go" onclick="movePiece(' . $square . ')"/></p>';
                    } else {
                        // それ以外のマス
                        echo '<p class="row square' . $square . '" id="square' . $square . '">' . $square . '</p>';
                    }
                }
                echo '</div>';
            }
            ?>
        </form>
    </div>
</body>
</html>
```

###2.2. どのボタンが押されたか区別できるように、押されたボタンには新たに「move」という名前をつける（JavaScript使用）

jsファイルは`public`フォルダに配置する。

クリックされたボタンのマス目を取得して、そのマス目と同じ番号のinputデータ（hiddenで作成した）に「move」という名前をつける。

```javascript:public/js/shogi.js
// 新規作成
var movePiece = function (square) {
    // クリックされたボタンのマスを取得
    const data = document.getElementById('data'+square);
    // そのマスを「move」と名付ける
    data.name = 'move';
    // フォームのデータを送信する。
    document.moveform.submit();
}
```

###2.3. 「move」と名前のついたボタンの情報から、移動先を決定する。

`index`へのPOST送信のルートを追加する。

```php:routes/web.php
Route::post('shogi', 'App\Http\Controllers\ShogiController@index');
```

POST送信時のデータを使用するために、コントローラにRequestクラスの使用を記述。

```php:app/Http/Controllers/ShogiController.php
// namespace App\Http\Controllers;の下に追加
use Illuminate\Http\Request;
```

`index`メソッドで「move」がある場合は、それを王将の位置としてビューに渡す。
これで、王将が位置が変化した`index`ビューが表示される。

修正後の`index`メソッド

```php:app/Http/Controllers/ShogiController.php
    // POST送信のデータを引数で受け取る
    public function index(Request $request)
    {
        if ($request->isMethod('post')) {
            // POSTでのアクセス時の処理
            $MyKing = $request->input('move');
        } else {
            // GETでのアクセス時の処理
            $MyKing = '59';
        }
        return view('shogi/index', compact('MyKing'));
    }
```

これで、駒押す→移動可能マス表示→移動可能マス選択→移動 の繰り返しができるようになった。

![移動できるようになった王将](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594194/08b98d24-12ec-c429-95d2-b449321ff143.png)

今回はここまで。

[Github](https://github.com/motoshifurugen/laravel-shogi)