##二次元配列
// 初期画面起動時
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個の要素を作る事が出来る。
解説参考
https://prokatsu.com/javascript_array/
Arryaオブジェクトについて
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/Array
##テーブルを取得
var ban =document.getElementById("field")
htmlでテーブルタグに```id="field"とつけたのを取得する
###なぜここで盤面作成と初期化の関数を呼び出すのか
//取得したテーブルに盤面を作成
ban_new()
//盤面の初期化
ban_init()
##クリック時のイベント
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がなぜ必要かがわからない
二次元配列だから?
##テーブルで盤面を作成する
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
ここまで書いたら盤面が表示されていると思うから確認
##全削除ボタン
function ban_init() {
//すべてクリア
for (var x = 0; x < 8; x++) {
for (var y = 0; y < 8; y++){
ban_ar[x][y] = 0
}
}
すべてのセルを0にして空欄にする
その後に
##黒白2枚ずつの初期状態
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][7] = 1
ban_ar[7][0] = 1
ban_ar[7][7] = -1```
とすれば最初から四つの角を埋めた状態になる(しかしゲームはルール上一生始まらない笑)
##ターンのリセット
```js
turn = 0
cheng_turn()
でターンをゼロ指定をしてターンを元に戻す関数を実行する
##盤面の状況を画面に反映させる処理
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の意味は?(なくても作動するが、、、)
##ターン変更時の処理
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
が成り立つのか?「=」は左から右に代入する代入演算子だから!!
//指定したセルから指定した方向への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では代入演算子と呼び、右側のデータなどを左の数値やプロパティなどに代入することである。
数学的な意味の「イコール」を示したい場合は「==」の等価や「===」の厳密等価を使う。