2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

日本語プログラミング言語「なでしこ」Advent Calendar 2023

Day 7

なでしこさんで「ひろいもの」を作るよ! ① ~キャンバスにゲーム画面を描画して石を取るまで~

Last updated at Posted at 2023-12-06

発端

 これまでアドベントカレンダーでは毎年、鶴亀算、ねずみ算、旅人算と、和算の問題を解いてきましたが、今年は良さそうなのが何もひらめかないぃ~orz
 和算の問題は沢山あるんですけどぉ~、ワタクシ算数がダメダメなので、特になんの解説もできませんので、なでしこさんで面白い感じにプログラムに出来るネタがないと意味無い感?
 というわけで、和算つながりで、「ひろいもの」を作ることにしました。
 やっぱゲームっぽいものつくりたい!
 例年のごとくカレンダーが埋まらず書くことがピンチなので、なでしこさんの機能とか紹介しながらダラダラと無駄に長期連載してゆくよてい~。

ひろいものとは?

 碁石拾いとも呼ばれる、碁盤の上に色々な形に置かれた碁石を順に拾い尽くす遊びです。

 ルールは、

  • どこでも好きなところから碁石を取り始める。
  • 碁盤の目に沿って順に石を取りながら進んでいく。
  • 全ての石を取り尽くしたらクリア!

 という単純なもの。
 ただし、

  • 石を飛ばして進むことは出来ない。
  • 斜めに進むことは出来ない。
  • 後戻りは出来ない。
  • 石の無いところは次の石まで直進で、途中で曲がることは出来ない。

 という制限があります。

 『勘者御伽双紙』や『和国知恵較べ』などに載っておりますが、問題っていうよりむしろもうめっちゃ答えが載っているので、ここでは原典へのリンクを付けません。

碁盤の目を描画します

 今回は、なでしこ3を使い、なでしこ貯蔵庫でやっていきますです。

 なでしこ3にはHTML5のcanvasを使った描画機能が備わっています。
 
👉 なでしこさん マニュアル > plugin_browser/描画
 
 今回は、エディタで標準に用意されているキャンバスを使わず、新たにキャンバスを作成してゲーム画面を作ります。
 理由は、ゲーム画面の上にもUIを置きたいからです。

 なお、キャンバスに格子を描いていくのは、一昨年のマルバツゲームを作った記事でも書きました。
 キャンバスの設置や描画開始、繰り返しを使ってまとめて線を引いていく的なコトはこちらでおさらい。

 で、こんな感じ。

#設定
画面幅300画面高さ360マス幅30
行数画面高さ/マス幅-1列数画面幅/マス幅-1

#ゲーム画面作成
ゲーム画面[画面幅,画面高さ]キャンバス作成

盤面描画

#マス目を描画
●盤面描画
  ベージュ色塗り色設定線太さ設定
  [0,0,画面幅,画面高さ]四角描画
  線太さ設定
  列数[マス幅*回数,0]から[マス幅*回数,画面高さ]まで線描画ここまで
    行数[0,マス幅*回数]から[画面幅,マス幅*回数]まで線描画ここまで
ここまで

盤面.png

 描けました☆
 早速カラフルなコードで載せてみましたが、どうでしょう?
 盤面描画は、この先何度も呼び出すことになるので、関数にしておきます。
 
👉 なでしこさん マニュアル > 文法/関数

問題を描画します

 まず最初に問題のデータを作ります。
 データは、碁石の有/無を、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)
      もし対象ならば[描画列,描画行]マス幅/2-1円描画
    ここまで
  ここまで
ここまで

 v3の「反復」は、v1と違ってなぜか「回数」のカウンタが回っていません。
 代わりに、配列の場合は「対象キー」に要素番号が入っていて、カウンタとして使えます。
 
👉 なでしこさん マニュアル > 文法/反復
 
 回数は1スタートですが、配列の要素番号は0スタートなので、気をつけます。
 配列を参照する時など「回数」は-1しなきゃなので、そうゆう時はむしろ良いのですが、今回は外枠には描画したくないので、1行(列)目からとなり、対象キー+1しています。

 さて、中之字問題描画してみると・・・

中之字1.png

 おっと、端の方に寄ってしまいました(知ってたけどね!w)

問題を整形します

 表示するだけなら、描画列,描画行の位置を計算して変更するだけで良さそげだけど、この先クリックして石を取った場所を反映したりするのとか分かりやすいように、問題データ自体を整形しちゃう。(アタマ悪いのでコンランしたくない!💧)
 最初から問題データを碁盤の目と同じだけ0で埋めて作ればいいんだけど、0いっぱい打たなきゃなんないし、後から碁盤のサイズを変えるのが困難になってしまうので、プログラムの方で碁盤と同じ行列数になるよう問題を整形することにします。

