なでしこ3でUIとして使えるDOM部品色々。
あるいは、DOMイベント発火した時
で全部出来るからって、v1と比べてイベントの種類少なくない?(日本語らしく書けない)と嘆いてみたりする。
あるいはまた、問題集を素材としてなでしこ貯蔵庫にアップロードして使うことについて。
UIを作ります
なでしこ3ではUIとして色々なDOM部品を作ることが出来ますので、活用して「ぽい」感じにしていきます。
👉 なでしこさん マニュアル > plugin_browser/DOM部品操作
一手戻るボタンと、最初からやり直すボタン
👉 なでしこさん マニュアル > plugin_browser/ボタン作成
あっ、まちがえた! となった時、戻すことが出来たら便利ですよね?
ていうか、ちょっと間違えたらもう1からやり直すしかないとか、ガックリきちゃいますよね💧
というわけで、一つ前の状態に戻せるボタンを作ります。
戻しボタン=「一手戻す」のボタン作成。
戻しボタンの「title」に「一つ前の状態に戻す」をDOM属性設定。
「title」属性を指定すると、マウスオーバーでツールチップが表示出来ます。
なくても別に困らないけど、あるとなんだかぽい感じ♪
戻しボタンをクリックした時には、
もし、(拾った履歴の要素数)≦0ならば、戻る。
ゲーム中フラグ=オン。
x=進行方向%列数。y=(進行方向/列数の整数部分)
拾った履歴から配列ポップ。
列,行,進行方向=それ。
現在データ[行][列]=1。
もし、進行方向=空ならば、ゲーム開始。# 最初から
違えば、[列-x,行-y]から拾えるデータ更新。
盤面描画。
ここまで。
「拾った履歴」があるので、一つと言わず最初まで順に遡って戻っていくことが出来るようにします。
拾うたびに追加していってるので、末尾にあるのが一つ前に拾ったデータということになります。
配列ポップ
は、配列Aの末尾を取り出して返す命令です。
取り出した部分は元の配列から消えてしまうけど、進むボタンは付ける予定がないのでそれで良い。
👉 なでしこさん マニュアル > plugin_system/配列ポップ
それにしても、こんなの前からあったっけ?
v1にはありませんでした。
A[Aの配列要素数-1]
みたいな指定をしなくてよくなり便利です♪
ついでに、最初からやり直すボタンも作ります。
最初ボタン=「最初から」のボタン作成。
最初ボタンの「title」に「この問題を最初からやり直す」をDOM属性設定。
最初ボタンをクリックした時には、
「最初からやり直しますか?」で二択。
もし、それ=はいならば、ゲーム開始。
ここまで。
うっかり間違えて押して最初に戻ってしまうとそれはそれで「あっ💧」て感じなので、二択で確認w
ヒントを表示するチェックボックス
👉 なでしこさん マニュアル > plugin_browser/チェックボックス作成
ヒントと言っても、攻略のヒントではないんですが、拾うことの出来る石を表示する機能です。
同一線上なら、どんなに離れていても取ることが出来るルールがあるので、うっかりしているとそこが取れるとは気づかないまま、何度やっても出来ない!? となっていることがあったりなかったりするかも知れませんからね!(ワタシがね!w)
前回、まだ取れるとこあるのに、「あれ? ゲームオーバーにならないな。バグか?」とかなっていたのは内緒www
ヒント表示=「❓」のチェックボックス作成。
ヒント表示「title」に「チェックを入れると拾える石を明示します」をDOM属性設定。
拾えるデータがあるので、「問題描画」関数で現在データを描画した後、色を変えて拾えるデータを上書きすればいいだけです。
変更した時
チェックボックスのチェック状態が変化したら、即表示が切り替わって欲しいですよね。
v1だと「変更した時」というイベントがあったのですが、v3ではありません。
「DOMイベント発火した時」というイベントがあって、いちおうこれで全てのイベントが使えるようになっていますので、これを使います。
ヒント表示の「change」がDOMイベント発火した時には、
問題描画。
ここまで。
「change」は使用頻度が結構高いので、「変更した時」くらいはあるとうれしい感。
ワタクシが「change」を綴らなくて良くなり、プログラムの見た目の日本語らしさが向上するってだけのことですけれどね😅
タブン、もともとのフォームの用途だと、色々入力して最後にsubmitを押して送信だからchangeで発動させることはそんなに無いという考えなのかもだけど、プログラムのUIとして活用する場合には、チェックボックスとかセレクトボックスとか変更したら即作動しないと気分良く使えないことが多いのねん。
チェックの有無を取得
次に、問題描画に、ヒント表示のチェックが入っていた場合の描画を追加。
チェックボックスにチェックが入っているか否かは、ヒント表示の「checked」をDOM属性取得
もしくはヒント表示["checked"]
を直接参照することで確認出来ます。
しかしながら、「checked」すら綴れないワタクシですよ💧
v1ですと、ヒント表示の値
で取得出来たのに比べると、ひじょーにツラい。
「checked」は、DOM和属性にも入っていないですし。
チェックボックスが作れるようになっているんだから「checked」を参照するのは必至なのにナゼなんだ。
でも、心配ご無用ですよ☆
DOM和属性やDOM和スタイルは辞書型変数なので、自前で好きに追加が可能です🎶
DOM和属性["チェック"]=「checked」
あっ、DOM和属性が使えるのはDOM属性取得
とDOM属性設定
だけで、プロパティ値を直接参照する場合は当然ですが使えません~。
で、こんな感じ?
#問題を描画
●問題描画
白色に塗り色設定。1.5に線太さ設定。
現在データを反復:
描画行=マス幅*(対象キー+1)。
対象を反復:
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
もし、(ヒント表示の「チェック」をDOM属性取得)がオンならば、:
黄色に塗り色設定
拾えるデータを反復:
描画行=マス幅*(対象キー+1)。
対象を反復:
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
ここまで。
突然のインラインインデント構文。
行末に「:」と書くことで一時的にインデント構文が使える便利機能です☆
👉 なでしこ3 マニュアル > 文法/インラインインデント構文
ワタクシ基本的には「ここまで」がだるく無い人なのですが、二次元配列の二重ループに、もし文まで加わって、「ここまで」いっぱい並びすぎ! 邪魔くさ!! ってなったのでw
こうゆう時に一時的にインデント構文の使えるインラインインデント構文が、個人的にとても好きです❤
あと、インラインインデント構文のhtml変換はまだ試したこと無かったなーと思いついたので。
バッチリだいじょぶでしたね👍
できました☆
問題選択のセレクトボックス
これまで問題のデータは一つだけだったので、「中之字」という変数に直接入れていましたが、問題の数が増えるので、問題の名称をキーにした辞書型変数で問題集を作ることにします。
辞書型変数
辞書型変数は、なでしこ1ではハッシュと呼ばれている機能です。
👉 なでしこさん マニュアル > 文法/辞書型変数
なでしこ3では、配列同様JSON記法で初期化することが出来るようになっていて、なにげに便利です☆
#問題集
問題集={
"中の字":[
[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,1,0,0,1,0],
[1,1,1,1,1,1],
[0,1,0,0,1,0],
[0,1,0,0,1,0],
[1,1,1,1,1,1],
[0,1,0,0,1,0]
]
}
こんな感じ?
実際にはもっとありますけれど、とりあえず。
セレクトボックスは、選択肢を配列で指定して作ります。
👉 なでしこさん マニュアル > plugin_browser/セレクトボックス作成
問題集のキー値が問題の名称になっているので、それを配列にして与えたいです・・・と思ったら、辞書キー列挙
という命令がありました!
👉 なでしこさん マニュアル > plugin_system/辞書キー列挙
辞書型変数のキー一覧を配列変数の型で取得する命令です。
まさにこれ!
問題一覧=問題集の辞書キー列挙。
問題セレクト=問題一覧のセレクトボックス作成。
ここでも、セレクトボックスで問題を選択したら、即石が置き換わって欲しいので「change」ですよ。
問題セレクトの「change」がDOMイベント発火した時には、
ゲーム開始。
ここまで。
そして、問題のデータを作ったり、各種データを初期化する部分を、「ゲーム開始」関数として呼び出せるようにします。
そうそう、最初作ったプログラムは動いたのに、関数に入れたら動かなくなっちゃった! とゆう事件があります。
たしか、掲示板の質問でもあったような気がする。
ローカル変数
なでしこでは、宣言せずに変数を使うことが出来ますが、関数の中で初めて出てきた変数はローカル変数となって、その関数内でしか使えない変数になるので、他から参照しようとするとそんな変数無いよ! と言われてしまうんだよね。
しかも、v1とv3では仕様に違いがあって、関数の中で宣言された変数は、どちらもローカル変数になるんですが、グローバルに同名の変数がなく、宣言無しで関数の中で初めて出てきた変数の場合、v1ではグローバル変数として扱われますが、v3ではローカル変数になるので注意が必要です。
👉 なでしこさん マニュアル > 文法/ローカル変数
というわけで、なんにしろグローバルで宣言しとくの忘れず。
#宣言
現在データ=空配列。
拾えるデータ=空配列。
拾った履歴=空配列。
進行方向=空。
●ゲーム開始
問題=問題集[問題セレクトのテキスト取得]を配列複製。
#初期化
現在データ=問題を行数と列数に碁石データ整形。
拾えるデータ=現在データを配列複製。
進行方向=空。拾った履歴=空配列。
#描画
盤面描画。
ゲーム中フラグ=オン。
ここまで。
できました☆
素材のアップロードとAJAX取得
なでしこ貯蔵庫にはプログラムに使う素材をアップロードすることが出来るようになっています☆
ワタシの知りうる古典に載っている問題は全部で12問あり、全部をプログラムの中に貼っ付けると邪魔くさいので、プログラムとは分けてデータとしてアップロードすることにします。
問題集のデータ部分を「問題集.json」として別途保存しておきます。
ここで!
タブン間違えてらっしゃる方が結構いるっぽいのですが、データとして素材ファイルに記述するのはデータ部分だけ。なでしこのプログラムではありません。
問題集={ JSONデータ }
みたいな変数への代入や、区切
ったりCSV取得
したりなどはプログラムの方で行うようにします。
問題集を貯蔵庫へアップロードします
なでしこ貯蔵庫では、ログインしなくてもプログラムを作ったり公開したり出来るようになっていますが、素材のアップロードはログインが必要です。
ログイン状態だと、エディタの下の方に「アップロード画面を開く」ボタンがあります。
アップロード出来るのは、画像、音声、テキスト。
より具体的に言えば、JPEG/PNG/GIF/MP3/OGG/CSV/TSV/JSON/TXT/MIDのみです。(と、これら以外の拡張子のファイルをアップロードしようとすると、言われます)
今回は、JSONデータなのでだいじょぶ✨
JSONさんの注意点
なでしこさんのJSON記法はルールが少しゆるくなっています。
たとえば、
[1,2,3,]
コレが通ります。
しかし、本物のJSONさんのルールでは、要素の末尾にいらないカンマ(,)が入っていたらエラーなります。
こうですね。
[1,2,3]
それで、直接プログラム中で指定していた時は出来たのに、データとしてアップロードして取得したらエラーなっちゃう的なことが起きることがあります(起こりました🤣)のでご注意です。
なんなら、JSONエンコード
したヤツをデータにすればOKです☆
著作権
ファイルを選択して、タイトルを入力して、著作権の確認。
著作権的に問題のないファイルって何なのさ。ふわっとした書き方すぎる~💧
しかし、利用規約を読むと、アップロード出来るファイルは、基本的には自分が作成したもののみと考えた方が良さそうです。
なぜなら、当サービスに書き込んだプログラムや素材データの著作権は投稿者にありますとの条項があるからです。
再配布可のフリー素材だとしても、著作権自体は作った人にあるハズですが、タイトル以外にファイルに関する付帯情報を記入出来る欄も無いため、他の人が作ったファイルを投稿すると自作発言してることになっちゃいます。
さて、今回の問題を作ったのはワタクシじゃありませんが、作者は江戸時代の人なので、とうの昔に著作権は消失しています。そして、JSONデータにしたのはワタクシです。だいじょぶ!
でも、リスペクトで原典を書き記しておきたいのが人情なのですが、書ける欄も無いのでこの記事の最後に記しておきます。
問題集をAJAXで取得する
アップロードが出来たらURLが表示されるので、それからAJAXで取得するだけ!
AJAXって何よ? 的な説明は出来ませんのでぐぐりましょう😅
#問題集取得
問題集URL=『https://n3s.nadesi.com/image.php?f=384.json』
問題集=問題集URLからAJAX_JSON取得。
なでしこのAJAX関係の命令はなんか色々紆余曲折があって命令が乱立しています。
似たような名前の違う命令や、違う名前の同じ命令があってコンランしますが、まけません!(>_<)/
マニュアルも整理されて、だいぶ見やすくはなりました。
今回は、直接JSONデータが取得出来る「AJAX_JSON取得」を使いました。
👉 なでしこ3 マニュアル > plugin_browser/AJAX_JSON取得
入りきらない問題
やってみたら、「五の字」の横幅が広くて、当初「中の字」に合わせていた碁盤の目に入り切りませんでした💧
問題集の中の最大値で行列数を設定し、キャンバスのサイズを計算するように変更しました。
なお、ここでの行数、列数は、実際に石の置ける外枠を除いた線の本数です。
できました!
#問題集取得
問題集URL=『https://n3s.nadesi.com/image.php?f=384.json』
問題集=問題集URLからAJAX_JSON取得。
#設定
DOM和属性["チェック"]=「checked」。
変数 [行数,列数,マス幅,画面幅,画面高さ]=[11,11,30,0,0]。
行列数カウントして画面サイズ計算。
●行列数カウント
問題集を反復
仮列数=対象[0]の要素数。もし、列数<仮列数ならば、列数=仮列数。
仮行数=対象の要素数。もし、行数<仮行数ならば、行数=仮行数。
ここまで。
ここまで。
●画面サイズ計算
画面幅=(列数+1)*マス幅。
画面高さ=(行数+1)*マス幅。
ここまで。
ゲーム中フラグ=オフ。
#データ
現在データ=空配列。
拾えるデータ=空配列。
拾った履歴=空配列。
空データ=空配列。
行数回。空データ[回数-1]=0を列数だけ配列要素作成。ここまで。
進行方向=空。# 戻しボタンで進行方向を使うため
問題一覧=問題集の辞書キー列挙。
#ゲーム画面とUI作成
問題セレクト=問題一覧のセレクトボックス作成。
「 」のラベル作成
戻しボタン=「一手戻す」のボタン作成。
戻しボタンの「title」に「一つ前の状態に戻す」をDOM属性設定。
最初ボタン=「最初から」のボタン作成。
最初ボタンの「title」に「この問題を最初からやり直す」をDOM属性設定。
ヒント表示=「❓」のチェックボックス作成。
ヒント表示の「title」に「チェックを入れると拾える石を明示します」をDOM属性設定。
改行作成。
ゲーム画面=[画面幅,画面高さ]のキャンバス作成。
改行作成。
#UIイベント
問題セレクトの「change」がDOMイベント発火した時には、
ゲーム開始。
ここまで。
最初ボタンをクリックした時には、
「最初からやり直しますか?」で二択。
もし、それ=はいならば、ゲーム開始。
ここまで。
戻しボタンをクリックした時には、
もし、(拾った履歴の要素数)≦0ならば、戻る。
ゲーム中フラグ=オン。
x=進行方向%列数。y=(進行方向/列数の整数部分)
拾った履歴から配列ポップ。
列,行,進行方向=それ。
現在データ[行][列]=1。
もし、進行方向=空ならば、ゲーム開始。# 最初から
違えば、[列-x,行-y]から拾えるデータ更新。
盤面描画。
ここまで。
ヒント表示の「change」がDOMイベント発火した時には、
問題描画。
ここまで。
ゲーム開始。
●ゲーム開始
問題=問題集[問題セレクトのテキスト取得]を配列複製。
#初期化
現在データ=問題を行数と列数に碁石データ整形。
拾えるデータ=現在データを配列複製。
進行方向=空。拾った履歴=空配列。
#描画
盤面描画。
ゲーム中フラグ=オン。
ここまで。
#マス目を描画
●盤面描画
ベージュ色に塗り色設定。5に線太さ設定。
[0,0,画面幅,画面高さ]へ四角描画。
1に線太さ設定。
列数回。[マス幅*回数,0]から[マス幅*回数,画面高さ]まで線描画。ここまで。
行数回。[0,マス幅*回数]から[画面幅,マス幅*回数]まで線描画。ここまで。
問題描画。
ここまで。
#問題を描画
●問題描画
白色に塗り色設定。1.5に線太さ設定。
現在データを反復:
描画行=マス幅*(対象キー+1)。
対象を反復:
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
もし、(ヒント表示の「チェック」をDOM属性取得)がオンならば、:
黄色に塗り色設定
拾えるデータを反復:
描画行=マス幅*(対象キー+1)。
対象を反復:
描画列=マス幅*(対象キー+1)。
もし、対象=1ならば[描画列,描画行]へマス幅/2-1の円描画。
ここまで。
#問題を盤面の中央に配置できるようデータ整形
●(Aを行数と列数に)碁石データ整形
問題=Aを配列複製。
追加行数=行数-(問題の表行数)。
追加列数=列数-(問題の表列数)。
上追加行数=追加行数/2を切り捨て。
下追加行数=追加行数/2を切り上げ。
左追加列数=追加列数/2を切り捨て。
右追加列数=追加列数/2を切り上げ。
追加行=空配列。
問題の表列数回。追加行に0を配列追加。ここまで。
上追加行数回。問題の0に追加行を配列挿入。ここまで。
下追加行数回。問題に追加行を配列追加。ここまで。
追加列=空配列。
問題の表行数回。追加列に0を配列追加。ここまで。
左追加列数回。問題の0に追加列を表列挿入して問題に代入。ここまで。
右追加列数回。問題の(問題の表列数)に追加列を表列挿入して問題に代入。ここまで。
問題を戻す。
ここまで。
#イベント
描画中キャンバスをマウス押した時には、
もし、ゲーム中フラグ=オフならば、戻る。
列,行=マウス位置取得。
もし、拾えるデータ[行][列]=1ならば、
現在データ[行][列]=0。
進行方向=[列,行]の進行方向更新。
拾った履歴に[列,行,進行方向]を配列追加。
進行方向と[列,行]から拾えるデータ更新。
ここまで。
盤面描画。0.1秒待つ。終了判定。
ここまで。
●マウス位置取得
列=((マウスX-マス幅/2)/マス幅)の整数部分。
行=((マウスY-マス幅/2)/マス幅)の整数部分。
[列,行]を戻す。
ここまで。
●(座標の)進行方向更新
列,行=座標。進行方向=空。
上,下,左,右=[列数*-1,列数,-1,1]。
もし、(拾った履歴の要素数)≠0ならば、
前列,前行=拾った履歴[(拾った履歴の要素数)-1]。
もし、(行<前行)ならば、進行方向=上
もし、(行>前行)ならば、進行方向=下
もし、(列<前列)ならば、進行方向=左
もし、(列>前列)ならば、進行方向=右
ここまで。
進行方向を戻す。
ここまで。
●(進行方向と座標から)拾えるデータ更新
列,行=座標。
拾えるデータ=空データを配列複製。
上下左右=[[0,-1],[0,1],[-1,0],[1,0]]。
上下左右を反復
x,y=対象。
もし、進行方向*-1=y*列数+xならば、続ける。# 後戻り禁止
[列,行]から対象へ拾える石探索。
ここまで。
ここまで。
●(座標から方向へ)拾える石探索
列,行=座標。x,y=方向。
もし、(列+x<0)または(行+y<0)または(列+x>(現在データの表列数)-1)または(行+y>(現在データの表行数)-1)ならば、戻る。
もし、現在データ[行+y][列+x]=1ならば、
拾えるデータ[行+y][列+x]=1。
違えば、
[列+x,行+y]から方向へ拾える石探索。
ここまで。
ここまで。
●終了判定
現在データと空データが同じ配列か確認。
もし、それ=はいならば、:
「クリア!」と言う。
ゲーム中フラグ=オフ。戻る。
拾えるデータと空データが同じ配列か確認。
もし、それ=はいならば、:
「失敗!」と言う。
ゲーム中フラグ=オフ。戻る。
ここまで。
●(AとBの|Bが)同配列確認
もし、(AをJSONエンコード)=(BをJSONエンコード)ならば、はいで戻る。
いいえで戻る。
ここまで。
動作確認
参考文献
問題集に収録した12問は、以下の古典に載っている物です。
答えがバッチリ載っているので、どうしても解けなかったらカンニングしましょう。
くずし字も変体仮名も読めなくてもだいじょぶ!
『勘者御伽双紙』 中根法舳 1743 「八 ひろひものの事 七ヶ條」
『和国知恵較べ 巻下』 環中仙 1727 「ますのひろい物」他4問
つづきます
完成したけど続きますw
当初の目標に、「問題を自分で作ったりしたい」てのがありましたよね~。忘れてましたが😅
とゆうわけで、次回は問題作成機能を追加してみます。