発端
これまでアドベントカレンダーでは毎年、鶴亀算、ねずみ算、旅人算と、和算の問題を解いてきましたが、今年は良さそうなのが何もひらめかないぃ~orz
和算の問題は沢山あるんですけどぉ~、ワタクシ算数がダメダメなので、特になんの解説もできませんので、なでしこさんで面白い感じにプログラムに出来るネタがないと意味無い感?
というわけで、和算つながりで、「ひろいもの」を作ることにしました。
やっぱゲームっぽいものつくりたい!
例年のごとくカレンダーが埋まらず書くことがピンチなので、なでしこさんの機能とか紹介しながらダラダラと無駄に長期連載してゆくよてい~。
ひろいものとは?
碁石拾いとも呼ばれる、碁盤の上に色々な形に置かれた碁石を順に拾い尽くす遊びです。
ルールは、
- どこでも好きなところから碁石を取り始める。
- 碁盤の目に沿って順に石を取りながら進んでいく。
- 全ての石を取り尽くしたらクリア!
という単純なもの。
ただし、
- 石を飛ばして進むことは出来ない。
- 斜めに進むことは出来ない。
- 後戻りは出来ない。
- 石の無いところは次の石まで直進で、途中で曲がることは出来ない。
という制限があります。
『勘者御伽双紙』や『和国知恵較べ』などに載っておりますが、問題っていうよりむしろもうめっちゃ答えが載っているので、ここでは原典へのリンクを付けません。
碁盤の目を描画します
今回は、なでしこ3を使い、なでしこ貯蔵庫でやっていきますです。
なでしこ3にはHTML5のcanvasを使った描画機能が備わっています。
👉 なでしこさん マニュアル > plugin_browser/描画
今回は、エディタで標準に用意されているキャンバスを使わず、新たにキャンバスを作成してゲーム画面を作ります。
理由は、ゲーム画面の上にもUIを置きたいからです。
なお、キャンバスに格子を描いていくのは、一昨年のマルバツゲームを作った記事でも書きました。
キャンバスの設置や描画開始、繰り返しを使ってまとめて線を引いていく的なコトはこちらでおさらい。
で、こんな感じ。
#設定
画面幅=300。画面高さ=360。マス幅=30。
行数=画面高さ/マス幅-1。列数=画面幅/マス幅-1。
#ゲーム画面作成
ゲーム画面=[画面幅,画面高さ]のキャンバス作成。
盤面描画。
#マス目を描画
●盤面描画
ベージュ色に塗り色設定。5に線太さ設定。
[0,0,画面幅,画面高さ]へ四角描画。
1に線太さ設定。
列数回。[マス幅*回数,0]から[マス幅*回数,画面高さ]まで線描画。ここまで。
行数回。[0,マス幅*回数]から[画面幅,マス幅*回数]まで線描画。ここまで。
ここまで。
描けました☆
早速カラフルなコードで載せてみましたが、どうでしょう?
盤面描画は、この先何度も呼び出すことになるので、関数にしておきます。
👉 なでしこさん マニュアル > 文法/関数
問題を描画します
まず最初に問題のデータを作ります。
データは、碁石の有/無を、1/0で設定した二次元配列とします。
中之字=[
[0,1,1,0,0],
[0,0,1,0,0],
[1,1,1,1,1],
[1,0,1,0,1],
[1,1,1,1,1],
[0,0,1,0,0],
[0,0,1,0,0],
[0,0,1,0,0],
[0,0,1,0,0]
]
なでしこv3ではこのように、JSON記法を使って配列を直接設定することが出来ます!
👉 なでしこさん マニュアル > 文法/配列変数
中の字という、わりと簡単めの、なんならわりと有名な問題です。
なでしこの助詞にあたる「の」が入っているため、「中の字」をそのまま変数名には出来ませんので、「中ノ字」とか「中之字」とかしなきゃです。
知ってるけど大体うっかりしてエラー出す人です💧
これを反復して、碁石がある(値が1である)場合に白丸を描いていくだけ!
#問題を描画
●(問題を)問題描画
白色に塗り色設定。1.5に線太さ設定。
問題を反復
描画行=マス幅*(対象キー+1)。
対象を反復
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
ここまで。
ここまで。
ここまで。
v3の「反復」は、v1と違ってなぜか「回数」のカウンタが回っていません。
代わりに、配列の場合は「対象キー」に要素番号が入っていて、カウンタとして使えます。
👉 なでしこさん マニュアル > 文法/反復
回数は1スタートですが、配列の要素番号は0スタートなので、気をつけます。
配列を参照する時など「回数」は-1しなきゃなので、そうゆう時はむしろ良いのですが、今回は外枠には描画したくないので、1行(列)目からとなり、対象キー+1しています。
さて、中之字を問題描画
してみると・・・
おっと、端の方に寄ってしまいました(知ってたけどね!w)
問題を整形します
表示するだけなら、描画列,描画行の位置を計算して変更するだけで良さそげだけど、この先クリックして石を取った場所を反映したりするのとか分かりやすいように、問題データ自体を整形しちゃう。(アタマ悪いのでコンランしたくない!💧)
最初から問題データを碁盤の目と同じだけ0で埋めて作ればいいんだけど、0いっぱい打たなきゃなんないし、後から碁盤のサイズを変えるのが困難になってしまうので、プログラムの方で碁盤と同じ行列数になるよう問題を整形することにします。
#問題を盤面の中央に配置できるようデータ整形
●(問題を行数と列数に)碁石データ整形
追加行数=行数-(問題の表行数)。
追加列数=列数-(問題の表列数)。
上追加行数=追加行数/2を切り捨て。
下追加行数=追加行数/2を切り上げ。
左追加列数=追加列数/2を切り捨て。
右追加列数=追加列数/2を切り上げ。
追加行=空配列。
問題の表列数回。追加行に0を配列追加。ここまで。
上追加行数回。問題の0に追加行を配列挿入。ここまで。
下追加行数回。問題に追加行を配列追加。ここまで。
追加列=空配列。
問題の表行数回。追加列に0を配列追加。ここまで。
左追加列数回。問題の0に追加列を表列挿入して問題に代入。ここまで。
右追加列数回。問題の(問題の表列数)に追加列を表列挿入して問題に代入。ここまで。
問題を戻す。
ここまで。
地道に上下左右に何行(列)追加が必要ですかね~? ってのを計算して追加してますw
配列追加
で配列の末尾に、0へ配列挿入
で配列の先頭に配列を追加できます。
👉 なでしこさん マニュアル > plugin_system/配列操作
また、表列挿入
で二次元配列の列に配列を追加出来ます。便利!
👉 なでしこさん マニュアル > plugin_system/二次元配列処理
さて、これで中之字を行数と列数に碁石データ整形して問題描画
すれば・・・
できました! やったね☆
マウスのイベント
マウスでクリックして石を拾えるようにします。
クリックしてと書きましたが、「クリックした時」のイベントはマウスの位置が取れないので、「マウス押した時」を使います。
と、マウスのイベントについて書く時には大体必ず書いているんですが、それでも時々間違えて、「あっ💧」てなる人です💦
👉 なでしこさん マニュアル > plugin_browser/マウス押時
とりあえずマウスの位置を取得
マウスX、マウスYから、問題データの行数、列数に変換します。
描画中キャンバスをマウス押した時には、
列,行=マウス位置取得。
「{行},{列}」を言う。
ここまで。
●マウス位置取得
列=((マウスX-マス幅/2)/マス幅)の整数部分。
行=((マウスY-マス幅/2)/マス幅)の整数部分。
[列,行]を戻す。
ここまで。
今回は、丸い碁石の隙間については考慮していません~💧
とりあえず石を取る
問題データのその位置を0に変えて再描画してやれば、石が消えます。
描画中キャンバスをマウス押した時には、
列,行=マウス位置取得。
問題データ[行][列]=0。
盤面描画。
問題データを問題描画。
ここまで。
コレで、一応遊べるようにはなりましたよ!
ここまでのコード
#設定
画面幅=300。画面高さ=360。マス幅=30。
行数=画面高さ/マス幅-1。列数=画面幅/マス幅-1。
#ゲーム画面作成
ゲーム画面=[画面幅,画面高さ]のキャンバス作成。
#問題
中之字=[
[0,1,1,0,0],
[0,0,1,0,0],
[1,1,1,1,1],
[1,0,1,0,1],
[1,1,1,1,1],
[0,0,1,0,0],
[0,0,1,0,0],
[0,0,1,0,0],
[0,0,1,0,0]
]
盤面描画。
//中之字を問題描画。
問題データ=中之字を行数と列数に碁石データ整形。
問題データを問題描画。
#マス目を描画
●盤面描画
ベージュ色に塗り色設定。5に線太さ設定。
[0,0,画面幅,画面高さ]へ四角描画。
1に線太さ設定。
列数回。[マス幅*回数,0]から[マス幅*回数,画面高さ]まで線描画。ここまで。
行数回。[0,マス幅*回数]から[画面幅,マス幅*回数]まで線描画。ここまで。
ここまで。
#問題を描画
●(問題を)問題描画
白色に塗り色設定。1.5に線太さ設定。
問題を反復
描画行=マス幅*(対象キー+1)。
対象を反復
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
ここまで。
ここまで。
ここまで。
#問題を盤面の中央に配置できるようデータ整形
●(問題を行数と列数に)碁石データ整形
追加行数=行数-(問題の表行数)。
追加列数=列数-(問題の表列数)。
上追加行数=追加行数/2を切り捨て。
下追加行数=追加行数/2を切り上げ。
左追加列数=追加列数/2を切り捨て。
右追加列数=追加列数/2を切り上げ。
追加行=空配列。
問題の表列数回。追加行に0を配列追加。ここまで。
上追加行数回。問題の0に追加行を配列挿入。ここまで。
下追加行数回。問題に追加行を配列追加。ここまで。
追加列=空配列。
問題の表行数回。追加列に0を配列追加。ここまで。
左追加列数回。問題の0に追加列を表列挿入して問題に代入。ここまで。
右追加列数回。問題の(問題の表列数)に追加列を表列挿入して問題に代入。ここまで。
問題を戻す。
ここまで。
描画中キャンバスをマウス押した時には、
列,行=マウス位置取得。
問題データ[行][列]=0。
盤面描画。
問題データを問題描画。
ここまで。
●マウス位置取得
列=((マウスX-マス幅/2)/マス幅)の整数部分。
行=((マウスY-マス幅/2)/マス幅)の整数部分。
[列,行]を戻す。
ここまで。
できました!
まるっとエディタに貼れば、動きます☆
と思いましたが、コードをまるっとコピーするボタンが無いので面倒かと思い、こちらにご用意しました。まだ完成ではないので、限定公開となっております。
つづきます
とりあえず実際に石を取って遊べるようにはなりました☆
しかーし!
これでは自分で碁石置いてやる場合と一緒で、その石が取れるか取れないか? 自分の判断ですよね。てきとーに取りまくるコトも可能。
こんぴゅーたーのゲーム的には、ちゃんとその石が取れるか取れないかを判定したいところです。
もちろんクリアやゲームオーバーの判定もしたいです。
あと、UIなど追加して、ぽい感じにしたい。
問題数を増やして、選んで遊べるようにしたい。
問題を自分で作ったりしたい。
という感じで、続きます~。