goo blog サービス終了のお知らせ 

星田オステオパシー

施術者は引退しちゃって美味しいバイト生活をしつつプログラミング学習とか自由研究をして野垂れ死ぬまでの備忘録

プログラミング学習日記 2025/03/13〜

2025-03-28 15:01:22 | プログラミング
2025/03/27
話題その1 GO言語をちょっと試してみる
 宿直バイト2に置いている元ChromebookのLinuxマシン。残りのストレージが(もともと32GBしかないので)850MBくらいしかなくなってしまった。ここに新たな環境を作るのはなぁ・・と、GO環境構築を躊躇っていたのだが、WEB実行環境(Playground)ではImportが出来ないっぽいし。
 思いつく限りではいらないファイルを消していたけど、Per様にダメ元で聞いてみる。そしてこの未使用パッケージの削除を行った結果・・残り容量が2.7GBまで爆増したので憂いなくGO言語を試してみようと。
 ターミナルからGolandを入れて

 SublimeのTool→Buildsystem→Newbuildsystemへと進み(この作業中はキャプチャのキーが効かなかったので撮影してます)

 中身にこう書いて

 セーブしようとすると名前を求められるのでこう名付けて

 拡張.goのファイルを作ってCtrl+Bを押せば即座に実行、これはやる気も湧いてくる!でも、今夜はここまでにしておきました。


話題その2 Sclilabで数値計算の続き

 行列の+は分かる。そのままだからな。でも*の結果に納得いかん!これどういうこと?

 え、何これは・・・内積・・前にCametanさんの記事で言及してもらってたはずだけどこんな風に計算するのか。これをそのまま放り込むだけで計算できるなら、そりゃMatlibとかSclilabとか必要とされるわけだわ

 はぁ、僕の予想していたのはアダマール積たらいうものだったらしいな

 で、何の役に立つのコレ?ってことで質問。ぬぅ・・xとyの2要素しかないのになんで2*2の4要素が必要なのか?そもそもCosとかSinとか結局分かってないからサッパリなのだが

 ま、この2つは分かる気がするな。

 ふーん・・これは是非取り組まねばならんな~。高校生の時にこういう話を聞きたかったが


  続いて、なんで座標に対して2*2のCosとかSinとかの行列を掛けたら移動後の座標が出るわけ!?ってのを質問。
 はぁ・・いや、ワタシそもそも三角関数もサッパリなんスよ~・・高校のときは三国志とスーパー大戦略の事ばっかり考えてたんで。


 ・・・

 これはまず三角関数をやらないと駄目だ。そもそもなんで1行目2要素目のSinだけマイナスなのか?多分、右回転させるとy軸の値が減るからだろうとは推測できるが


 Per様の解説には(僕の環境では)図表が表示できないみたい(リンク切れのマークみたいなのが出るだけで見れない)なので予備校の解説ページみたいなのを見てみる。で、この単位円の図を見てようやく分かった。Cosは座標のx、Sinは座標のyになるってことか~(実はこの時点で誤解してます)

 なるほどはいはい

 はいはい

 
 なるほど、確かに

 なるほど⤴️? いや、でも計算式に行列が出てくる理由が分からんのだが!いやもう続きは明日にする。

 はいはい、Boolね


 
 行と行の掛け算は出来ないと

 本にはSclilabのSort方法が出てなかったでPer様に質問。オプションが必要なのか

 最新バージョンのSclilabではSortは使用されてなくてGsortになってる模様

 Matrixをしたところ、並び方がなんか変だ。

 ソートせずに作った行列では問題がない。ま、でも別に今は良いかw

 スカラーとベクトル。はいはい

 本内でカンマがあったりなかったりして違いがあるのか気になったので。同じか!

 なるほど、僕が最初イメージしてたのは.*だったか。ここでは行*行だけど行列では?

 まあ+は良しとして

 なるほどね!
 
 というわけで、明日は座標の移動がなんで[cos, -sin ; sin, cos] [x, y]で出来るのかをちゃんと理解する努力をしよう
 




