2026年2月2日月曜日

TidalCycles / Strudel 系について教えてください

 TidalCycles / Strudel 系は「コードで時間のパターンを書く」ライブコーディング音楽の系統で、同じ“パターン言語”の発想を Haskell本家(TidalCycles)ブラウザ版(Strudel) で使い分けられるのがポイントです。

TidalCycles(本家)

  • Haskell上で動くパターン言語で、リズムや音列を関数で合成・変形しながら演奏します。

  • 音作りは多くの場合 SuperCollider / SuperDirt 側で鳴らし、TidalがOSCなどで制御します(いわゆる「パターンはTidal、音は外部」構成)。

  • 公式ドキュメントの導入に「必要コンポーネント(Git / Haskell / SuperCollider / SuperDirt / エディタ)」がまとまっています。

向いている場面

  • しっかりした制作環境で、外部シンセやセットアップ込みで強く運用したい

  • Haskell側の表現力や拡張も含めて深掘りしたい

Strudel(ブラウザ版・公式ポート)

  • ブラウザで動くライブコーディング環境で、TidalCyclesのパターン言語を JavaScriptで実装した公式ポートです。

  • まずはWeb上のREPLで即プレイでき、学習ページも公式に用意されています。

  • 内蔵のWeb Audioシンセ(SuperDough)で鳴らせるほか、MIDI / OSC / MQTT にも出せます。

向いている場面

  • インストール無しでまず触りたい、ワークショップや授業、短い検証

  • ブラウザで完結しつつ、必要なら外部機材にも繋げたい

補足(開発拠点の移動)

  • StrudelやTidalのGitHubリポジトリは Codebergへ移行している案内があります(GitHub側はアーカイブ扱い)。

ざっくりした違い

  • TidalCycles: 本格環境(Haskell + SuperCollider/ SuperDirt)で強い。セットアップは重め。

  • Strudel: ブラウザで即開始。Tidalの発想を最短で体験できる。I/Oも拡張可能。

最短の始め方(おすすめルート)

  1. まず StrudelのREPL を開いて、学習ページの最初の例を動かす

  2. 「パターンを関数で変形する感覚」が掴めたら、必要に応じて TidalCycles のセットアップへ進む

2026年2月1日日曜日

底哩三昧耶不動尊威怒王使者念誦法

 

典籍の同定

  • **1200『底哩三昧耶不動尊威怒王使者念誦法』**は、大正新脩大藏經の No.1200 として整理されているテキストです。

  • 大正蔵の区分では **第21巻・密教部(四)**に収録されています。

  • 東洋文庫の底本・校本DBでは、訳者(Translator/Author)が **唐 釋不空(不空)**と明記されています。

  • 同DBでは、このテキストの **別題(Alternative Title)**として「底哩三昧耶經」「威怒王使者念誦法」「不動使者念誦法」が挙げられています。

略名と正式名の関係

  • 国立国会図書館のレファレンス協同DBの事例では、
    正式名:底哩三昧耶不動尊威怒王使者念誦法
    略名:底哩三昧耶不動尊聖者念誦秘密法
    と整理されています。

  • 同事例は、該当経文が 『大正新修大蔵経 21(密教部4)』の p13–22 にある、と案内しています。

閲覧できる一次資料(本文)

  • SAT(東京大学のSAT大蔵経テキストDB)で T1200 のページが提供されています。

  • CBETAでも 大正蔵 第21冊 No.1200 としてオンライン閲覧できます(本文)。

