見出し画像

古典パズルゲーム「ペグソリティア」を作ろう!クミタテ式プログラミングドリル(p5JavaScript / Processing)

- 17世紀のフランス生まれ

今回作るのは、ペグソリティアという古典パズルゲームです。
ペグソリティアは17世紀のフランスで、監獄の囚人の暇つぶしで生まれ、その後、数学者によって広まったそうです。
ゲームを作るというのは環境や人を選ばず、そして優秀なゲームは数学的にも美しいということを象徴するような歴史エピソードだなと個人的に思います。
数学的なゲームを、数学的なプログラムコードに落とし込んでいきましょう。

デモアプリはこちらから。https://openprocessing.org/sketch/1501864

- クミタテ式プログラミングドリルとは?

クミタテ式は英語のコードを、日本語で書かれた図解(通称、図解くん)を使って解説し、プラモデルのように図解通りにコードを組み立てていきながら学習する、プログラミング教材です。プログラミング的思考を学ぶよりも、コードの書き方を優先的に学習することを目的としています。

図解くんの例

- 動画を見ながら学習する

動画と並行しながら学習するとより効率的に学習できるようになっています。たくさんのゲームジャンルのプログラミング方法をお伝えしているのでチャンネル登録もよろしくお願いします。

- 開発環境

OpenProcessingを使ったp5js、Processingを環境を前提としています。

- ハートを押す

この記事にいいね(ハート)をお願いします。
押すと何か良いことが起きます。


■[ここからスタート!]画面のサイズを決める

画面サイズを600x400の固定サイズにしましょう。


■背景を黄色で塗りつぶし続ける

drawの中で背景を黄色で塗りつぶし続けてアニメーションの基礎を作りましょう。


■マスとなる円を、とりあえず1つ表示する

(140, 40)の座標に白い円を1つ表示します。


■マスとなる円を、とりあえず重ねて81個表示する

9x9のマスを作っていきます。
たくさんのマスを表示するため、繰り返し処理forの中で81個のマスを一気に作ります。
ここではとりあえず、同じ座標に重ねて81個のマスを作ります。


■マスを9x9になるよう綺麗に並べる

重なってしまったマスを分解して9x9のマスに並べていきます。ここで使えるのが繰り返し処理forの中で使える変数「i」です。
変数iは0〜80まで1つずつ増えていきます。この性質を利用してマスごとに座標を変えていきます。
また、「割った余り(剰余)」や「割り算の商」を駆使することでマスの折り返し地点が制御できます。試しに9の部分を別の数字にしてみるとこの性質がよくわかります。


■マスの情報を管理する9x9の配列を用意する

9x9のマスに情報を持たせるため、9x9の情報を持った配列を用意します。配列は少し難しいのでテキストとして用意してあります。
マイナス1は石を置くことができない外枠であり、1は石が置かれていることを意味します。0は石が置いていない空きマスです。

// P5.js
let slotList = [
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1,  1,  1,  1,  1,  1,  1,  1, -1,
  -1,  1,  1,  1,  0,  1,  1,  1, -1,
  -1,  1,  1,  1,  1,  1,  1,  1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
];

