jsでオセロゲーム作成

##二次元配列

```js
// 初期画面起動時
var turn = 0 //ターン目　1：黒、‐1：白
var ban_ar = new Array(8) //ここで要素数が8の配列にする
for (var x = 0; x < ban_ar.length; x++){
    ban_ar[x]=new Array(8)
}
```
盤面の状況を二次元配列で定義する。
まずはArrayオブジェクトで```bar_ar```の要素を8つ作る。
それからfor文でban_ar[0~7]の要素に8つの要素を作ることで8×8の64個の要素を作る事が出来る。


これをconsoleで出力すると
![スクリーンショット 2020-11-21 133601.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481470/9f1e3244-44f9-26ce-9c67-8a1576db3833.png)
となる


>解説参考
https://prokatsu.com/javascript_array/
Arryaオブジェクトについて
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/Array


##テーブルを取得

```js
var ban =document.getElementById("field")
```
htmlでテーブルタグに```id="field"とつけたのを取得する

###なぜここで盤面作成と初期化の関数を呼び出すのか

```js
//取得したテーブルに盤面を作成
ban_new()

//盤面の初期化
ban_init()
```

##クリック時のイベント

```js
for (var x = 0; x < 8; x++){
    for (var y = 0; y < 8; y++)
    var select_cell = ban.rows[x].cells[y];
    select_cell.onclick = function () {
        if (ban_ar[this.parentNode.rowIndex, this.cellIndex] == 0) {
            if (check_reverse(this.parentNode.rowIndex, this.cellIndex) > 0) {
                ban_set()
                cheng_turn()
            }
        }
    }
}
```
これはfor文の中にfor文が入ってるので
xが0の間にyが0~7をfor文を回し、次にxが1の間にyが0~7までfor文を回すという事。

その中は
```var select_cell =どの配列.どこ```
を定義するもの。
その後に、そのcellがクリックされたときのイベントについて（無名関数）の記述。
日本語に訳すと

```
if(ban_ar[ban_arのxの位置、banのyの位置]置く前どっちも0の時＝まだ何も置かれていなくて新たに置ける時｛
if(石を置いてひっくり返せるか確認する関数(親ノード.rowのxのセル、ban_arのyのセル)が0より大きい時＝石が置ける時){
石を置く
ターンを変わる
    }
   }
  }
}
```
クリックされた時の処理は
クリックされた場所に石がないことを確認
↓
その場所に置く側の石が置けるかを確認
↓
置ける場合は盤面を更新して相手にターンを渡す

≻parentnodeがなぜ必要かがわからない
二次元配列だから？

##テーブルで盤面を作成する
```js
function ban_new() {
    for (var x = 0; x < 8; x++){
        var tr = document.createElement("tr")
        ban.appendChild(tr)
        for (var y = 0; y < 8; y++){
            var td = document.createElement("td")
            tr.appendChild(td)
        }
    }
}

