今回は、手軽に作って遊べる15パズルを作ってみましょう。なでしこ3ならブラウザで動くので、ゲームのルールやステージを自分で作ってみんなに遊んでもらいましょう。

作成した15パズル

○15パズル - ゲームのルール

今回作るパズルゲームは、15パズルです。15パズルというのは、スライドパズル(または、スライディングパズル)と呼ばれるゲームの一種です。画面に4×4のブロックがあり、そのうち1つのブロックが空の状態になっています。

そして、各ブロックには1から15までの数字が描かれています。空のブロックの上下左右にあるブロックを空のブロックに動かすことができます。ゲームを開始するとき、この番号はランダムにシャッフルされます。それで、空きの部分を活かして、ブロック1から15までを順番に左上から右下へと綺麗に並べ替えることができればゲームクリアです。

15パズルのルール

○ブラウザ画面に図形を描画しよう

昨今のモダンブラウザであれば、高度な描画機能を備えています。そのため、ブラウザ上で動くなでしこ3からもブラウザの画面に図形を描画することができます。

今回の15パズルを作る際にも、描画機能を使ってみましょう。まずは、なでしこ3を手軽に実行できる「なでしこ3簡易エディタ(グラフィックス用)」にアクセスしましょう。

最初に簡単な図形を描画してみます。以下のプログラムを入力して「実行」ボタンを押してみましょう。

5に線太設定。

青色に線色設定。

赤色に塗り色設定。

[20,30,200,200]の四角描画。

2に線太設定。

「#FF9090」に線色設定。

「#f0f0f0」に塗り色設定。

[200,200]へ110の円描画。

実行すると以下のように正方形と正円を描画できます。

図形を描画したところ

図形を描画するときに、色や輪郭線の太さなど指定できることが分かります。こうした図形を描画する命令を組み合わせることで、ゲームの画面も描画できます。今回の15パズルの画面も、縦横方向にブロックを順に繰り返し描画することで成り立っています。

それでは、15パズルの画面を描画してみましょう。以下のプログラムを簡易エディタに入力して実行してみましょう。

DW=90 # ブロックの幅

データ=[

 [1,2,3,4],

 [5,6,7,8],

 [9,10,11,12],

 [13,14,15,0]

]

ブロック描画。

●ブロック描画とは

 [0,0,DW*4,DW*4]の描画クリア。

 DW2=DW÷2

 黒色に線色設定

 1に線太設定。

 「40px Aria」に描画フォント設定

 Yを0から3まで繰り返す

  Xを0から3まで繰り返す

   DX=X*DW

   DY=Y*DW

   V=データ[Y][X]

   もし、V > 0ならば

    「#733」に塗色設定。

    [DX, DY, DW, DW]へ四角描画。

    「#baa」に塗色設定。

    [DX+DW2, DY+DW2]へ(DW2-3)の円描画。

    「#333」に塗色設定。

    [DX+17, DY+60]に(Vを2でゼロ埋め)を文字描画。

   違えば

    「#999」に塗色設定。

    [DX, DY, DW, DW]へ四角描画。

   ここまで。

  ここまで

 ここまで

ここまで。

実行してみると、以下のように表示されます。

15パズルの盤面を描画したところ

プログラムの上部にある変数「データ」に指定した数字を変更して、改めてプログラムを実行してみてましょう。描画される数字が変わります。また、0の値が空きブロックです。

○ブロックデータの表現

さて、ゲームを作るときに大切なのが、ゲーム画面をどのようなデータ構造で表現するのかという点です。今回、数字ブロックを表現するのに二次元配列変数を利用することにしました。一つ前の画面を描画するプログラムでも示しましたが、縦4×横4個の二次元配列を用いて、ブロックの配置を表現します。

データ=[

 [ 1, 2, 3, 4],

 [ 5, 6, 7, 8],

 [ 9,10,11,12],

 [13,14,15, 0]

]

このようなデータをプログラムで初期化する方法も確認していきましょう。二次元配列変数を操作する参考になります。

●ブロック初期化とは

 データ=[]

 Yを0から3まで繰り返す

  データ[Y] = []

  Xを0から3まで繰り返す

   データ[Y][X] = 1 + (Y * 4 + X) # --- (*1)

  ここまで

 ここまで

 データ[3][3] = 0 # 空きブロック

ここまで

最初に「繰り返す」構文を縦方向と横方向に入れ子状に配置することにより、4×4回の繰り返しを実行している点に注目しましょう。そして、(*1)の部分にも注目しましょう。データ[Y][X]の値を設定していますが、1 + (Y * 4 + X)を計算すると、左上から右下に向かって順に1から16までの値を設定できます。

○15パズルのゲーム

それでは、実際のゲームを作ってみましょう。以下のプログラムをエディタに貼り付けて実行するとゲームが始まります。

# -------------------------------

# 15パズルのプログラム

# -------------------------------

データ=[]

DW=90 # ブロック幅

上下左右=[[-1,0],[1,0],[0,-1],[0,1]]

Fステージ=「#nako3_canvas_1」

