WSN追加案:カードに状態変数をくっつける

Issue #477 resolved
req created an issue

ステップ<=>クーポン連番変換でやりたかったことはこういうことです。

数値管理はステップが直観的で使いやすいので、カードに状態変数をくっつけて外部持ち出しして、使用時イベントで状態変数でコンテントを操作することを考えます。

これは、カードのデータ構造の後付拡張なので、大変なことが想定されますが、実現したいものであります。

Comments (13)

  1. k4nagatsuki repo owner

    宿への状態変数の保存についての考え方とも関連する話になりますが、ALGOL系プログラミング言語でよく見かける変数のスコープの概念を導入してみるのが1つの手段だと思います。

    例えば以下のような感じに:

    int a = 0; // グローバル
    
    class A {
        int a = 1; // クラスA内スコープ
    
        void func() {
            int a = 2; // 関数func内スコープ
            static int b = 3; // 関数func内スコープ(静的)
        }
    }
    

    ここで、関数funcの中でaという名前の変数を使用した場合、もっとも内側のスコープであるfunc内のaを操作する事になります。funcを出てAの他の関数を実行中の場合はA内のa、さらにその外の場合はグローバルのaを相手にする事になります。

    このやり方のいいところは、色々なプログラミング言語で考え方に実績がある事です。CW的に1から考えると「カードに状態変数があったとして、じゃあ使用時イベントからパッケージを呼び出したら、そのパッケージ内で使った変数はどこのものになるのか?」というような面倒な問題が色々出てきますが、イベントツリーを関数として考えてみると、「関数のスコープを出ているからカードの状態変数は使えない」という結論がすぐに出ます(じゃあどうやってパッケージでカードの状態変数を使うのか、となると、パッケージの引数のような別の課題が発生しますが、それは別に考えるべきです)。

    ところで、関数func内のaは、funcが実行されるたびに初期化される事にお気づきだと思います。これでは状態の保存に使えません。そこで、静的変数のような概念も導入するとよいでしょう。

    Cのような言語では、変数にstatic属性をつける事で、値が関数を出ても保存されるようにする事ができます。変数bの内容はfuncを出ても変わらず、次の呼び出しで保存されていた値が使えます。同じような属性が状態変数につけられるようにすればよいでしょう。


    実装を焦らず慎重になっていただけるようお願いします。これは明らかに大きな機能になるので、私はWsn.2までに実現するのは無理だと思っています。

  2. req reporter

    なるほど、元のシナリオ内ではスコープが拡大するのか。

    実装を焦らず慎重になっていただけるようお願いします。これは明らかに大きな機能になるので、私はWsn.2までに実現するのは無理だと思っています。

    これはマクロと同様、全然焦っていません。大丈夫です。自分もWsn.2までに実現するのは無理だと思っています。

  3. k4nagatsuki repo owner

    この手の複雑な機能は試しに実装してみないと知見が得られないので、少し手を動かしてみました。現時点での成果はcwxeditorの私の個人リポジトリにあります。

    以下の2点は試験実装によって見つかった検討事項です。


    カードがローカルに状態変数を持てるようになるこの機能をローカル変数と呼ぶ事にしますが、最も重要な検討事項は、状態変数のパスをどうするかという事です。

    1. 従来の状態変数(ローカルに対してグローバル変数と呼びます)と同じパスを持てるようにする。ローカル変数とグローバル変数が同じ名前で参照された時は、ローカル変数が優先して参照されるようにする。
    2. ローカル変数のパスを工夫して絶対にグローバル変数と重複しないようにする。\Local\フラグ名のように、冒頭に従来はありえないパスを加えれば可能です。

    最初はグローバル変数のあるプログラミング言語に習って1.で実装してみたのですが、どうもこの方向はあまりうまくいかなさそうな事が分かりました。

    • メリットがほぼありません。パッケージ呼び出しの時に状況によって同じ名前で参照できる変数を変えたりできるのですが、それによって発生するバグの方が多そうです。
    • エディタのUI上、ローカル変数とグローバル変数の区別がつけづらくなってしまい、やはりバグを誘発します。
    • ローカル変数とグローバル変数をパスで区別できないので、エンジンもエディタも実装がかなり面倒になります。

    という事で2.の方向を採るのがいいかと思います。

    \Local\のような文字列がつくのが煩わしいという問題は、エディタの実装によってある程度軽減できるはずです。


    仮にローカル変数のパスが指定されていても、実際に参照してはならない箇所が存在します。理由はどれも同じで、ローカル変数は永続性を持たないので、カードやセルのようなイベント終了後も残る可能性のあるリソースからの参照を許すと無理が発生するためです。

    • カード・セルの表示フラグ。
    • メニュー・エネミーカードの上書き名内の特殊文字展開。
    • テキストセル内の特殊文字展開。ローカル変数の場合は必ず表示時に内容を固定するなどすれば可かもしれませんが、仕様上の例外になってしまうので検討が必要です。最初は不可が安全だと思います。

    これらに対して、メッセージやクーポン名などは、その場で文字列を生成したあとは参照が不要なのでローカル変数を使用可能です。

  4. k4nagatsuki repo owner

    上にパッケージ云々と書いてしまいましたが、呼び出し先パッケージまでローカル変数が伝播するとなるとスコープが壊れてしまい、明らかに筋が悪いので、伝播しないようにするべきでしょう。

    パッケージ内へ状態変数の値を伝えるためには、引数・戻り値など、別の仕組みが必要です。

  5. tachi gigas

    お疲れ様です。 Issue #541 の件で、これは仕様に触れると思うので、相談させてください。

    ローカル変数を他シナリオに持ち出して使用する際、各種変更が効かないという問題を確認しました。どうも、content.pyis_differentscenarioで処理が弾かれてしまうようです。どのようにすれば正着でしょうか。

  6. k4nagatsuki repo owner

    あ、これは仕様としてローカル変数は動くべきなのが自明なので単なるミスですね。

    今から修正します。

  7. k4nagatsuki repo owner

    pull request #2487

    操作ミスで他のPull Requestに混ぜてしまいましたが、修正しました。

  8. Log in to comment