ナノコア戦争


21

これは、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-(等しくない場合は比較およびスキップ)-命令のフィールドABが等しくない場合、次の命令をスキップします。

    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に感謝します。コントローラのローカルコピーがある場合は、ファイルを更新する必要があります。


2つの競合するボットが同じラベルを使用しようとするとどうなりますか?
mbomb007

1
@ mbomb007ラベルは前処理であり、ボットのソースファイルが解析されているときに計算されます。ラベルは競合他社のラベルと相互作用しません。
PhiNotPi

1
@ mbomb007プログラムが重複しないように。また、このバージョンに機能を追加する予定はありません。MicroCore Warの機能は保存します。
PhiNotPi

1
@ mbomb007間接アドレス指定は、参照を作成している同じフィールド(1番目または2番目)を参照します。命令修飾子はありません。私はこの挑戦を'94規格に基づいているわけではありません。
PhiNotPi

2
@Thrax私はノーと言うつもりです、あなたは1つの提出に限定されていません。いずれにしてもコア戦争での協力の余地はあまりありませんが、典型的な複数提出ルールが適用されます(タグチーミングなどはありません)。
-PhiNotPi

回答:


9

ドワーフのエンジニア

新しく改善されたドワーフ。これまでに提出された他のすべてに対して勝ちます。派手なコアステップ-最適化されたステップサイズは、おそらくここでは過剰です。

        MOV bomb    @aim
aim     MOV bomb    @-6326
        SUB step    aim
step    JMZ #0      6328
        MOV 0       1
bomb    DAT 0       3164

注目すべき機能には、4サイクルで2発の爆弾を投げる高速爆撃ループがあり、古いコア戦争用語では平均爆撃速度が0.5cでありJMZ、爆撃実行が完了し、プランBに切り替わる時期を検出するための使用が含まれます(ここでは、インプ)。


私は90年代にCore Warをプレイしていました(97年に書き直した基本的なガイドブックを見たことがある人もいるかもしれません)ので、RedCode '88 / '94の世界の古い戦略がどれであるかを見るのは面白いと思いましたこのバリアントで便利です。

私の最初の考えは:

  • がないSPLため、レプリケーターもありません(インプリング/スパイラルもありません)。これは爆撃機を強くするはずです。(また、レプリケーターとインプスパイラルに対処するために設計されたすべての空想爆撃戦略は、ここではまったく不要で役に立たない。どんな爆弾でも爆弾を投下するだけだDAT。)

  • この場合も、CMPスキャンは爆撃よりも潜在的に高速であるため、高速のスキャナーチャンスを得る可能性があります。

  • イン/デクリメントがないため、コアのクリアが非常に遅くなります。実際、このバリアントのコアは、±1の(最適ではない)ステップサイズの爆撃機にすぎません。繰り返しますが、これもスキャナーを傷つけます。ただし、ワンショットスキャナー→爆撃機戦略機能する可能性があります。

  • Quickscanners / quickbombers(展開されたスキャン/爆撃ループを使用した初期のゲーム戦略、Core Warの専門用語にそれほど馴染みのない人にとって)はまだ潜在的に有用ですが、長いプログラムに対してのみです(それ自体は一種のフィードバックがあります)ここで効果)。それが本当に面倒な価値があるかどうかを言うのは難しい。

  • 得点システムは興味深い。タイは勝利の半分のポイントを獲得し(従来のコアウォーのように1/3ではなく)、より魅力的になります。繰り返しになりますが、これらの規則の下で多くの同点を獲得する可能性が高い唯一のプログラムについては重要ではありません。(また、デ/増分の不在はそうでも簡単なインプは実際、ハードIMPゲートを作る彼らは彼らの対戦相手が生き達した場合にネクタイを得点のチャンスがあります。)

  • また、最後のランキングはあなただけはビート、そしてませんどのようにどのプログラムに依存しているため多くのあなたがで彼らを倒す、それはジェネラリストのエントリを好む傾向があります。対戦相手の半分を完全に破壊し、残りのプレイヤーにかろうじて負けるよりも、すべての対戦相手をかろうじて倒す方が良いです。

  • コードは公開されているため、一般的にどれほど優れていても、以前に提出されたもの(場合によってはそれらのいくつかでも)を打ち負かすことができるプログラムを常に見つけることができます。ただし、そのようなトリック(ステップサイズを調整して相手にヒットする直前にヒットさせるなど)は、簡単に思えます。そして、もちろん、ターゲットプレーヤーは常に、異なる定数を使用して新しいバージョンを送信することもできます。