シャッフル回数=0

初期化処理。

# マウスイベントの処理 --- (*1)

Fステージをマウス押した時には

 Y=INT(マウスY÷DW)

 X=INT(マウスX÷DW)

 [Y,X]のブロック移動。

 ブロック描画。

 0.1秒後には

  クリア確認。

  もし、それがオンならば、

   初期化処理。

  ここまで。

 ここまで。

ここまで

●初期化処理とは # --- (*2)

 ブロック初期化。

 番号シャッフル。

ここまで。

●ブロック初期化とは

 データ=[]

 Yを0から3まで繰り返す

  データ[Y] = []

  Xを0から3まで繰り返す

   データ[Y][X] = 1 + (Y * 4 + X)

  ここまで

 ここまで

 データ[3][3] = 0 # 空きブロック

ここまで

●(YXの)ブロック移動とは # --- (*3)

 Y=YX[0]。X=YX[1]

 RY=-1。RX=-1。

 #空白のブロック位置を探す

 上下左右を反復

  FY=対象[0] + Y。

  もし((FY3))ならば、続ける。

  FX=対象[1] + X。

  もし((FX3))ならば、続ける。

  V=データ[FY][FX]

  もし、V=0ならば

   RY=FY。RX=FX。抜ける。

  ここまで

 ここまで。

 もし(RX=-1)ならば

  オフで戻る。#見つからなかった場合

 ここまで。

 # ブロックを入れ替える

 TMP=データ[Y][X]

 データ[Y][X] = データ[RY][RX]

 データ[RY][RX] = TMP

 オンで戻る

ここまで

●番号シャッフルとは # --- (*4)

 シャッフル回数=0

 番号シャッフルGO

ここまで。

●番号シャッフルGOとは

 もし、シャッフル回数>30ならば、戻る。# --- (*5)

 オンの間

  Y=4の乱数

  X=4の乱数

  [Y,X]のブロック移動。

  もし、それがオンならば、抜ける。

 ここまで。

 ブロック描画。

 0.1秒後には

  シャッフル回数=シャッフル回数+1

  番号シャッフルGO

 ここまで。

ここまで

●クリア確認とは # --- (*6)

 Yを0から3まで繰り返す

  Xを0から3まで繰り返す

   V=データ[Y][X]

   もし、V=0ならば、続ける。

   もし、V≠(Y*4+X+1)ならば、オフで戻る。

  ここまで

 ここまで

 「ゲームクリア」と言う。

 オンで戻る。

ここまで。

●ブロック描画とは

 [0,0,DW*4,DW*4]の描画クリア。

 DW2=DW÷2

 黒色に線色設定

 「40px Aria」に描画フォント設定

 Yを0から3まで繰り返す

  Xを0から3まで繰り返す

   DX=X*DW

   DY=Y*DW

   V=データ[Y][X]

   もし、V > 0ならば

    「#733」に塗色設定。

    [DX, DY, DW, DW]へ四角描画。

    「#baa」に塗色設定。

    [DX+DW2, DY+DW2]へ(DW2-3)の円描画。

    「#333」に塗色設定。

    [DX+17, DY+60]に(Vを2でゼロ埋め)を文字描画。

   違えば

    「#999」に塗色設定。

    [DX, DY, DW, DW]へ四角描画。

   ここまで。

  ここまで

 ここまで

ここまで。

プログラムを簡単に確認してみましょう。(*1)の部分では、15パズルのブロックが描画されているステージをクリックした時(タブレットならタップした時)のイベントを設定します。どのブロックが押されたのかを判別し、ブロックが移動可能かどうかを確認します。その後、クリアしたかどうかを毎回確認します。

(*2)の部分ではゲームの初期化処理を行います。ブロックを初期化してシャッフルします。

そして、(*3)の部分ではブロックが移動可能かを確認する関数を定義します。移動可能かどうかは、指定したブロックの上下左右を順に確認し、移動可能ならブロックを入れ替えるという処理になっています。移動可能かは、指定ブロックの上下左右のどこかに空きブロック(値0)があるかを調べることで判別できます。

それから、(*4)の部分ではゲーム開始時にブロックをシャッフルする処理を記述します。注意したい点ですが、ブロックを完全にランダムに並び替えてしまうとゲームがクリアできない可能性があります。そこで、一度クリア状態に数字を並べた状態で、ランダムに空きブロックの周囲のブロックを移動することで、シャッフルを行います。

なお、(*5)の部分で、30手ブロックを移動しているので、最短30手位内でクリアが可能です。もし、ゲームをもっと難しくしたい場合には、この値を50とか200とか大きな値に変更しましょう。するとゲームが難しくなります。

○まとめ

以上、今回は15パズルを作る方法を紹介しました。この15パズルの変形版には、ブロックに書かれている数字がイラストになっていたり、4×4マスではなく5×5マスであったりと、さまざまな改良版が考えられます。それほど難しくないので改良してみると良いでしょう。プログラムの改良こそが、プログラミング上達の近道です。やってみましょう。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。