```
今回はtrで横一列を8つ作りそれをthで8のセルに分けた。
```createElement```で要素を作り```appendChild```でそれを追加しています。
2重のfor文はさっきと同じ
もしここで```x<4```にしたら上半分しか盤面がなくなる（笑）

>trタグ
http://www.htmq.com/html/tr.shtml
tdタグ
http://www.htmq.com/html/td.shtml
createElement
https://itsakura.com/js-createelement
appendChild
https://developer.mozilla.org/ja/docs/Web/API/Node/appendChild

**ここまで書いたら盤面が表示されていると思うから確認**

##全削除ボタン

```js
function ban_init() {
    //すべてクリア
    for (var x = 0; x < 8; x++) {
        for (var y = 0; y < 8; y++){
            ban_ar[x][y] = 0
        }
    }
```
すべてのセルを0にして空欄にする

その後に
##黒白2枚ずつの初期状態
```js
    ban_ar[3][3] = -1
    ban_ar[4][3] = 1
    ban_ar[3][4] = 1
    ban_ar[4][4] = -1
    ban_set()
```
で黒白を2枚ずつ配置することが出来る。
ちなみに
```   ban_ar[0][0] = -1
    ban_ar[0][7] = 1
    ban_ar[7][0] = 1
    ban_ar[7][7] = -1```
とすれば最初から四つの角を埋めた状態になる（しかしゲームはルール上一生始まらない笑）

##ターンのリセット
```js
　　turn = 0
　　cheng_turn()
```
でターンをゼロ指定をしてターンを元に戻す関数を実行する


##盤面の状況を画面に反映させる処理

```js
function ban_set() {
    var stone = ""//基本は何も置いていないから空欄
    for (var x = 0; x < 8; x++){
        for (var y = 0; y < 8; y++){
            switch (ban_ar[x][y]) {
                case 0:
                    stone = ""
                    break;
                case -1:
                    stone = "○"
                    break;
                case 1:
                    stone = "●"
                    break;
            }
            ban.rows[x].cells[y].innerText = stone;
        }
    }
    return true
}
```
ここのメインはswitch文でもし
2つのfor文ですべてマスを確認する任意のマスが
0なら空白
－1なら白
1なら黒
として反映させる
このswitch文によって各セルの状況がわかったのでinnerTextでレンダリング（表示）する


≻switch文
https://www.javadrive.jp/javascript/if/index4.html
innerText
https://techacademy.jp/magazine/15332
>>ban_ar[x][y]=盤面の白黒空白の判断するのはどこだ？
ここでのreturn trueの意味は？（なくても作動するが、、、）

##ターン変更時の処理
```js
function cheng_turn() {
    var tarn_msg = document.getElementById("view_tarn")
    if (turn == 0) {
        turn = 1
        turn_msg.textContent = "黒の番です"
        return
    }
    //ターンを変更
    turn = turn * -1
    //ターンを交代して、置けるところがあるかを確認する
    //現状の配置をバックアップ
    var ban_bak = new Array(8)
    var check_reverse_cnt = 0
    for (var i = 0; i < ban_ar.length; i++){
        ban_bak[i]=new Array(8)
    }
    for (var x = 0; x < 8; x++){
        for (vary = 0; y < 8; y++){
            ban_bak[x][y]=ban_ar[x][y]
        }
    }
    var white_cnt = 0
    var black_cnt = 0
    for (var x=0; x < 8; x++) {
        for (var y = 0; y < 8; y++){
            //空白マスのみ置けるのでチェック
            //それ以外は石の数の計算
            switch(ban_ar[x][y]){
                case 0:
                check_reverse_cnt = check_reverse_cnt + check_reverse(x, y)
                //バックアップから元に戻す
                for (var i = 0; i < 8; ii++){
                    for (var ii = 0; ii < 8; ii++){
                        ban_ar[i][ii]=ban_bak[i][ii]
                    }
                }
                break;
                case -1:
                white_cnt++
                break
                case 1:
                black_cnt++
                break
            }
        }
    }
    //白と黒の合計が8*8=64の場合は終了
    if (white_cnt + black_cnt == 64 || white_cnt == 0 || black_cnt == 0) {
        if (white_cnt == black_cnt) {
            alert("引き分けです")
        } else if (white_cnt > black_cnt) {
            alert("勝負は黒："+black_cnt+"対、白："+white_cnt+"で白の勝ち")
        } else {
            alert("勝負は黒:"+black_cnt+"対、白："+white_cnt+"で黒の勝ちです")
        }
    } else {
        //置ける場所がない場合はターンを相手に戻す
        if (check_reverse_cnt == 0) {
            switch (turn) {
                    case -1:
                    alert("白のおける場所がありません。続けて黒の番になります")
                    turn = turn * -1
                    break;
                    case 1:
                    alert("黒のおける場所がありません。続けて白の番となります。")
                    turn = turn * -1
                    break;
            }
        }
    }
    //ターンを表示
    switch (turn) {
        case -1:
            tarn_msg.textContent = "白の番です";
            break;
        case 1:
            tarn_msg.textContent = "黒の番です";
            break;
    }
}
```
ここはかなり文量が多いですが1つずつ分解していきます

まず```tarn_msg```にhtmlで定義した```view_tarn```を与えます
次にif文でゲーム開始時はturnが0でどちらのターンにもならないのでturnを1にして黒のターンにしてあげます。

それから```turn = turn * -1```でターンを変更する

バックアップを取るために64個のマスと同じように2次元配列で64個の配列を作る。
それからban_bak[x][y]にban_bar[x][y]を入れる事でバックアップを同期する

white_cntとblack_cntは盤上に各色の石の枚数を定義する

その後switch文でセルが空欄の時check_reverseが空欄だからcheck_cntは変わらない
もし-1なら白をカウントしてる数に+1をする
もし1なら黒のカウントに+1をする

###試合が続行できない場合
試合が続行できない状況は
・すべてのマスが埋まる
・どちらかが0になる
・白もしくわ黒のどちらかが置けるマスがない時
それらをif文で処理してきます。
上の2つの場合はどちらも勝敗が決まるのでif文のor演算子を使ってまとめて書きます。

2つ目に置ける場所がない時は先使ったswitch文のように白の場合は黒のターンにして、黒の場合は白のターンにします。

>or演算子「｜」
https://udemy.benesse.co.jp/development/system/javascript-if-else.html
>>なぜバックアップをとるのか？
check_reverse_cntがよくわからない
check_reverse_cnt = check_reverse_cnt + check_reverse(x, y)が謎

###ターン表示
こちらも白黒に応じてテキスト内容を変えるだけなのでswitch文を使います。



##指定したセルにターン側の石が置けるかを確認
check_reverse関数の引数にはセルの縦横軸の数値を入れるようにして
>>　なぜ```x=x+1```が成り立つのか？「=」は左から右に代入する代入演算子だから！！



```js
//指定したセルから指定した方向へのreverseを行う
function line_reverse(row_index, cell_index, add_x, add_y) {
    //最初に今の盤状況を対比する
    var ban_bak = new Array(8)
    for (var i = 0; i < ban_ar.length; i++){
        ban_bak[i]=new Array(8)
    }
    for (var x = 0; x < 8; x++){
        for (var y = 0; y < 8; y++){
            ban_bak[x][y]=ban_ar[x][y]
        }
    }
    var line_reverse_cnt = 0
    var turn_flg = 0
    var xx = row_index
    var yy = cell_index
    //指定したセルから指定された方向へ移動
    //完了条件になるまで石を返す
    while (true){
        xx = xx + add_x
        yy = yy + add_y
        //盤の端」に到達したら抜ける
        if (xx < 0 || xx > 7 || yy < 0 || yy > 7) {
            break;
        }
        //移動先のセルに石がなかったら抜ける
        if (ban_ar[xx][yy] == 0) {
            break
        }
        //移動先のセルが自分自身であれば、石があった事を判断し抜ける
        if (ban_ar[xx][yy] = turn) {
            turn_flg = 1
            break;
        }
        //上記以外は相手の石であるので、裏返して裏返した件数の加算
        ban_ar[xx][yy] = ban_ar[xx][yy] * -1
        line_reverse_cnt++
    }
    //裏返しを行ったが移動先に自分の石がなかった場合は元に戻す
    if (line_reverse_cnt > 0) {
        if (turn_flg == 0) {
            for (var i = 0; i < 8; i++){
                for (var ii = 0; ii < 8; ii++) {
                    ban_ar[i][ii] = ban_bak[i][ii]
                    line_reverse_cnt=0
                }
            }
        } else {
            //ちゃんと裏返しが出来たら置いた所に自分の石を置く
            ban_ar[row_index][cell_index]=turn
        }
    }
//最後に裏返しを行った件数を戻す
    return line =line_reverse_cnt
}

```

##指定したセルから指定した方向へのリバースを行う
バックアップを取った時と同じ形で対比をする
while文でいくつひっくり返せるかを計算する。
しかし8方向中すべて返せるかはわからないのでここで処理する
（石をひっくり返すには相手の石がないといけないから）
そこで残った方向にひっくり返せえるという事だから、そこでいくつひっくり返せるかを計算したら、そこに石を置いて自分のスコアをreturnで返す。
>>なぜ対比するのか？


≻このゲームを通じて「x=x+1」が成り立つ理由にずっと悩んでいたがjsでの「=」は数学的な意味での「=」とは違う
jsでは代入演算子と呼び、右側のデータなどを左の数値やプロパティなどに代入することである。
数学的な意味の「イコール」を示したい場合は「==」の等価や「===」の厳密等価を使う。