12. 湊だけで簡単になる書き方

ここまでは、壊れるものの話でした。この節では、逆に、里々では苦労した処理が湊で素直に書けるものを挙げます。移行の価値を判断する材料にしてください。

構造化されたデータ

里々では、$好感度_湊、$勝ち数、$負け数 のように、変数名にキーを埋め込むしかありませんでした。湊では、配列とマップで入れ子にして持てます。途中のマップは自動で作られます。

OnBoot => {
    global save.stats.win += 1
    global save.stats.lose += 2
    global save.fav.湊 = 10
    湊: ${save.stats.win}勝${save.stats.lose}敗
}
\01勝2敗\e
{"stats":{"win":1,"lose":2},"fav":{"湊":10}}

マップの繰り返し

foreach マップ as キー, 値 で、キーと値を順に取り出せます。

OnBoot => {
    let scores = {"りんご": 3, "みかん": 5}
    foreach scores as name, n {
        湊: ${name}は${n}点\n
    }
}
\0りんごは3点\nみかんは5点\n\e

存在しないキーの安全な参照

get(マップ, キー, 既定値) で、キーがなくても警告を出さずに既定値が返ります。?? は null のときだけ代替値を使います。

OnBoot => {
    let m = {"a": 1}
    湊: ${get(m, "a", 0)}|${get(m, "b", 0)}|${m["b"] ?? "なし"}
}
\01|0|なし\e

正規表現と日付の計算

里々では、SAORI(ssu)や自作の関数を組み合わせていた処理が、そのまま書けます。

OnBoot => {
    let c = regex_captures("2026年1月2日", "(\d+)年(\d+)月(\d+)日")
    湊: ${c[1]}-${c[2]}-${c[3]}
    湊: ${days_between(2026, 1, 1, 2026, 1, 31)}日
}
\02026-1-2\n30日\e

regex_match、regex_find、regex_replace、regex_split も使えます。days_since(年, 月, 日) は、指定した日から今日までの日数です。

関数と再帰

引数と戻り値のある関数が書けます。

func 階乗(n) {
    if (n <= 1) {
        return 1
    }
    return n * 階乗(n - 1)
}

OnBoot => {
    湊: 5の階乗は${階乗(5)}
}
\05の階乗は120\e

かな順のソートと整形

里々では、五十音順に並べるには自分で比較の処理を書く必要がありました。湊では sort(配列, "kana") の1行で済みます。ひらがな・カタカナ・濁点・小書き文字の違いを無視して、五十音順に並べます。漢字は読みに変換されないので、漢字まじりの項目は読みをキーにして並べます。format で桁を揃えられます。

OnBoot => {
    湊: ${join(sort(["りんご", "ぶどう", "みかん"], "kana"), ",")}
    湊: ${format("%02d:%02d", 7, 5)}
}
\0ぶどう,みかん,りんご\n07:05\e

ファイルの読み書き

ghost/master の中のテキストファイルを、file_read / file_write / file_append で扱えます(file_move で移動もできます)。パスは、ゴーストのホームからの相対パスで、書き込めるのは ghost/master の中だけです。

OnBoot => {
    let ok = file_write("ghost/master/memo.txt", "こんにちは")
    湊: ${ok}|${file_read("ghost/master/memo.txt")}
    湊: ${file_write("memo.txt", "x")}
}
\0true|こんにちは\nfalse\e
  • 文字コードの既定は UTF-8 です。Shift_JIS のファイルは、file_read(パス, "sjis") で読めます。
  • talks の中、config.toml、descript.txt、save.json で始まるファイル(save.json.bak なども含む)、.dll、minato_ で始まるファイルには書き込めません。詳しくはビルトイン関数の「ファイル操作」を参照してください。
  • 1MBを超えるファイルは読めません。
  • 書き込みは、途中で落ちても既存のファイルが壊れないように、一時ファイルを経由します(file_append を除く)。

事前の構文チェック

里々では、辞書のミスはゴーストを起動して初めて分かることが多くありました。湊には、SSPなしで動く構文チェッカー minato_check があります。

minato_check.exe "ghost/masterのフォルダ"

talks/main.mnt を含むフォルダ(ゴーストの ghost/master)を指定します。 構文エラーは、該当する行の抜粋つきで表示されます。結果はすべて標準エラー出力に出ます(問題がなかったときのメッセージだけ標準出力)。 色付きで表示されます。色を付けたくないときは --no-color を付けてください。さらに、次の静的チェックを行います。

チェックレベル
ループの外の break / continueエラー(ゴーストは起動しない)
存在しないトーク・関数を call している通知(notice)

終了コードは、エラーがなければ 0、あれば 1 です。ビルド・配布の手順に組み込めます。

ログを残す

log("メッセージ") は、config.toml(と save.json)で debug_log が有効なときだけ、minato_debug.log に書き込みます。台本の途中経過を確認できます。

任意のトークが存在するかの確認

talk_exists("名前") で、トークまたは関数が定義されているかを確認できます。ゴーストの一部の機能を、ファイルの有無で切り替える設計にできます。

短絡評価

&&、||、?? は、左辺で結果が決まると右辺を評価しません。choose(条件, 値, 値) も、選ばれなかった側の式は評価しません。副作用のある式(saori() など)を安全に書けます。

次は13. 段階移行 vs 全置換に進んでください。