スポンサーリンク

【JavaScript】リバーシ(オセロ)の作り方を初学者向けに1行づつ解説!④【ゲーム】

javascript
勉強の為にJavaScriptでリバーシ(オセロ)を作りたい!
簡単なCPUを実装したい!

という方、初学者向けの解説記事です。

この記事を読んでできること

オセロの作り方を理解することができる
簡単なCPUを実装することができる

対象読者様

javascriptだけで簡単なゲームを作りたい方
コードの意味作り方を理解したい方

上記のような読者様を想定しております。

当記事では javascriptで初めて何かを作りたい方 を想定している為
4つのパートに分けて解説をしていきます。

今回は第4回(前回はこちらリバーシの作り方を初学者向けに1行づつ解説!③)
CPUが自動で考えて、石を置いてくれるを解説していきます。

今回でついに最終回です。がんばっていきましょう!

概要説明

今回はついにCPUが自動で考えて、石を置いてくれるを実装していきます。

…といってもあまり身構えなくても大丈夫です。
ちょっとの追加と関数を3つ理解するだけで↓を完成させることができます。

◆ポイント

①配列とsetTimeoutを追加する
②keisanOmomiData()/copyData()  → どのマスの点数が高いか判定する③cpuThinking() → ひっくり返せるマスをCPUが探して実行する
やはり一番大変なのは③の関数です。
それを②の関数で補助しているような関係です。

順に解説していきます。

①配列とsetTimeoutを追加しよう!

//変数の宣言するところに追加する
let omomiData = [
 [30, -12, 0, -1, -1, 0, -12, 30],
 [-12, -15, -3, -3, -3, -3, -15, -12],
 [0, -3, 0, -1, -1, 0, -3, 0],
 [-1, -3, -1, -1, -1, -1, -3, -1],
 [-1, -3, -1, -1, -1, -1, -3, -1],
 [0, -3, 0, -1, -1, 0, -3, 0],
 [-12, -15, -3, -3, -3, -3, -15, -12],
 [30, -12, 0, -1, -1, 0, -12, 30]
]; 

//kousin()の最後に追加する
if (myTurn === false) {
  setTimeout(cpuThinking, 1000);
}

まずは、関数以外のお話です。上記2点を追加します。

色部分はなんとなくお分かりかと思います。

setTimeout(cpuThinking, 1000)
1秒(=1000ミリ秒)経過したら関数cpuThinkingを実行してねという関数です。

kousin()は自分のターンの処理が終わると発動し、画面を再描画するもの
setTimeoutを設定することがCPUが悩んでいるようになり、ゲームっぽくなります。

重みデーター とは

続いて配列についてです。

気づいた方もいらっしゃると思いますが、8×8のマスそれぞれに対応する数字になっています。具体的にはどのマスに置くと価値が高いかを表します。

・四隅が「30」
・四隅の隣のマスが「-12」
・四隅の斜めのマスが「-15」
・それ以外は大体マイナス

オセロは4隅をとると大体勝てちゃいますよね。
それを数字で表したのがこの配列です。

一旦は「価値の高さをマスごとに数字で設定している」ことだけ分かれば大丈夫です。

②keisanOmomiData()/copyData()を理解しよう!

function keisanOmomiData(kariData) {
 let score = 0;
 for (let x = 0; x < 8; x++) {
  for (let y = 0; y < 8; y++) {
   if (kariData[x][y] === KURO) {
   score += omomiData[x][y];
   }
  }
 }
return score;
}


// 石テーブルデータをコピー;
function copyData() {
 let kariData = [];
  for (let x = 0; x < 8; x++) {
  kariData[x] = [];
   for (let y = 0; y < 8; y++) {
   kariData[x][y] = data[x][y];
   }
  }
 return kariData;
}
2つの関数がでてきました。それぞれ、score/kaiDataを返す為のものです。

keisanOmomiData(kariData)return score
copyData()return kariData
kariDataはとてもシンプル

xを8回、yを8回まわした後にkariData[x][y] = data[x][y]としているので
64個分の配列(kariData[0][0]、kariData[0][1]…kariData[7][7]) がreturnされます。