#問題を盤面の中央に配置できるようデータ整形
●(問題を行数と列数に)碁石データ整形
  追加行数行数-(問題表行数)
  追加列数列数-(問題表列数)
  上追加行数追加行数/2切り捨て
  下追加行数追加行数/2切り上げ
  左追加列数追加列数/2切り捨て
  右追加列数追加列数/2切り上げ
  追加行空配列
  問題表列数追加行0配列追加ここまで
  上追加行数問題0追加行配列挿入ここまで
  下追加行数問題追加行配列追加ここまで
  追加列空配列
  問題表行数追加列0配列追加ここまで
  左追加列数問題0追加列表列挿入して問題代入ここまで
  右追加列数問題(問題表列数)追加列表列挿入して問題代入ここまで
  問題戻す
ここまで

 地道に上下左右に何行(列)追加が必要ですかね~? ってのを計算して追加してますw

 配列追加で配列の末尾に、0へ配列挿入で配列の先頭に配列を追加できます。
 
👉 なでしこさん マニュアル > plugin_system/配列操作
 

 また、表列挿入で二次元配列の列に配列を追加出来ます。便利!
 
👉 なでしこさん マニュアル > plugin_system/二次元配列処理
 
 さて、これで中之字行数列数碁石データ整形して問題描画すれば・・・

中之字2.png

 できました! やったね☆

マウスのイベント

 マウスでクリックして石を拾えるようにします。
 クリックしてと書きましたが、「クリックした時」のイベントはマウスの位置が取れないので、「マウス押した時」を使います。
 と、マウスのイベントについて書く時には大体必ず書いているんですが、それでも時々間違えて、「あっ💧」てなる人です💦
 
👉 なでしこさん マニュアル > 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]
]

盤面描画
//中之字を問題描画。
問題データ中之字行数列数碁石データ整形
問題データ問題描画

#マス目を描画
●盤面描画
  ベージュ色塗り色設定線太さ設定
  [0,0,画面幅,画面高さ]四角描画
  線太さ設定
  列数[マス幅*回数,0]から[マス幅*回数,画面高さ]まで線描画ここまで
  行数[0,マス幅*回数]から[画面幅,マス幅*回数]まで線描画ここまで
ここまで

#問題を描画
●(問題を)問題描画
  白色塗り色設定1.5線太さ設定
  問題反復
    描画行マス幅*(対象キー+1)
    対象反復
      描画列マス幅*(対象キー+1)
      もし対象ならば[描画列,描画行]マス幅/2-1円描画
    ここまで
  ここまで
ここまで

#問題を盤面の中央に配置できるようデータ整形
●(問題を行数と列数に)碁石データ整形
  追加行数行数-(問題表行数)
  追加列数列数-(問題表列数)
  上追加行数追加行数/2切り捨て
  下追加行数追加行数/2切り上げ
  左追加列数追加列数/2切り捨て
  右追加列数追加列数/2切り上げ
  追加行空配列
  問題表列数追加行0配列追加ここまで
  上追加行数問題0追加行配列挿入ここまで
  下追加行数問題追加行配列追加ここまで
  追加列空配列
  問題表行数追加列0配列追加ここまで
  左追加列数問題0追加列表列挿入して問題代入ここまで
  右追加列数問題(問題表列数)追加列表列挿入して問題代入ここまで
  問題戻す
ここまで

描画中キャンバスマウス押した時には
  ,マウス位置取得
  問題データ[][]0
  盤面描画
  問題データ問題描画
ここまで

●マウス位置取得
  ((マウスX-マス幅/2)/マス幅)整数部分
  ((マウスY-マス幅/2)/マス幅)整数部分
  [,]戻す
ここまで

 できました!
 まるっとエディタに貼れば、動きます☆

 と思いましたが、コードをまるっとコピーするボタンが無いので面倒かと思い、こちらにご用意しました。まだ完成ではないので、限定公開となっております。

つづきます

 とりあえず実際に石を取って遊べるようにはなりました☆
 しかーし!
 これでは自分で碁石置いてやる場合と一緒で、その石が取れるか取れないか? 自分の判断ですよね。てきとーに取りまくるコトも可能。

 こんぴゅーたーのゲーム的には、ちゃんとその石が取れるか取れないかを判定したいところです。
 もちろんクリアやゲームオーバーの判定もしたいです。
 あと、UIなど追加して、ぽい感じにしたい。
 問題数を増やして、選んで遊べるようにしたい。
 問題を自分で作ったりしたい。

 という感じで、続きます~。

2
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?