Lattice リファレンス · 4 分の 3
CYOA の選択と有限 State
CYOA は明示的な経路の選択と、任意の有限 State を扱えます。TypeApe は、読者にストーリーを届ける前に、すべての可能な経路を検査できます。
State のない CYOA
分岐だけの CYOA は、State、Pool、Module を宣言せずに next、choice、end を使えます。
自動継続
next -> target_block;対象は同じ所有者(メインストーリーまたは現在の Module)の中に留まらなければなりません。
プレイヤーの選択
choice {
option inspect_key: { Inspect the key } -> inspect;
option leave_garden: { Leave the garden } -> departure;
}choice は次の条件を満たします。
- 少なくとも二つの
option宣言を含む。 - 各 option に、その choice 内で一意な ID を与える。
- 読者向けのラベルに本文を使う。
- 同じ所有者の既存の Block を対象にする。
- 閉じ
}の後にセミコロンを付けない。
option の ID は、その choice 内の行動を識別します。State ではありません。option を選ぶと経路は変わりますが、選択に関する事実は永続化されません。
結末
end;end はストーリー全体を終わらせます。これは Module の中でも同様です。Module が Pool に制御を返すべき場合は complete を使います。
分岐グラフの規則
Pool も Module もない CYOA では、次の条件を満たします。
- Story の entry がメインストーリーに存在し、入力エッジがない。
- すべての Block が entry から到達可能である。
- 経路が非循環である。
- 少なくとも一つの結末が存在する。
- 分岐は共有された Block に合流できる。
- 到達可能なすべての経路が終端する。
合流が Linear story との重要な違いです。複数の選択が同じ後続の Block を対象にできます。
有限状態の境界
Lattice の State は閉世界で、宣言から導かれます。意図的に、変数、カウンター、算術、スクリプト、関数、再帰、乱数値、動的 State、外部入力を持ちません。
State は、利用可否や Pool の終了が、名前の付いた有限の事実を記憶しなければならない場合にのみ使います。通常の経路のトポロジーは、通常の choice のままにしておくべきです。
Predicate 宣言
Predicate はタプルスキーマ内の実体 kind を宣言します。
predicate knows (
subject: character,
object: item
);
predicate at (
subject: character,
place: location
);subject は必須です。object と place は任意のスキーマフィールドです。各フィールドの型は character、location、item のいずれかです。
Predicate は真偽値の変数ではなく、推論も行いません。その Predicate を使う接地された State 宣言が従わなければならない正確な形を定義します。
接地された State 宣言
State は一つの Predicate に完全に接地されたタプルを与え、タイトルを必要とします。
state st_knows_signal (
title: "Signal understood"
): event {
subject: ch_mara,
object: it_key,
predicate: knows
};
state st_at_gate (
title: "At the gate"
): event {
subject: ch_mara,
place: loc_gate,
predicate: at
};State の検証は次を要求します。
- スキーマが必須とするすべてのフィールドが存在する。
- Predicate スキーマにないフィールドが含まれない。
- すべての実体参照が宣言された kind と一致する。
predicateが接地するスキーマを参照する。- 任意の
timeが一つの正確な有限リテラルである。 - 二つの State ID が同じ接地されたタプルを表さない。
任意フィールドを省略することは「任意の値」ではなく「不在」を意味します。Predicate は異なる State タプル間の関係を含意しません。Guard は常に State ID を直接参照します。
フラグと State Group
グループ化されないフラグ
どのグループにも属さない State は、単調な真偽値フラグです。story.initial_state で名指しされない限り無効で始まり、add で有効化でき、削除操作を持ちません。
相互排他的なグループ
State Group は一つの有限スロットを定義します。
state group location (
members: [st_at_gate, st_in_garden]
);members は必須で、空であってはなりません。グループは重複できません。ランタイム State は、すべてのグループからちょうど一つの有効なメンバーを含みます。
Story は初期値を選択します。
story main (
title: "Signal Garden",
language: "en",
format: novel,
entry: arrival,
initial_state: [st_at_gate]
);initial_state は、すべての State Group からちょうど一つのメンバーを選択しなければなりません。リストにないグループ化されないフラグは無効で始まります。空のリストが有効なのは、選択すべき必須のグループメンバーがない場合だけです。
Guard
Module は requires、requires_any、forbids を使います。Pool は対応する終了フィールド exit_requires、exit_requires_any、exit_forbids を使います。
| Guard フィールド | 一致する条件 |
|---|---|
requires: [a, b] | リストされたすべての State が有効 |
requires_any: [a, b] | リストされた State の少なくとも一つが有効 |
forbids: [a, b] | リストされたすべての State が無効 |
Guard の参照は存在しなければならず、重複できません。同じ State を同時に要求し、禁止することはできません。Module は Guard を持たなくてもかまいません。Pool の終了 Guard は、その終了フィールドを通じて少なくとも一つの条件を含まなければなりません。
Guard は現在の State ID だけを検査します。宣言された State が関連する事実を明示的に記録しない限り、本文、ナラティブの setup マーカー、以前の choice option の ID、完了した Module の数、宣言の順序を検査することはできません。
Pool
Pool はメインストーリーから進入する有限状態のチェックポイントです。
pool investigation (
title: "Investigate the garden",
exit_requires: [st_knows_signal]
);title は必須です。すべての Pool には、到達可能なメインストーリーの enter がちょうど一つあります。
scene garden (title: "The garden") {
block arrival (title: "Arrival", purpose: setup) {
text: { The buried key pulses beneath Mara's hand. };
enter investigation -> departure;
}
}enter の後の識別子が Pool です。-> の後の識別子は、終了 Guard が一致した後に読書を再開するメインストーリーの Block です。
enter はメインストーリー専用です。Module は Pool に入れず、Pool は入れ子にできず、Pool は複数の進入地点を持てません。
Pool の評価順序
進入時と各 Module の完了後に、TypeApe は次の正確な順序に従います。
- Pool の終了 Guard を評価します。
- 一致すれば、
enterが記録した Block から再開します。 - そうでなければ、条件を満たす未完了の Module をすべて、安定したインポート / 宣言順に列挙します。
- 読者に一つの Module を選ばせます。
- 終了が偽で、条件を満たす Module がない場合は、ソフトロックを報告します。
終了は Module の適合可否より優先されます。Module の順序は提示順であり、自動スケジューラや意味的な優先度ではありません。
浮動 Module
Module は一つの Pool に属し、その入れ子の Scene と Block を所有します。
module md_decode (
title: "Decode the key",
pool: investigation,
entry: decode,
requires: [st_at_gate],
forbids: [st_knows_signal]
) {
scene decoding (title: "The buried code") {
block decode (
title: "Decode",
purpose: development
) {
text: { The light resolves into a patient sequence. };
complete (
add: [st_knows_signal],
set: [st_in_garden]
);
}
}
}必須の Module フィールドは次のとおりです。
title:読者に見えるテキスト。pool:所有する Pool の ID。entry:この Module が所有する Block。
Guard フィールドは任意です。Module が適合するのは、Guard が一致し、まだ完了していない間だけです。すべての Module は一度きりです。
Module のフローはその Module の中に留まります。メインストーリー、別の Module を対象にしたり、別の Pool に入ったりはできません。
Module の完了と Effect の適用
complete は Module 専用の終端です。
complete (
add: [st_knows_signal],
set: [st_in_garden]
);これは原子的に次を行います。
addのグループ化されないフラグをすべて有効化する。setのグループ化された State をすべて選択し、そのグループの以前のメンバーを置き換える。- 現在の Module を完了として記録する。
- 所有する Pool に制御を返す。
- Pool の終了と適合可否の規則を再評価する。
add はグループ化されない恒久フラグにのみ使います。set はグループ化された State にのみ使います。一回の完了で、各グループのメンバーを最大一つ設定できます。remove、toggle、フラグとグループメンバー間の暗黙の変換はありません。
Effect は完了全体が適用された後にのみ再検討されるため、Guard が半端に更新された State を観測することはありません。
完全な Pool / Module の例
story main (
title: "Signal Garden",
language: "en",
format: novel,
entry: arrival,
initial_state: [st_at_gate]
);
entity character ch_mara (name: "Mara", role: protagonist);
entity location loc_gate (name: "Garden gate");
entity location loc_garden (name: "Signal Garden");
entity item it_key (name: "Signal key");
predicate knows (subject: character, object: item);
predicate at (subject: character, place: location);
state st_knows_signal (title: "Signal understood"): event {
subject: ch_mara,
object: it_key,
predicate: knows
};
state st_at_gate (title: "At the gate"): event {
subject: ch_mara,
place: loc_gate,
predicate: at
};
state st_in_garden (title: "Inside the garden"): event {
subject: ch_mara,
place: loc_garden,
predicate: at
};
state group location (
members: [st_at_gate, st_in_garden]
);
pool investigation (
title: "Investigate the signal",
exit_requires: [st_knows_signal]
);
scene garden (title: "The garden", pov: ch_mara) {
block arrival (title: "Arrival", purpose: setup) {
text: { The buried key pulses beneath Mara's hand. };
enter investigation -> departure;
}
block departure (title: "Departure", purpose: resolution) {
text: { With the signal understood, Mara turns home. };
end;
}
}
module md_decode (
title: "Decode the key",
pool: investigation,
entry: decode,
requires: [st_at_gate],
forbids: [st_knows_signal]
) {
scene decoding (title: "The buried code") {
block decode (title: "Decode", purpose: development) {
text: { The light resolves into a patient sequence. };
complete (
add: [st_knows_signal],
set: [st_in_garden]
);
}
}
}arrival では st_knows_signal が無効なので、Pool は終了できません。マラは門のそばにおり、まだ信号を知らないため、md_decode が適合します。これを完了するとフラグが有効になり、場所のグループが変わり、Pool に戻ります。終了が一致するようになったので、読書は departure から再開します。
ランタイムの有効性の規則
完全な CYOA 検証は、ソースの参照以上のものを検査します。
- メインストーリーと各 Module ローカルの Block グラフが非循環である。
- すべてのフローの対象が所有者の中に留まる。
- すべての Pool に一つの entry と到達可能な終了がある。
- 到達可能なすべての非終端の構成が、最終的に結末へ到達できる。
- 到達可能なソフトロックされた構成がない。
- ランタイムの遷移が循環しない。
- ソース順だけでなく、読者が選択できる Module の順序がすべて有効である。
- 決して適合しない Module は警告を生む。
- TypeApe がすべての可能な経路の検査を完了できる。
ストーリーが完全に検査するには複雑になりすぎた場合、Validate は不完全な結果を提示せず、診断とともに停止します。
カウンター、繰り返し可能な遭遇、ランダムなスケジューリング、可逆的な移動、隠れた蓄積を x_ メタデータで模倣しないでください。それらの機能は Story DSL v1 の範囲外です。
次へ:検証と診断。