score って何を表しているの?

一方でscoreは合計した値です。
黒の置かれた場所の重み(omomiData)を合計した値です。

合計値が一番大きくなるマスを探して石を置くという処理をcpuThinkingで実装します。その判断基準がこの合計値です。

kariData[x][y] === KURO、つまりCPU(黒)の石があるなら
score += omomiData[x][y]でマス目に対応した数値(0,-30,15…)を加えてね

という処理になっています。

③cpuThinking()を理解しよう!

function cpuThinking() {
 let highScore = -1000;
 let px = -1;
 let py = -1;
  for (let x = 0; x < 8; x++) {
   for (let y = 0; y < 8; y++) {
   let kariData = copyData();
   let cpuCanReverceMasu = canReverceMasu(x, y, KURO);
    if (cpuCanReverceMasu.length > 0) {
     for (let i = 0; i < cpuCanReverceMasu.length; i++) {
     let p = cpuCanReverceMasu[i][0];
     let q = cpuCanReverceMasu[i][1];
     kariData[p][q] = KURO;
     kariData[x][y] = KURO;
    }
   let score = keisanOmomiData(kariData);
   if (score > highScore) {
   highScore = score;
   (px = x), (py = y);
   }
  }
 }
}


if (px >= 0 && py >= 0) {
  let cpuCanReverceMasu = canReverceMasu(px, py, KURO);
   if (cpuCanReverceMasu.length > 0) {
     for (let k = 0; k < cpuCanReverceMasu.length; k++) {
     put(cpuCanReverceMasu[k][0], cpuCanReverceMasu[k][1], KURO);
     }
   }
  put(px, py, KURO);
 }
kousin();
}

ついに最後の関数までやってきました…!
処理の流れはこのようになります。①②③の順に解説します。

①CPU(黒)の石を置ける場所を探す
②置いた状況を再現
③②の状態で一番点数の合計値が高い座標を求める
④石を置く

①仮データー(kariData)を作成しよう

let kariData = copyData();
let cpuCanReverceMasu = canReverceMasu(x, y, KURO);

kariDataは64個分の配列(kariData[0][0]、kariData[0][1]…kariData[7][7])のこと

cpuCanReverceMasuは黒をひっくり返すことができるマスのことです
どのマスをひっくり返せるかは前の章で説明した内容ですので、こちらをご参考いただければ幸いです。リバーシの作り方を初学者向けに1行づつ解説!③

②置いた状況を再現

  if (cpuCanReverceMasu.length > 0) {
     for (let i = 0; i < cpuCanReverceMasu.length; i++) {
     let p = cpuCanReverceMasu[i][0];
     let q = cpuCanReverceMasu[i][1];
     kariData[p][q] = KURO;
     kariData[x][y] = KURO;
    }
注目いただきたいのは太文字です。

cpuCanReverceMasuはCPUの石をおける座標
そのx,y座標をp,qとしてkariData[p][q] = KUROを設定します。

こうすると、KUROが置かれたと仮定した状況を作ることができます。

③②の状態で一番点数の合計値が高い座標を求める

let score = keisanOmomiData(kariData);
 if (score > highScore) {
 highScore = score;
 (px = x), (py = y);
}

if (px >= 0 && py >= 0) {
//略
  put(px, py, KURO)
//略
}
keisanOmomiDataはCPUの石を置いた時の合計点数
これを1つ前のscore(highScore)と比較して優先度が高いならhighScoreを更新。
その座標をpx,pyに格納します。
この関数の冒頭でpx = -1,py = -1としていました。
これがif (px >= 0 && py >= 0) 、両方0以上になる場合ならどこかに石を置けたことになります。
改めて完成品を見てみましょう。
しっかりゲームとして機能していることがわかりますね!

まとめ

ここまで4回にわたり、オセロの実装方法について解説致しました。
分かりづらかったところも多々あると思いますが、javascript学習の一助になれば幸いです。

お疲れさまでした!

前:【JavaScript】リバーシ(オセロ)の作り方を初学者向けに1行づつ解説!③