Skip to content

課題: サイコロ陣取りゲームの作成

timtakamura edited this page Oct 9, 2013 · 2 revisions

概要

HTML/CSS/JavaScriptを利用してWebブラウザで遊べる簡単なボードゲームを作成してもらいます。 内容的には前回の課題: オセロの作成と似たようなものですが、オセロよりもややルールが複雑なので、ゲームエンジンとAIとUIを適宜切り分けて実装するよう注意してください。

0. 実際のゲームで遊んでみる

恐らく知らないゲームだと思いますので、いきなりルールを説明してもピンと来ないと思います。 なのでまず実際にゲームをプレイしてください。 5~10分くらい遊んでみて大体どんな感じか掴めたら次に進んでください。 これと同じようなものを作ってもらいます。

ゲームのルール(バージョン1)

  • プレイヤーは2人です(それぞれ「A」「B」と呼ぶことにします)。

  • 先手はAです。

  • 盤面は六角形の升目(いわゆる「ヘックス」)で構成されています。

  • 盤面はN×Nのヘックスを平行四辺形になるよう敷き詰めた形状をしています。

  • 最初から大きい盤面を扱うのは難しいのでN=2とします。

  • 例: N=4での盤面は下図のようになります(文字で六角形を書くのが難しいので四角形になっていますが、格子状に並んではいないところがポイントです)

         -------------------------
         |     |     |     |     |
      ----------------------------
      |     |     |     |     |
   ----------------------------
   |     |     |     |     |
----------------------------
|     |     |     |     |
-------------------------
  • 各ヘックスには最大で1個以上3個以下のサイコロが存在します。
  • 各ヘックスはいずれかのプレイヤーの陣地となっています。
  • ゲーム開始時の各ヘックスの状態はランダムで決めます。
    • 公平を期すなら「各プレイヤーの陣地の個数はなるべく同じにする」だの「サイコロの総数はなるべく同じにする」だのの「調整」を行った方が良いのですが、最初からそういうことを考えると難しいので、考えないことにします。
  • 例: ゲーム開始時点での盤面(「A 3」と書かれているヘックスはAの陣地でサイコロが3個あることを表しています。以降の図も同様です)
   -------------
   | A 3 | B 2 |
----------------
| A 2 | B 2 |
-------------
  • プレイヤーは自分の手番に何回でも手を指せますが、最低1回は手を指さなければなりません。
  • 指す手が無いならパスとなり次のプレイヤーの手番となります。
  • 指す手は「敵陣地への攻撃」のみです。自分の陣地に隣接する敵の陣地に対して攻撃ができます。ただし、攻撃する際には攻撃元にあるサイコロの数が攻撃先にあるサイコロの数より多くなければなりません。
  • 攻撃された陣地にあるサイコロは取り除かれます。その後、攻撃元にあるサイコロを1個だけ残し、攻撃先の陣地に配置します。攻撃された陣地は攻撃したプレイヤーの陣地になります。
  • 例: 下図の盤面(1)でAの手番の場合を考えると:
    • 左上のヘックスに隣接するのは右(B3)/右下/(B2)左下(A3)のヘックスで、敵陣地かつサイコロの数が少ない場所は右下のヘックスしかありません。
    • 左下のヘックスに隣接するのは右上(A3)/右(B2)のヘックスで、このうち攻撃できるのはB2のみです。B3はそもそも隣接していないので攻撃できません。
    • 右上と左下のヘックスはそもそもAの陣地ではないのでここから攻撃することはできません。
    • 盤面(1)で左下のヘックスから右へ攻撃したとすると結果は盤面(2)のようになります。
    • 盤面(2)になるとAはこれ以上攻撃することができません。Aはパスするしかありません。
   -------------
   | A 3 | B 3 |
----------------    ... (1)
| A 3 | B 2 |
-------------

   -------------
   | A 3 | B 3 |
----------------    ... (2)
| A 1 | A 2 |
-------------
  • プレイヤーの手番が終わる際に「補給」が行われます。その時点でのプレイヤーが所有する各陣地に対してサイコロを1個づつ追加します。
    • 補給は最も左上にある陣地から始めて右方向に行います。右端まで行ったら次の行の左端の陣地から右方向に行います。以下同様です。
    • 補給されるサイコロの数はその手番に攻撃して取り除いたサイコロの数から1つ減らしたものになります。
  • 例: 盤面(1)から盤面(2)のようにAが攻撃して手番を終了した場合を考えると:
    • 取り除いたサイコロの数は2個なので、補給されるサイコロの数は1個になります。
    • 最も左上の陣地はA3になりますが、ここは既にサイコロの個数が上限に達しており、これ以上追加できません。なのでこの陣地は飛ばします。
    • 次の陣地は左下です。ここはまだサイコロが1個だけなので補給ができます。
    • 残る陣地は右下ですが、もう補給できるサイコロが無くなったので、これ以上の補給はできません。
    • 結果は盤面(3)のようになります。
   -------------
   | A 3 | B 3 |
----------------    ... (3)
| A 2 | A 2 |
-------------
  • 各プレイヤーが連続してパスしたら(=どのプレイヤーも打つ手が無くなったら)ゲームは終了です。
  • ゲーム終了時に所有する陣地の数が最も多いプレイヤーが勝利します。同じ数なら引き分けです。
  • 例: 仮に盤面(3)の状態でゲームが終了したとすると、Aの陣地が3個に対しBの陣地は1個なので、Aの勝利となります。

