追加案: 計算可能な汎用変数の追加
たぶん実現はWsn.2よりずっと後の話になるのではないかと思うのですが、端緒として立てておきます。
CardWirthにはフラグとステップという2種類の状態変数があります。これはプログラミングの知識が無くても取り回しが簡単で、それがシナリオの作りやすさに寄与している面も大きいと思いますが、少し複雑な事をしようとすると以下のような欠点が露呈します。
- 大きな桁の数値を作るのが簡単ではありません。
- 計算は非常に困難です。
- 工夫すればある程度文字列を操れますが、柔軟な操作はできません。
- カードの配置位置など様々な場面で使用する事ができません(それらの値は固定値で指定しなければなりません)。
これら全てを克服するには、いわゆるVariant変数のような、数値も文字列も、必要なら実数も扱え、しかも数値や文字列が必要となるデータから参照可能な、汎用的な種類の状態変数を1つ追加すればよいはずです。
しかし、その実装までには、いくつか困難な仕様上の決断を経る必要があります。
- 計算はどのような方法と構造で実現するか。エディタでの編集はどのようにできればよいか。
- 関数はどうするか。どのような関数を用意すればよいのか。
- 文字列としてカードや称号の名前を取得するような機能を追加するとして、どこまでできるようにするべきか。
これはどうあがいても仕様衝突の可能性が非常に大きくなる機能ですから、慌ててもどうせ実装はできません。じっくり考えていけばよいと考えてはいます。
今の状況では仕様を考えても実現できないという事を鑑みて、優先度は少し低めにしておきます。
Comments (22)
-
reporter -
reporter - 代入は「フラグ代入」「ステップ代入」で代入元に指定できればよさそうです。
- 初期値をどうするか。当面、初期化に関数や式は使えないようにしてしまってもよさそうに思えます。さもないと循環参照などのややこしい問題が出てしまいます。
- CWでは実数はほとんど出番がありません。当面は整数演算だけでよさそうに思えます。しかし整数演算はプログラマならぬ普通の感覚からすると不自然でもあります。
- 計算エラーはイベント中止にしてしまってもよさそうです。後付でオプション化も可能です。
- 整数・文字列の他に真偽値もほしい感じがします。
フラグやステップの値の取得などの処理に関しては、専用の関数を用意すればよさそうに思えます。
たとえばフラグ「A」の値を取る時:
FlagValue("A")
というようにできます。
このやり方のメリットは、拡張が容易な事です。たとえばフラグの値の文字列の取得は:
FlagText("A")
というように簡単に定義できますし、特定の値の時の文字列を得るように拡張するのも簡単です:
StepText("A", 4)
一方で、汎用変数そのものは
$NAME
のように専用の書式を用意してもよさそうです。 -
reporter - 実数について。やはりあった方がよさそうです。まともな算数が通用するようになるという事の他に、三角関数のような便利な道具が将来導入できるというメリットがあります。私はExcelとCWXスクリプトを使って円弧を描くようにセルアニメを行うという事例を見た事があります。整数演算を行いたい向きには
INT
関数を提供できます。 - 真偽値について。整数を真偽判定で使えるようにすると、比較演算の結果を引き算したりするような火遊びじみた事ができてしまうので、やはり安全のために必要です。値は
TRUE
とFALSE
です。
実は最も難しい問題は、この汎用変数の名前をどうするか、という事です。
実はプログラミングの世界にはこのような変数を指す言葉がすでにあります。バリアント(Variant)というのですが、これがCWの世界ではすでに別の意味で使われてしまっています。
- 実数について。やはりあった方がよさそうです。まともな算数が通用するようになるという事の他に、三角関数のような便利な道具が将来導入できるというメリットがあります。私はExcelとCWXスクリプトを使って円弧を描くようにセルアニメを行うという事例を見た事があります。整数演算を行いたい向きには
-
reporter 今考えている具体的な仕様です。
- 汎用変数(仮)を定義できるようにする
- 初期値にいずれかを設定可能にする
- 整数または実数(小数点の有無で判定)
- 文字列(
"
で囲う) - 真偽値(
TRUE
・FALSE
)
- 以下のコンテントを用意し、式を記入可能にする
- 汎用変数(仮)演算コンテント … 式の処理結果を使用しないもの
- 汎用変数(仮)分岐コンテント … 式の処理結果を真偽値として分岐を行うもの
- 式内で大文字・小文字は区別しない
- 以下の演算子を用意する。
~
・=
・<>
以外は文字列をが対象となったらエラー+
… 加算-
… 減算*
… 積算/
… 除算%
… 剰余~
… 連結。左右の値は文字列化されるor
… 論理和。左右の値が真偽値でなければエラーand
… 論理積。〃<
… 未満<=
… 以下>
… 超過>=
… 以上=
… 一致。左右値のどちらかが文字列であれば文字列化比較する<>
… 不一致。〃
- 以下の関数を用意する(str=文字列, n=数値, bool=真偽値, ?=式)
LEN(str) As n
… 文字列の長さを返す。LEFT(str, n) As str
… 文字列の左側を取り出す。LEN(str) < n
の場合は全て取り出すRIGHT(str, n) As str
… 文字列の右側を取り出す。〃MID(str, n1, n2) As str
… 文字列のn1からn2文字を取り出す。n1は1から開始する。文字数をオーバーした場合はn1以降を全て取り出すSTR(?) As str
… ?を文字列化するVALUE(?) As n
… ?を数値化する。数値化不能な文字列であればエラーINT(?) As n
… ?を整数化する。数値化不能な文字列であればエラーIF(bool, ?1, ?2) As ?
… boolがTRUE
であれば?1を、そうでなければ?2を返すFLAGVALUE(str) As bool
… strが指すフラグの値(真偽値)を返すFLAGTEXT(str[, bool]) As str
… strのフラグの値boolの文字列を返す。boolを省略した場合はFLAGTEXT(str, FLAGVALUE(str))
と同様に動くSTEPVALUE(str) As n
… strが指すステップの値(数値)を返すSTEPTEXT(str[, n]) As str
… strのステップの値nの文字列を返す。boolを省略した場合はSTEPTEXT(str, STEPVALUE(str))
と同様に動く
- 式には
$dir\name
という書式で汎用変数(仮)パスを記入できるようにする - フラグ代入・ステップ代入に、汎用変数(仮)の値が数値であれば代入する機能を追加
- フラグ代入では真偽値でなければ何もしない
- ステップ代入で実数は整数化する
- ステップ代入で上下限オーバー時は丸める
- 計算エラーが発生したり、分岐コンテントの結果が真偽値以外の時は、エラーとする
名前とエラー処理のみ、まだ考え中です。どちらかというと、エラー値という特別な値を用意して伝播させた方がよさそうな気がします。
-
reporter この機能はWsn.3での実装を無理に目指す事はないと思っていますが、Wsn.4までは目標にしたいです。
おそらくこのような機能がCWに存在する事そのものに嫌悪感を示す人もいるはずです。議論を煮詰めるだけの時間が必要です。
-
reporter 名前についてですが、いわゆる普通の変数という意味での「コモン」辺りがいいんじゃないかなぁと思っています。カタカナ名であれば、フラグやステップと並べても違和感は無いはずです。
定数でないという事で、変数を意味する「バリアブル」を持ってきてもいいかもしれません。
-
私は、汎用変数よりも先に数値ステップを 実装すべきと思います。 <Value>Step-0</Value> <Value>Step-1</Value> ... の行はかなり重たく、 シナリオ起動時に負担が大きいです。
NEXTからPyへのシナリオ移行を視野に入れるためにも よろしくお願い致します。
-
reporter 上の方にも書きましたが、この機能の具体的な検討はissue
#604に応じて進めています。変換に関していえば、この機能があれば数値ステップは不要という事です。 -
reporter メッセージ等に変数値を出す方法を考えなくてはなりません。新書式(#714)では予め用意できるのであまり悩む必要はありませんが、新書式の実装はいつになるか分かりませんし、旧書式で表示できないようでは不便です。
幸い、CWのメッセージは、
$存在しないステップ$
のように存在しない変数を指定すると、指定文字列がそのまま表示される仕様です。汎用変数は古いバージョンのシナリオには存在しませんから、古いバージョンのメッセージでは必ず指定文字列がそのまま表示される事になり、互換性問題は発生しません。好きな記号を使う事ができます。特殊文字ですでに使われている記号は
#$%&
、パス区切り文字として\
です。余っている記号は!"'()-~[]{}@*:;+<>?/
辺りでしょうか。この中では@
が$
や%
と並べても違和感が無さそうに思います。 -
reporter 手元で式の試験的な実装を作ってみたのですが、真偽値反転の演算子を忘れていました。
not
でよいかと思います。 -
reporter 式の中で汎用変数値を読む際、
$dir\name
という書式ではうまくいきません。というのも、CWの状態変数には好きな名前をつけられるので、文字列のように左右を囲わない場合、構文解析が非常に難しくなってしまうからです。そもそもフラグやステップは動的にパスを生成して
FLAGTEXT(<path>)
のようにできるのですが、汎用変数もそうした読み方ができるべきです。VAR("dir\name")
のように関数で変数値を読めるようにし、その構文糖として$"dir\name"
だとか{dir\name}
のような書き方ができる、という風にするのがおそらく自然です。書式の要件はパスの左右を囲える事と、ただも文字列と区別が可能な事です。
$"dir\name"
と{dir\name}
のどちらでもよいわけですが、パスが文字列である事を考えると、それを意識した前者の方がよさそうな気がします。もう少し考えてみます。 -
reporter ステップと同等の事をするには次の関数も必要です:
STEPMAX(str) As n
… strが指すステップの最大値を返すMAX(n, ...)
… 可変個のnの中から最大の数値を返すMIN(n, ...)
… 可変個のnの中から最小の数値を返す
ステップ判定コンテントに対応する次のコンテントも必要になります:
- 汎用変数(仮)判定コンテント … 式の処理結果が真であれば以降のイベントツリーが出現する
-
reporter 演算子の優先順位です:
+
(単項)-
(単項)/
*
%
+
-
~
<=
>=
<>
<
>
=
not
and
or
not
がC言語の!
等と異なってかなり低いのは、BASICやPythonの仕様に倣っての事です。これにより、not 1 <> 2
のような式を括弧無しで書けるようになります。優先度の高い否定演算子が必要になった時には!
演算子を用意する余地があります。 -
reporter - attached VariantTest.zip
pull request #2403
以上を踏まえた試験的な実装です。
今はエンジン側の実装で精一杯なので、エディタ側の作業は全くしていません。そのうち時間のある時にやります。
テキストエディタの手作業でシナリオを編集してわずかながらのテストを行いました。そのシナリオを添付しておきます。
デバッガでコモンの値を編集する事が可能です。
-
reporter - attached VariantTest.zip
テストケースをちょっと増やしました。
-
reporter pull request #2411
エディタ側の実装を行いました。
その過程で気づきましたが、フラグやステップへの代入は、代入コンテントではなくコモン設定コンテントで行った方が整理がついてよさそうです。フラグ・ステップのために用意されたコンテントにコモンの取り扱いを追加すると混乱を助長する可能性があります。とりあえず、対応を取り除いておきます。
$"path"
という形のコモン参照ですが、メッセージコンテントでの記号に合わせて@"path"
にした方がいいかもしれません。予定はしていないにせよ、将来フラグやステップの値を簡単に参照する方法がほしくなる事もありえます。特に実装上の問題はないはずなので、これから変更してみます。
-
reporter pull request #2412
$"..."
→@"..."
-
reporter - attached VariantTest.wsn
- marked as major
現状の仕様に合わせてテストシナリオを更新。
実際に動き始めたので優先度を通常に変更しました。
-
reporter 以上で基礎部分は実装まで完了です。
関数の追加など新規の提案を行う場合は、個別のIssueを立ててください。
基礎部分の変更の提案は、このIssueにお願いします。
-
reporter pull request #2413
文字の任意位置から右側を取る手段が無かったので、
MID
関数の長さ省略で対応しました。 -
reporter コモンと式の解説記事を書きました。
-
reporter - changed status to resolved
基礎部分は全て実装済みなので、クローズします。
- Log in to comment
issue
#604のご意見も来ましたし、そろそろ具体的な事を考えるべきかと思います。汎用変数は、ゴールがかなりはっきりしている分、最初から完全なものを作ろうとせず、段階的に実装していく事が可能です。
草稿にもならないものですが、以下に最初期段階の考えを記しておきます。
以下は検討して決めなくてはならない事です。
以下は、一番最初の段階では手をつけなくてもいいかと思っている事です。