これは、20世紀に遡るプログラミングKOTH であるCore Warの適応です。具体的には、主に元の提案に基づいて非常に単純化された命令セットを使用しています。
バックグラウンド
コア戦争には、コンピューターの制御のために戦っている2つのプログラムがあります。各プログラムの目標は、相手のプログラムを見つけて終了することで勝つことです。
戦闘はコンピューターのメインメモリ内で行われます。このメモリはコアと呼ばれ、8192個のアドレスが含まれています。戦闘が始まると、各競技者(戦士と呼ばれる)のコードがランダムなメモリチャンクに配置されます。プログラムの実行は戦士間で交互に行われ、それぞれ1つの命令を実行します。各命令はコアの一部を変更できるため、プログラムを自己変更する可能性があります。
目標は、対立するプログラムを終了することです。プログラムは、無効な命令(任意のDAT
命令)を実行しようとすると終了します。
命令セット
各プログラムは一連の低レベルの命令で構成され、各命令はAおよびBフィールドと呼ばれる2つのフィールドを取ります。
この命令セットは、元の仕様から大きく引き出されます。主な変更点は、1)コマンドの追加/減算の明確化、および2)#
どこでも使用できるようにするためのアドレス指定モードの変更です。Core Warsのほとんどのフルバージョンには、20を超えるオペコード、8つのアドレス指定モード、および「命令修飾子」のセットがあります。
オペコード
各命令には、7つの異なるオペコードのいずれかが必要です。
DAT A B
-(データ)-これは単に数字A
とを保持しますB
。重要なのは、DAT命令を実行しようとするとプロセスが停止することです。MOV A B
-(移動)-これにより、メモリ位置の内容がメモリ位置A
に移動しますB
。以下は、前後のデモンストレーションです。MOV 2 1 ADD @4 #5 JMP #1 -1
MOV 2 1 JMP #1 -1 JMP #1 -1
ADD A B
-(追加)-これは、メモリロケーションの内容をメモリロケーションA
に追加しますB
。両方の最初の2つのフィールドが追加され、2番目のフィールドが追加されます。ADD 2 1 MOV @4 #5 JMP #1 -1
ADD 2 1 MOV @5 #4 JMP #1 -1
SUB A B
-(減算)-これは、メモリ位置A
からメモリ位置の内容を減算(および結果をメモリ位置)しますB
。SUB 2 1 MOV @4 #5 JMP #1 -1
SUB 2 1 MOV @3 #6 JMP #1 -1
JMP A B
-(ジャンプ)-A
次のサイクルで実行される場所にジャンプします。B
数字である必要がありますが、何もしません(ただし、情報を保存するために使用できます)。JMP 2 1337 ADD 1 2 ADD 2 3
ジャンプは、
ADD 2 3
次のサイクルで実行されることを意味します。JMZ A B
-(ゼロの場合ジャンプ)-行の両方のフィールドB
が0の場合、プログラムはlocationにジャンプしますA
。JMZ 2 1 SUB 0 @0 DAT 23 45
命令1の2つのフィールドは0であるため、DATコマンドは次のターンに実行され、差し迫った死につながります。
CMP A B
-(等しくない場合は比較およびスキップ)-命令のフィールドA
とB
が等しくない場合、次の命令をスキップします。CMP #1 2 ADD 2 #3 SUB @2 3
命令1と2の2つのフィールドの値は等しいため、ADDコマンドはスキップされず、次のターンに実行されます。
2つの命令が加算/減算されると、2つのフィールド(AとB)がペアで加算/減算されます。アドレス指定モードとオペコードは変更されません。
アドレス指定モード
アドレッシングモードには3種類あります。命令の2つのフィールドにはそれぞれ、これら3つのアドレス指定モードのいずれかがあります。
即時
#X
-X
計算で直接使用される行です。たとえば#0
、プログラムの最初の行です。負の行は、プログラムの開始前のコアの行を指します。... //just a space-filler ... ADD #3 #4 DAT 0 1 DAT 2 4
これらはそれぞれ3行目と4行目にあるため、2行目のDAT行の最初を2行目に追加します。ただし、DATは次のサイクルでボットを殺すため、このコードは使用したくないでしょう。
相対
X
-数値X
は、現在のアドレスに対するターゲットメモリアドレスの位置を表します。この場所の番号は計算に使用されます。行#35
が実行されており、が含まれている-5
場合、行#30
が使用されます。... //just a space-filler ... ADD 2 1 DAT 0 1 DAT 2 4
これにより、2行目のDAT行が1行目に追加されます。
間接
@X
-数値X
は相対アドレスを表します。その場所のコンテンツは一時的に番号Xに追加され、新しい相対アドレスが形成され、そこから番号が取得されます。行#35
が実行されており、その2番目のフィールドが@4
であり、行の2番目のフィールドに#39
数値が含まれている場合-7
、行#32
が使用されます。... //just a space-filler ... ADD @1 @1 DAT 0 1 DAT 2 4
これにより、最初のDATが2番目のDATに追加されますが、より複雑な方法で追加されます。最初のフィールドは@ 1で、その相対アドレスからデータを取得します。これは、最初のDATの最初のフィールドである0です。これは、その場所からの2番目の相対アドレスと解釈されるため、1 + 0 = 1元の命令からのオフセット。2番目のフィールドでは、@ 1はその相対アドレス(最初のDATの2番目のフィールドの1)から値を取得し、同じ方法でそれを自分自身に追加します。合計オフセットは1 + 1 = 2です。したがって、この命令はと同様に実行され
ADD 1 2
ます。
各プログラムには、最大64個の命令を含めることができます。
ラウンドが開始されると、2つのプログラムは8192の場所を持つメモリバンクにランダムに配置されます。各プログラムの命令ポインターは、プログラムの先頭から始まり、実行サイクルごとに増分されます。命令ポインターが命令を実行しようとすると、プログラムは終了しDAT
ます。
コアのパラメーター
コアサイズは8192で、タイムアウトは8192 * 8 = 65536ティックです。コアは周期的であるため、アドレス8195への書き込みはアドレス3への書き込みと同じDAT #0 #0
です。未使用のアドレスはすべてに初期化されます。
各競技者は64行を超えてはいけません。整数は、32ビットの符号付き整数として保存されます。
解析
競合他社のプログラミングを容易にするために、パーサーに行ラベル機能を追加します。オペコードの前の行にある単語はすべて行ラベルとして解釈されます。たとえばtree mov 4 6
、行ラベルがありtree
ます。プログラムのどこかに、tree
#tree
またはを含むフィールドがある場合@tree
、数値が置換されます。また、大文字は無視されます。
行ラベルの置換方法の例を次に示します。
labelA add labelB @labelC
labelB add #labelC labelC
labelC sub labelA @labelB
ここでは、ラベルA、B、およびCが行0、1、および2にあります。インスタンス#label
は、ラベルの行番号に置き換えられます。のインスタンス、label
または@label
ラベルの相対位置で置換されます。アドレス指定モードは保持されます。
ADD 1 @2
ADD #2 1
SUB -2 @-1
得点
競技者のペアごとに、可能なすべての戦いが行われます。戦闘の結果は2つのプログラムの相対的なオフセットに依存するため、可能なすべてのオフセット(約8000)が試行されます。さらに、各プログラムは、各オフセットで最初に移動する機会があります。これらのオフセットの大部分を獲得したプログラムがペアの勝者です。
戦士が勝つペアごとに、2ポイントが与えられます。ネクタイごとに、戦士に1ポイントが与えられます。
複数の戦士を提出することができます。タグチーミングなし、協力なし、キングメイキングなしなど、複数のサブミッションの一般的なルールが適用されます。コアウォーにはこれの余地がまったくないので、大したことではないはずです。
コントローラー
コントローラーのコードと2つの簡単なボットの例は、こちらにあります。(公式設定を使用して実行する場合)この競争は完全に決定的であるため、作成するリーダーボードは公式のリーダーボードとまったく同じになります。
ボットの例
以下は、言語のいくつかの機能を示すボットの例です。
main mov bomb #-1
add @main main
jmp #main 0
bomb dat 0 -1
このボットは、コア内の他のすべてのメモリを「爆弾」に置き換えてゆっくり消去することで動作します。爆弾はDAT
指示であるため、爆弾に到達したプログラムはすべて破棄されます。
2つの行ラベル、「main」と「bomb」があり、これらは番号を置き換えるのに役立ちます。前処理後、プログラムは次のようになります。
MOV 3 #-1
ADD @-1 -1
JMP #0 0
DAT 0 -1
最初の行は、爆弾をプログラムのすぐ上の行にコピーします。次の行は、爆弾の値(0 -1
)を移動コマンドに追加し、@
アドレス指定モードの使用方法も示しています。この追加により、移動コマンドは新しいターゲットを指すようになります。次のコマンドは無条件でプログラムの先頭にジャンプして戻ります。
現在のリーダーボード
24-Turbo
22-DwarvenEngineer
20-HanShotFirst
18-Dwarf
14-ScanBomber
10-Paranoid
10-FirstTimer
10-Janitor
10-Evolved
6-EasterBunny
6-CopyPasta
4-Imp
2-Slug
ペアワイズ結果:
Dwarf > Imp
CopyPasta > Imp
Evolved > Imp
FirstTimer > Imp
Imp > Janitor
Imp > ScanBomber
Slug > Imp
DwarvenEngineer > Imp
HanShotFirst > Imp
Turbo > Imp
EasterBunny > Imp
Paranoid > Imp
Dwarf > CopyPasta
Dwarf > Evolved
Dwarf > FirstTimer
Dwarf > Janitor
Dwarf > ScanBomber
Dwarf > Slug
DwarvenEngineer > Dwarf
HanShotFirst > Dwarf
Turbo > Dwarf
Dwarf > EasterBunny
Dwarf > Paranoid
Evolved > CopyPasta
FirstTimer > CopyPasta
Janitor > CopyPasta
ScanBomber > CopyPasta
CopyPasta > Slug
DwarvenEngineer > CopyPasta
HanShotFirst > CopyPasta
Turbo > CopyPasta
CopyPasta > EasterBunny
Paranoid > CopyPasta
Evolved > FirstTimer
Evolved > Janitor
ScanBomber > Evolved
Evolved > Slug
DwarvenEngineer > Evolved
HanShotFirst > Evolved
Turbo > Evolved
EasterBunny > Evolved
Paranoid > Evolved
Janitor > FirstTimer
ScanBomber > FirstTimer
FirstTimer > Slug
DwarvenEngineer > FirstTimer
HanShotFirst > FirstTimer
Turbo > FirstTimer
FirstTimer > EasterBunny
FirstTimer > Paranoid
ScanBomber > Janitor
Janitor > Slug
DwarvenEngineer > Janitor
HanShotFirst > Janitor
Turbo > Janitor
Janitor > EasterBunny
Janitor > Paranoid
ScanBomber > Slug
DwarvenEngineer > ScanBomber
HanShotFirst > ScanBomber
Turbo > ScanBomber
ScanBomber > EasterBunny
ScanBomber > Paranoid
DwarvenEngineer > Slug
HanShotFirst > Slug
Turbo > Slug
EasterBunny > Slug
Paranoid > Slug
DwarvenEngineer > HanShotFirst
Turbo > DwarvenEngineer
DwarvenEngineer > EasterBunny
DwarvenEngineer > Paranoid
Turbo > HanShotFirst
HanShotFirst > EasterBunny
HanShotFirst > Paranoid
Turbo > EasterBunny
Turbo > Paranoid
Paranoid > EasterBunny
最新のアップデート(TurboおよびParanoidの新しいバージョン)は、古いラップトップで実行するのに約5分かかりました。コントローラーの改良についてIlmari Karonenに感謝します。コントローラのローカルコピーがある場合は、ファイルを更新する必要があります。