1. 開発の準備

  • Git リポジトリを作成してください。名前は dice-of-doom-js とします。
  • GitHub にも同名のリポジトリを作成してください。
  • 以下のファイルを作成してください:
    • index.html
    • app.css
    • app.js
  • app.jsapp.css はこの段階では中身は空で構いません。
  • index.html からはCSS/JavaScriptの各ファイルを参照するようにしてください。この段階では <body> の内容は空で構いません。
  • 一通りできたらコミットし、 GitHub のリポジトリにも push してください。
    • この後は適宜コミットして GitHub のリポジトリに push してください。
    • GitHub のリポジトリに push するときは master ブランチだけでなく gh-pages ブランチにも master と同様の内容を push してください。
  • 実装にあたって必要なライブラリがあれば自由に追加してください。

2. ゲームの実装(バージョン1)

  • 「ゲームのルール(バージョン1)」で示したゲームを実装してください。
  • 最初は人間が一人二役で両方のプレイヤーの手を指すものとします。
  • 盤面の表示は凝り始めると終わらないので、先述したようなテキストベースの表示で済ませてください。ヘックス同士の境界線も今の段階では表示しなくても構いません。
  • UIも凝り始めると大変なので、次にプレイヤーが指せる手をボタンの形で列挙して、ボタンを押下すると対応する手を指したものとしてゲームが進む形にしてください。

3. AIの実装(1)

  • 一人二役では面白くないのでAIを実装してください。
  • プレイヤーAを人間が、プレイヤーBをAIが担当する形にしてください。
  • AIは先の手をどんどん読んで最終的に最も「優勢」な盤面に辿り着く手を選ぶようにしてください。
    • AIの手番を読む時はAIにとって最も「優勢」な盤面になる手を選んでください。
    • 人間の手番を読む時は人間にとって最も「優勢」な盤面になる手を選んでください。
  • 「優勢」の度合いは以下の基準で点数化してください:
    • 次にさせる手が無い盤面の場合: 自分だけが勝利するなら1.0; 引き分けなら0.5; 自分が負けるなら0.0。
    • 次にさせる手がある盤面の場合: 次にさせる全ての手の点数の最大値または最小値。

4. 盤面の拡大

  • 盤面をN=3に拡大してください。
  • 快適な速度でゲームができるようならさらに盤面をN=4に拡大してください。
  • そうでないなら快適な速度になるよう工夫してください。

5. AIの実装(2)

  • AIが先読みする手数を4手までに制限してください。
  • 手数を制限すると最初に決めた「優勢」度合いの定義は不適切になるので、何か適切な基準を決めて点数化の処理を改めてください。

6. 盤面の表示の改善

  • 盤面の表示をテキストベースのものからグラフィカルなものに変更して、ゲームの状態を分かり易くしてください。
  • 使う技術は何でも構いません。CanvasでもSVGでもただの画像でもご自由にどうぞ。
  • ただし、少なくとも:
    • ヘックスは六角形で表示してください。
    • プレイヤーの陣地の違いは色で区別が付くようにしてください。
    • ヘックスにあるサイコロの数はサイコロを個数分だけ積み重ねる形で表現してください。
  • 可能なら実際のゲームのようにクォータービューっぽい表示にするとなお良いです。

7. UIの改善

  • 手の選択をボタン式からヘックスをクリックして選ぶ形にしてください。
    • パスに関しては盤面をクリックする訳にはいかないので従来通りボタン式のままとします。
    • 攻撃に関しては「攻撃元をクリックして、次に攻撃先をクリックする」ことで手を選ぶものとします。
    • 攻撃元を変えられるよう「攻撃元をクリックして、再度攻撃元をクリックする」と攻撃先の選択をキャンセルできるようにしてください。

8. ゲームの実装(バージョン2)

  • バージョン1では攻撃は常に成功していました。これでは面白くないのでサイコロを振る形にしましょう。
    • バージョン1では「攻撃元の陣地のサイコロの数が攻撃先よりも多い」場合にしか攻撃できませんでした。これを「攻撃元の陣地のサイコロの数が2個以上」の場合に変更してください。
    • 勝敗の判定は「攻撃元の陣地のサイコロを全て振って出た目の合計」と「攻撃先の陣地のサイコロを全て振って出た目の合計」を比較して行います。前者の方が大きければ勝利で、それ以外の場合は敗北です。
    • 敗北した場合、攻撃元の陣地のサイコロは1個を残して消えます。攻撃先の陣地は変化しません。
  • 勝敗が確率によって変動することになったので、AIの「優勢」度合いの点数化もそれに応じて更新してください。

9. ゲームの実装(バージョン3)

  • バージョン1では補給されるサイコロの個数は「攻撃して取り払った敵のサイコロの個数 - 1」でした。これを「自分の陣地で連続した領域のうち、最も広いものの大きさ」に変更してください。
  • 補給のルールが変わったので、AIの思考ルーチンを必要に応じて更新してください。

10. さらなる拡張

  • 盤面をN=10に拡大してください。
  • 1つのヘックスに配置できるサイコロの上限を3個から5個に増やしてください。
  • プレイヤー数を2名から4名に増やしてください。それぞれA/B/C/Dとして、Aは従来通り人間が担当し、B/C/Dは全てAIが担当する形にしてください。