近接テキスト(あなたが挙げた1199との並び)

  • **1199『金剛手光明灌頂經最勝立印聖無動尊大威怒王念誦儀軌法品』**は、大正蔵 No.1199 として整理されています。

  • 1199も訳者が 不空とされ、SATとCBETAで本文が閲覧可能です。

  • つまり、あなたのメモにある「密教部(四)第21巻 No.1199-1420」のうち、**1199と1200は連番で並ぶ“不空訳の不動(無動尊)系の儀軌”**として、DB上でも同じ巻・同じ領域に配置されています。

  • 横山裕明「Trisamayarājasādhanaについて」(佛教文化学会紀要 29号, 2020)は、『底哩三昧耶経』に基づく2つの成就法を扱う、という問題設定です。

  • 同論文は、『底哩三昧耶経』が諸文献に引用され、Śikṣāsamuccayaにも複数引用が見出せるため 7世紀前後には現行に近い形が成立していた可能性に触れています。

  • 同論文はまた、『底哩三昧耶経』について サンスクリット写本と漢訳が存在せず、チベット訳に頼らざるを得ないため研究が進みにくい、という状況説明をしています。


  • 大正蔵では、T1200『底哩三昧耶不動尊威怒王使者念誦法』とT1201『底哩三昧耶不動尊聖者念誦秘密法』は別番号で連番収録です。東洋文庫DBではT1200の別題は「底哩三昧耶経」「不動使者念誦法」など。国会図書館レファレンスでは、T1200の略名としてT1201題名を挙げる例があります。

  • Redcode 入門ガイド(初心者向け), v1.23(日本語訳)

    Redcode 入門ガイド(初心者向け), v1.23(日本語訳)

    Redcode 入門ガイド(初心者向け)

    バージョン 1.23


    目次


    はじめに(Preface)

    最近は Core War というゲームに興味を持つ初心者が、あまり多くありません。もちろん、これは自然なことです。アセンブリコードの最適化を楽しいと感じる人は、そもそも多くないからです。しかし、出発点の敷居が高い理由の 1 つに、「ゲームの基本中の基本」についての情報が見つけにくいこともあります。良い文書は多く存在しますが、技術的すぎる、古い、探しにくい、あるいは不完全といった問題が起こりがちです。

    そこで私はこのガイドを書くことにしました。目的は、Core War と Redcode に初めて触れる人を、動く(勝てなくてもよい)ウォリアーを書けるところまで案内し、さらに技術的な資料へ進めるようにすることです。

    正直に言えば、私自身もまだこのゲームの初心者です。言語についてはかなり理解していますが、本当に成功したウォリアーをまだ作れていません。ただ、経験を積むまで待つのではなく、「新規プレイヤーとして、ゲームの癖を理解しようとして苦労する感覚」を鮮明に覚えているうちに、できるだけ早く書くことにしました。

    このガイドは 本当に 初心者向けです。アセンブリ言語(あるいはプログラミング一般)の知識は不要で、概念をうっすら知っている程度なら用語理解の助けになります。Redcode(特に現代の仕様)は見た目こそアセンブリ風ですが、多くの点でより抽象的で、他のアセンブリ言語とは細部がかなり異なります。

    このガイドで扱う Redcode は(概ね)現在の de facto 標準である ICWS ’94 Standard Draft に pMARS 0.8 拡張を加えたものです。(HTML に対する Netscape 拡張のようなものです…うーん…。幸い、Microsoft Corewar Simulator はまだありません。市場が小さすぎると思っているのでしょう。)古い ’88 標準についても軽く触れますが、中心は ’94 標準です。’88 を学びたい人向けのチュートリアルは Web にたくさんあります。

    重要:Redcode(あるいはどんなプログラミング言語でも)を、完全に直線的な順序で教える簡単な方法はありません。このガイドも、ある程度は筋の通った順序に整理しましたが、飛び飛びに読んでも全く構いません。そのための 目次 です。

    全体の整合性を保つために、先に例を見せてから数章後で説明する、という構成がしばしば登場します。理解しにくい点があれば、少し先まで読み進めてください。それでも分からなければ、別の章で説明されていないか探してみてください。

    学び方は人それぞれなので、あなたが選ぶ読み順は、私が選んだ順序より良い可能性があります。ただし、退屈だからと完全に読み飛ばすと、重要な情報を取り逃がすことがあります。重要な箇所には 強調 を付けるよう努めました。とはいえ、すべてを逐一書き切ると、このガイドは長くなりすぎて読めなくなります。できるだけ丁寧に読んでください。


    Core War 入門

    Core War とは?

    Core War(または Core Wars)は、シミュレートされたコンピュータのメモリ上で、アセンブリプログラム同士が互いを破壊し合うプログラミングゲームです。プログラム(warriors=ウォリアー)は Redcode という特別な言語で書かれ、MARSMemory Array Redcode Simulator)という実行環境で動作します。

    Redcode と MARS の環境は、普通のコンピュータシステムに比べて大きく単純化され、抽象化されています。これは良いことです。Core War のプログラムは可読性ではなく性能のために書かれます。もし通常のアセンブリ言語を使うゲームだったら、世界で 2〜3 人しか「効果的で丈夫な」ウォリアーを書けず、しかも本人たちですら完全には理解できないかもしれません。可能性は大きいものの、そこそこに到達するだけでも何年もかかるでしょう。

    どう動くのか?

    プログラムが走るシステムはとても単純です。core(シミュレートされたコンピュータのメモリ)は連続した命令の配列で、競技プログラム以外は空です。core は環状に繋がっており、最後の命令の次は最初の命令に戻ります。

    実際、プログラムは core の終端を知る手段がありません。絶対アドレスが存在しないからです。つまり、アドレス 0 は「メモリの最初の命令」ではなく、「そのアドレスを含む命令自身」を意味します。次の命令は 1、前の命令は -1 です。

    ご覧の通り、Core War のメモリの基本単位は通常の 1 バイトではなく「1 命令」です。各 Redcode 命令は 3 つの部分からなります。OpCode(命令そのもの)、ソースアドレス(別名 A-field)、デスティネーションアドレス(B-field)です。A-field と B-field の間でデータを移すことも可能ですが、基本的には命令を分割不能なブロックとして扱う必要があります。

    実行も同様に単純です。MARS は 1 サイクルに 1 命令を実行し、命令が別アドレスへのジャンプを指示しない限り次の命令へ進みます。複数のプログラムが走る場合(通常そうです)、各プログラムは交互に 1 命令ずつ実行されます。MOV でも DIV でも、プロセスを殺す DAT ですら、実行時間は等しく 1 サイクルです。


    Redcode を始める

    Redcode の命令セット

    Redcode の命令数は標準が新しくなるたびに増え、最初は 5 つ程度だったものが、現在は 18 か 19 になりました。しかも修飾子とアドレッシングモードが増え、組み合わせは文字通り数百になります。とはいえ、全部を暗記する必要はありません。命令と、修飾子がどう作用を変えるかを覚えれば十分です。

    Redcode で使われる命令の一覧です:

    • DAT — data(データ。実行するとプロセスを殺す)
    • MOV — move(あるアドレスから別アドレスへコピー)
    • ADD — add(加算)
    • SUB — subtract(減算)
    • MUL — multiply(乗算)
    • DIV — divide(除算)
    • MOD — modulus(剰余。割って余りを得る)
    • JMP — jump(別アドレスへ制御移動)
    • JMZ — jump if zero(値を調べ、0 ならジャンプ)
    • JMN — jump if not zero(0 でなければジャンプ)
    • DJN — decrement and jump if not zero(1 減算し、結果が 0 でなければジャンプ)
    • SPL — split(別アドレスで第 2 のプロセスを開始)
    • CMP — compare(SEQ と同義)
    • SEQ — skip if equal(2 命令を比較し、等しければ次命令をスキップ)
    • SNE — skip if not equal(等しくなければ次命令をスキップ)
    • SLT — skip if lower than(2 値を比較し、第 1第 2 より小さければ次命令をスキップ)
    • LDP — load from p-space(プライベート領域から読み込む)
    • STP — save to p-space(プライベート領域に書き込む)
    • NOP — no operation(何もしない)

    いくつかが(控えめに言って)妙に見えても心配しないでください。Redcode は抽象的なので、一般的なアセンブリ言語とはかなり違います。

    Imp(インプ)

    真実として、Redcode でいちばん重要な部分は、いちばん簡単な部分です。基本的なウォリアーの多くは、新しい命令やモードが登場する前に発明されました。最も単純で、おそらく最初の Core War プログラムは Imp です。A. K. Dewdney が 1984 年の Scientific American の記事で Core War を一般に紹介した際に掲載されました。

            MOV 0, 1

    はい、これだけです。たった 1 つの MOV。では、これは何を する のでしょうか? MOV は命令をコピーします。Core War のアドレスは現在命令からの相対なので、Imp は自分自身を「自分の直後の命令」にコピーします。

            MOV 0, 1         ; いま実行した行
            MOV 0, 1         ; 次に実行される行

    Imp は、いま書いた命令を次に実行します。全く同じ命令なので、また 1 命令先へ自分をコピーし、そのコピーを実行し…という動きを繰り返し、core を MOV で埋めながら前進します。core には終端がないので、全域を埋めた後は起点に戻り、ad infinitum(永遠に)ぐるぐる回り続けます。

    つまり Imp は、実行しながら自分のコードを生成します! Core War では自己書き換えは例外ではなくルールです。勝つには効率が必要で、ほぼ必ず「その場でコードを変える」ことになります。抽象化された環境のおかげで、通常のアセンブリより追いやすいのが救いです。

    ちなみに、Core War にキャッシュはありません。まあ正確には、現在 実行中の命令だけはキャッシュされるので、実行の 途中 でそれを変えることはできませんが、その話は後にしましょう…。

    Dwarf(ドワーフ)

    Imp にはウォリアーとして小さな欠点があります。勝ちにくいのです。相手を上書きしても、相手も MOV 0, 1 を実行し始めてインプ化し、引き分けになりがちです。相手を殺すには DAT を相手コードにコピーする必要があります。

    そこで Dewdney の別の古典ウォリアー Dwarf(ドワーフ)が登場します。これは core を一定間隔で DAT で「爆撃」し、自分に当たらないようにしながら相手を殺します。

            ADD #4, 3        ; ここから実行開始
            MOV 2, @2
            JMP -2
            DAT #0, #0

    これは Dewdney の原文と寸分違わずではありませんが、動きは同じです。実行は先頭命令から始まります。最初は ADD です。ADD はソースとデスティネーションを足し、結果をデスティネーションへ置きます。他のアセンブリ言語を知っているなら、# は即値(immediate)を示す記号として見覚えがあるでしょう。つまりこの ADD は「アドレス 3 の命令」に 4 を足します。「命令 4 を命令 3 に足す」ではありません。ADD の 3 つ後の命令は DAT なので、結果は次の通りです:

            ADD #4, 3
            MOV 2, @2        ; 次の命令
            JMP -2
            DAT #0, #4

    命令どうしを足す場合、A-field と B-field は独立に加算されます。1 つの数値を命令に足す場合、デフォルトでは B-field に加算されます。ADD の B-field にも # を付けられます。その場合、A-field が ADD 自身の B-field に足されます。

    即値アドレッシングは簡単で馴染み深く見えますが、ICWS ’94 の新しい 修飾子 が、これに 全く新しいひねり を加えます。ですが、まずはドワーフを見ていきましょう。

    MOV には別のアドレッシングモードが出てきます。@ は間接(indirect)です。見た目通りに DAT を自分自身へコピーする(それで何が嬉しいのか?)のではなく、「B-field が指す先の命令」へコピーします:

            ADD #4, 3
            MOV 2, @2  ;  --.
            JMP -2     ;    | +2
            DAT #0, #4 ; <--' --. MOV の B-field がここを指す
            ...                 |
            ...                 | +4
            ...                 |
            DAT #0, #4 ; <------' DAT の B-field がここを指す

    ご覧の通り、DAT は自分から 4 命令先にコピーされます。次の JMP は 2 命令後ろへ飛び、ADD へ戻します。JMP は B-field を無視するので空にしました。MARS は 0 で初期化します。

    なお、MARS は間接参照の鎖をさらに辿りません。間接オペランドが指す先が B-field=4 の命令であれば、実際の宛先は「そこから 4 命令先」になり、アドレッシングモードは関係ありません。

    さて ADDMOV が再び実行されます。実行が JMP に戻ったとき、core は次のようになっています:

            ADD #4, 3
            MOV 2, @2
            JMP -2           ; 次の命令
            DAT #0, #8
            ...
            ...
            ...
            DAT #0, #4
            ...
            ...
            ...
            DAT #0, #8

    ドワーフは core を一周して自分の位置に戻るまで、4 命令おきに DAT を落とし続けます:

            ...
            DAT #0, #-8
            ...
            ...
            ...
            DAT #0, #-4
            ADD #4, 3        ; 次の命令
            MOV 2, @2
            JMP -2
            DAT #0, #-4
            ...
            ...
            ...
            DAT #0, #4
            ...

    この状態で ADDDAT を再び #0, #0 に戻し、MOV は無意味にも DAT を「既にある場所へ」コピーし、全体が最初から繰り返されます。

    これは core のサイズが 4 で割り切れないと成立しません。そうでないと、ドワーフは DAT の 1〜3 命令手前を踏んで自滅します。幸い、よく使われる core サイズは 8000 が最も一般的で、次いで 8192、55400、800 などで、いずれも 4 で割り切れるので、このドワーフは安全です。

    補足として、ウォリアーに DAT #0, #0 を含める必要は本当はありません。core が最初に埋められている命令(ここでは三点リーダ ... と書いたもの)は実際には DAT 0, 0 です。読みやすいので、以後も空の core を三点リーダで表します。

    アドレッシングモード

    Core War の初期バージョンでは、アドレッシングモードは即値(#)、直接($ または無指定)、B-field 間接(@)の 3 つだけでした。後に、プリデクリメント(predecrement)である < が追加されました。これは間接と同じですが、ターゲットアドレスを計算する前にポインタを 1 減らします。

            DAT #0, #5
            MOV 0, <-1       ; 次の命令

    この MOV が実行されると、結果は次のようになります:

            DAT #0, #4 ;  ---.
            MOV 0, <-1 ;     |
            ...        ;     | +4
            ...        ;     |
            MOV 0, <-1 ; <---'

    ICWS ’94 Standard Draft では、主に A-field の間接参照に対応するために 4 つのモードが追加され、合計 8 モードになりました:

    • # — 即値(immediate)
    • $ — 直接(direct。$ は省略可)
    • * — A-field 間接(A-field indirect)
    • @ — B-field 間接(B-field indirect)
    • { — A-field 間接+プリデクリメント
    • < — B-field 間接+プリデクリメント
    • } — A-field 間接+ポストインクリメント
    • > — B-field 間接+ポストインクリメント

    ポストインクリメントはプリデクリメントに似ていますが、命令が実行された にポインタが 1 増えます。

            DAT #5, #-10
            MOV -1, }-1      ; 次の命令

    は、実行後に次のようになります:

            DAT #6, #-10 ;  --.
            MOV -1, }-1  ;    |
            ...          ;    |
            ...          ;    | +5
            ...          ;    |
            DAT #5, #-10 ; <--'

    プリデクリメント/ポストインクリメントで覚えておくべき重要点は、ポインタは「実際に参照に使われない場合でも」増減することです。たとえば JMP -1, <100 は、値を使わないのに命令 100 をデクリメントします。DAT <50, <60 も、プロセスを殺すだけでなくアドレスをデクリメントします。

    プロセスキュー

    上の命令表をよく見た人は SPL に気づいたかもしれません。普通のアセンブリ言語にはまずありません…。

    Core War の歴史のかなり初期に、「マルチタスクを入れればもっと面白くなる」という提案がありました。通常の OS のタイムスライス方式は抽象環境に合わない(何より OS が必要)ため、各プロセスを 1 サイクルずつ順番に実行する方式が考案されました。

    新しいプロセスを作る命令が SPL です。A-field にアドレスを取り、JMP と同様に見えます。違いは、SPL は新しいアドレスから実行を開始する だけでなく、次の命令でも実行を 継続する 点です。

    こうして生まれた 2 つ以上のプロセスは、同じ実行時間を等しく分け合います。単一のプロセスカウンタではなく、MARS は process queue(プロセスキュー)という「開始順に繰り返し実行されるプロセスのリスト」を持ちます。SPL で作られた新プロセスは「現在のプロセスの直後」に追加され、DAT を実行したプロセスはキューから削除されます。全プロセスが死ぬと、そのウォリアーは負けです。

    重要なのは、各プログラムが 自分専用の プロセスキューを持つことです。core に複数のプログラムがある場合、各プログラムはキューの長さに関係なく、常に 1 サイクルずつ交互 に実行されます。したがって処理時間は常に等分されます。たとえば プログラム A が 3 プロセス、プログラム B が 1 プロセスなら、実行順は次のようになります:

    1. プログラム A、プロセス 1
    2. プログラム B、プロセス 1
    3. プログラム A、プロセス 2
    4. プログラム B、プロセス 1
    5. プログラム A、プロセス 3
    6. プログラム B、プロセス 1
    7. プログラム A、プロセス 1
    8. プログラム B、プロセス 1
      ...

    最後に、SPL の小さな例です。より詳しい話は後の章で扱います。

            SPL 0            ; ここから実行開始
            MOV 0, 1

    SPL が自分自身を指しているので、1 サイクル後にはプロセスはこうなります:

            SPL 0            ; 第 2 プロセスはここ
            MOV 0, 1         ; 第 1 プロセスはここ

    両方のプロセスが実行されると、core は次のようになります:

            SPL 0            ; 第 3 プロセスはここ
            MOV 0, 1         ; 第 2 プロセスはここ
            MOV 0, 1         ; 第 1 プロセスはここ

    つまりこのコードは、次々に Imp を発射していくのが分かります。Imp たちが core を一周して SPL を上書きするまで続きます。

    各プログラムのプロセスキューには上限があります。最大プロセス数に達している場合、SPL次の命令だけ で実行を継続し、結果として NOP と同じ挙動になります。多くの場合、上限は core の長さと同程度でかなり大きいですが、もっと小さく設定されることもあります(1 の場合は分割が実質無効です)。

    それと、「現実は小説より奇なり」という話として、私は最近 "Opcodes that should've been" というページを見ました。そこには荒唐無稽な命令がいろいろあり、その中に "BBW — Branch Both Ways" がありました。架空の命令のはずなのに、作者は Redcode を知らなかったのだろうとしか思えません…。

    命令修飾子(modifier)

    ICWS ’94 標準がもたらした最重要の新要素は、新命令や新アドレッシングモードではなく「修飾子」です。古い ’88 標準では、アドレッシングモードだけが「命令のどの部分が操作対象か」を決めます。たとえば MOV 1, 2 は常に命令全体を移動し、MOV #1, 2 は数値 1 つだけを移動します(しかも 常に B-field へ)。

    当然、これでは困る場面が出ます。OpCode を変えずに A/B フィールドだけ移したい場合は?(ADD を使う必要があります) B-field から A-field に移したい場合は?(可能ですが、とても厄介) そこで状況を明確化するために、修飾子が導入されました。

    修飾子は命令に付ける接尾辞で、ソースとデスティネーションのどの部分に作用するかを指定します。たとえば MOV.AB 4, 5 は「アドレス 4 の A-field を、アドレス 5 の B-field に移す」ことを意味します。修飾子は 7 種類あります:

    • MOV.A — ソースの A-field をデスティネーションの A-field へ移す
    • MOV.B — ソースの B-field をデスティネーションの B-field へ移す
    • MOV.AB — ソースの A-field をデスティネーションの B-field へ移す
    • MOV.BA — ソースの B-field をデスティネーションの A-field へ移す
    • MOV.F — ソース両フィールドを、同じ対応フィールドへ移す
    • MOV.X — ソース両フィールドを、逆対応フィールドへ移す
    • MOV.I — ソース命令全体をデスティネーションへ移す

    当然ながら、これらの修飾子は MOV だけでなく全命令で使えます。ただし JMPSPL のように、修飾子を気にしない命令もあります。(データを扱わず、ジャンプするだけだからです。)

    すべての修飾子がすべての命令で意味を持つわけではないので、意味が通る「最も近いもの」にフォールバックします。よくある例が .I です。Redcode は単純で抽象的な言語にするため、OpCode の数値的な等価物を定義していません。従って OpCode に数学演算をかける意味がありません。このため MOVSEQSNE(および別名の CMP)以外では .I.F と同義になります。

    .I.F についてもう 1 点。アドレッシングモードも OpCode の一部であり、MOV.F ではコピーされません。

    例として、古いプログラムを修飾子付きで書き直してみます。Imp は自然に MOV.I 0, 1 になります。Dwarf はこうです:

            ADD.AB #4, 3
            MOV.I  2, @2
            JMP    -2
            DAT    #0, #0

    JMPDAT は修飾子を実質使わないので省略しています。MARS は(例として)JMP.BDAT.F に補うかもしれませんが、あまり気にしなくてよいでしょう。

    もう 1 つ。どうやってどの修飾子を付けるか(また、付けなかった場合に MARS がどう補うか)ですが、常識的に決められる場合が多いものの、’94 標準はルールとして定義しています。

    DAT, NOP
    常に .F だが無視される。
    MOV, SEQ, SNE, CMP
    A-mode が即値なら .AB
    B-mode が即値で A-mode が即値でないなら .B
    どちらも即値でないなら .I
    ADD, SUB, MUL, DIV, MOD
    A-mode が即値なら .AB
    B-mode が即値で A-mode が即値でないなら .B
    どちらも即値でないなら .F
    SLT, LDP, STP
    A-mode が即値なら .AB
    即値でないなら(常に).B
    JMP, JMZ, JMN, DJN, SPL
    常に .B(ただし JMPSPL では無視される)。

    ’94 標準をもう少し深く

    # は見た目以上の意味がある…

    ’94 標準における即値アドレッシング(#)の定義は、かなり独特です。旧来の構文と 100% 互換でありながら、即値は非常に巧妙で一意な方法で定義されており、あらゆる命令と修飾子と論理的に組み合わせられ、強力な道具になります。

    修飾子を見て、MOV.F #7, 10 が何をするのか疑問に思うかもしれません。.F は両フィールドを移すはずなのに、ソースには数値が 1 個しかありません。では 7 をデスティネーションの両フィールドに入れるのでしょうか?

    いいえ、そうはなりません。実際には、デスティネーションの A-field に 7 を、B-field に 10 を移します。なぜでしょう?

    理由は、’94 の構文では、ソース(およびデスティネーション)は 常に 命令全体だからです。即値の場合、ソース命令は「現在の命令(すなわち 0)」として扱われます。実際の値が何であってもそうです。したがって MOV.F #7, 10 は、ソース(0)の両フィールドをデスティネーション(10)へ移すのです。驚きますよね?

    同じ考え方は MOV.I にも適用されます。この定義により、修飾子なしでは ’88 標準で意味を持たなかった JMP #1234 のような命令も合理的に使えます。数値へジャンプはできませんが、「その数値のアドレス(0)へジャンプ」なら可能です。これは多くの利点をもたらします。A-field に「ただで」データを置けるだけでなく、誰かにデクリメントされてもコードが生き残ります。先ほどの Imp 生成コードも少し丈夫にできます:

            SPL    #0, }1
            MOV.I  #1234, 1

    動きは同じですが、今度は A-field が自由になりました。お遊びとして、SPL に Imp の A-field をインクリメントさせ、Imp がそれぞれ違う見た目になるようにしています。SPL は B-field を使わないので、この増分も「ただ」です。動作します。信じてもよいし、自分で試してもよいでしょう!

    剰余(モジュロ)計算

    core のアドレスが環状であることは既に分かっているはずです。現在命令から coresize だけ進んだり戻ったりすると、同じ命令を指します。しかし実際には、これはさらに深いところまで及びます。Core War では全ての数値が 0 から coresize-1 の範囲に正規化されます。

    範囲付き整数演算に慣れている人向けに言うと、Core War の数値は符号なしとして扱われ、最大値は coresize-1 です。それでもピンと来なければ続きを読んでください。

    要するに、Core War の全ての数値は core の長さ coresize で割られ、余りだけが保持されます。たとえば 8 桁しか表示できない電卓を想像してください。桁あふれの上位桁は捨てられます。100*12345678 は 1234567800 ですが 34567800 だけが表示され保持されます。同様に core=8000 の場合、7900+222 は 8122 ですが 122 になります。

    負数はどうなるでしょう? これも正規化されます。正になるまで coresize を足します。つまり -1 は MARS では coresize-1 として保存され、core=8000 なら 7999 です。

    アドレスは元から環状なので、これは大抵は問題になりません。単純な ADDSUB でも、coresize=8000 なら 6+7998 は 4(または 8004)になり、6-2 と同じ結果です。

    では何が問題かというと、いくつかの命令では差が出ます。DIVMODSLT は常に符号なしとして扱います。したがって -2/2 は -1 ではなく、(coresize-2)/2 です。つまり (coresize/2)-1(core=8000 なら 7998/2=3999)になります。同様に SLT は -2(7998)を 0 より 大きい とみなします。Core War では 0 が最小であり、それ以外は全て 0 より大きいのです。

    ’94 標準の命令を 1 つずつ

    ここまで耐えてくれたあなたにご褒美です。これまでは断片的な情報を渡してきました。ここで一度まとめとして、各命令を順に説明します。

    もちろん、最初に命令一覧を出した時点で説明しておけば推測が減ったでしょう。でも待った理由があります。実用的なコードを先に見せたかったのと、何よりアドレッシングモードと修飾子の基本感覚を掴んでから命令を説明したかったからです。修飾子の前に命令を説明すると、まず ’88 のルールを教え、後で修飾子込みでもう一度教える必要が出ます。学習法として悪くないですが、このガイドが不必要に複雑になります。

    DAT
    元々 DAT は名前通りデータ保存用でした。Core War では命令数を減らすため、未使用フィールドにポインタなどを入れることが一般的です。そのため DAT の最重要点は「実行するとプロセスが死ぬ」ことです。’94 標準では不正命令が存在しないため、DAT は完全に合法な命令として定義され、現在実行中のプロセスをプロセスキューから取り除きます。些細な言い回しに見えるかもしれませんが、当たり前を厳密に定義すると混乱が減ります。

    修飾子は DAT に影響しません。MARS によっては削除します。ただし、プリデクリメント/ポストインクリメントは値が使われなくても評価されることを忘れないでください。もう 1 つ、過去標準の名残として、引数が 1 つしかない場合は B-field に入ります。
    MOV
    MOV は命令から命令へデータをコピーします。ここまでの章で十分理解できていなければ、前を読み返した方がよいでしょう。MOV は数少ない .I 対応命令で、修飾子が省略され(かつ即値が絡まないなら)デフォルトは .I
    ADD
    ADD はソース値をデスティネーション値へ加算します。修飾子の挙動は MOV に似ていますが、.I はサポートされず .F と同じ意味になります。(MOV.ABDJN.F の足し算、という概念は意味を持たないでしょう?) また、Core War の演算は全て modulo coresize で行われます。
    SUB
    これも ADD と同様に動きますが、違いは明白です。実際、算術系命令はだいたい同じです。
    MUL
    MUL も同様です。何をするか分からないなら、かなり重要なものを見落としています。
    DIV
    DIV も概ね同様ですが、注意点があります。まず 符号なし除算 なので意外な結果になることがあります。ゼロ除算はプロセスを殺しますDAT と同様)かつデスティネーションは変更されません。DIV.F.X で 2 つ同時に割り算をして、一方の除数が 0 でも、もう一方の割り算は通常通り行われます。
    MOD
    DIV と同様の注意が全て当てはまります(ゼロ除算の扱いも含む)。MOD.AB #10, #-1 のような結果は core サイズに依存することを覚えてください。一般的な 8000 core なら結果は 9(7999 mod 10)です。
    JMP
    JMP は A-field が指すアドレスへ実行位置を移します。算術命令との重要な違いは、JMP は「そのアドレスが指すデータ」ではなく「アドレスそのもの」だけを気にする点です。さらに JMP は B-field を使わないため、修飾子も無視します。2 つのアドレスへ同時にジャンプ(あるいは分岐)できると強すぎますし、次の 3 命令の実装も難しくなります。とはいえ、未使用の B-field に増減を仕込めば、運が良ければ相手コードを傷つけられます。
    JMZ
    JMZJMP に似ていますが、B-field を無視せず、B-field が指す値をテストし、0 ならジャンプします。0 でないなら次へ進みます。テスト対象が 1 命令だけなので修飾子の選択肢は限られます。.AB.B と同義、.BA.A と同義、.X.I.F と同義です。JMZ.F で両フィールドをテストする場合、両方が 0 のときだけ ジャンプします。
    JMN
    JMNJMZ と同様ですが、テスト値が 0 でない 場合にジャンプします(驚きはありませんね)。JMN.Fどちらかのフィールドが 0 でなければ ジャンプします。
    DJN
    DJNJMN に似ていますが、テストの に値を 1 減らします。ループカウンタに便利ですし、相手の破壊にも使えます。
    SPL
    これが大物です。SPL の導入は Redcode 史上最も重要な変更の 1 つで、ICWS ’94 の導入と並ぶほどです。SPLJMP のように動きますが、実行は 次の命令でも 継続し、プロセスが 2 つに分かれます。次の命令側のプロセスが、ジャンプ先へ行くプロセスより 先に 実行されます。これは小さな違いに見えますが、非常に 重要です(多くの現代ウォリアーがこれなしでは動きません)。最大プロセス数に達している場合、SPLNOP と同じです。JMP と同様に B-field と修飾子は無視されます。
    SEQ
    SEQ は 2 命令を比較し、等しければ次の命令をスキップします。(飛ぶのは 2 命令先だけです。ジャンプ先を書ける場所がありません。) 等値比較なので .I がサポートされます。.F.X.I では、全フィールドが一致 したときだけスキップします。
    SNE
    予想通り、比較した命令が等しくない場合に次命令をスキップします。複数フィールドを比較する場合、どれか 1 組でも一致しなければスキップします。(JMZJMN の関係と似ていますね。)
    CMP
    CMPSEQ の別名です。SEQ/SNE が導入される前はこの名前しかありませんでした。今では多くの MARS が ’88 モードでも SEQ を認識するので、どちらを使っても大差ありません。
    SLT
    SLT は「第 1 の値が第 2 より小さい」場合に次命令をスキップします。これは論理比較ではなく算術比較なので .I を使う意味はありません。SGT(大きいならスキップ)があってもよさそうですが、多くの場合はオペランドを入れ替えれば同じ効果が得られます。全ての値は符号なし として扱われるため、0 が最小で、-1 が最大 です。
    NOP
    何もしない命令です。(何もしないことに関しては完璧です。) 実戦ウォリアーではほぼ使いませんが、デバッグには有用です。増減が設定されていれば、それは評価されます。

    なお LDPSTP の 2 命令が未説明ですが、比較的新しい追加であり、次で説明します。:-)

    P-space — 最後のフロンティア

    P-space は pMARS 0.8 で導入された Redcode の最新要素です。P は private / permanent / personal / pathetic など、お好きな意味でどうぞ。要するに P-space は「自分のプログラムだけがアクセスでき」「マルチラウンドの対戦でラウンド間を越えて保持される」メモリ領域です。

    P-space は通常の core と多くの点で異なります。まず、各 P-space の場所は命令ではなく数値 1 つだけを保存します。また、P-space のアドレスは絶対で、core 内のどこにその命令が置かれていても P-space のアドレス 1 は常に 1 です。さらに、P-space へアクセスできる命令は LDPSTP の 2 つだけです。

    この 2 命令の構文は少し変わっています。たとえば STP は core の通常値をソースに取り、その値を「デスティネーションが指す P-space フィールド」に書き込みます。つまり P-space の場所は「デスティネーションの アドレス」ではなく「デスティネーションの 」で決まります。もしこれが MOV だったなら上書きされる値、ということです。

    たとえば STP.AB #4, #5 は、 4 を P-space フィールド 5 に保存します。同様に、

            STP.B  2, 3
            ...
            DAT    #0, #10
            DAT    #0, #7

    は、値 10 を P-space フィールド 7 に書き込みます。3 ではありません! STP 自身が間接アドレッシングを使うと、ある種の「二重間接」になり、かなり混乱します。

    LDP は同様ですが、ソースが P-space フィールドになり、デスティネーションが core 命令になります。

    P-space のサイズは通常 core より小さく、典型的には core サイズの 1/16 です。P-space のアドレスも core と同様に環状です。P-space のサイズは core サイズの因数でなければならず、そうでないと妙なことが起きます。

    P-space の 0 番地は特別で、各ラウンドの前に特別な値で初期化されます。第 1 ラウンドでは -1、前ラウンドで死んだ場合は 0、それ以外は生存プログラム数です。1 対 1 なら 0 は負け、1 は勝ち、2 は引き分けです。この初期化により、0 番地はラウンド間の任意情報の受け渡しには使えません。次ラウンド開始前に MARS が上書きするからです。

    pMARS 実装には P-space に関する癖があります。P-space アクセスを遅く保つ意図から、1 命令で 2 フィールド同時にロード/セーブすることは許可されていません。これは良いのですが、結果は少なくとも不格好です。具体的には LDP.F.X.I は全て LDP.B と同じ動きになります(STP も同様です)。

    P-space の最も一般的な用途は、戦略選択です。最も単純には、前回の戦略を P-space に保存し、P-space の 0 番地が「前回負け」を示していれば戦略を切り替えます。この種のプログラムは P-warriors、P-switchers、P-brains(pea-brains と発音)などと呼ばれます。

    残念ながら P-space は見かけほど私的ではありません。相手はあなたの P-space を直接読み書きできませんが、あなたのプロセスが捕獲されて相手コード(STP を含む)を実行させられることがあります。この種の手法は brainwashing(洗脳)と呼ばれ、P-switcher はそれに備え、戦略フィールドが妙な値になっても暴走しないようにする必要があります。


    パーサ(アセンブラ)

    ラベルとアドレス

    これまでは、例のプログラムでアドレスを「現在命令からの相対命令番号」で書いてきました。しかし大きなプログラムでは面倒で、読みづらくもなります。幸い、Redcode ではラベル、記号定数、マクロなど、良いアセンブラに期待する機能が使えます。命令にラベルを付け、ラベルで参照すれば、実アドレスはパーサが計算してくれます:

    imp:    mov.i   imp, imp+1

    どうでしょう? これは最初に出したプログラムと同じです。数値アドレスをラベル "imp" 参照に置き換えただけです。ただ、この例では有効性は薄いです。ラベルを使っているのは "imp" 自身だけで、ここは 0 に置き換わるからです。

    実行前に、MARS のパーサはラベルなどの記号を数値へ変換します。こうして「前処理された」Redcode ファイルは load file(ロードファイル)と呼ばれます。全ての MARS はロードファイルを読めますが、完全なパーサを持たないものもあります。ロードファイル形式では先ほどのコードは MOV.I 0, 1 になります。また、同じコードを次のようにも書けます:

    imp:    mov.i   imp, next
    next:   dat     0, 0            ; あるいは何でも

    この場合、"next" は "imp" の 1 命令後なので 1 に置き換わります。実アドレスは相対数値のままなので、Imp が "next" の上へコピーして進んでも、Imp は相変わらず MOV.I 0, 1 のままです。

    ラベル末尾の : は必須ではありません。ここでは見やすさのため付けましたが、私は自分のコードでは通常付けません。好みの問題です。

    念のため。Redcode 命令は大文字小文字を区別しません。私はソースは小文字の方が見た目が良いので小文字を好み、コンパイル済み(ロードファイル)だけ大文字にします(主に伝統です)。

    全体像

    これまでの例はコンパイルできるかもしれませんが、プログラムの断片に過ぎません。典型的な Redcode ファイルには、MARS 向けの追加情報があります。

    ;redcode-94
    ;name Imp
    ;author A.K. Dewdney
    
            org     imp
    
    imp:    mov.i   imp, imp+1
            end

    既に気づいていると思いますが、Redcode では ; 以降はコメントです。ただし先頭の数行は単なるコメントではありません。MARS はそこからプログラム情報を取得します。

    最初の行 ;redcode-94 は「これは Redcode ファイルである」ことを示します。この行より上は MARS に無視されます。実際は ;redcode で始まればよいのですが、残りで Redcode の方言を識別できます。特に KotH サーバ はこの行を自分で読み、どの hill に送るかを判断します。

    ;name;author はプログラム情報です。任意形式でも書けますが、特定コードを使うと MARS が読み取って実行時に表示できます。

    END 行は、(予想通り)プログラムの終端です。以後は無視されます。;redcode と組み合わせると、メールに Redcode を埋め込む用途にも使えます。

    ORG は実行開始位置を示します。これにより、プログラム本体の前に他命令を置けます。ORG は ’94 標準で追加されたものです。古い書き方では開始アドレスを END の引数にします。

    ;redcode-94
    ;name Imp
    ;author A.K. Dewdney
    
    imp:    mov.i   imp, imp+1
    
            end     imp

    単純で短いのですが、残念ながら理屈としては微妙です。長いプログラムでは開始位置を見るために末尾までスクロールする必要も出ます。Redcode では ORGENDpseudo-OpCodes(疑似命令)と呼びます。命令のように見えますが、実際にはプログラムへコンパイルされません。

    Imp はこのくらいにして、Dwarf を現代 Redcode で書くとこうです:

    ;redcode-94
    ;name Dwarf
    ;author A.K. Dewdney
    ;strategy 一定間隔で core を爆撃する。
    ;(slightly modified by Ilmari Karonen)
    ;assert CORESIZE % 4 == 0
    
            org     loop
    
    loop:   add.ab  #4, bomb
            mov.i   bomb, @bomb
            jmp     loop
    bomb:   dat     #0, #0
    
            end

    ラベルがあると理解しやすいですね。ここではコメント行も 2 つ追加しました。;strategy はプログラムの簡単な説明で、複数行書けます。多くの MARS は無視しますが、hill は ;strategy を表示します。上のプログラムを送ると、例えば次のように見えるかもしれません:

    A new challenger has appeared on the '94 hill!
    
    Dwarf by A.K. Dewdney: (length 4)
    ;strategy Bombs the core at regular intervals.
    
    [other info here...]

    環境と ;assert

    例に新しく出てきたのが ;assert 行です。これはプログラムが現在の設定で本当に動作するかを確認するために使えます。Dwarf は core サイズが 4 で割り切れないと自滅するので、;assert CORESIZE % 4 == 0 を入れて常に成り立つことを保証しています。

    CORESIZE は core サイズを示す定義済み定数です。つまり n+CORESIZE は常に n と同じアドレスです。% は剰余演算子です。;assert 行などで使える式の構文は C 言語と同じ ですが、演算子の種類はかなり限定されています。

    C を知らない人向けに、Redcode 式で使われる演算子の一覧です:

    算術:
    + 加算
    - 減算(または符号反転)
    * 乗算
    / 除算
    % 剰余
    比較:
    == 等しい
    != 等しくない
    < 小さい
    > 大きい
    <= 以下
    >= 以上
    論理:
    && AND
    || OR
    ! NOT
    代入:
    = 変数 への代入

    ;assert の後ろには論理式が続きます。偽ならコンパイルされません。C と同様、0 が偽でそれ以外が真です。論理演算子と比較演算子は真なら 1 を返し、後で便利なことがあります。

    典型的には ;assert は core サイズが想定通りか確認します(例:;assert CORESIZE == 8000)。P-space を使う場合は ;assert PSPACESIZE > 0 で存在確認できます。Dwarf は適応性があるので、特定値ではなく割り切れ条件だけを確認しました。Imp は どんな 設定でも動くので ;assert 1;assert 0 == 0 のように常に真の式でも構いません。そうしないと MARS が "missing ;assert line -- warrior may not work with current settings." と警告する場合があります。

    定義済み定数の一部(CORESIZE など)は ’94 標準が定義し、他は追加され得ます。pMARS 0.8 は少なくとも次をサポートするはずです:

    • CORESIZE — core のサイズ(既定 8000)
    • PSPACESIZE — P-space のサイズ(既定 500)
    • MAXCYCLES — 引き分けになるまでのサイクル数(既定 80000)
    • MAXPROCESSES — プロセスキュー最大(既定 8000)
    • WARRIORS — core 内のプログラム数(通常 2)
    • MAXLENGTH — プログラム最大長(既定 100)
    • CURLINE — いままでにコンパイルした命令数(0 から MAXLENGTH
    • MINDISTANCE — 2 ウォリアー間の最小距離(既定 100)
    • VERSION — pMARS バージョン×100(80 以上)

    #define? まあ、ほぼそれ…

    定義済み定数もラベルも便利ですが、それだけでしょうか? 変数のようなものは使えないのでしょうか?

    Redcode はアセンブリ言語なので変数は多く使いません。しかしそれに近いもの(時にはそれ以上)があります。疑似命令 EQU で独自の定数、式、さらにはマクロ的なものも定義できます:

    step    equ     2667

    これ以後、step は常に 2667 に置換されます。ただし罠があります。置換は数値ではなくテキストです。この例なら問題になりにくいですが、EQU を強力にする一方で、C のマクロと同様の問題も起こります。例を見ましょう。

    step    equ     2667
    target  equ     step-100
    
    start   mov.i   target, step-target

    MOV の A-field は 2567 になりますが、B-field は 2667-2667-100 == -100 になってしまいます。本来は 2667-(2667-100) == 100 を意図したでしょう。解決は簡単です。EQU の式には常に括弧を付けることです。例えば "target equ (step-100)" のように。

    最近の pMARS では複数行 equ が使え、マクロ風にできます:

    dec7    equ     dat #1, #1
            equ     dat $1, $1
            equ     dat @1, @1
            equ     dat *1, *1
            equ     dat {1, {1
            equ     dat }1, }1
            equ     dat <1, <1
    
    decoy   dec7
            dec7            ; 21 命令のデコイ
            dec7

    "rof" は何のため?

    pMARS パーサの機能はまだあります。これは上のどれよりも強力で(そして学びにくい)かもしれません。FOR/ROF はソースを短くし、複雑なコード列を簡単に作るだけでなく、設定に応じた条件付きコードも作れます。

    FOR ブロックは疑似命令 FOR と「繰り返し回数」で始まります。前にラベルがあると、ループカウンタとして使われます:

    index   for     7
            dat     index, 10-index
            rof

    ブロックは ROF で終わります。(古い決まり文句 NEXTREPEAT より良いと思います。) 上は pMARS により次のように展開されます:

            DAT.F   $1, $9
            DAT.F   $2, $8
            DAT.F   $3, $7
            DAT.F   $4, $6
            DAT.F   $5, $5
            DAT.F   $6, $4
            DAT.F   $7, $3

    FOR ブロックは入れ子にもできます。中に EQU も入れられ、面白いコードが作れます。さらに便利なのは、ループカウンタを & 演算子でラベルに結合できる点です。ラベル重複を避ける用途が多いですが、他にも使えます。

    dest01  equ     1000
    dest02  equ     1234
    dest03  equ     1666
    dest04  equ     (CORESIZE-1111)
    
    jtable
    ix      for     4
    jump&ix spl     dest&ix
            djn.b   jump&ix, #ix
            rof

    これは FOR/ROF の処理後、次になります:

    jtable
    jump01  spl     dest01
            djn.b   jump01, #1
    jump02  spl     dest02
            djn.b   jump02, #2
    jump03  spl     dest03
            djn.b   jump03, #3
    jump04  spl     dest04
            djn.b   jump04, #4

    これを何に使うかは想像次第です。ここまで複雑な式を使うウォリアーは、私が見た範囲では quickscanner くらいです。定義済み定数は FOR/ROF でも使えます。例えば:

    ; ここにウォリアー本体
    
    decoy
    foo     for     (MAXLENGTH-CURLINE)
            dat     1, 1
            rof
    
            end

    これはウォリアーの残り領域を DAT 1, 1 で埋めます。自分のプログラムをデコイから離れた場所へコピー(boot)していれば、攻撃の誤誘導に使えます。ここで foo を意味のないループカウンタとして置いているのは、そうしないと MARS が decoy をループカウンタと誤認するためです。

    最後に、FOR/ROF をより創造的に使う例です:

    ;redcode-94
    ;name Tricky
    ;author Ilmari Karonen
    ;strategy とても複雑なウォリアー的な何か
    ;strategy (条件付きコードの分かりやすい例)
    ;assert CORESIZE == 8000 || CORESIZE == 800
    ;assert MAXPROCESSES >= 256 && MAXPROCESSES < 10000
    ;assert MAXLENGTH >= 100
    
            org     start
    
            for     0
    これは for/rof のコメントブロックです。繰り返し回数が 0 なので、
    ここは MARS に無視されます。複雑な戦略の説明を書くのに最適です。
            rof
    
    ;もちろん普通のコメントでも可能です。好みでどうぞ。
    
            for     (CORESIZE == 8000)
    step    equ     normalstep
    ;比較が真なら 1、偽なら 0 を返すので、このコードは条件が真のときだけコンパイルされます。
            rof
    
            for     (CORESIZE == 800)
    step    equ     tinystep
    ;小さい core 用の最適化定数をここに置けます。
            rof
    
            for     0
    ;strategy strategy と assert 行はコメントなので、FOR 0 / ROF の中でも解析されます!
            rof
    
    ;[ここに実コード..]

    変数でバリエーション

    EQU で定義した定数の問題は、まあ、定数であることです。定義後に値を変えられません。多くの場合はそれで十分ですが、いくつかの技巧がほぼ不可能になります。

    幸い pMARS には実変数が少し用意されています。使い方は少し癖があり、実際に使う人は長らく見ていませんが、存在はします。

    変数名は 1 文字で、実質 26 個(a から z)です。EQU ではなく、= で代入します。癖のある点は、代入するには式が必要なことです。さらに pMARS はコンマ演算子を認識しないので、ダミー式が必要になる場合があります。

    それでも変数は役に立ちます。例えば次の自動生成フィボナッチ列は、変数がなければおそらく不可能でしょう。

            dat     #1, (g=0)+(f=1)
    idx     for     15
            dat     #idx+1, (f=f+g)+((g=f-g) && 0)
            rof

    (g=f-g) を 0 との AND で「隠して」いる点に注目してください。この仕組みは、pMARS が式を並べ替えず、加算の左側を常に先に評価するため成立します。右側を計算するときには f が既に増えている、というわけです。

    PIN と針の穴

    さて、もう 1 つ疑似命令がありました。ほとんど使われませんが存在します。PIN は "P-space Identification Number" の略です。2 つのプログラムが同じ PIN を持つと P-space を共有します。これはプロセス間通信や協調にも使えます。しかし、効果的で高速な通信手段を作る手間に見合う戦略は、あまりなさそうです。とはいえ試したいならどうぞ。成功するかもしれません。

    プログラムに PIN がない場合、P-space は常に私有です。共有していても、特殊な 0 番地(読み取り専用として扱われる特別初期化領域)は常に私有です。

    丘に登る(KotH)

    もし知らないなら説明します。King of the Hill サーバ(しばしば hills と呼ぶ)は、インターネット上で継続運用される Core War トーナメントです。ウォリアーをメール(または Web フォーム)で送ると、サーバが hill 上の(通常 10〜30)プログラムすべてと対戦させます。合計スコアが最低のプログラムは hill から落ち、新規ウォリアーがそれに入れ替わります(少なくとも 1 つ以上の既存プログラムより良いスコアを出した場合)。この基本形には、無限 hill、diversity hill など様々な派生もあります。

    hill は実行時間節約のため、実際の対戦前にロードファイルへ事前コンパイルすることがよくあります。その結果、WARRIORS のような定義済み定数が不正確になり、謎の ;assert 問題を引き起こすことがあります。

    現在(2012 年 4 月時点)利用可能な主な KotH サーバは 2 つあります:

    KotH.org
    現存する中で最古かつ最も有名な KotH サーバ。現在 7 つの hill をホストし、設定の違いがある。うち 2 つはマルチウォリアーの melee、2 つは古い Redcode ’88 標準を使う。
    KOTH@SAL
    こちらも 7 つの hill をホスト。Beginners' hill(初心者 hill)があり、50 回のチャレンジを生き残ると自動的に押し出され、新規プレイヤーが載りやすいようになっている。

    また、Koenigstuhl サーバは、公開済みウォリアー向けに 10 個の「無限」hill をホストしています。これらの hill ではウォリアーは押し出されず、hill は増え続けます。Koenigstuhl はランキングに応じて寄与度を調整する再帰的スコアリングアルゴリズムも使っています。

    上の一覧は網羅ではなく、古くなる可能性があります。稼働中の KotH サーバ一覧のより詳しく最新の情報は、(現時点では)corewar.info のページ にあります。


    更新履歴

    v. 0.50
    パーサ章を書き終えた。(1997 年 3 月 25 日)
    v. 0.51
    for/rof 例のバグを修正
    v. 0.52
    最初の公開版
    v. 0.53
    誤字脱字を修正
    v. 0.54
    ’88 から ’94 への変換ルールを追加
    v. 0.55
    HTML を少し整形
    v. 1.00
    = 演算子の情報を追加。これを機に「バージョン 1」とする。(1997 年 5 月 5 日)
    v. 1.01
    <DD> タグの小さな互換性問題を修正。
    v. 1.02
    誤字と不自然な文を修正。ナビゲーションバーをサイトの他ページと共通スタイルに変更。
    v. 1.03
    画像と align 属性を削除し、doctype を Strict に変更。
    v. 1.10
    うわっ! ずっと SLT の説明を逆に書いていた!修正。(1998 年 3 月 8 日)
    v. 1.20
    Climbing the hill を現状に合わせて大幅に書き直し、他にも軽微な変更。文書を vyznev.net の新アドレスへ移動。Creative Commons ライセンスへ変更。(2003 年 10 月 7 日)
    v. 1.21
    CSS 対応ブラウザ向けに色を追加。軽微な変更と誤字修正。タイトルの表記を統一。vyznev.net での最初の公開版。(2004 年 4 月 11 日)
    v. 1.22
    ライセンスを CC-By-NC 2.0 から CC-By 3.0 に更新し、商用利用制限を撤廃。ページ移動通知ボックスを削除。KotH サーバ一覧を更新し、停止した hill を削除。内容はそれ以外変更なし。(2012 年 4 月 16 日)
    v. 1.23
    pMARS における P-space の 0 番地の扱い説明の長年の誤りを修正。(読み取り専用ではなく、各ラウンド前に自動上書きされる。) Aritz Erkiaga が 発見 し報告してくれたことに感謝。(2020 年 8 月 11 日)

    著作権

    Creative Commons License Copyright 1997-2020 Ilmari Karonen.

    本作品は Creative Commons Attribution 3.0 Unported License(CC BY 3.0)で提供されています。

    この日本語版は上記原文を翻訳した派生物です。原著者・出典・ライセンス表記を保持し、変更(翻訳)を明示しています。