とにかく、このすべての結論は私が速い爆撃機かのどちらか書いてみる必要があることを決めたということです非常に高速なスキャナを、そして多分その上にquickscanner /爆撃機をタック。これらのオプションのうち、高速爆撃機が最も簡単で、動作する可能性が最も高いと思われました。

その時点で、PhiNotPiのインタープリターコードを微調整して最適化するのに時間がかかりすぎたのは、定数を最適化するために、多くのブルートフォーストライアルを実行している可能性が高いからです。偶然にも、私はそれをする必要はありませんでした。上記のコードは、実際に動作した最初のバージョンです(ばかげたバグのために自殺したばかりの試みが2回失敗した後)。


私の爆撃機を速くするトリックは、間接的なアドレスを使用してそれぞれに2つの爆弾を投げることADDです。仕組みは次のとおりです。

  1. 最初のサイクルで、を実行しMOV bomb @aimます。これにより、bomb命令がコアのBフィールドのaimポイントにコピーされます(最初は、正確に6326命令前aim、または6328命令前step。これらの数値が重要である理由は後でわかります)。

  2. 次のステップでは、aim命令自体を実行します!最初のパスでは、次のようになりますMOV bomb @-6326。したがって、bomb6326行前の命令のBフィールドが指す場所にコピーします。

    それでは、6326行前には何がありaimますか?なぜ、それはbomb1サイクル早くそこに置いたばかりのコピーです!そして、たまたまBフィールドのbomb値がゼロ以外になるように配置したため、新しい爆弾は古い爆弾の上にコピーされず、少し離れています(実際、ここでの距離は3164です。これは名目上のステップサイズ6328の半分ですが、他のオフセットでも機能する可能性があります。

  3. 次のサイクルで、を使用して目標を調整しますSUB step aim。これにより、step命令の値(たまたま単純に実行できますが、次に実行するジャンプでもあります)が減算さDATaimます。

    (ここで注意すべき詳細は、私たちということである種類のは、のA-値が欲しいstepゼロになるように、我々はまだ次の反復で同じ爆弾を投げるだろうだから、にもかかわらず、厳密には必要ではないこと;だけ爆弾が投げ最初の 3164に等しいそのB-フィールドを持つ命令の必要性、残りの部分は何もすることができます。)

  4. 次に、JMZ命令6328が命令から離れるというチェックはまだゼロであり、そうであれば、コードの先頭にジャンプして戻ります。現在、6328は爆撃機のステップサイズであり、8で割り切れます(16ではありません)。したがって、6328ステップごとに爆弾を投げ続けた場合、最終的には開始点に戻り、コアの8命令ごとに爆弾を投じました(そして、追加の爆弾は3163 = 6328/2≡4(mod 8)で相殺されました) 、4命令ごとにヒットします)。

    しかし、我々は6328回の指示で、私たちの爆撃の実行を開始する前にJMZ、私たちは場所に6328個の手順を爆撃しようとしているので、すべての反復で-6328によって後方ステップの後にJMZ私たちが当たると考え前に一つだけの繰り返しJMZ自体を。そのJMZため、その後6328命令で爆弾を検出すると、それは私たちが自分自身を打つことなくできるだけ多くのコアをカバーしたことを示しており、自殺する前にバックアップ戦略に切り替える必要があります。

  5. バックアップ戦略に関してはMOV 0 1、今のところこれ以上良いものは考えられないので、それは単なる古臭いものです。私が見るように、コアの4箇所ごとに爆撃してもまだ勝てない場合は、おそらく非常に小さいか非常に防御的なものと戦っています。そのような小規模なプログラムや防御的なプログラムは一般に他の何かを殺すのがあまり得意ではないので、大丈夫です。したがって、たまたまわずかな戦いに勝ったとしても、おそらく先に出てくるでしょう。