2025/03/26 Scilabで理解する数値計算
 タワテツの作成が、後は積み木を組み立てていくだけ・・って感じになってきたのでプログラミング学習として、ずっと気になっていたScilabを動かしてみることにした。実はGO言語をやろうかとも思ってたんだけど、並行で別言語は良くないかな?と思い至りまして。
 正直、今のところは数値計算がどのように役立つか具体的には分からないけど、今後、最終的にはシミュレーターみたいなものを作って眺めて遊ぶ・・ってのが目標かな?とは思ってるので多分必要になりそうということで。



2025/03/20 コルーチン関連を継続

 Yieldの動作が謎だったので小分けにして結果を見ることにした。
 謎だったけど、Resumeされた時点でYiledの引数がResume側に引き渡され、コルーチン側のYieldが確定して、ここではLocal aに値が代入されるとようやく理解する

 そして、Resumeで呼び出すときにコルーチンを第一引数、第二引数に値を与えた場合、それがコルーチン側でのYieldの返り値になるとようやく理解する。値の交換を行ってるようなものなのか・・

 この解説の時点では全くなんのためにこんな引数の交換みたいな仕組みになってるのか理解不能だったけど、メニュー表示の中で有用性がちょっと分かった気がしたので良し


 Coroutine.wrapについての質問をしてみた


 Resumeしなくても関数みたいに呼び出すだけで再開と一旦停止って感じで、これはジェネレーターって感じなのかな。

 あれ?Resumeの場合にはYiledへの引数として第二引数を使って渡すことができけど、Wrapの場合は無理なのか?

 渡せるけど、1回目はYieldじゃなくて上位のLambdaに渡されてしまう模様。2回目以降は(一個目の)Yieldに渡るので、分かってればResumeと同じようには使えるっぽいな

==============================
1日経過
==============================
 ここ数日、Per様に書いてもらったLuaでのコルーチンを使ったメニュー表示サンプルを呼んで理解しようとしてたのだけど、一通り終えた後に「そう言えば」と思って実行してみたところメニュー選択でのキー入力が全く効かないという状態。
 しょうがないので、コードと症状をPer様に渡して「動かないぞ!」と訴えてみる。

 結果、一発でちゃんと動くコードを作ってくれたので、どこがおかしかったのかとかを考えつつ、ちょっと読んで見る


 こちらが以前の動かないもの

 そしてこちらが動くもの。短い!内容が全然変わってる!
 新板では返すのがテーブルで、中が変数crに束縛されたコルーチン、表示用文字列テーブル、現在の選択場所になっている。旧版では関数を返していたように見える。
 旧版では書かれていたLove.draw用の部分が全く無くなっている。考えてみたら、描画部分をここに書くのも妙に思える
 


 続いてSetting_menuの旧版
 


 こちら新板。と言っても基本的にMain_menuと同じ変更がされてるので別にエエか・・

 同様にVolume_menu


 ここは旧版と一緒

 うむ、旧版ではLove.draw内からResumeを行って描画コードを呼び出す仕組みになってたのがやっぱり変だったんだな。DrawはDrawのみを行うべき。テーブルcrの.selectionを使って選択候補の>を表示する仕組みがある。
 気になるのはIf current.vlumeで、これってテーブル内に特定の変数が合った場合に表示を変えるって仕組みなんだけど・・これで良いのか?ある意味合理的ではあるんだけど・・


 そしてポイントになりそうなKeypressed


 最初の if not currentは終了条件って感じか
 なるほど、キー入力で参照渡しされてるcurrent.selectionを破壊的変更、上だったら現在よりも−1、これは旧版は明らかにおかしかったからな・・。んで、未知の関数math.maxだけど、多分第一引数より下にはならないって感じかな?つまりメニューは上下で循環できないハズ。今、確かめたらやっぱり出来なかったか。
 同様に下だった場合のmath.minは最大でも第一引数までって事だな。これ便利なので覚えておく努力をしようっと。
 左右は実装されてないな

 で、問題はReturnが押された場合で、この時点でようやく現在のメニューテーブルの中の関数部分(各メニューによって違う処理)に対してのResume信号が渡されて、第2引数のCurrent.selectionが、その返り値となるのでSelectedの値がCurrent.selection(このKeypressedで変更される可能性がある)になると