// Processing
int[] slotList = new int[]{
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1,  1,  1,  1,  1,  1,  1,  1, -1,
  -1,  1,  1,  1,  0,  1,  1,  1, -1,
  -1,  1,  1,  1,  1,  1,  1,  1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1,  1,  1,  1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

■外枠のマスは黒くする

配列に-1が設定されているマスは外枠として使用しません。ここでは黒いマスとして表現しましょう。


■外枠のマスは表示されないようにスキップする

先ほど外枠を黒くしましたが見栄えがよくありませんね。外枠は一切表示されないようにしましょう。
今回は、外枠を判定したらループをスキップして次のループに移るというcontinueというキーワードを使いましょう。
キーワードは、命令と違い、カッコ()などがつきません。ちょっと特殊な書き方である点に注意してください。

 - ワンポイント -
continueに似たキーワードに「break」があります。
continueは一周スキップしてループ続行なのに対して、breakはループ自体を停止してループから抜けます。


■石を表示する

9x9の配列の情報をもとに、配列の情報が1であれば石が置かれているとし、石を表示しましょう。ここでは青色の石を表示します。


■選択中の石をハイライトする

現在選択中の石の明るさを変えてハイライト演出をします。
選択中の石は変数「bango」で管理し、ここではとりあえず22番目の石をハイライトしてみましょう。


■クリックした石を選択中としてセットする

クリックしたとき、マウスの座標から何番目の石をクリックしたかを特定して、選択中としてセットします。
マスの直径は35なので、マウスと石との距離が半径17.5以内であればクリックしたと判定できます。今回はマス同士のスペースもあるので余裕を持たせてちょうどよく20で判定します。


■石を移動するオリジナル命令を作る

from番目の石を、to番目に移動するオリジナル命令move関数を作ります。
ここではとりあえず上方向にのみ移動できるように作ります。
上のマスは-9番目であり、さらにその上は-18番目です。
選択中の石より2つ上のマスがクリックされた時、1つ上のマスに石があるか、2つ上のマスは空きマスかをチェックし、ゲームルールに乗っ取り、石を取捨させていきます。


クミタテ式の設計図はここまでです。
以下の応用課題は自分で考えてプログラミングしてみましょう。

課題1. move関数を呼び出して上方向の空きマスに移動しよう

オリジナル命令move関数はまだ未完成で上方向にしか進めません。
ですが一旦、move関数を適切な場所で呼び出して上方向の空きマスに移動できるようにしましょう。

課題2. 左右上下に移動できるようにmove関数を完成させよう

オリジナル命令move関数は上方向にしか進めない未完成品です。
下や左右の方向にも進めるようにmove関数を完成させましょう。

(難)課題3. move関数を繰り返し処理をさらにグレードアップする

課題2では左右上下の条件分岐が面倒だったと思います。プログラム難易度はあがりますが、もっと楽に判定する方法があります。
石の移動には法則性がありますので、全ての方向を条件分岐しなくても繰り返し処理でアルゴリズムに落とし込めます。
例えば・・・

function move(from, to){
  let diff = to - from;
  let directions = [
    -9, 9, 1, -1,
  ];
  for(let i=0; i<4; i++){
    let dir = directions[i];
    if(diff == dir * 2){
      if(slotList[from + dir] == 1){
        //...省略
      }
    }
  }
}

(難難)課題4. やり直し機能(UNDO)を実装しよう

ペグソリティアは1ゲームが長く、1度のミスが命取りです。そこで1つ前の状態に戻れるUNDO機能を実装しましょう。
考え方としては配列の配列です。石を動かす前に現在の配列の状態をクローンしてリストで保持していきます。UNDOしたいときは、リストの最後の配列の状態に戻せば良いわけです。

課題5. オリジナルゲームに仕上げよう

マスの配置などをカスタマイズしてオリジナルのゲームに仕上げましょう。
あるいはルール自体を変えても良いかもしれません。

- コラム「ゲームデザイン」 -
ゲームというのは気持ちよさが重要です。同時にプレイヤーにストレスを与えないことも重要です。
このペグソリティアは1ゲームが長く感じ、そしてどうしたらクリアできるのかよくわからないままプレイさせられるストレスがあります。
僕なら石の数を極端に減らし、難易度を徐々に上げていくステージ制にしていきます。
また、気持ちよさの観点から、複数の石を一気に飛び越えて取捨できるコンボのようなものを考えるかなぁと思います。

(有料エリア)完成コード

完成コードを配布しています。

ここから先は

1,854字

¥ 100

期間限定 PayPay支払いすると抽選でお得に!

この記事が気に入ったらサポートをしてみませんか?