追伸 他の誰かがそれを望んでいる場合のために、PhiNotPiのトーナメントコードのフォークを少し改良しました。約2倍の速度で、古い戦闘結果を保存して再実行する必要がなくなり、戦闘結果の計算におけるマイナーバグと思われるものを修正します。変更は、PhiNotPiによってメインラインバージョンマージされました。ありがとう!


1
ご存知のように、スコアリングは、プログラムの開始場所のあらゆる組み合わせをテストし、最も多くのポイントを獲得したプログラムをテストします。これにより、プログラムが自分自身を殺すことがなく、少なくとも1つのアドレスを一度爆撃する限り、インプを打ち、1回勝利し、残りはタイになるため、タイは不可能または完全に不利になります。
mbomb007

9

グラフ表示

これは、デバッグツールとして使用できます。コアが表示され、プレーヤーの場所が表示されます。それを使用するには、コードから呼び出す必要があります。Game.javaGraphViewを自動的に表示する変更も提供しました。

PhiNotPiとIlmari Karonenは最近、コントローラーを変更しました。Ilmari Karonenは、この場所で更新されたGameViewを提供するのに十分親切です

import javax.swing.*;
import java.awt.*;

public class GameView extends JComponent{

    final static Color[] commandColors = new Color[]{
            Color.black, //DAT
            Color.blue,  //MOV
            Color.blue,  //ADD
            Color.blue,  //SUB
            Color.blue,  //JMP
            Color.blue,  //JMZ
            Color.blue,  //CMP
    };

    final static Color[] specialColors = new Color[]{
            new Color(0,0,0),
            new Color(190, 255, 152),
            Color.yellow,
            new Color(0, 93, 14),
            new Color(96, 92, 4),
            new Color(0, 93, 14),
            new Color(96, 92, 4),
            new Color(0, 93, 14),
            new Color(96, 92, 4)
    };

    final static Color playerOneColor = Color.green;
    final static Color playerTwoColor = Color.white;

    final Game game;

    int playerOneLocation;
    int playerTwoLocation;

    final static int width = 128;
    final static int height = 64;

    public GameView(Game game) {
        this.game = game;
    }

    @Override
    public void paint(Graphics g) {
        int pixelWidth = getSize().width;
        int pixelHeight = getSize().height;
        if (width > pixelWidth){
            pixelWidth = width;
            setSize(width, pixelHeight);
        }
        if (height > pixelHeight){
            pixelHeight = height;
            setSize(pixelWidth, height);
        }
        int squareWidth = Math.min(pixelWidth / width, pixelHeight / height);
        for (int x = 0; x < squareWidth * width; x += squareWidth){
            for (int y = 0; y < squareWidth * height; y += squareWidth){
                int index = (y / squareWidth) * width + (x / squareWidth);
                Color color = commandColors[game.core[index][0]];
                if (game.coreData[index] != 0){
                    color = specialColors[game.coreData[index]];
                }
                if (index == playerOneLocation){
                    color = playerOneColor;
                }
                if (index == playerTwoLocation){
                    color = playerTwoColor;
                }
                g.setColor(color);
                g.fillRect(x, y, squareWidth, squareWidth);
            }
        }
    }

    public void setLocations(int p1loc, int p2loc){
        this.playerOneLocation = p1loc;
        this.playerTwoLocation = p2loc;
    }
}

変更されたGame.java:

import javax.swing.*;
import java.util.Random;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * This runs a game of Core Wars between two players.  It can be called mutiple times.
 * 
 * @author PhiNotPi 
 * @version 3/10/15
 */