2025/03/17 Luaでコルーチンに触れてみる
 Cametanさんの記事でLuaにもコルーチンの機能が備わっているという事を知ったのでバイト先でちょっとPer様に聞いてみる。


 ふーん・・

 1つ前のコメントによるとYieldは実行件の放棄だから、つまり一旦中断って事か?

 ん?中断も何も、Resumeで呼び出さないと1つ目も出ないとは・・
 下の例を見ると、こっちは一度目のResumeでYield自体の引数が返ってきてて、二度目で次のReturnが返ってるか。1つ前の例はForの内部だったから、Yieldが現れた時点で一旦停止、ResumeされるとYieldの部分からの実行になるということか。問題は上の例のReturn 30の後に続いてPrintなんかを入れた場合にはResumeしなくても30に続いてPrintの内容も出るかどうかだな?

 と、これを書きながら色々とPer様に質問してみました。なるほど〜!そちらは次回の分で。 


 応用例。気になるのは「ステートマシンの実装」だな!タワテツのメニュー表示は確か「ステートマシン」方式を使って書いてくれてるはずなので、大体の原理は分かってるのだが、あれをコルーチン版で書いてもらったら理解の助けになるはず


 ここでCoroutine.wrapというのと遭遇。もちろん意味がわからないのでPer様にお聞きするわけだけが・・これがすごく便利!関数っぽく呼び出すだけでResumeが出来ると言うね。

 超絶期待できる!

 むっ!?Whileの中で直接描画が行われている・・ってことは、この関数はLove.drawの内部で呼ばれるということか・・
 selectedはResumeというかWrapが呼ばれるまでは確定せずに待機か。
 呼ばれた場合にselectedの内容によって分岐と。
 うーん、入力待ち状態を非同期で維持できるのが利点ということか?知らんけど。分岐後は、またそこでストップ、2の場合だとSetting_menuのWrapを呼んで待機。

 呼ばれたSetting_menu
 構造はMainと同じでメニュー表示用のテーブルを用意して、入力待ちで待機
 
 ここも構造は全く一緒だな。
 違うのは3を選んだ場合にReturnで(なぜか)親メニューに戻れるようだ

 Volume_menuも基本一緒。ただ、SelectedじゃなくてInput(恐らくはKeypressedから変更される)てのが違うところ

 ここでLove2Dの基本関数。最初に宣言したMenu_stuckの先頭にMain_menu関数を入れる
 Love.updateで
・CurrentにMenu_stackの最後尾を束縛
・CoroutineのステータスがDead=再開済みなら最後尾のMenu_stackを削除。なんと、Love.updateでの処理はこれだけなのか!つまり、コルーチンが有効かどうかしかチェックしてない
 Love.drawで
・同じく最後尾(最新)のものを束縛
・{}でなければコルーチンを再開して描画

 キー入力のKeypressed
・入力部分は普通
・selectedが変更された結果、next_menuに、Currentに束縛された関数のYieldへ、引数Selectedを使ったResumeを束縛する・・と、そうするとYield()が実行されて、ここで送りつけたSelectedがMain_menuのSelectedにも入って、
・んで、Main_menuの次はSelectedで分岐したところで、またYieldがあるのでそのYieldの引数(1だとStart_new_game)を返して停止するので、Next_menuにはStatr_new_gameがMenu_stackの最後尾に追加されると。ややこしい!よく出来てるけど。
・後は多分Love.drawでループする


 はぁなるほどねぇ!

 とりあえず、今の所の感想としては・・・前に書いてもらったLove.updateで判定&更新する方が楽な気がするなぁ・・



 とりあえずコルーチンの「入門以前」としてはこんなモンで良いだろう。会話システムとかアニメーション、AI行動パターン管理とかも気になるが、それもいずれ解説してもらうとしよう。