public class Game
{
    final Player p1;
    final Player p2;
    final int coreSize;
    final int coreSizeM1;
    final int maxTime;
    final int debug;
    public int[][] core;
    public int[] coreData; //Used in debugging.
    int offset1;
    int offset2;
    Random rand;
    ArrayList<int[]> p1code;
    ArrayList<int[]> p2code;
    int p1size;
    int p2size;
    GameView gameView;
    int time = 1000000; //Time in nanoseconds between frames
    public Game(Player A, Player B, int coreSize, int maxTime, int debug)
    {
        p1 = A;
        p2 = B;

        coreSize--;
        coreSize |= coreSize >> 1;
        coreSize |= coreSize >> 2;
        coreSize |= coreSize >> 4;
        coreSize |= coreSize >> 8;
        coreSize |= coreSize >> 16;
        coreSize++;

        this.coreSize = coreSize;
        this.coreSizeM1 = coreSize - 1;
        this.maxTime = maxTime / 2;
        this.debug = debug;
        core = new int[coreSize][5];
        rand = new Random();
        p1code =  p1.getCode();
        p1size = p1code.size();
        p2code =  p2.getCode();
        p2size = p2code.size();
        if (debug == 1){
            gameView = new GameView(this);
            JFrame frame = new JFrame("Game");
            frame.add(gameView);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            frame.setSize(128, 64);
            coreData = new int[coreSize];
        }
    }

    public int runAll()
    {
        int sum = 0;
        for(int i = 0; i < coreSize - p1size - p2size; i++)
        {
            sum += run(i) - 1;
        }
        if(sum > 0)
        {
            return 1;
        }
        if(sum < 0)
        {
            return -1;
        }
        return 0;
    }

    public int run()
    {
        return run(rand.nextInt(coreSize - p1size - p2size + 1));
    }

    public int run(int deltaOffset)
    {
        core = new int[coreSize][5];
        //offset1 = rand.nextInt(coreSize);
        offset1 = 0;
        for(int i = 0; i != p1size; i++)
        {
            //System.arraycopy(p1.getCode().get(i), 0, core[(offset1 + i) % coreSize], 0, 5 );
            int[] line = p1code.get(i);
            int loc = (offset1 + i) & coreSizeM1;
            core[loc][0] = line[0];
            core[loc][1] = line[1];
            core[loc][2] = line[2];
            core[loc][3] = line[3];
            core[loc][4] = line[4];
            if (debug != 0){
                coreData[loc] = 1;
            }
        }
        offset2 = offset1 + p1size + deltaOffset;
        for(int i = 0; i != p2size; i++)
        {
            //System.arraycopy(p2.getCode().get(i), 0, core[(offset2 + i) % coreSize], 0, 5 );
            int[] line = p2code.get(i);
            int loc = (offset2 + i) & coreSizeM1;
            core[loc][0] = line[0];
            core[loc][1] = line[1];
            core[loc][2] = line[2];
            core[loc][3] = line[3];
            core[loc][4] = line[4];
            if (debug != 0){
                coreData[loc] = 2;
            }
        }

        int p1loc = offset1 & coreSizeM1;
        int p2loc = offset2 & coreSizeM1;
        for(int time = 0; time != maxTime; time++)
        {
            if(debug != 0)
            {
                //printCore(p1loc,p2loc);
                //System.out.println("p1loc " + p1loc);
                //System.out.println("offset " + offset1);
                gameView.setLocations(p1loc, p2loc);
                gameView.repaint();
                try {
                    Thread.sleep(time / 1000000, time % 1000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if(core[p1loc][0] == 0)
            {
                return 0;
            }
            p1loc = execute(p1loc, offset1, 1);

            if(debug != 0)
            {
                //printCore(p1loc,p2loc);
                //System.out.println("p2loc " + p2loc);
                //System.out.println("offset " + offset2);
                gameView.setLocations(p1loc, p2loc);
                gameView.repaint();
                /*try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
            }
            if(core[p2loc][0] == 0)
            {
                return 2;
            }
            p2loc = execute(p2loc, offset2, 2);

        }
        return 1;
    }
    public int execute(int ploc, int offset, int player)
    {
        int line1 = offset + core[ploc][3];
        if(core[ploc][1] != 0)
        {
            line1 += ploc - offset;
        }
        if(core[ploc][1] == 2)
        {
            line1 += core[line1 & coreSizeM1][3];
        }
        int line2 = offset + core[ploc][4];
        if(core[ploc][2] != 0)
        {
            line2 += ploc - offset;
        }
        if(core[ploc][2] == 2)
        {
            line2 += core[line2 & coreSizeM1][4];
        }
        line1 = line1 & coreSizeM1;
        line2 = line2 & coreSizeM1;
        int opcode = core[ploc][0];
        ploc = (ploc + 1) & coreSizeM1;
        //String opDescription = "";
        if(opcode == 1)
        {
            core[line2][0] = core[line1][0];
            core[line2][1] = core[line1][1];
            core[line2][2] = core[line1][2];
            core[line2][3] = core[line1][3];
            core[line2][4] = core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 2;
            }
            return ploc;
            //opDescription = "Moved from " + line1 + " to " + line2;
        }
        if(opcode == 2)
        {
            core[line2][3] += core[line1][3];
            core[line2][4] += core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 4;
            }
            return ploc;
            //opDescription = "Added " + line1 + " to " + line2;
        }
        if(opcode == 3)
        {
            core[line2][3] -= core[line1][3];
            core[line2][4] -= core[line1][4];
            if (debug != 0) {
                coreData[line2] = player + 6;
            }
            return ploc;
                //opDescription = "Subtracted " + line1 + " to " + line2;
        }
        if(opcode == 4)
        {
            ploc = line1;
            return ploc;
                //opDescription = "Jumped to " + line1;
        }
        if(opcode == 5)
        {
                if(core[line2][3] == 0 && core[line2][4] == 0)
                {
                    ploc = line1;
                    //opDescription = "Jumped to " + line1;
                }
                else
                {
                    //opDescription = "Did not jump to " + line1;
                }
                return ploc;
        }
        if(opcode == 6)
        {
            if(core[line1][3] == core[line2][3] && core[line1][4] == core[line2][4])
            {
                //opDescription = "Did not skip because " + line1 + " and " + line2 + " were equal.";
            }
            else
            {
                ploc = (ploc + 1) & coreSizeM1;
                //opDescription = "Skipped because " + line1 + " and " + line2 + " were not equal.";
            }
            return ploc;
        }
        if(debug != 0)
        {
            //System.out.println(opDescription);
        }
        return ploc;
    }
    /*public void printCore(int p1loc, int p2loc)
    {
        int dupCount = 0;
        int[] dupLine = new int[]{0,0,0,0,0};
        for(int i = 0; i < core.length; i++)
        {
            int[] line = core[i];
            if(Arrays.equals(line, dupLine) && i != p1loc && i != p2loc)
            {
                if(dupCount == 0)
                {
                    System.out.println(Player.toString(line));
                }
                dupCount++;
            }
            else
            {
                if(dupCount == 2)
                {
                    System.out.println(Player.toString(dupLine));
                }
                else if(dupCount > 2)
                {
                    System.out.println("    " + (dupCount - 1) + " lines skipped.");
                }
                System.out.println(Player.toString(line));
                if(i == p1loc)
                {
                    System.out.print(" <- 1");
                }
                if(i == p2loc)
                {
                    System.out.print(" <- 2");
                }
                dupLine = line;
                dupCount = 1;
            }
        }
        if(dupCount == 2)
        {
            System.out.println(Player.toString(dupLine));
        }
        else if(dupCount > 2)
        {
            System.out.println("    " + (dupCount - 1) + " lines skipped.");
        }
    }*/
}

Playerにも変更を加えたようです。私が得る./Game.java:275: error: method toString in class Object cannot be applied to given types; System.out.println(Player.toString(line)); ^ required: no arguments found: int[]
-AShelly

@AShellyそれについてすみません。printCore()メソッドをコメントアウトする必要があります。
TheNumberOne

9

ターボ

main   add three target
test   jmz -1 @target
bomb   mov three @target
       sub j1 target 
       mov jump @target
       sub j1 target 
       mov copy @target
       sub j1 target
two    mov decr @target
j1     jmp @target 1
target dat -8 -8   
decr   sub #two 3
copy   mov 2 @2
jump   jmp -2 0
three dat -9 -9

私の2回目のCoreWarの試み。ドワーフを倒すように設計されています。データを3回スキャンし、2回ごとに爆弾を置きます。ドワーフの爆弾がミスすることを期待して、各ステージは3つの命令のみで実行されます。

新しいTurbo ++:拡張されました。データを見つけるまで逆方向にスキャンし、そこに移動してから逆方向に爆撃します。希望は、その動きが敵を破壊するか、すでに爆撃された場所への移動であり、したがって安全であるということです。

...また、スキャンをよりまばらにするための編集により、誰もが勝ちます!


単なるドワーフよりも多くを打ち負かすようです。おめでとうございます!インプを倒すことさえできれば、3位に到達できると思います。
イルマリカロネン

私はこれを更新しましたが、実際には前のものからかなり大きな進化です。代わりに新しいエントリを作成する必要がありますか?
AShelly

PhiNotPiを代弁するつもりはありませんが、あなた次第だと思います。インプレース更新を行うことは、基本的に古いエントリを取り消すことを意味します。とにかく、爆弾をかわして3位になったことをおめでとうございます!これまでのところ、DwarvenEngineerをペアで倒したのはあなただけだと思います。
イルマリカロネン

よくやった ;)。あなたは今勝つためのものです!
ヒット

8

ドワーフ

石を投げる小人を表す一般的でシンプルなプログラム。DAT4アドレスごとに命令を配置します。

add 2 3
mov 2 @2
jmp -2 #4
dat #0 #4

編集:アドレス指定を修正。どうやらアドレッシングモードは、OPがリンクしている仕様とは異なります。


最初の行は「#3 3を追加」だと思います。
ヒット

@Hit Nope。4番目のアドレスごとにヒットさせたい。を使用することもできますがadd 3 3、追加する代わりに各ループが2倍になり、それは役に立ちません。#4は即時であるため、現在のアドレスの後の4アドレスの2番目の値に数値を追加し3ます。
mbomb007

#チャレンジでアドレス指定モードを誤って解釈していると思います。仕様に記載されているように、#アドレス指定モードを変更しました。
PhiNotPi

「add 2 3 mov 2 @ 2 jmp -2 4 dat 0 4」
ヒット

正しい振る舞いで、それは進化を打ち負かします
ヒット

7

進化した

正直なところ、どのように機能するかわかりません。何かをする前にソースコードを構築しているようです。誰かが私にそれがどのように機能するかの説明を与えてくれたらそれが大好きです。

それを研究した後、私はそれが単にインプガードを備えた修正された小人であることを発見しました。DAT指示で敵を爆撃する代わりに、敵のコードをシャッフルします。また、4つのレジスタごとではなく、2つのレジスタごとに爆撃します。十分な時間があれば、それは間違いなくそれ自体を破壊するでしょう。

MOV -2 #-1
MOV #4 -9
SUB -5 #6
MOV #1 1
MOV #-6 #4
SUB @8 @7
JMP -3 @4
DAT #-4 8
JMP -1 9
JMP 5 #-10
CMP @-1 #0
SUB 3 #-10
JMP @10 #-9
JMZ #1 10
MOV #3 2
ADD @9 @-3
CMP #-3 @7
DAT @0 @-2
JMP @-7 #6
DAT @-8 -6
MOV @0 #9
MOV #2 1
DAT @6882 #-10
JMP @3 4
CMP @8 2
ADD -7 @11
ADD @1 #-9
JMZ @-5 7
CMP 11 5526
MOV @8 6
SUB -6 @0
JMP 1 11
ADD @-3 #-8
JMZ @-14 @-5
ADD 0 @-8
SUB #3 @9
JMP #-1 5
JMP #9 @1
CMP -9 @0
SUB #4 #-2
JMP #-8 5
DAT -1 @-10
MOV 6 #2
CMP @-11 #-14
ADD @4 @-3
MOV @5 #-6
SUB -3 -2
DAT @-10 #-1
MOV #-13 #-6
MOV #1 5
ADD 5 #-5
MOV -8 @-1
DAT 0 10
DAT #5 #7
JMZ 6 -5
JMZ -12 -11
JMP 5 @-7
MOV #7 -3
SUB #-7 @-3
JMP -4 @-11
CMP @-5 #-2
JMZ @-1 #0
ADD #3 #2
MOV #5 @-6

1
それからどこで入手しましたか?
PyRulez

4
@PyRulez遺伝的アルゴリズムによって生成されたコンピューターです。
TheNumberOne

1
実行は実際には6行目よりも進んでいないように見えます。プログラムにジャンプして戻るからです。成功する理由は、競合他社よりも多くの動き/ループがあるからだと思います。
PhiNotPi

6

FirstTimer

動作する場合は、コアの開始時に位置を取得し、防御を作成する必要があります

main MOV 5 #0
     ADD #data #main
     CMP #main #max
     JMP #0 0
     JMP #main 0
     MOV #data #100
     ADD #data -1
     JMP -2 0
data DAT 1 1
max  DAT 8 3

それは私があなたが思っていたようにはまったく機能しません:コアの開始ではなく、プログラム#0の開始(つまり、と同じ)を指します#mainとにかく実際には意味のある概念ではありません-コアは循環、コードはそれがどこで開始または終了するかを知ることができません)。最初の命令(main)がで上書きされると、MOV #data #100コードは事実上0.25c(= 4サイクルに1命令)のフォワードコアクリアになります。
イルマリカロネン

@IlmariKaronenああ、説明してくれてありがとう。#0コアの開始を間違えました。最初の5つの指示はまったく役に立ちません。
スラックス

6

CopyPasta

CoreWarに参加したことのないこの単純なプログラムは、自分自身をコピーして貼り付けてからコピーを実行しようとしています。正しく動作しない可能性があります。その場合は教えてください。

それはあまりにも平和主義者であり、実際に勝つことはできません。

MOV 6 0
MOV @-1 @-1
CMP @-2 3
JMP 4242 0
SUB -3 -4
JMP -4 0
DAT 0 4244

この現在の編集は、おそらく次のリーダーボードの更新には含まれないでしょう(私は今トーナメントを運営しています)。ただし、古いバージョンは(小さなコアサイズの)予備的な結果に勝っていました。
PhiNotPi

わかりました:)古いバージョンはloop1から出ませんが、それは実際に望んでいる動作ではありません。私はそれを修正しようとしています。
ヒット

現在のバージョンは壊れているようです。理由はまだわかりません。
PhiNotPi

1
デバッグツールを刷新し、問題を診断できるようになりました。何が起こっているのかというと、プログラムは(から始まるJMP loop 0)後半のみをコピーするということです。次に、コピーの開始位置にジャンプすると、空のスペースになり、失われます。
PhiNotPi

2
以前の(現在削除されている)コメントを無視してください。私はあなたのコードの間違ったバージョンをテストしました(皮肉なことに、コピーと貼り付けのミスが原因でした)。
イルマリカロネン

6

用務員

次のアドレスが空であるかどうかをチェックし、空でない場合はクリーンアップします(したがって、できれば、相手のボットを消去します)。

編集:この新しいバージョンはより速くなるはずです(JMZコマンドと@リファレンスが正しく理解できたので)。

JMZ 2 6
MOV 4 @-1
ADD 2 -2
JMP -3 0
DAT 0 1
DAT 0 0

管理人は最初のJMZで自殺していませんか?少なくともJMZ 2 8である必要があります。@を使用することで、2つの加算を1つに減らすことができます。「JMZ 2 @ 5 MOV 5 @ 4 ADD 2 3 JMP -3 0 DAT 0 1 DAT 0 2 DAT 0 0」(未テスト)
ヒット

@Hitそこからのアドレス2はなのでジャンプしませんがADD 3 -2、彼はそれを変更すべきだと思います。
mbomb007

はい、私は指示を読み違えて、明らかにそれが反対であるときに0にチェックしてジャンプするJMZと思っJMZ A Bた。気づいてくれてありがとう:)AB
plannapus

5

スキャンボンバー

コンパイルする前にコメントを削除してください。しばらくスキャンしてから、プログラムが見つかると爆弾を送ります。ただし、おそらく私のドワーフにとってはまだ失われます。

scan add #eight #range  ; scan
jmz #scan @range
sub #six #range
fire mov #zero @range   ; bombs away! (-6)
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range        ; (+0)
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range
add #two #range
mov #zero @range        ; (+8)
range jmp #scan 6
two dat 0 2
six dat 0 6
zero dat 0 0
eight dat 0 8

OP #は仕様とは完全に異なって定義されています(彼がリンクしたリンクを読んでください)。このプログラムをまだ修正していません。
mbomb007

@TheBestOne修正したと思う。今では理にかなっているように見えますか?または、#すべての参照の前に置く必要がありzeroますか?ええ、私は必要だと思うの...
mbomb007

今はうまく機能しています。DwarfとImpを除くすべてのボットに勝ちます。
TheNumberOne

@TheBestOne Dwarfは小さすぎて、可能なプログラム配置の50%でのみ検出されます。メモリ全体を巡回した後、爆弾を爆破するため、Impに負ける可能性が高いです。
mbomb007

5

ハンショットファースト(v2)

競争にはもっと多様性を使用できると考えたので、2番目のエントリーはワンショットCMPスキャナーです。

これは、改善されたImp防御を備えたバージョン2です。たった1点だけであれば、Impを打ち負かすことができます。まだドワーフのエンジニアには負けていますが、これまでのところ他のすべてに勝っており、現在は同点の第1位になっています。

scan    ADD bomb    aim
aim     CMP 17      12
        JMZ scan    #-3
loop    MOV bomb    @aim
        ADD step    aim
step    JMP loop    #2
bomb    DAT 10      10

違いが見つかるまで、隣接するコアの位置を5ステップずつ、10ステップ間隔で比較することで機能します。すると、敵を殺すか、コアの周りをループして自分自身に到達するまで、2ステップ間隔で爆弾を投げ始めます。

スキャンが他に何も見つからなかった場合、最終的にループして独自のコードを見つけて攻撃します。これは自殺になりますが、幸運なことに、最初の爆弾がaimライン、次の爆弾がコアを下って12ポジション(通常の2ではなく)スローされ、コードをスキップします。(これは、スキャンが何かを見つけても相手を殺すことに失敗した場合も50%の確率で起こります。)コアサイズは2の倍数であるため、爆撃がループした場合にも発生し続けます。さらにバックアップ戦略。

(この自己爆撃のトリックはもともと純粋な偶然でした。何も見つからない場合はスキャンから爆撃モードに切り替えるまったく異なる方法を計画していましたが、コードを最初にテストしたとき、定数がたまたま正しいようになりましたこのように動作し、私はそれに固執することにしました。)



4

ナメクジ

     mov    ones    @-1024
     mov    from    -3
     mov    here    -3
loop mov    @-5 @-4
     add    ones  -5
     jmz    -17 -6
     add    ones  -8    
     jmp    loop    42
ones dat    1   1
from dat    2   2
here dat    -11 -11

メモリ空間を逆方向にクロールします。時折、遠くに爆弾を投げます。


3

イースターのウサギ

彼は後方に飛び跳ねるのが好きです:)

loop mov 0 -10
     add data loop
     cmp -7 data
     jmp -13 0
     jmp loop 0
data dat 1 1

3

妄想

コピーパスタのようなものですが、コードが爆撃によって変更されたかどうかをチェックします。その場合、ドワーフをコピーして実行します。もう一度GameViewを作成できた場合は、いくつかの定数を変更しようとします。

copy    MOV data copy
loop    MOV @-1 @-1
    CMP @copy end
out JMP check 0
    SUB loop copy
    JMP loop 0
data    DAT 0 4109
check   MOV data copy
loop2   CMP @copy @copy
    JMP ok 0
    MOV aah 2
ok  CMP @copy end
    JMP 4098 0
    SUB loop copy
    JMP loop2 0
panic   MOV end copy
    MOV jump out
    JMP loop 0
jump    JMP 4124 0
dwarf   ADD 2 bomb
    MOV bomb @bomb
    JMP dwarf 4
bomb    DAT 0 4
aah JMP 3 0
end DAT 19 4127

さて、実際には動作しており、新しい実行のおかげで、私はちょうどmessignでした;)
ヒット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.