2025/03/14 Luaでの疑似オブジェクト指向についての疑問

 テーブル内に関数を放り込むのは分かった。けど、それに何のメリットが?名前空間の問題だけなのか?


 まあ、名前空間は目的の一つではあるようだ


 なんのこっちゃ?と思ったが、例えばここでのactive_timersなんかのように外からは直接触れないデータを作って保護するという効果があるという。
 あれ? update = function() って、前は先にテーブルを作っておいて後から.updateで追加してたけど違いがあるのか?



 そうそう、最初に入れとくのと後から追加の違いだな

 テーブルの更新の問題か・・。そもそも書き方2でも後から追加は出来そうな気がするが?


 ま、実質同じなら良いか

 モジュール読み込みの仕組みを聞く。モジュールが参照渡しということであればMain.lua側から更新したり出来るのだろうか?

 質問の意図は伝わってないけど有用な内容なので心にとどめておこう


 ズバリ聞いてしまう


 あ、そういう事か〜・・メモリにテーブルが保持されて、メモリ上のテーブルだけは更新されると。はぁ〜・・ま、実際書き換えられたらマズいだろうな、とは思ってましたけどね

 モンキーパッチってw

 これまでの解説でたびたび、別にクラスを作ってないのにインスタンス化というのが出てきてLuaで言うインスタンスが気になったので質問

 いや、クラスとかメタテーブルとかいらんから

 うーん・・つまり同じ名前のテーブル内変数やメソッドを持った新たなテーブルを作ることを今までインスタンス化って言ってたわけか


 サンプルのTimerを見てみると、途中でTimer.instanceにnewTimerを追加した上で返り値としてもnewTimerを返してる。これって参照なので片方を更新したらもう片方も変化するのか?と質問。

 あ、やっぱり変化するのか・・(同じテーブルを参照してるから)。実はこれと同じ共同を狙ってたのがタワテツ(仮称)での表示用Current_propertiesなんだよな〜・・つまり、あそこで.nameだけ抜き出して・・って事をせずに元になるテーブルごと引っ張ってきていたら、その後の破壊的変更で即座に表示が変えられたっぽいな


 ふーん、なるほどね!また忘れると思うけどとりあえず今は納得した


2025/03/13 Timer機能のコードを読み解く努力をする

 以前Per先生に書いてもらった自作版のTimer.every機能。使うだけだったら別に良いけど折角なので読み解いて何かを学ぶとしよう!



 コード全体としてはこういう感じ。これをTime.luaという別ファイルに入れておいてライブラリとして呼び出して使うと。で、読んでたんですけど・・どうにも分からない。
 まずTimer{}って何のために作ってるのか?
 最後にTimerを返してるので、もしかしてライブラリの書式として要請されてる操作なのか?(ファイル名もTime.luaだし)
 そもそもselfとか出てきてるけど、そんなのあったっけ?
 

 というわけでまずはselfについて質問。あ・・コロン構文って前に見たことがあるような?


 あ、なんかそういう話あったな!今、(うっすら)思い出した。なるほど!:だとselfが使えるってことだな

 なるほど〜・・まあ、覚える努力をしておこう。多分、.構文しか使わないと思うけど
 
 そしてTable と Return Tableについても質問してみた。

 えっ!?(・_・;)
 何ぃ!?function Timer.updateってTimer{}内にupdate関数(メソッド?)を作るって意味だったのか!なんだ、コレで謎が解けた!
 

 なるほど、self定義無しのメソッドとして追加してるわけかいな!そういう仕組みだったのか〜

 ふんふん、理論としては連想配列みたいになってるわけだな

 これな〜・・統一してくれても良くない?個人的にはTimer関係で先に見慣れてしまったFunction Timer.update(dt)で行こうかな・・

 これで謎だったスコープの問題が解決したわ

 ちなみに、Timer.luaで返ってくるテーブルもTable(return Table)なのでややこしくて質問したけど、ここでのreuquire "Timer"はTimer.luaファイルを読み込むという意味で確定。いや、そうだとは思いましたけどね?でも念の為に聞いてみました。
 

 ここでの3戻り値を受け取るってのがTimerテーブルを受け取るってことか。ここで色々と疑問が浮かんだ
・これってインスタンスを作るって事?(違うが)
・もしもMain.lua内でTimer.something_new()みたいにしたらモジュールはどうなるの?(メモリ上でのみ変更されて元ファイルは変更されないが)
 などなど・・これらは質問したので、また次回に。