Lab Rat Race:遺伝的アルゴリズムの演習


113

これは、フォートナイトリーチャレンジ#3です。テーマ:遺伝的アルゴリズム

この挑戦はちょっとした実験です。私たちは、遺伝的アルゴリズムを使用して、挑戦的に何ができるかを見たかったのです。すべてが最適であるとは限りませんが、アクセスできるように最善を尽くしました。これがうまくいけば、誰が私たちが将来見るかもしれないことを知っています。おそらく遺伝的なキングオブザヒルですか?

仕様は非常に長いです!仕様をThe Basics(フレームワークでプレイを開始し、回答を送信するために知っておく必要のある最低限)と、The Gory Details-コントローラーに関するすべての詳細を含む完全な仕様に分割しようとしました。自分で書くことができます。
ご質問がある場合は、お気軽にチャット参加してください!

あなたは行動心理学の研究者です。金曜日の夕方、あなたと同僚は楽しい時間を過ごし、実験用のネズミを小さなネズミのレースに使用することにしました。実際、私たちが感情的になりすぎる前に、それらを標本と呼びましょう。

標本用の小さなレーストラックを設定しました。さらに面白くするために、トラック全体にいくつかの壁とトラップとテレポーターを配置しました。今、あなたの標本はまだネズミです...彼らはトラップやテレポーターが何であるかを知りません。彼らが見るのは、色の違うものだけです。彼らはまた、どんな種類の記憶も持っていません-彼らができることは、彼らの現在の環境に基づいて決定を下すことだけです。自然選択は、そうでないものからのtrapを避ける方法を知っている標本を選ぶと思います(この種族はしばらく時間がかかります...)。ゲームを始めよう!

使用中のボードのサンプル画像

†84,465個の標本がこの課題の作成で被害を受けました。

基礎

これはシングルプレイヤーゲームです(あなたと同僚は人口を混同したくないので、それぞれが独自のレーストラックを構築しました)。レーストラックは、高さ15セル、幅50セルの長方形のグリッドです。左端(ここでx = 0)のランダム(必ずしも別個ではない)セルの15個の標本から始めます。あなたの標本は、任意の細胞である目標到達しようとする必要があり、X≥4914≤Y≤0を(標本が右にトラックをオーバーシュートがあります)。これが起こるたびに、あなたはポイントを獲得します。また、1ポイントでゲームを開始します。10,000ターン後にポイントを最大化するようにしてください。

複数の標本が同じセルを占有する場合があり、相互作用しません。

各ターンで、各標本は周囲の5x5グリッド(中央にある)を見ます。そのグリッドの各セルにはの色が含ま-115ます。-1境界外のセルを表します。標本が範囲外に移動すると、標本は死にます。他の色については、空のセル、トラップ、壁、テレポーターを表します。しかし、あなたの標本はどの色が何を表しているのか分からず、あなたもそうではありません。ただし、いくつかの制約があります。

  • 8色は空のセルを表します。
  • 4色はテレポーターを表します。テレポーターは、9x9エリア内の特定のセルに標本を送ります。このオフセットは、同じ色のすべてのテレポーターで同じです。
  • 2色が壁を表します。壁に移動することは、じっと立っているのと同じです。
  • 2色はトラップを表します。トラップは、すぐ近くにある9 のセルの1つが致命的であることを示します(トラップセル自体である必要はありません)。このオフセットは、同じ色のすべてのトラップで同じになります。

さて、その自然選択について...各標本にはゲノムがあり、それは100ビットの数字です。新しい標本は、2つの既存の標本を交配し、ゲノムをわずかに変異させることによって作成されます。標本が成功すればするほど、繁殖の可能性が大きくなります。

ここにあなたのタスクがあります:標本が見る色の5x5グリッドとそのゲノムを入力として受け取る単一の関数を書きます。関数は、標本の移動(Δx、Δy)を返し{-1, 0, 1}ます。ここで、ΔxとΔyはそれぞれの1つです。関数呼び出し間でデータを永続化しないでください。これには、独自の乱数ジェネレーターの使用が含まれます。関数にはシードされたRNGが提供され、必要に応じて自由に使用できます。

提出のスコアは、50のランダムトラック全体のポイント数の幾何平均です。このスコアにはかなりのばらつきがあることがわかりました。したがって、これらのスコアは暫定的なものです。この課題が終了すると、締め切りが発表されます。締め切りの終わりに、100のボードがランダムに選ばれ、すべての提出物がこれらの100のボードで採点されます。推定スコアを回答に自由に入力してください。ただし、だれもチートしないように、すべての提出物にスコアを付けます。

コントローラープログラムは少数の言語で提供されています。現在、Python(2または3)、RubyC ++C#またはJavaで提出物を書くことができます。コントローラーはボードを生成し、ゲームを実行し、遺伝的アルゴリズムのフレームワークを提供します。必要なのは、移動機能を提供することだけです。

待って、それではゲノムを使って正確に何をしますか?

課題はそれを理解することです!

標本には記憶がないため、与えられたターンで得られるのは、あなたにとって何の意味もない5x5の色のグリッドだけです。そのため、目標を達成するにはゲノムを使用する必要があります。一般的な考え方は、ゲノムの一部を使用して色またはグリッドレイアウトに関する情報を保存し、ボットはゲノムに保存されている追加情報に基づいて決定を下すというものです。

もちろん、手動で何かを実際に保存することはできません。したがって、そこに保存される実際の情報は、最初は完全にランダムになります。しかし、遺伝的アルゴリズムは間もなく、ゲノムに正しい情報が含まれる標本を選択し、間違った情報を持つ標本を殺します。目標は、ゲノムビットと視野から移動へのマッピングを見つけることです。これにより、目標へのパスを迅速に見つけ、一貫して勝利戦略に進化することができます。

これは、開始するのに十分な情報である必要があります。必要に応じて、次のセクションをスキップして、下部のコントローラーのリストから選択するコントローラーを選択できます(特定のコントローラーの使用方法に関する情報も含まれています)。

すべてが必要な場合は読んでください...

ゴーリーの詳細

この仕様は完全です。すべてのコントローラーはこれらのルールを実装する必要があります。

特に明記しない限り、すべてのランダム性は均一な分布を使用します。

トラック生成:

  • トラックは、X = 53セル幅、Y = 15セル高さの長方形のグリッドです。有する細胞のx≥49は、ある目標セル(ここで、xはゼロベースです)。
  • 各セルは単一の色を有し、またはあってもなくてもよい致死 -以下の細胞型のいずれかで指定されない限り、細胞は致死的ではありません。
  • からまでラベル付けされた16の異なるセルの色があり、その意味はゲームごとに変わります。さらに、境界外のセルを表します-これらは致命的です。015-1
  • 8つのランダムな色を選択します。これらは空のセルになります(効果はありません)。
  • さらに4つのランダムな色を選択します。これらはテレポーターです。これらの2つの色について、9x9近傍のゼロ以外のオフセットを選択します((-4、-4)から(0,0)を除く(4,4)まで)。他の2色については、それらのオフセットを反転します。標本がテレポーターに乗ると、そのオフセット分だけすぐに移動します。
  • さらに2つのランダムな色を選択します。これらはトラップです。これらの各色について、3x3近傍のオフセットを選択します((-1、-1)から(1,1)まで)。トラップは、そのオフセットのセルが致命的であることを示します。注:トラップセル自体は必ずしも致命的ではありません。
  • 残り2色は壁で、動きを妨げます。壁のセルに移動しようとすると、移動が静止したままになります。壁細胞自体は致命的です。
  • グリッドの非目標セルごとに、ランダムな色を選択します。各ゴールセルに対して、ランダムな空の色を選択します。
  • トラックの左端にある各セルについて、100ターン以内に目標に到達できるかどうかを決定します(以下のターン順序規則に従って)。その場合、このセルは許容可能な開始セルです。開始セルが10未満の場合は、トラックを破棄して新しいセルを生成します。
  • 15個の標本を作成します。各標本にはランダムなゲノムがあり、年齢は0です。ランダムな開始セルに各標本を置きます。

順番を変える:

  1. 次の手順は、各標本に対して順番に実行されます。標本は相互に作用したり、互いに見えたりせず、同じ細胞を占有する場合があります。
    1. 標本の年齢が100歳の場合、死にます。そうでない場合は、経過時間を1ずつ増やします。
    2. 標本には視野が与えられます-標本を中心とした色の5x5グリッド-3x3の周辺で動きを返します。この範囲外に移動すると、コントローラーが終了します。
    3. ターゲットセルが壁の場合、移動は(0,0)に変更されます。
    4. ターゲットセルがテレポーターの場合、標本はテレポーターのオフセット分だけ移動します。注:このステップは、反復ではなく1回実行されます。
    5. 標本が現在占有しているセルが(可能性として1つのテレポーターを使用した後に)致命的である場合、標本は死にます。これは、標本が死ぬ唯一の時間です(上記のステップ1.1を除く)。特に、致命的な細胞に出現する新しい標本はすぐに死ぬことはありませんが、最初に危険な細胞から移動する機会があります。
    6. 標本が目標セルを占有している場合、ポイントを獲得し、標本をランダムな開始セルに移動して、その年齢を0にリセットします。
  2. ボードに残っている標本が2つ未満の場合、ゲームは終了します。
  3. 年齢0の新しい標本を10個作成します。各ゲノムは、以下の育種ルールによって(個別に)決定されます。ランダムな開始セルに各標本を置きます。

育種:

  • 新しい標本が作成されると、2つの異なる親をランダムに選択し、さらに右に進む標本へのバイアスを選択します。標本が選択される確率は、現在の適応度スコアに比例します。標本のフィットネススコアは

    1 + x + 50 *目標に到達した回数

    ここで、xは 0系の水平インデックスです。同じターンに作成された標本を親として選択することはできません。

  • 2つの親のうち、最初のゲノムビットを取得するランダムな親を選択します。

  • ゲノムを歩きながら、0.05の確率で親を切り替え、結果の親からビットを取り続けます。
  • 完全に組み立てられたゲノムを突然変異させます:各ビットごとに、確率0.01でそれを反転させます。

得点:

  • 1ゲームは10,000ターン続きます。
  • プレイヤーは1ポイントでゲームを開始します(幾何平均を使用できるようにするため)。
  • 標本が目標に到達するたびに、プレーヤーはポイントを獲得します。
  • 現時点では、各プレイヤーの提出は、それぞれが異なるランダムトラックを持つ50ゲームで実行されます。
  • 上記のアプローチは、望ましいよりも多くの分散をもたらします。この課題が終了すると、締め切りが発表されます。締め切りの終わりに、100のボードがランダムに選ばれ、すべての提出物がこれらの100のボードで採点されます。
  • プレーヤーの総合スコアは、これらの個々のゲームのスコアの幾何平均です。

コントローラー

次のコントローラーのいずれかを選択できます(機能的に同等であるため)。すべてテストしましたが、バグを見つけたり、コードやパフォーマンスを改善したり、グラフィック出力のような機能を追加したい場合は、GitHubで問題を提起するか、プルリクエストを送信してください!別の言語で新しいコントローラーを追加することもできます!

各コントローラーの言語名をクリックして、GitHubの正しいディレクトリに移動します。このディレクトリには、README.md正確な使用手順が記載されています。

gitやGitHubに精通していない場合は、フロントページからリポジトリ全体をZIPとしてダウンロードできます(サイドバーのボタンを参照)。

Python

  • 最も徹底的にテストされています。これがリファレンス実装です。
  • Python 2.6+とPython 3.2+の両方で動作します!
  • とても遅いです。大幅な高速化のために、PyPyで実行することをお勧めします。
  • pygameまたはを使用してグラフィカル出力をサポートしますtkinter

ルビー

  • Ruby 2.0.0でテスト済み。新しいバージョンで動作するはずです。
  • また、かなり遅いですが、Rubyは提出のアイデアをプロトタイプ化するのに便利かもしれません。

C ++

  • C ++ 11が必要です。
  • オプションでマルチスレッドをサポートします。
  • 群を抜いて最速のコントローラー。

C#

  • LINQを使用するため、.NET 3.5が必要です。
  • むしろ遅い。

Java

  • 特に遅くはありません。特に高速ではありません。

予備リーダーボード

すべてのスコアは予備的なものです。それにもかかわらず、何かが明らかに間違っているか時代遅れである場合、私に知らせてください。サンプルの送信は比較のためにリストされていますが、競合ではありません。

  Score   | # Games | User               | Language   | Bot           
===================================================================================
2914.13   |   2000  | kuroi neko         | C++        | Hard Believers
1817.05097|   1000  | TheBestOne         | Java       | Running Star
1009.72   |   2000  | kuroi neko         | C++        | Blind faith
 782.18   |   2000  | MT0                | C++        | Cautious Specimens
 428.38   |         | user2487951        | Python     | NeighborsOfNeighbors
 145.35   |   2000  | Wouter ibens       | C++        | Triple Score
 133.2    |         | Anton              | C++        | StarPlayer
 122.92   |         | Dominik Müller     | Python     | SkyWalker
  89.90   |         | aschmack           | C++        | LookAheadPlayer
  74.7    |         | bitpwner           | C++        | ColorFarSeeker
  70.98   |   2000  | Ceribia            | C++        | WallGuesser
  50.35   |         | feersum            | C++        | Run-Bonus Player
  35.85   |         | Zgarb              | C++        | Pathfinder
 (34.45)  |   5000  | Martin Büttner     | <all>      | ColorScorePlayer
   9.77   |         | DenDenDo           | C++        | SlowAndSteady
   3.7    |         | flawr              | Java       | IAmARobotPlayer
   1.9    |         | trichoplax         | Python     | Bishop
   1.04   |   2000  | fluffy             | C++        | Gray-Color Lookahead

クレジット

この課題は、大きな共同作業でした。

  • Nathan Merril: PythonおよびJavaコントローラーを作成しました。チャレンジコンセプトをキングオブザヒルからラットレースに変えました。
  • trichoplax:プレイテスト。Pythonコントローラーで作業しました。
  • feersum: C ++コントローラーを作成しました。
  • VisualMelon: C#コントローラーを作成しました。
  • MartinBüttner:コンセプト。Rubyコントローラーを作成しました。プレイテスト。Pythonコントローラーで作業しました。
  • Tアブラハム:プレイテスト。Pythonをテストし、C#およびC ++コントローラーを確認しました。

上記のすべてのユーザー(およびおそらく私が忘れていたさらに2、3人)は、チャレンジの全体的な設計に貢献しました。

C ++コントローラーの更新

Visual StudioとマルチスレッドでC ++を使用している場合は、ボードの複製を生成できる乱数ジェネレーターのシードにバグがあるため、最新の更新プログラムを入手する必要があります。


3
誰かがこの問題に最適な遺伝的アルゴリズムを見つけるために遺伝的遺伝的アルゴリズムを作成することはできませんか?
mbomb007

1
@ anon3202ええと、もちろん、あなたは自分の現在地を測定できるので、トラックレイアウトに関する詳細情報が得られます。基本的に、ボットのインターフェイスをシンプルに保ち、それを純粋にローカルな問題にして、どのローカルソリューションがグローバルな進歩に最も有益であるかを知るためにゲノムが必要になるようにしました。
マーティンエンダー

1
@matovitchのセクション5を参照してください。電源を入れオーダー:Goryの詳細(フルスペック)のセクション'In particular, a new specimen which spawns on a lethal cell will not die immediately, but has a chance to move off the dangerous cell first.'
センモウヒラムシ

1
サンプルの平均、stddev、stderr、および99%conf-intervalを表示するようにC ++コードを微調整し(「幾何学的な」log / expの前に)、驚くべき発見をしました。「Blind Faith」の回答には、「50回実行した後のサンプル平均116529 +-2.78337e + 010(99%)stddev = 7.77951e + 010」がありました。幾何平均はしかし安定した: "159.458 +の平均- 117262(99%)STDDEV = 32.6237"(彼の800スコア更新前)
ダックMooing

1
突然変異率でいくつかの実験を行ったが、確率が.01から.0227に引き上げられた場合、チャレンジはより興味深いものになると思います(そしてコントローラーははるかに速く動作します)。現在の値で37%の代わりに変化のない突然変異。これにより、ばかげた人口爆発が回避され(計算時間を大幅に節約できます)、多様性の不足による多くの失敗が防止されます。個人のスコアは低くなりますが、より多くのランが勝者を生み出すため、世界平均は上昇する傾向があります。

回答:


37

盲信-C ++-2000回の実行で800(!)

謎のトラックフィードバックと効果的な壁バンギング抑止力を備えたカラーコーディングゲノム

#include "./gamelogic.cpp"

#define NUM_COLORS 16

// color meanings for our rats
typedef enum { good, bad, trap } colorType_t;
struct colorInfo_t {
    colorType_t type;
    coord_t offset; // trap relative location
    colorInfo_t() : type(good) {} // our rats are born optimists
};

// all 8 possible neighbours, carefully ordered
coord_t moves_up  [] = { { 1, 0 }, { 1,  1 }, { 1, -1 }, { 0,  1 }, { 0, -1 }, { -1, 0 }, { -1,  1 }, { -1, -1 } };  // toward the goal, going up   first
coord_t moves_down[] = { { 1, 0 }, { 1, -1 }, { 1,  1 }, { 0, -1 }, { 0,  1 }, { -1, 0 }, { -1, -1 }, { -1,  1 } };  // toward the goal, going down first

// map of the surroundings
struct map_t {
    static const size_t size = 5;
    static const int max = size / 2;
    static const int min = -max;
    colorType_t map[size*size];
    colorType_t & operator() (int x, int y) { return map[(x + max)*size + y + max]; }
    colorType_t & operator() (coord_t pos) { return operator()(pos.x, pos.y); }
    bool is_inside(int x, int y) { return abs(x) <= max && abs(y) <= max; }
    bool is_inside(coord_t pos) { return is_inside(pos.x,pos.y); }
};

// trap mapping info
struct trap_t {
    coord_t detector;
    colorInfo_t color;
    trap_t(int x, int y, colorInfo_t & color) : color(color) { detector.x = x; detector.y = y; }
    trap_t() {}
};

coord_t blindFaith(dna_t d, view_t v)
{
    colorInfo_t color[NUM_COLORS]; // color informations

    // decode colors
    for (size_t c = 0; c != 16; c++)
    {
        size_t base = c * 4;
        if (d[base])
        {
            color[c].type = d[base+1] ? good : bad;
        }
        else // decode trap location
        {
            color[c].type = trap;
            int offset = d[base+1] + 2 * d[base+2] + 4 * d[base+3];
            color[c].offset = moves_up[offset]; // the order is irrelevant as long as all 8 neighbours are listed
        }
    }

    // build a map of the surrounding cells
    map_t map;
    unsigned signature = 0;
    int i = 0;
    for (int x = map.min; x <= map.max; x++)
    for (int y = map.min; y <= map.max; y++)
    {
        int c = v(x, y);
        map(x, y) = (c == -1) ? bad : color[c].type;
        if (c != -1) signature ^= v(x, y) << ((i++) % 28);
    }

    // map traps
    for (int x = map.min; x <= map.max; x++)
    for (int y = map.min; y <= map.max; y++)
    {
        if (map(x, y) != trap) continue;
        const colorInfo_t & trap = color[v(x, y)];
        int bad_x = x + trap.offset.x;
        int bad_y = y + trap.offset.y;
        if (!map.is_inside(bad_x, bad_y)) continue;
        map(bad_x, bad_y) = bad;
        map(x, y) = good;
    }

    // pick a vertical direction according to surroundings signature
    int go_up = d[64 + signature % (DNA_BITS - 64)];

    // try to move to a good cell nearer the goal
    for (const coord_t &move : go_up ? moves_up : moves_down) if (map(move.x, move.y) == good) return move;

    // try not to increase fitness of this intellectually impaired specimen
    return{ -1, 0 };
}

int main() {
    time_t start = time(NULL);
    double score = runsimulation(blindFaith);
    slog << "Geometric mean score: " << score << " in " << time(NULL) - start << " seconds";
}

サンプル結果:

Scores: 15 4113306 190703 1 1 44629 118172 43594 63023 2 4 1 1 205027 1 455951 4194047 1 5 279 1 3863570 616483 17797 42584 1 37442 1 37 1 432545 5 94335 1 1 187036 1 4233379 1561445 1 1 1 1 35246 1 150154 1 1 1 1 90141 6 1 1 1 26849 1 161903 4 123972 1 55 988 7042063 694 4711342 90514 3726251 2 1 383389 1 593029 12088 1 149779 69144 21218 290963 17829 1072904 368771 84 872958 30456 133784 4843896 1 2 37 381780 14 540066 3046713 12 5 1 92181 5174 1 156292 13 1 1 29940 66678 125975 52714 1 5 3 1 101267 69003 1 1 10231 143110 282328 4 71750 324545 25 1 22 102414 1 3884626 4 28202 64057 1 1 1 1 70707 4078970 1623071 5047 1 1 549040 1 1 66 3520283 1 6035495 1 79773 1 1 1 218408 1 1 15 33 589875 310455 112274 1 1 4 1 3716220 14 180123 1 2 12785 113116 12 2 1 59286 822912 2244520 1840950 147151 1255115 1 49 2 182262 109717 2 9 1049697 59297 1 11 64568 1 57093 52588 63990 331081 54110 1 1 1537 3 38043 1514692 360087 1 260395 19557 3583536 1 4 152302 2636569 12 1 105991 374793 14 3934727 1 2 182614 1 1675472 121949 11 5 283271 207686 175468 1 1 173240 1 138778 1 1 59964 3290382 1 4 1757946 1 23520 1 2 94 1 124577 497071 1749760 39238 1 301144 3 1 2871836 1 1 10486 1 11 8 1 111421 11 1807900 1 587479 1 42725 116006 3 1 6 5441895 1 1 22 52465 952 1 18 1 1 46878 2 1 1 1994 4 593858 123513 4692516 820868 4247357 1 1 2 1 2 8770 2 1 95371 4897243 2 22741 1 1 1 1 325142 6 33650 4 51 102993 1 182664 1 4040608 18153 2045673 462339 1 1 617575 2 2551800 3 7760 1 108012 76167 143362 1148457 1 53460 1 71503 1 1 1 1 81482 3208 62286 69 139 1 3503941 1 253624 101903 3081954 80123 84701 9 16 1 1070688 71604 613064 2076 15009 9 1 1 1 199731 1 2 1 63132 1 1843855 27808 1 3569689 273144 1 460524 2703719 22443 10876 51242 1 6972678 4591939 1 140506 43981 45076 2 1 91301 5 1 1874615 1758284 608 13 1 96545 75161 1 618144 4 2056133 1 1 2 57401 1394307 6 188116 83545 1 41883 1 1 467189 371722 1 1122993 1 17912 159499 1 5 3355398 33 1 2 246304 1 2 168349 1 50292 12 141492 2723076 3 1 6 3060433 223360 171472 106409 1 2 1 102729 8814 1 285154 1 11 1 65 930 2 689644 3271116 1 5 4 60 77447 1 1 1477538 256023 100403 2480335 1 39888 1 1 70052 66090 1 250 1 2 8 115371 1523106 1424 168148 1 1 1 42938 17 1 364285 185080 1 1 36 4903764 13 51987 1106 276212 67460 1 251257 2 6867732 1 1 1890073 1 1 8 5 2118932 210 0 3792346 5209168 1 1 1 1 51 1 4621148 1 37 337073 3506096 1 1 1 1 458964 2 16 52930 1 15375 267685 1 1 1259646 14930 3248678 527105 1 103 24 1 3252685 6009 1 1 176340 3971529 121 1722808 1 31483 194232 2314706 95952 3625407 3 216755 56 1 8 1 1 1 1 885 229 9056 172027 31516 2526805 1 76076 1589061 1 1 8 90812 1 21 72036 1681271 2 212431 1581814 85993 79967 4 7 514708 1070070 1 71698 1 23478 15882 94453 1 27382 495493 277308 12127 91928 248593 1 1 1 26540 1709344 2119856 1 1 48867 107017 251374 64041 15924 15 87474 8 1 23 9 48 1 1 1 51793 2 61029 84803 15 689851 1 1 873503 10 140084 420034 87087 82223 1 163273 12 1 5 570463 19 26665 1 170311 1 39983 1 475306 1 2 36417 746105 11 141345 1 3 1 30 3 1 1 1 1 1312289 408117 1 42210 273871 561592 1 1 1 1 4448568 48448 7 378508 1 351858 278331 1 79515 1169309 3670107 14711 4686395 1156554 33 2528441 24537 76 335390 63545 122108 76675 21929 34 1 861361 83000 417781 1 90487 1 1 85116 7 2 1 60129 647991 79 1 2755780 726845 244217 50007 187212 1 3674051 286071 44068 3 307427 26973 1 26059 1957457 230783 58102 545318 1 4 172542 168365 1 89402 1 4 1 1 1 1 2 3 16 62935 5643183 117961 109942 85762 5 117376 118883 1 61 23893 122536 70185 1 64252 208409 179269 55381 1579240 3434491 1 4964284 3356245 3 21 2197119 346542 44340 59976 772220 5590844 199721 90858 63785 125989 57219 129737 81836 1 3671 16810 1 4151040 1 15 40108 1 443679 3224921 2 27498 2 3 146529 169409 19 1 1 1 1 41627 1 3 2722438 1 2013730 1 1649406 1 1 6943 125772 58652 1 1 1 2413522 1 2 48 36067 253807 2 146464 1 248 07 3359223 139896 395985 65241 43988 594638 69033 275085 1 17973 1 1 1 594835 1 1 4468341 3496274 222854 94769 55 161056 36185 8793 277592 3 1 6746 1 138151 66 37365 1 2729315 1 3 57091 22408 249875 246514 85058 1 20 5463152 1 3 1 45293 1 70488 2792458 461 441 951926 2236205 2 171980 1 1 48 3893009 1 458077 1 268203 1 70005 7 19299 1 278978 1 45286 26 2 1883506 274393 342679 1 1 913722 911600 12688 1 1 115020 1249307 1529878 53426 1 226862 3721440 23537 86033 397433 1 1 1 161423 96343 94496 1 1 1 2 1 111576 1 4039782 1 1 1 5742393 3569 46072 1 1 2 1 1 85335 219988 1 78871 115876 43405 1 300835 1 166684 53134 1 3 111487 6 3 3 77 1 115971 3 205782 10 1932578 356857 43258 47998 1 27648 127096 573939 32650 523906 45193 1 2 128992 1 10144 1 257941 1 19841 5077836 14670 5 3 6 1 1 21 14651 2906084 37942 45032 9 304192 3035905 6214026 2 177952 1 51338 1 65594 46426 553875 2676479 245774 95881 3 216364 3064811 1198509 223982 3 6 1 533254 1 590363 264940 68346 127284 1 7 1 1 4617874 5 45400 1 1 3097950 360274 1 3 1 8421 14 469681 418563 3 1 6 1 1 575766 405239 11 2631108 152667 1 1 1 467383 1 1 775499 1 157998 2 1 143351 92021 1 1 1173046 3636579 1 70635 162303 1 1534876 834682 2 1 1 11981 346908 245124 607794 17 1570641 126995 13 57050 1 2 33731 29739 1 1 35460 1 33716 168190 214704 1 443156 701674 2636870 108081 1604895 1 1 11 115901 23 571891 360680 1 1 35 1 2036975 1 1 2555536 4742615 5 360553 287044 1 1814255 7 59632 1 216 41546 1 540920 353424 2625301 223744 1 1 1 15717 3 429871 1 4 2329632 18 11 1 2 4 1 3905 5 1 1 1 2 5431442 1 859628 1 3 338378 15236 13764 1 3384362 1 15 65293 24 619599 152620 2 189921 35854 16647 7 2 404790 360096 1 2 189459 1097768 191610 1 1 470254 1 12 2 330299 364219 2365542 312023 2273374 2 10527 1 115453 1 2 3845592 52388 913449 1 14695 1 44 37352 90302 1 1 1 233577 51639 3474983 44010 1650727 31 2 2 1 8 7 1 3 5 25603 17799 45630 758457 1 4571839 37 4 3 2 1 1 1351271 196673 12 2880765 263886 2926173 1 2 1 241502 5 6 1 278576 9 7 290722 42749 143391 82753 21771 57887 1 1 60400 1766903 1 296392 1 5 2861787 125560 1 9 199218 1 1 308226 517598 2246753 12 1168981 3 98447 1 488613 9 842865 202108 10 1 238493 1 1523706 5383982 29435 1 1 207071 1 8 4 125742 70531 253135 72207 124291 23364 184376 2 40034 9569353 194109 102854 2 3247153 58313 85995 1 598 63 1 2676692 10 3573233 1 36651 118016 2486962 65456 46760 1 5813 723 178120 2 153305 1 1 2 1 2354413 3 1 17126 132953 437123 299778 3070490 1 6490 403704 2261 511439 1 39 33410 173045 1 1 120970 641346 132042 1 44906 1 33940 132124 467702 45472 9 44 1 1 1 107008 1 46635 1 121431 130760 1 7 3 1 56251 1299306 3 1 1 1 15 2147678 215169 1374943 1 332995 231089 269310 1 7816944 1 1 1 46 134426 1 1 1 2 76112 1 1 30438 299927 25 139373 76048 278757 71 3474997 1 294046 1 3126554 2518019 2 1 6 1 3054393 1 1 1 2 525 96 419528 1 1 154718 233 207879 26 1 6 57436 3 5944942 1 1 318198 147536 1 22 420557 1 1 120938 1 1 167412 4082969 73299 1 11 3557361 1 4 330028 269051 1 2569546 2 1 1 4 1 1 377412 1 1 1 213800 58131 1422177 54 109617 117751 12432 3830664 419046 3 6821 741 919 1 22335 1 1 15069 80694 488809 2389 2308679 145548 51411 115786 110984 107713 1 12 6 1 5 8365 1 2001874 210250 4674015 14 1 1204101 314354 89066 1 1 2438200 68350 1 1575329 5593838 2743787 151670 57 16 5948210 597158 128060 189160 23628 1 1 15 4171774 1 8206 4157492 1 2 315607 1618680 24736 18520 4787225 33842 134431 1 1 1 1 1 1115809 17759 1 33016 123117 1 77322 169633 219091 1 321593 57231 135536 175401 4 1 435702 1 253132 100707 114547 1 119324 6382967 1472898 3 72567 1707408 177958 26 208719 1 27083 74 12 576410 19375 177069 4 3 1 31 507048 2 1 1 2 1 2 1 40 7 99892 95202 60649 241396 232370 1 136579 70649 1 2877 280695 13603 102860 404583 29717 112769 1 54089 1 97579 40819 2 868629 64848 2 63432 5 1 1888426 99623 2 1 7911 53646 3047637 1 2 3 152910 1 3244662 105187 1 1 1 1 8966 200347 1 1 22 302654 6 17 1 10 328150 55259 1016 117291 2 1 224524 23846 74645 1 1 1 1 1 3117394 10847 33976 144613 4 201584 1 1 26959 3 4410588 27019 6 66749 55935 23 4126812 4089989 99959 1 1 1 1 55490 1 4275599 13652 33967 2 8126062 337093 320653 128015 4 1 7729132 1 10594 116651 20990 3046630 1 353731 132989 2066431 4 80 15575 147430 1 621461 3100943 2306122 5 33439 407945 25634 1 2911806 32511 2174235 298281 15159 54125 1 2 3063577 2205013 1 407984 1 319713 1 22171 1 2763843 1 2607606 1 100015 3096036 1 55905 1 1 635265 2890760 1 1 1 1 35854 1 352022 2652014 1 2 274366 1 4 1 602980 4 83828 602270 2816 2 59116 25340 1 11 1 5162051 34 8 218372 1186732 142966 1 1 170557 503302 1 84924 5 1 1350329 1 1 1 130273 78055 902762 1 8581 5 1 3635882 1 1 1 224255 44044 61250 2 438453 8 1 2729357 28 1 17658 82640 1 31809 10 1 33 1 1 45495 5798 5000217 40018 588787 67269 1 12 83512 2798339 1 609271 1 3 1 7 67912 189808 3388775 60961 81311 1167 24939 433791 405306 85934 1 1170651 2 1 66 552579 122985 515363 2188340 1 1 1 3807012 1502582 4 13 149593 1 1 2108196 3 34279 24613 1282047 27 1 2 1 1 584435 27487 1 1 5 33278 1 1 1202843 1 1 1 6 3649820 3100 2 266150 13 164117 10 53163 3295075 1 1 1 1 77890 1 286220 90823 18866 3139039 481826 1 3994676 23 116901 132290 6 3927 84948 1 1 1 1 256310 1 11 8 1 102002 8392 887732 98483 444991 1 1 49408 409967 1158979 1 1 1 81469 189764 3960930 296231 64258 1 1 176030 4 1 2 1 486856 1 1135146 31 2 13112 227077 31
Geometric mean score: 831.185 in 14820 seconds

feersumの不本意に長いテストに基づいて、2000回の実行で十分に安定した結果が得られると考えています。
変更したコントローラーは各実行後に現在の幾何平均を表示するため、最後の50回の実行の変動が比較的小さい(+-10ポイント)ことを視覚的に確認しました。

これらの生き物にカチカチさせるのは何ですか

各色に等しい優先順位を与える代わりに、これらの可能な値を考慮します。

  1. 良い ->ネズミは安全にそこに行くことができると思う
  2. 悪い ->ネズミはそこに行きません
  3. trap- >ラットは、トラップの位置を不良とみなし、トラップを示すセルを良好と見なします。
    名前を変更するにはあまりにも怠Thoughですが、これは実際のトラップ、壁、疑わない放浪者を不快な場所に送り込むのを待っているテレポーター、または死者の入り口を示す「危険検出器」です-終わり。要するに、賢明なネズミがむしろ行きたくない場所。

良い遺伝子または悪い遺伝子は、格納するのに2ビットしか必要としませんが(たとえば11、および10)、トラップには4ビットが必要です(0tttここtttで、8つの「危険な」位置の1つを表します)。

(すなわち、その意味は、後に固定位置になるように各色コードする遺伝子を必要と完全に異なるゲノム中に混合されて保持)一貫性の各遺伝子を保つために、すべての値が4ビットで符号化される(そう良いとして符号化される11xx、不良として10xx)、合計16 * 4 = 64ビット。

残りの36ビットは「反壁バンガー」として使用されます(詳細は後ほど)。周囲の25色は、これらの36ビットのインデックスにハッシュされます。各ビットは、優先される垂直方向(上または下)を示します。これは、2つのセル間で可能な選択肢がある場合に使用されます。

戦略は次のとおりです。

  • ゲノムに従って各色をデコードします(または、オフトラックの「不良」セルの直接コントローラレポート)
  • 周辺の地図を作成します(3x3セル、8人の可能な隣人)
  • 周囲の署名を計算する(オフトラックセルを除く25色のハッシュ)
  • 署名から優先的な垂直方向を選択します(36個のハッシュバケットから)
  • 「良い」と示唆された隣人に移動しようとします。目標に最も近いものから始めて、優先される垂直方向に最初に行きます。
  • 「良い」隣人が見つからない場合は、1つのセルを戻そうとします(したがって、不幸な事故の犠牲者であり、いずれにしてもレートを上げることを避けます)

あなたがげっ歯類、あなたの種類の敵を見よ

恐ろしい壁 テレポートループ

個体群に起こりうる最悪の事態は、まだ勝者を出していないことですが、多くのネズミが壁に突き当たったり、ゴールに十分近い無限テレポートループの内側に立ち往生したりして、繁殖に選ばれる支配的なチャンスを得ます。
ネズミがトラップで押しつぶされたり、壁にテレポートされたりするのとは反対に、これらのげっ歯類は老齢によってのみ殺されます。
彼らは最初から3細胞に付着したいとこに競争上の優位性はありませんが、クレチンの世代からゲノムが支配的になるまで世代を繁殖させる十分な時間があるため、正当な理由もなく遺伝的多様性をひどく害します。

この現象を緩和するために、アイデアはこれらの悪い、悪いネズミの子孫を彼らの祖先のステップに従うことを避ける可能性が高くすることです。
垂直方向の表示は1ビット長で(基本的に「これらの環境で最初に上下に移動してください」と言います)、かなりのビットがパスに影響を与える可能性が高いため、突然変異やクロスオーバーには重大な影響。
子孫の多くは異なる行動をとり、同じ壁に頭をぶつけてしまうことはありません(飢えた先祖の死体の中で)。
ここでの微妙な点は、この徴候がラットの行動の支配的な要因ではないということです。ほとんどの場合、色の解釈は依然として優先されます(実際に2つの「良い」が存在する場合にのみ、上下の選択が重要になりますそしてどのようなラットは無害色として見ていると、壁にそれをキャストするために待っているテレポーター)がありません。

なぜ(どうやら)動作するのですか?

まだ正確な理由はわかりません。

未解決の謎のままである運の絶対ストロークは、トラップマッピングロジックです。それは間違いなく成功の礎ですが、それ自身の神秘的な方法で機能します。

コーディングを使用すると、ランダムゲノムは25%の「良好」、25%の「不良」、および50%の「トラップ」カラー識別子を生成します。
「トラップ」識別子は、5x5の環境と相関して「良い」および「悪い」推定を生成します。
その結果、特定の場所にいるネズミは、世界を安定した文脈上の「ゴー/ノーゴー」カラーの混合物として「見る」ことになります。

非常に成功したアンチバンギングメカニズムが示すように、トラック上の最悪の種類の要素は恐ろしい壁です(そしてその従兄弟はテレポートループですが、これらははるかに一般的ではないと思います)。

結論として、成功するプログラムは、目標に到達せずにゆっくりとした飢slowにつながる位置を検出できるラットを進化させる必要があります。

壁を表す2色を「推測」しなくても、「トラップ」色は壁を「見た」ためではなく、「トラップ」推定がこれらを除外したため、ラットがいくつかの障害物をバイパスできるようにすることで、壁回避に寄与するようですこれらの特定の環境における特定の壁細胞。

ネズミはゴールに向かって移動しようとしますが(最も「有用な」トラップインジケータは前方の危険を示すものであると考えるかもしれません)、すべてのトラップの方向はほぼ同じ影響を与えると思います。 」ラットの前に2つのセルを配置すると、その上にラットが立っているときに「前方の危険」を示すセルと同じ影響があります。

なぜこのミックスにゲノムを収束させる特性があるのか​​は、残念ながら私の数学をはるかに超えています。

私は、壁を叩く抑止力により快適に感じています。これは計画どおりに機能しましたが、私の期待をはるかに上回っていました(基本的にスコアに4を掛けました)。

いくつかのデータを表示するために、コントローラーを大幅にハッキングしました。以下にいくつかの実行を示します。

Turns:2499 best rat B  B  B  G  B  G  T3 G  T4 B  G  B  B  B  G  G  ^vv^^vv^v^v^^^vvv^v^^^v^^^v^vv^^v^^^ Max fitness: 790 Specimens: 1217 Score: 2800
Turns:4999 best rat B  B  B  G  B  G  T3 G  T4 B  G  B  B  B  G  G  ^vv^^vv^v^v^^^vvv^v^^^v^^^v^vv^^v^^^ Max fitness: 5217 Specimens: 15857 Score: 685986
Turns:7499 best rat B  B  B  G  B  G  T3 G  T4 B  G  B  B  B  G  G  ^vv^^vv^v^v^^^vvv^v^^^vvvvv^^v^v^^^^ Max fitness: 9785 Specimens: 31053 Score: 2695045
Turns:9999 best rat B  B  B  G  B  G  T3 G  T4 B  G  B  B  B  G  G  ^vv^^vv^v^v^^^vvv^v^^^vvvvv^^v^v^^^^ Max fitness: 14377 Specimens: 46384 Score: 6033904
Scored 6035495 in game 146 current mean 466.875

ここでは、スーパーラットの品種が早期に出現しました(トラックはおそらく直線的に走ることができ、最初の世代のラッキーラットの中には、それを利用するのに適したDNAを持っている人もいました)。最後の標本の数は、約100,000匹のラットの理論上の最大値の約半分です。これは、ほぼ半数の生き物がこの特定のトラックを無期限に生き残る能力を獲得したことを意味します(!)。
もちろん、得られるスコアは単純にわいせつです-ところで、計算時間もそうです。

Turns:2499 best rat B  T0 G  B  T7 B  G  B  T6 T0 T3 B  G  G  G  T4 ^v^^^^^v^^v^v^^^^^^^^v^v^v^^vvv^v^^^ Max fitness: 18 Specimens: 772 Score: 1
Turns:4999 best rat T7 G  G  G  G  T7 G  B  T6 T0 T3 T5 G  G  B  T4 ^vvvvvvv^^^vvv^^v^v^^^^^^^^^^^^^v^^^ Max fitness: 26 Specimens: 856 Score: 1
Turns:7499 best rat G  T0 G  T3 G  T0 G  B  T6 T0 T2 B  T4 G  B  T4 ^^v^vvv^^^vv^^v^vvv^v^^vvvv^^^^^^^^^ Max fitness: 55 Specimens: 836 Score: 5
Turns:9999 best rat T6 T0 G  T5 B  T1 G  B  T6 T0 T3 B  T4 G  B  T4 ^^vv^^^^vv^^v^v^^v^^vvv^vv^vvv^^v^^v Max fitness: 590 Specimens: 1223 Score: 10478
Scored 10486 in game 258 current mean 628.564

ここで、作業中のゲノムの洗練を見ることができます。最後の2つのゲノム間の系統が明確に表示されます。良い悪い評価が最も重要です。トラップの適応症は、彼らがいずれかの「便利」に安定するまでに振動するように見えるかに変異良い悪いです

色の遺伝子にはいくつかの有用な特徴があるようです:

  • それらは自己完結した意味を
    持っています(特定の色は特定の方法で処理する必要があります)
    各色コーディングは、色が実際に決定的なものである場合を除き、動作を劇的に変更することなく完全に異なるゲノムに投げ込むことができます無限ループにつながる壁またはテレポーター)。
    最も優先順位の高い色がどこに移動するかを決定するために使用される唯一の情報であるため、これは基本的な優先順位のコーディングではあまり当てはまりません。ここでは、すべての「良い」色が等しいため、「良い」リストに追加された特定の色はあまり影響しません。
  • それらは突然変異に対して比較的弾力性があり
    、良い/悪いコーディングは4のうち2つの重要なビットのみを持ち、トラップの位置はラットの行動を大きく変えることなくほとんどの時間変更されます。
  • それらは小さい(4ビット)ので、クロスオーバーによって破壊される可能性は非常に低いです。
  • 突然変異は意味のある変化のいずれかを無害に
    する「良い」に突然変異する遺伝子はほとんど効果がありません(たとえば、空のセルに対応する場合、新しい短い経路を見つけることができますが、それはラットをまっすぐに導く可能性もありますトラップ)、または劇的なもの(色が壁を表す場合、新しいラットはどこかに引っ掛かる可能性が非常に高い)。
    「トラップ」にひっくり返る遺伝子は、ラットの本質的な色を奪うか、目立った効果はありません。
    トラップの場所の突然変異は、比較的小さな確率でトラップ(または有害なもの)が実際に存在する場合にのみ問題になります(1/3のようなことを言います)。

最後に、最後の36ビットは、ラットが立ち往生するのを防ぐだけでなく、ラットをトラック上でより均等に広げるのに貢献し、したがって、カラーコーディング部分を通じて勝利ゲノムが出現して支配的になるまで、遺伝的多様性を維持していると思います。

今後の作業

私はこれらの小さな生き物が魅力的だと思う必要があります。
この素晴らしい挑戦に貢献してくれたすべての人に感謝します。

成功したネズミの祖先のように、より重要なデータを表示するためにコントローラーをさらに屠殺することを考えています。

私はこれらのネズミが動作しているのを見たいとも思っていますが、言語のこのC ++ b ** chは、(他の多くのことの中でも)イメージの作成を面倒な雑用にします。

最後に、少なくともトラップシステムの説明を作成し、おそらく改善します。

コントローラーのハッキング

誰かが興味を持っている場合は、コントローラーに加えた変更を公開できます。
彼らは汚くて安いですが、彼らは仕事をします。

私はGitHubに精通していないので、それは単なる投稿を通過する必要があります。


16
10,000ゲームで208.14のスコアを獲得しました。1000でテストしようとしていましたが、余分な0を入力したことに気付かなかったため、7時間以上かかりました。
feersum

みんなありがとう。2回の1000回の実行と比較すると、約2000回の実行で安定した結果が得られるようです。

あなたの^^v^vvv^^^vv^^v^vvv^v^^vvvv^^^^^^^^^意味は何ですか?残りは推測できますが、そのビットに問題がありますか?
Mooingダック

私は、一度に1匹のラットを実行する別個の「デバッグ」コントローラーを作成することを考えていました。新しいラットが生成されるたびに、親と子のDNAが表示されます(カスタマイズ可能な機能を使用)。それはラットがどのように働いているかを調べることをはるかに簡単にするでしょう。
Mooingダック

2
これは36の「アップ/ダウン」インジケータビットを表しますが、これらの例では、勝つDNAがすでに支配的になっているため、それほど変化しません。

18

ハード信者-C ++-(改良されたテレポーター):2000回の実行で10.000以上

(これは進化のあるブラインド・フェイスので、あなたはこの前にテキストの別の壁を登るしたい場合があります)

#ifndef NDEBUG
#define NDEBUG
#include "./gamelogic.cpp"
#endif // NDEBUG
#include <cassert>

#define NUM_COLORS 16
#define BITS_OFFSET  3
#define BITS_TYPE    2
#define BITS_SUBTYPE 2
#define BITS_COLOR (BITS_TYPE+BITS_OFFSET)

// how our rats see the world
typedef unsigned char enumSupport_t;
typedef unsigned char trapOffset_t;
typedef enum : enumSupport_t {
    danger,   // code      trap detector
    beam,     // code      safe teleporter
    empty,    // code      empty
    block,    // code      wall, pit or teleporter
    trap,     // computed  detected trap
    pit,      // read      off-board cell
} colorType_t;

// color type encoding (4 first bits of a color gene)
// the order is critical. A single block/empty inversion can cost 2000 points or more
const colorType_t type_decoder[16] = {
    /*00xx-*/
    danger,
    empty,
    beam,
    block,
    /*01xx-*/
    beam,
    danger,
    empty,
    block,
    /*10xx-*/
    empty,
    beam,
    block,
    danger,
    /*11xx-*/
    block,
    empty,
    danger,
    beam,
};

// all 8 possible neighbours, carefully ordered
typedef coord_t neighborhood_t[8];
neighborhood_t moves_up =   { { 1, 0 }, { 1,  1 }, { 1, -1 }, { 0,  1 }, { 0, -1 }, { -1, 0 }, { -1,  1 }, { -1, -1 } };  // toward the goal, going up   first
neighborhood_t moves_down = { { 1, 0 }, { 1, -1 }, { 1,  1 }, { 0, -1 }, { 0,  1 }, { -1, 0 }, { -1, -1 }, { -1,  1 } };  // toward the goal, going down first

// using C++ as a macro-assembler to speedup DNA reading
/*
Would work like a charm *if* a well-paid scatterbrain at Microsoft had not defined
std::bitset::operator[] as

bool operator[](size_t _Pos) const
{   // subscript nonmutable sequence
return (test(_Pos));
}

Bounds checking on operator[] violates the spec and defeats the optimization.
Not only does it an unwanted check; it also prevents inlining and thus generates
two levels of function calls where none are necessary.
The fix is trivial, but how long will it take for Microsoft to implement it, if
the bug ever makes it through their thick layer of tech support bullshit artists?
Just one of the many reasons why STL appears not to live up to the dreams of
Mr Stroustrup & friends...
*/
template<size_t BITS> int DNA_read(dna_t dna, size_t base)
{
    const size_t offset = BITS - 1;
    return (dna[base + offset] << offset) | DNA_read<offset>(dna, base);
}
template<> int DNA_read<0>(dna_t, size_t) { return 0; }

// color gene
struct colorGene_t {
    colorType_t  type;
    trapOffset_t offset;  // trap relative location
    colorGene_t() : type(empty) {} // our rats are born optimists
};

// decoded DNA
class dnaInfo_t {
private:
    const dna_t & dna;
    static const size_t
        direction_start = NUM_COLORS*(BITS_TYPE + BITS_OFFSET),
        direction_size = DNA_BITS - direction_start;

public:
    colorGene_t color[NUM_COLORS];
    int         up_down; // anti-wall-banger

    // decode constant informations during construction
    dnaInfo_t(const dna_t & d) : dna(d)
    {
        for (size_t c = 0; c != NUM_COLORS; c++)
        {
            unsigned raw = DNA_read<BITS_COLOR>(d, c * BITS_COLOR);
            color[c].type = type_decoder[raw >> 1];
            if      (color[c].type == danger) color[c].offset = raw & 7;
            else if (color[c].type == beam  ) color[c].offset = raw & 3;
        }
    }

    // update with surroundings signatures
    void update(size_t signature)
    {
        // anti-blocker
        up_down = (direction_size > 0) ? dna[direction_start + signature % direction_size] : 0;
    }
};

// map of the surroundings
class map_t {
    struct cell_t {
        coord_t pos;
        int     color;
    };

    static const size_t size = 5;
    static const int max = size / 2;
    static const int min = -max;

    size_t local_signature[size*size]; // 8 neighbours signatures for teleporters
    cell_t track_cell[size*size]; // on-track cells
    size_t cell_num;
    colorType_t map[size*size];
    size_t raw_index(int x, int y) { size_t res = x * size + y + max + max * size; assert(res < size*size); return res; }
    size_t raw_index(coord_t pos) { return raw_index(pos.x, pos.y); }

    bool is_inside(int x, int y) { return abs(x) <= max && abs(y) <= max; }

public:
    size_t compute_signatures(view_t v, dnaInfo_t genome)
    {
        cell_num = 0;
        size_t signature = 0;
        memset (local_signature, 0, sizeof(local_signature));
        int i = 0;
        for (int x = min; x <= max; x++)
        for (int y = min; y <= max; y++)
        {
            int c = v(x, y);
            if (c == -1)
            {
                (*this)(x, y) = pit; continue;
            }
            track_cell[cell_num++] = { { x, y }, c };
            signature ^= c << (4 * (i++ & 1));

            if (genome.color[c].type == beam)
            {
                int in = 0;
                for (coord_t n : moves_up)
                {
                    coord_t pn = {x+n.x,y+n.y};
                    if (!is_inside(pn)) continue;
                    int cn = v(pn.x, pn.y);
//                    if (cn == -1) continue;
                    local_signature[raw_index(pn.x,pn.y)] ^= cn << (4 * (in++ & 1));
                }
            }
        }
        return signature;
    }

    void build(dnaInfo_t genome)
    {
        coord_t traps[size*size];
        size_t t_num = 0;

        // plot color meanings
        for (size_t c = 0; c != cell_num; c++)
        {
            const cell_t& cell = track_cell[c];
            const colorGene_t& color = genome.color[cell.color];
            (*this)(cell.pos) = (color.type == beam && (local_signature[raw_index(cell.pos.x,cell.pos.y)] % 4) == color.offset)
                    ? block
                    : color.type;

            // build a list of trap locations
            if (color.type == danger)
            {
                coord_t location = cell.pos + moves_up[color.offset];
                if (is_inside(location)) traps[t_num++] = location;
            }
        }

        // plot trap locations
        while (t_num) (*this)(traps[--t_num]) = trap;
    }

    // quick & dirty pathing
    struct candidate_t {
        coord_t pos;
        candidate_t * parent;
        candidate_t() {} // default constructor does not waste time in initializations
        candidate_t(int) : parent(nullptr) { pos.x = pos.y = 0; } // ...this is ugly...
        candidate_t(coord_t pos, candidate_t * parent) : pos(pos), parent(parent) {} // ...but so much fun...
    };

    coord_t path(const neighborhood_t & moves)
    {
        candidate_t pool[size*size]; // private allocation for express garbage collection...
        size_t alloc;

        candidate_t * border[size*size]; // fixed-size FIFO 
        size_t head, tail;

        std::bitset<size*size>closed;

        // breadth first search. A* would be a huge overkill for 25 cells, and BFS is already slow enough.
        alloc = head = tail = 0;
        closed = 0;
        closed[raw_index(candidate_t(0).pos)] = 1;
        border[tail++] = new (&pool[alloc++]) candidate_t(0);
        while (tail > head)
        {
            candidate_t & candidate = *(border[head++]); // FIFO pop
            for (const coord_t move : moves)
            {
                coord_t new_pos = candidate.pos + move;
                if (is_inside(new_pos))
                {
                    size_t signature = raw_index(new_pos);
                    if (closed[signature]) continue;
                    closed[signature] = 1;
                    if ((*this)(new_pos) > empty) continue;
                    if (new_pos.x == 2) goto found_exit; // a path to some location 2 cells forward
                    assert(alloc < size*size);
                    assert(tail < size*size);
                    border[tail++] = new(&pool[alloc++]) candidate_t(new_pos, &candidate); // allocation & FIFO push
                    continue;
                }
                // a path out of the 5x5 grid, though not 2 cells forward
            found_exit:
                if (candidate.parent == nullptr) return move;
                candidate_t * origin;
                for (origin = &candidate; origin->parent->parent != nullptr; origin = origin->parent) {}
                return origin->pos;
            }
        }

        // no escape
        return moves[1]; // one cell forward, either up or down
    }

    colorType_t & operator() (int x, int y) { return map[raw_index(x, y)]; }
    colorType_t & operator() (coord_t pos) { return operator()(pos.x, pos.y); }
    bool is_inside(coord_t pos) { return is_inside(pos.x, pos.y); }
};

std::string trace_DNA(const dna_t d, bool graphics = false)
{
    std::ostringstream res;
    dnaInfo_t genome(d);
    for (size_t c = 0; c != NUM_COLORS; c++)
    {
        if (graphics)
        {
            res << "tbew--"[genome.color[c].type];
            if (genome.color[c].type == danger) res << ' ' << moves_up[genome.color[c].offset].x << ' ' << moves_up[genome.color[c].offset].y;
            if (genome.color[c].type == beam) res << ' ' << genome.color[c].offset << " 0";
            if (c != NUM_COLORS - 1) res << ',';
        }
        else switch (genome.color[c].type)
        {
        case danger: res << "01234567"[genome.color[c].offset]; break;
        case beam  : res <<     "ABCD"[genome.color[c].offset]; break;
        default: res << "!*-#X@"[genome.color[c].type]; break;
        }
    }
    return res.str();
}

coord_t hardBelievers(dna_t d, view_t v)
{
    dnaInfo_t genome(d); // decoded DNA
    map_t     map;       // the surroundings seen by this particular rodent

    // update genome with local context
    genome.update(map.compute_signatures(v, genome));

    // build a map of the surrounding cells
    map.build(genome);

    // move as far to the right as possible, in the contextually preffered direction
    return map.path(genome.up_down ? moves_up : moves_down);
}

int main() {
    time_t start = time(NULL);
    double score = runsimulation(hardBelievers, trace_DNA);
    slog << "Geometric mean score: " << score << " in " << time(NULL) - start << " seconds";
}

エピソードIV:グリッドにベアリングを配置する

結果

Scores: 309371 997080 1488635 1 19 45832 9 94637 2893543 210750 742386 1677242 206614 111809 1 1738598 1 1 342984 2868939 190484 3354458 568267 280796 1 1 1 679704 2858998 1 409584 3823 200724 1 973317 849609 3141119 1 1987305 1 1 57105 245412 1223244 2 1603915 2784761 9 12 1 1839136 1 298951 2 14 138989 501726 1365264 308185 707440 22 772719 17342 63461 3142044 19899 3 409837 48074 3549774 138770 32833 1 1 1184121 67473 310905 1996452 4201 1701954 2799895 2041559 218816 174 433010 51036 1731159 1871641 1 23 2877765 1 127305 27875 626814 142177 2101427 167548 2328741 4 8433 2674119 2990146 466684 1 2 8 83193 388542 2350563 1 1140807 100543 1313548 31949 73117 73300 121364 1899620 1280524 1 10726 12852 7 2165 1 3 44728 2 122725 41 2 1902290 3 1 8581 70598 1148129 429767 1 112335 1931563 521942 3513722 1 2400069 1 3331469 141319 220942 205616 57033 63515 34 6 1419147 1983123 1057929 1 599948 2730727 2438494 5586 268312 1728955 1183258 95241 1537803 11 13 1157309 1750630 1 1 2690947 101211 3463501 1 258589 101615 212924 137664 19624 251591 509429 510302 1878788 1 4045925 1 21598 459159 118663 7 3606309 3 13016 17765 640403 1 72841 695439 1 135297 2380810 1 43 31516 14 1442940 1001957 95903 194951 1 238773 773431 1 1 975692 2 4990979 52016 3261784 2 413095 12 3 420624 7905 60087 760051 2702333 2572405 1 1717432 1 12 3040935 1 1 31787 60114 513777 1 3270813 9639 581868 127091 270 164228 274393 1275008 261419 597715 138913 28923 13059 1848733 2895136 7754 14 1 107592 1 3557771 2067538 147790 112677 119004 1 13791082842974 249727 838699 4067558 6 470799 695141 1 3 1 1276069 23691 831013 5 165142 1236901 1 187522 2599203 1 67179 81345 44111 2909946 94752 7 406018 991024 4 1 3 573689 6 748463 2166290 33865 670769 322844 5657 1131171 1990155 5 4536811 1785704 3226501 2030929 25987 3055355 192547 1761201 433330 27235 2 312244 13203 756723 81459 12 1 1 54142 307858 2 25657 30507 1920292 3945574 1 191775 3748702 3348794 4188197 366019 1540980 3638591 1 1840852 1 26151 2888481 112861 8 11 2 1 27231 1 74 106853 3 173389 2390495 25 1 83116 3238625 75443 1 1 2125260 1 49626 1 6 312084 159735 358268 54351 367201 2868856 5779 172554 119016 141728 3 1 6 9 1 1504011 1 168968 1868493 1 5 1 244563 2 2887999 3144375 1598674 1 1578910 45313 176469 30969 8 127652 1911075 9 1300092 224328 168752 8 1619669 292559 9090 2040459 705819 1852774 10 139217 16 1221670 355060 339599 3 2184244 2546028 1 1 11 70958 242187 1 80737 1 190246 3 1 1 577711 150064 1 1047154 3851461 92399 224270 612237 1 3 3330053 1 1 1192533 615756 267923 144724 2 1 150018 4621881 1 6 299247 115996 2 10 6 185495 76351 465554 178786 1802565 257101 56 2491615 1 24547 1 1203267 32 5741149 541203 11393 1 368082 540534 16167 113481 2004136 13045 17 1 12 333803 14 1955075 1 4 38034 1286203 2382725 26777 1 180312 1 87161 4773392 1244024 1146401 3 80598 2983715 1 63741 1 1 2561436 16 1 1 1807854 1239680 200398 2 46153 1400933 11 5058787 8787 1 98841 89162 1106459 112566 1 4138891 2858906 101835 81375 539485 6587808 1 5359988 1 1 869106 443452 120748 436156 2 2 3944932 1 1875599 2 3081185 733911 447824 1 1 23187 3082414 33 3 1 1 2053904 410824 104571 885952 1946162 2 294773 364169 1 101310 2166548 1177524 2192461 12 4 3457016 90975 2356374 573234 53746 187527 7837 1441335 458407 52139 3387239 2030900 38 1648216 215105 212589 8278 1201586 244282 1 1 1897515 3957343 46 1 134481 1 1 2041785 3 1 37593 163173 1565457 3 1026885 1 34530 4655639 2 18 1940645 1550444 593209 1 2270700 706918 1 1 610113 9 1287883 3 1472134 1998685 1916822 1 296017 2 1 1737607 4155665 1510560 553342 56130 14436 13240604 4025888 1 4253261 174177 2043316 504151 2370989 420666 155232 1 219327 3752236 130062 571247 24 1 29015 31392 1020196 3 1117502 460873 7 1 228 8 133656 1 147008 1 93471 1 1 1 513410 4834094 1 14 1875636 182714 1504903 95263 4418053 1 357853 1135536 3698641 3 239316 4237884 131730 3878724 2158931 55650 1906785 1 26372 32 99217 1645677 379838 1 450352 7329657 112909 1 897980 2114198 308917 126215 1 53839 539997 238036 2 2270000 5 2388928 1668820 519153 58227 347528 1 1 2339954 10 5 2031341 54 2341529 2189774 112731 1 21918 748662 2068921 2 2232504 2923457 97740 3858 16604 398940 388755 1875003 667810 53633 315866 839868 1 7 1 14238 185 4 14 1 2 178947 1965719 398323 120849 48 1397222 961772 34124 2 160652 1 252629 246554 14529 1 299866 135255 490837 2863773 8 10 2 1906405 57 9782 118940 870003 255097 6 4187677 50965 3354376 17611 1804789 183601 158748 1539773 116107 77684 34738 2862836 1 2081903 727739 50328 2740070 17 923524 18 3089706 3144082 1 20 205247 347420 2076952 3725220 39270 2 15 49329 422629 5 1693818 2570558 2146654 1 5 129085 653766 47438 102243 389910 59715 21769 1246783 361571 4 120502 255235 1314165 3 3 5 2902624 76351 3117137 174413 2546645 14534 166054 1013583 1 1 2 9 3027288 3173742 338261 94929 1071263 4659804 1 506576 42798 4 984508 1 4 4 1 18541 7 1 269761 188905 2 1 92011 147031 677955 27484 1291675 2420682 99970 57943 1 4081062 1 250953 704904 4 349180 4273479 30528 2092508 2352781 3700946 1 77799 328993 3684623 3930179 1250080 1975798 54981 1621677 91664 1355832 1084049 721612 56950 197563 246868 5031 1 924076 1328694 58562 1 457662 2445958 1345169 957845 1056809 2485300 1687907 199029 3 9474 86928 1 2419980 3585265 570673 1 1514184 437383 1596697 29709 199606 126031 2 1541777 1 3 2090249 2402438 15 19 1423959 28 37852 4 1652596 1 405512 52 3 1948029 1 2 376 1155902 3 631665 3741991 57673 284026 424787 1 11569 5 1200313 1 20 2360854 1 119994 3889143 673424 797763 1 1 144306 1007659 1231874 75607 1 15 66187 8763 21366 146277 2684501 4458542 162223 3 1 5 94232 3036009 401312 19775 510737 3305062 58905 125783 274094 3089988 118483 1 106213 1 1289180 127905 30 528859 2 1215596 1955900 30 2236528 218643 1 2396631 1598175 1148688 452064 1 1840394 198540 1 1307187 107463 341396 2684981 9602 536871 1 148107 4068 4918434 1 2430254 2066144 88915 3585780 6464 259394 3098337 49601 42 79205 925658 1 2513666 26817 2738302 1 28 345735 5086930 361294 505662 386194 1103890 2653001 412247 4074274 2217918 1 519433 1338570 4289317 140138 18 2519983 168656 4546204 8 1 76545 511580 979214 9318 210013 50508 40 152908 17969 922507 1 7 32 1 388579 1 49886 13319 1066048 4663 27883 38419 1418098 2538216 1 778734 3556791 490764 666880 22746 5666164 4 20 1806284 21142 1 527906 2 12417 182224 49536 105029 206917 2427623 294247 1405136 321480 354137 84225 50 128073 1391176 352835 26074 91159 34229 237942 1 1519676 1 2428669 272681 148689 528951 560736 1 3548197 3833513 1438699 286613 1 1290904 47145 3456135 249648 277045 1012397 271073 1 6 149276 94843 11 177134 32336 2772732 7 22 37065 1 105299 76735 44 2211334 511942 30639 522056 5162 1899842 74 1 1448039 1 88817 21 1027532 555416 1 364383 1335609 167332 283252 49564 220972 1006800 3108886 801258 265596 61651 1 2413276 252747 416606 960925 54 311956 267135 3871698 22581 8978 2 10 1966155 3123429 28 46409 1 18433963725323 1769396 114766 49071 1 1 4228762 3483932 1139490 602592 2700468 770273 3 1 1 212087 281247 27093 156094 286299 1204001 18374 1 330780 1 1 25384 906728 99334 1250819 2161201 34 1027892 1 33449 2 129787 52246 94872 1536841 23470 1 1700323 1 1 3785351 1 95315 1014155 56570 22586 66842 7 156840 48752 1 3143722 1 1168309 2 4 101423 385892 42868 2893851 7 1783109 217499 24 460497 2003214 180135 3503010 131137 2 5240 1621601 2754811 11198 1 1 1105643 1 1671021 3 139611 18268 107229 44582 2211034 1 2880152747163 231008 262504 1 257760 1 1 52992 804418 2 2 4811272 1772250 3 1796530 1918647 1 1934549 1 100550 3448657 1681262 3 604526 320865 1901079 556908 2794800 2472000 637735 123663 1 3213187 118199 2553610 1 1750628 2563806 1 1670872 1 999609 50200 654831 1 164612 2865759 1841739 9 3744159 1331395 3202501 1 7 1 1 239868 1 1 581984 112413 401 1 29656 359367 74532 27226 51752 2583 1 645443 1559731 1 114195 1 85473 229474 111353 1 1521653 1 2568733 444398 2593568 18546 1 158085 1211147 1020006 23407 42514941388799 158442 1 1660358 5 34874 1594789 1551270 386464 502417 32280 170606 1954278 72486 3406066 11 52896 345631 4010742 33307 1951926 1441325 1886066 1 3 402778 3089364 351 28028 4301364 1 431569 5 3054030 375986 404966 1 449317 1230292 1 7 763949 1 2 3197443 1537806 335317 2 1 161263 1 1959902 1664530 139136 447570 1 1 50 158825 222939 1842131 11252 1680094 1017889 71 144808 1 53679 1 41278 1226724 1 1 2 10 2 1 112451 42133 1406662 1 112593 2 2832116 1544488 3579017 3029492 2752014 6 255091 731329 540861 1 426725 440330 212602 202358 173553 4 1189793 11031 84073 2084554 3963 1473295 1 642570 1 1423688 34509 75056 163273 490193 3200250 451777 157797 4156542 2386299 2794795 2735308 1332758 1193296 1131014 1001570 414257 4415511 4 3 1 3499595 536583 16731 93839 92382 1 45890 1 17695 8 867246 18 1607123 3197052 5 40009 1 329895 3497309 2416600 2316390 11 118179 2166659 2 136426 76762 2 14 2 3632525 214889 6 3900942 270409 230143 120414 417489 16706 1563597 31418 2 73 468763 88585 428274 3537347 2 1 491461 2806485 1 7 2950804 115684 4 1 429002 85771 2480 285541 186486 1 1 2430862 6 9 4 1833423 17143 353689 2568741 408890 2929237 208679 2198380 1 2501053 1933666 180843 1 1 2569886 1 17035 3449472 71357 246257 217898 1 47601 589824 401679 362878 13178 34464 1076419 1 554417 1 21248 2136449 1068 23029 8 766649 4 302879 274751 19 1 390259 1899931 233910 1392272 184492 2 2752059 55813 1 6 64674 205205 595508 1714309 582492 4821971 63973 1708726 189200 4548446 479425 2866037 1 1 1 2139319 1 1 3 1572621 2086152 2341038 1 619612 1 78942 772466 18932 1404368 936790 2263929 230200 3009227 251065 835010 88225 642856 824193 5559048 1 36348 2338046 481447 108132 2728223 3539009 1 197164 181408 171634 2172263 2317332 1598340 1318829 1746303 7 59657 1 1415452 122924 915828 1063890 40339 430186 4 2165185 2250922 704568 85138 4417453 255 326360 33541 3 49759 72127 912537 599665 1 29169 168741 349838 996835 1548193 2 28449 803521 4 2 2 3359043 3243259 1 491574 1675000 186105 3203018 11 39127 959876 334480 873131 70262 137080 1076591 1 2155613 74804 893022 2473922 1 1 269835 5 2407308 3 55200 905207 1 1 1245609 65934 7 1372126 530582 1383562 1 1 2718341 1 3947638 4 76837 412551 11 1 1 1208080 3024670 277 46485 1 9 562183 46 2985858 3379885 67816 1896527 1 105478 2035453 3026415 1 189256 2992616 2098002 1099666 775250 5913 13 406948 166773 1 322250 41919 480047 64950 17435 2147428 2336270 3330243 352709 86029 1398723 106236 312951 1 408211 252689 847088 2 17 34088 13128 187366 2 1559482 2349010 1651122 2371088 401005 1715445 1 29483921 1464444 50228 2365851 1651636 768715 226704 23677 83501 1 252623 444628 34 3640316 3602127 45369 1 1 1978261 1 3019189 1 25411 2177552 192839 191146 293712 3840622 182598 4069200 175757 1 2250458 4 1 7 2740824 2753005 1 2836428 1 12 19 2 1788326 3302198122211 3386546 1176663 20847 28 1194294 794665 2630378 13624 722012 2273872 1549353 1 3 1735700 1668388 416 970581 258382 295427 1 121571 3193610 3764806 1 368985 20436 89411 3 16130 2 241879 1 2996216 136958 2382095 510146 1762872 1372194 4215387 346915 4423 1 904153 2004500 248495 836598 3529163 27 2547535 1424181 1885308 1 1056747 289743 176929 2299073 170473 1 1 839941 12382 51457 608526 1684239 4843522 34550 929855 2767014 2979286 1 340808 184830 131077 57298 63854 381689 201998 1715328 118687 69190 123466 1 2 69392 159797 382756 1513430 2506318 457 1
Geometric mean score: 10983.8 in 31214 seconds

g ++ / MinGWと3つのスレッドに切り替えました。
GNUによって生成されるコードは、Microsoftの2倍以上の速度です。
不思議なことに、彼らのぞっとするようなSTL実装はどうでしょうか。

テレポーター

テレポーター効果は、位置に大きく依存します。これまで、私はテレポーターを常に良いもの(空のスペースとして見られる)または常に悪いもの(ネズミがそれを受け取らないように壁として見られる)のいずれかと考えていました。

これはモデルが粗すぎます。
特定のテレポーターは、ラットをゴールから数セル離れるまで前進させることができますが、同じテレポーターがラットをボードから追い出すことができます。
このようなテレポーターは無難であると認識される可能性が高く(同じx位置に「歩く」よりも速くフィットネスが増加するため)、支配的なゲノムの一部となり、「常に安全」であると信頼するほぼすべてのラットを殺します。
ラットにはX位置を知る手段がないため、これらの危険なテレポーターを検出する唯一の解決策は、利用可能な唯一のコンテキストデータ、つまり5x5カラーグリッドに基づいてそれらを踏むかどうかを決定することです。

そのために、4種類の色遺伝子を定義しました。

  • 危険トラップ検出器
  • 空のトラック上まずまずのどこでも
  • トラックのどこでも禁止されているブロック
  • 周囲に応じてまたはブロックとして見られるビーム

考えは、テレポーターをすぐ近くの8人の隣人を見ることで区別しようとすることです。特定の場所に8人の同一の近隣者がいる可能性は非常に低いため、各テレポーターの一意のインスタンスを識別することができます。

8つの隣接する色を組み合わせて、ラビリンスの位置ごとに不変のローカルシグネチャを形成できます。残念ながら、8つの隣人は3x3の視界の内側の正方形内にあるセルに対してのみ表示されるため、視界の縁では署名が不正確になります。
それにもかかわらず、これは私たちにすぐ近くで一定のコンテキスト情報を提供し、テレポーターをうまくナビゲートする確率を高めるのに十分です。

ビーム遺伝子には2ビットの可変フィールドがあります。
所与テレポーターローカル署名、4つの内の1つの可能性があるビームセルを通行考えるが。フィールドの各値は、これら4つの可能性のいずれかを選択します。
その結果、これらの2ビットでのビーム遺伝子の突然変異は、色の4つの可能な文脈的意味を循環します。

その上、推測する最も重要な色はまだ壁とandです。つまり、ラットが壁とトラップの場所を学習したにのみ、テレポーターの検出を許可する必要があります。

これは、ローカル署名をスパーリングのみで更新することにより行われます。ローカル署名を更新するための現在の基準は、潜在的なテレポーターとして識別される色の近くにあることです。

コーディングでは、色遺伝子ごとに5ビットを使用し、タイプをグループ化して、下位3ビットを解放して0..7値をエンコードします。

  • 4危険
  • 4空
  • 4ブロック
  • 4ビーム

各ビーム遺伝子には、ブロックとみなされる確率が1/4あり、空とみなされる確率が3/4であるため、4つのビームは平均で1ブロックと3つの空を表します。

したがって、16色のランダムな広がりで表される平均的な割合は次のとおりです。

  • 4危険
  • 7空
  • 5ブロック

これまでのところ、このミックスは最良の結果をもたらすようですが、私はそれを微調整していません。

遺伝子変異性

1つ確かなことは、遺伝子型を表すために選択されたコード値が重要であることです。2つの値を反転すると、2000ポイント以上かかる場合があります。

ここでも、理由は私の数学を超えています。

私の推測では、あるタイプから別のタイプへの突然変異の確率はバランスが取れていなければなりません。そうでなければ、Markowマトリックスのように、累積確率は値を最も高い入力遷移確率を持つサブセットに制限する傾向があります。

救助への道

パスを使用すると、訪問したセルの数が劇的に減少し、目標につながる可能性が最も高いもののみをテストできます。したがって、いくつかの頻繁な行き止まりが回避されるだけでなく、間違った色コードも以前に発見される可能性がはるかに高くなります。
その結果、収束時間が大幅に短縮されます。

ただし、これは、ゲノムがトラックの適切な表現を生成できないマップの解決には役立ちません。

バカをどうするか?

トラックを視覚的に確認した後、前の壁以外に見えない場合でも前進しようとするデフォルトの戦略が、控えるよりも本当に良い理由を理解しました。
「壁」は実際には非常に多くの不幸な結果を生成するテレポーターであり、ゲノムはそれらを踏まないように障害物としてマッピングしますが、まれにこのいたずらなテレポーターの特定のインスタンスがポジティブ(または少なくとも致命的ではない)効果を持つことがあります、後退する代わりにそれを取ると、勝利への道を見つける可能性が高まります。

早期収束

私には、突然変異率が少し低すぎるようです(少なくとも私のげっ歯類にとって)。

現在の0.01設定では、DNAが37%の確率で変異プロセスを無傷で生き延びます。パラメーターを0.0227に変更すると、この確率が約10%に低下します

謎の公式は、P 1ビット突然変異 = 1-P 全ゲノム無傷1 / 100、100はゲノムビット長です。

たとえば、10%の確率の場合、P 1ビットの突然変異 = 1-0.1 1/100 = 0.0277
5%の確率の場合、P = 1-0.05 1/100 = 0.0295
式を逆にすると、0.01の確率は37%突然変異によって変化しません。

10%の確率で(ランダムシードの固定シーケンスを使用して)まったく同じテストを再実行しました。
多くのマップで、以前の失敗は(限られた)成功に変わりました。一方、膨大な人口爆発は少なかった(これにより、計算が大幅に高速化されるという興味深い副作用がありました)。
非常に高いスコア(100万以上)はそれほど一般的ではありませんでしたが、成功した実行の数はそれを補うには十分でした。
最終的に、平均は1400+から約2000に上昇しました。

反対に、Pを5%に設定すると、平均で約600
になりました。突然変異率が非常に高かったため、勝ったラットのゲノムはあまりにも頻繁に効率の悪いバリアントに進化しました。

これの仕組み

テレポーター検出器の追加により、失敗したゲーム(スコア<10)の数が大幅に減少しました。
2000回の試行では、失敗の1/3しかありませんでした。
幾何平均は2900から3300にしか上昇しませんでしたが、この数値は改善を反映していません。

空の色は、ビームや危険(通常2〜5)として頻繁に推測されます。ゲノムはこれらの色を「使用」して、ラットを困らせる経路をブロックします。

ゲノムはトラップの推測に非常に優れています(つまり、ラットが目標に到達できるようになると、実際のトラップ検出器を表す色は約90%の時間で推測されます)。
また、まれにではありますが、新しいビームコードをテレポーターに使用します(おそらく、「危険な」テレポーターはトラップほど一般的ではなく、他のビーム/危険色はこれらの裏切り者の最後のインスタンスへのパスをブロックするために進化します)。

5000ターン以上後に勝利ゲノムが出現するゲームの数から判断すると、この新しい品種は突然変異率の増加から大いに恩恵を受けると思います。


トラップ、エンプティ、壁、テレポートの数が偶数であるため、比率を正確に格納するために必要なのは3ビットのみです(traps == wallsを考慮しても)。また、ウォールバンギング対策で未使用のトラップオフセットビットを使用するという考えを検討/破棄しましたか?目標は親から継承しないことなので、実際にはすべてのビットをアンチウォールバンギングで使用できます。それらがユニークである理由はないと思います。
Mooingダック

1
@MooingDuckオフセットビットを再利用するというアイデアをテストしましたが、失敗しました。私が恐れていたように、2つの異なる目的のために情報を再利用することはうまくいかないようです。たとえば、ゲノムが特定のパスで適切な垂直方向を選択するために特定の色のオフセットビットが必要であると仮定します。この色は、同じデータに依存するパスを破壊しない限り意味のあるトラップを表すことはできません。私も6ビットを使用しようとしましたが、残りの4つのアンチウォールバンガーも不足しているのではないかと恐れました。

1
知っておくと良いのですが、私は2つのアイデアを提案しました.1つはすべてのビットを使用すること(一部を再利用する)、もう1つは未使用のトラップオフセットビットを壁/空に使用することでした。両方試してみましたか?(試してみたいと思わない場合、私は完全に理解します。望まない場合、試してみる必要はほとんどありません)
Mooing Duck

1
両方試してみましたが、両方とも失敗しました。トラップオフセットは、遺伝子がそれらを使用しない場合でも重要です。なぜなら、この遺伝子はまだトラップカラーに戻って変異する可能性があるためです。 。これで、有益なオフセット値に戻り、コンテキストインジケーターとしてそれに依存していたラットの経路を破壊します。グラフィックツールでこのような振動のケースを見たと思いますが、この問題の明確な例を示すのは簡単ではありません。

16

ColorScorePlayer、予備スコア≈22

これは、チャレンジでGIFに表示されるボットです。

これは、開発フェーズ全体のテストボットでした。ゲノムを使用して、16色それぞれの品質スコアを保存します。次に、前方に移動して、最高のスコアを持つ色に移動します(決して移動しません-1)。同点の場合、同点のセル間のランダムな動きが選択されます。

このプレーヤーはすべてのコントローラー言語に移植されているため、使用方法の例として機能します。

Python

class ColorScorePlayer(Player):
    def __init__(self):
        Player.__init__(self)
        self.coords = [Coordinate( 1, 0),
                       Coordinate( 1,-1),
                       Coordinate( 1, 1)]
        self.n_moves = len(self.coords)

    def turn(self):
        max_score = max([self.bit_chunk(6*self.vision_at(c.x, c.y), 6) for c in self.coords if self.vision_at(c.x, c.y)>=0])
        restricted_coords = [c for c in self.coords if self.vision_at(c.x, c.y)>=0 and self.bit_chunk(6*self.vision_at(c.x,c.y), 6) == max_score]

        return random.choice(restricted_coords)

ルビー

class ColorScorePlayer < Player
    def initialize(rng)
        super(rng)
        @coords = [Vector2D.new( 1,-1),
                   Vector2D.new( 1, 0),
                   Vector2D.new( 1, 1)]
    end

    def vision_at(vec2d)
        @vision[vec2d.x+2][vec2d.y+2]
    end

    def turn
        max_score = @coords.map { |c|
            color = vision_at(c)
            color < 0 ? -1 : bit_chunk(6*color, 6)
        }.max

        restricted_coords = @coords.select { |c|
            color = vision_at(c)
            color >= 0 && bit_chunk(6*color, 6) == max_score
        }

        restricted_coords.sample(random: @rng)
    end
end

C ++

coord_t colorScorePlayer(dna_t d, view_t v) {
    const int chunklen = DNA_BITS / N_COLORS;
    int ymax[3], nmax, smax = -1;
    for(int y = -1; y <= 1; y++) {
        if(v(1, y) == OUT_OF_BOUNDS) continue;
        int score = dnarange(d, v(1, y)*chunklen, chunklen);
        if(score > smax) {
            smax = score;
            nmax = 0;
        }
        if(score == smax) ymax[nmax++] = y;
    }
    return {1, ymax[v.rng.rint(nmax)]};
}

C#

public static void ColorScorePlayer(GameLogic.IView v, GameLogic.IGenome g, Random rnd, out int ox, out int oy)
{
    ox = 0;
    oy = 0;

    var max_score = cspcoords.Where(c => v[c.x, c.y] > -1).Select(c => g.cutOutInt(6 * v[c.x, c.y], 6)).Max();
    var restrictedCoords = cspcoords.Where(c => v[c.x, c.y] > -1 && g.cutOutInt(6 * v[c.x, c.y], 6) == max_score).ToArray();

    Coord res = restrictedCoords[rnd.Next(restrictedCoords.Length)];

    ox = res.x;
    oy = res.y; 
}

Java

package game.players;

import java.awt.*;
import java.util.Map;

public class ColorScorePlayer extends Player{
    private static final Point[] possibleMoves = {new Point(1, 0), new Point(1, -1), new Point(1, 1)};

    @Override
    public Point takeTurn(String genome, Map<Point, Integer> vision) {
        int chunkLength = genome.length()/16;
        int maxSum = -1;
        Point maxSumMove = possibleMoves[0];
        for (Point move: possibleMoves){
            if (vision.get(move) == -1){
                continue;
            }
            int initialPoint = chunkLength*vision.get(move);
            int sum = 0;
            for (int i = initialPoint; i < initialPoint + chunkLength; i++){
                sum = (sum<<1)+Integer.parseInt(genome.charAt(i)+"");
            }
            if (sum > maxSum){
                maxSum = sum;
                maxSumMove = move;
            }
        }
        return maxSumMove;
    }
}

プレーヤーのスコアはかなり一貫していません。以下は50回のランダム実行です。

Scores: 1 1 1132581 3 43542 1 15 67 57 1 11 8 623162 1 1 1 134347 93198 6 1 2 1 1 245 3 1 1 27 1 31495 65897 9 5 1 2 20 2 117715 1 1 1 20 64616 5 38 1 2 1 2 12

12

ColorFarSeeker、C ++≈74.7

試してみると、この挑戦​​は本当に楽しく簡単です。

長い説明に惑わされないでください。
GitHubにアクセスして確認してください...すべてがより明確になります!:)

C ++シミュレーターは、その速度のために強く推奨されます。pythonプログラムをC ++に変換し終えた後でも、pythonシミュレーションは停止していません。

これはColorScorePlayerの改良版です。5x5ビューを有効に活用するために、加重関数を使用して2ステップ移動することを考慮しています。それよりも1ステップ先に移動すると、生存率にすぐに影響するため、より大きな重みが与えられます。2ステップ先に移動すると、重みが小さくなります。

前方への移動を試みますが、安全な移動が見られない場合は...次に横向きに試行します...他のすべてが失敗した場合は、ランダムに後方に移動します。

coord_t colorFarSeeker(dna_t d, view_t v) {
#define s(w,x,y) (v(x,y)>-1?((b+dnarange(d,l+m+n*v(x,y),n))*w):0)
#define max2(a,b) (((a)>(b))?(a):(b))
#define max3(a,b,c) (max2(a,max2(b,c)))
#define push(vec,maxScore,score,x,y) if(score==maxScore&&v(x,y)>-1)vec.push_back({x,y});
#define tryReturn() if(vec.size()){return vec[v.rng.rint((int)vec.size())];}vec.clear();

    // Some constants to tweak
    int k = 4;
    int l = 3;
    int m = dnarange(d, 0, l);
    int n = 4;
    int b = dnarange(d, l, k) + 10;

    std::vector<coord_t> vec;

    // Looks forward for good moves...
    int upRightScore = s(1,0,-2) + s(1,1,-2) + s(1,2,-2) + s(5,1,-1);
    int forwardScore = s(1,2,-1) + s(1,2,0) + s(1,2,1) + s(5,1,0);
    int downRightScore = s(1,0,2) + s(1,1,2) + s(1,2,2) + s(5,1,1);
    int maxForwardScore = max3(upRightScore,forwardScore,downRightScore);
    push(vec,maxForwardScore,upRightScore,1,-1);
    push(vec,maxForwardScore,forwardScore,1,0);
    push(vec,maxForwardScore,downRightScore,1,1);
    tryReturn();

    // Looks sideways for good moves...
    int upScore = s(1,-1,-2) + s(1,0,-2) + s(1,1,-2) + s(5,0,-1);
    int downScore = s(1,-1,2) + s(1,0,2) + s(1,1,2) + s(5,0,1);
    int maxSideScore = max2(upScore,downScore);
    push(vec,maxSideScore,upScore,0,-1);
    push(vec,maxSideScore,downScore,0,1);
    tryReturn();

    // If all else fails, move backwards randomly.
    // I have tried considering the scores of backmoves,
    // but it seems worse than just randomly moving backwards. 
    vec.push_back({-1,-1});
    vec.push_back({-1,0});
    vec.push_back({-1,1});
    return vec[v.rng.rint((int)vec.size())];

}

スコア:

かなり1があります...コンソールが次々と1を吐き出しているのを見ると、少し気分が悪くなることがあります。生命のすべての必需品を備えた惑星のようだが、高度なネズミ文明の兆候はありません...
それから時折のス​​パイク。:)

うーん...どうやら私はラッキーだったのは、最初のバッチの実行で、幾何学的な300以上を得ました。スコアはかなり変動します。しかし、とにかく、シミュレータの実行回数が増えると、おそらく74に近くなります(シミュレーションを支援してくれたThx feersumと彼の非常に高速なプログラム)

ランニングのスコア:6 6 53 1 5 101223 89684 17 2 303418 4 85730 24752 1 1 1 3482515 39752 1 59259 47530 13 554321 1 563794 1 1770329 1 57376 1 123870 4 1 1 79092 69931 594057 1 69664 59 1 6 37857 1733138 55616 2 1 51704 1 254006 4 24749 1 117987 49591 220151 26 4292194 23 57616 72 67 1 4 308039 1 1 103 89258 1 286032 1 5 3 1 5 114851 46 143712 5 15 9 80 7425 1 1 7 1 108379 70122 97238 1 1 5 2 23 104794 1 10476 59245 1 204 1 1 12 1 29641 1 314894 18785 13 1 3 1 1 1 2 2 526001 1 1 1 27559 29285 3 3 128708 70386 30 2 2 1 208531 331 1 2 1 61 114993 1 15 51997 1 2 1 146191 1 31 4 3 1 161422 207 1 64 1 1 1 68594 145434 87763 150187169 185518 1 1 1 1 1 24208 2570 1 1 537 1 1 462284 1 2 55 1 1 1 214365 1 40147 2 213952 1 29 3 1 2144435 5 4502444 72111 1 1 1 1 1 774547


1
私は1000ゲームで74.7の幾何平均を得た、いい仕事だ。
feersum

8

ビショップ-Python、予備スコア1.901

ビショップは常に斜めに移動するため、ボードの半分はボード上の所定のトレッキングでアクセスできませんが、これはエンコードする潜在的な動きが少ないことを意味するため、ゲノムの個々のビットは動きを表すことができます(ビショップは決して後退しません)。どのビットを参照するかは、標本の前方(右側)にある3x3の正方形ブロックに基づいて決定されます。特定の状況に最適な方法は、1ビットの突然変異だけです。

このボットは最初はすぐに学習しますが、多くの場合、フィニッシュに到達する前に天井にぶつかります。おそらく次の2つの問題のいずれかが発生する場所です。

  • ボードの2つ以上の部分が同じビットにマップされますが、異なる移動が必要です。
  • 一部のボードは、斜めの動きだけでは通れません。

コード

class BishopPlayer(Player):
    def __init__(self):
        Player.__init__(self)
        self.coords = [Coordinate(1,-1),
                       Coordinate(1, 1),
                       ]
        self.inputs = [(x,y) for x in (0,1,2) for y in (-1,0,1)]

    def turn(self):
        # Move away from out of bounds areas
        if self.vision_at(0,-1) == -1:
            return self.coords[1]
        if self.vision_at(0,1) == -1:
            return self.coords[0]

        # Move right, and either up or down based on one bit of the genome
        bit_to_use = sum(self.vision_at(self.inputs[i][0],
                                        self.inputs[i][1]
                                        ) * (16 ** i) for i in range(9)
                         ) % 100
        return self.coords[self.bit_at(bit_to_use)]

これらの制限にもかかわらず、まれにビショップがうまくいくことがあり、個々の標本がそれぞれボードの数周を完了します。あるラップでは、標本はボードの半分しか移動できないと考えていました(チェス盤の黒い四角だけ、または白い四角だけに相当します)。ただし、MartinBüttnerが指摘したように、テレポーターは標本を黒い四角から白い四角に、またはその逆に移動できるため、ほとんどのボードでは制限されません。

(一致するテレポータータイプには2つのペアがあり、それぞれ0.5の確率で標本が黒と白の正方形の残りの半分に移動する可能性があります。ラップあたりのボードの半分はわずか0.25です。)

スコアは、時折の勝利がフィニッシュに届かない長い期間に散在していることを示しています。

スコア:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 2 1 1 1 1 1 6 1 8 1 10 15 1 1 12544 1 2 1 1 1 1 3 7554 1 1 1 1 1


8

実行ボーナスプレーヤー:幾何平均50.35(5000ゲームのテスト)

このボットは、カラースコアプレーヤーのようなDNAの6ビットセクションに基づいて、それぞれ異なる色で正方形を採点しますが、数値システムは異なります。このボットは、ビットの1つが32だけスコアの値を変更し、もう1つが1だけ変更するというかなりrather意的であるという考えに動機付けられました。これは、n(n + 1)/ 2の値をランの実行に割り当てますn個の連続した1ビット。さらに、スタックを回避するために、ランダム化メカニズムを追加します。30分の1の確率でランダムに前進します。

比較のために、カラースコアプレーヤーは、2つの1000ゲームテストで30から35を獲得しました。興味深いことに、カラースコアプレーヤーの最大ゲームスコアは300〜500万の範囲でしたが、ランボーナスの最大値はわずか20万でした。実行ボーナスは、ゼロ以外のスコアをより一貫して取得することにより、対数平均スコアリングシステムの恩恵を受けます。

5000のゲームを実行するには、C ++コントローラー上の6つのスレッドで約20分かかりました。

coord_t runbonus(dna_t d, view_t v) {
    int ymax[3], nmax, smax = -1;
    if(!v.rng.rint(30)) {
        int y;
        while(!~v(1, y = v.rng.rint(-1, 1)));
        return {1, y};
    }
    for(int y = -1; y <= 1; y++) {
        if(v(1, y) == OUT_OF_BOUNDS) continue;
        int score = 0;
        int streak = 0;
        for(int i = 0; i < 6; i++) {
            if(d[6*v(1,y) + i])
                score += ++streak;
            else
                streak = 0;
        }
        if(score > smax) {
            smax = score;
            nmax = 0;
        }
        if(score == smax) ymax[nmax++] = y;
    }
    return {1, ymax[v.rng.rint(nmax)]};
}

好奇心から、5000トラックのテストにどれくらい時間がかかりましたか?私のネズミは、1000トラックを完了するのに1時間以上かかるので、テストケースを再現するために、コンピューターを一晩中走らせる必要があります。

@kuroinekoあなたの質問に対する答えはすでに私の答えにありました。
feersum

おっと、ごめんなさい。その後、PCでコードを試し、速度の違いでハードウェアがどの部分を果たしているかを確認します。そして、MSVCの代わりにgccを使用してみてください。他のいくつかの計算量の多いコードでは、MSVCよりも30%パフォーマンスが向上していることに気付きました。

あなたのコードは、4つのスレッドで私のi3-2100@3.1GHzの1000トラックに対して20分以上かかりました。スコアは約56でした。私のPCはあなたのPCの5倍遅く、特定のマシン上で私のコードは約6倍遅いことを意味しているようです(しかし、より良いスコアを持つことは機械的に長い計算時間を意味します)。私はあまりにも壊れて新しいPCを購入できないので、少し最適化する時間です

8

StarPlayer | C ++ | スコア:162(500ゲームの実行に基づく)

このプレーヤーは、A *を使用して最適な方法を見つけようとします。ColorScorePlayerと同じ方法で重みを割り当て、ビューの右端までの経路を見つけようとします。実装は、私がこれまで行った中で最も美しいものではありませんが、少なくとも遅くはありません。

#include <utility>

#define IDX(a,b) a[VIEW_DIST + b.x][VIEW_DIST + b.y]

std::pair<coord_t,int> planAhead(int weights[N_COLORS], view_t &v, coord_t target) {
    bool open[VIEW_DIST*2+1][VIEW_DIST*2+1] = {false};
    bool closed[VIEW_DIST*2+1][VIEW_DIST*2+1] = {false};
    int f_score[VIEW_DIST*2+1][VIEW_DIST*2+1] = {0};
    int g_score[VIEW_DIST*2+1][VIEW_DIST*2+1] = {0};
    coord_t came_from[VIEW_DIST*2+1][VIEW_DIST*2+1] = {{0,0}};
    open[VIEW_DIST][VIEW_DIST] = true;
    g_score[VIEW_DIST][VIEW_DIST] = v.rng.rint(5);
    f_score[VIEW_DIST][VIEW_DIST] = (abs(target.x) + abs(target.y)) * 10;
    for (;;) {
        coord_t current{VIEW_DIST+1,0};
        for (int x = 0; x < (VIEW_DIST*2+1); x++)
            for (int y = 0; y < (VIEW_DIST*2+1); y++)
                if (open[x][y] && (current.x > VIEW_DIST || f_score[x][y] < IDX(f_score,current)))
                    current = {x - VIEW_DIST, y - VIEW_DIST};
        if (current.x > VIEW_DIST)
            return {{1,0}, 1000000};
        if (current.x == target.x && current.y == target.y)
            break;
        IDX(open,current) = false;
        IDX(closed,current) = true;
        for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) {
            if (dx == 0 && dy == 0)
                continue;
            coord_t tentative{current.x + dx, current.y + dy};
            if (abs(tentative.x) > VIEW_DIST || abs(tentative.y) > VIEW_DIST)
                continue;
            if (IDX(closed,tentative))
                continue;
            auto color = v(tentative.x, tentative.y);
            if (color == OUT_OF_BOUNDS)
                continue;
            auto tentative_g = IDX(g_score,current) + weights[color];
            if (!IDX(open,tentative) || tentative_g < IDX(g_score,tentative)) {
                IDX(came_from,tentative) = current;
                auto distance = abs(tentative.x - target.x) + abs(tentative.y - target.y);
                IDX(f_score,tentative) = tentative_g + distance * 10;
                IDX(g_score,tentative) = tentative_g;
                IDX(open,tentative) = true;
            }
        }
    }
    auto prev = target, current = target;
    while (current.x != 0 || current.y != 0)
        prev = current, current = IDX(came_from,current);
    return {prev, IDX(g_score,target)};
}

coord_t starPlayer(dna_t d, view_t v) {
    const int chunklen = DNA_BITS / N_COLORS;
    int weights[N_COLORS];
    for (int i = 0; i < N_COLORS; i++)
        weights[i] = dnarange(d, i*chunklen, chunklen);
    std::pair<coord_t,int> choice{{1,0}, 1000000};
    for (int y = -VIEW_DIST; y <= VIEW_DIST; y++) {
        auto plan = planAhead(weights, v, {VIEW_DIST, y});
        if (plan.second < choice.second)
            choice = plan;
    }
    return choice.first;
}

サンプルのスコア:

4 92078 1 10 1 1 3 2 2862314 5 24925 1 3 2 126502 1 24 1097182 39 1 1 1 47728 227625 137944 15 1 30061 1 1 1 3171790 19646 10 345866 1 1 1 829756 425 6699 22 8 1 1 6 6 104889 125608 1


1
1000ゲームで、133.2のスコアを獲得しました。
feersum

7

WallGuesser-1000ゲームテストで113.266を獲得

エンコーディング

本当にシンプルな6ビット/カラーエンコーディングを作成しました。color [n]をデコードするには

  • ゲノムのnビットごとに最大96を合計
  • 合計スコアが4以上の場合、この正方形はブロックされていると言います
  • 合計スコアが<= 4の場合、最終スコアは合計スコアの2 ^です。

ゲノム全体に色のビットを広げることで、両方の親からのビットが各色に使用される可能性を高めています。

移動

私は(非常に効率的ではないと確信しています)A *ベースの検索を使用して、右端の正方形のいずれかへの最低コストのパスを探します。色が「ブロック」にマッピングされている場合、検索によって入力されることはありません。検索でパスが見つからない場合、このラットは繁殖に適していないと見なされ、1つを左に移動して終了しようとします。

不適合ラットの数を減らす

私のゲノムは、どの正方形が壁または後方テレポーターであるかを効果的に推測しているため、推測のない(ブロックにマップされる色がない)ラットはあまり適合しません。色がブロックされているとマークされていない場合、これらのラットを削除しようとすると、すべての色がブロックされているとマークされ、ラットは常に1つを左に移動します。

TODO

現在、行動にランダム性はないため、ラットが立ち往生するのは簡単です。

#include "./gamelogic.cpp"

#include <algorithm>
#include <set>
#include <map>
#include <climits>

bool operator< (const coord_t &a, const coord_t &b){
    if(a.x != b.x){ return a.x < b.x; }
    else if (a.y != b.y){ return a.y < b.y; }
    else{ return false; }
}

bool operator== (const coord_t &a, const coord_t &b){
    return (a.x == b.x) && (a.y == b.y);
}

int coordDistance(const coord_t &a, const coord_t &b){
    int xDif = abs(a.x - b.x);
    int yDif = abs(a.y - b.y);
    return xDif > yDif ? xDif : yDif;
}

int coordMinSetDistance(const coord_t &a, const std::set<coord_t> &ends){
    int min = INT_MAX;
    for (auto i : ends){
        int cur = coordDistance(a, i);
        if (cur < min){
            min = cur;
        }
    }
    return min;
}


class ColorMap{
public:
    view_t *v;
    int colors[16] = {};
    const int Blocked = -1;

    ColorMap(dna_t &d, view_t *v){
        this->v = v;

        //Decode the genome
        for (int i = 0; i <= (16*6); i++){
            if (d.at(i) == true){
                colors[i % 16]++;
            }
        }

        //Encode the result
        bool guessedWalls = false;
        for (int i = 0; i < 16; i++){
            if (colors[i] >= 4){
                colors[i] = Blocked;
                guessedWalls = true;
            }
            else{
                colors[i] = pow(2, colors[i]);
            }
        }

        if (guessedWalls == false){
            for (auto i : colors){
                i = Blocked;
            }
        }
    }

    int operator() (coord_t pos){
        if (abs(pos.x) > VIEW_DIST || abs(pos.y) > VIEW_DIST){
            return Blocked;
        }

        int value = (*v)(pos.x, pos.y);
        if (value == OUT_OF_BOUNDS){
            return Blocked;
        }
        else{
            return colors[value];
        }
    }

    void print(){
        int lower = -1 * VIEW_DIST;
        int upper = VIEW_DIST;
        for (int y = lower; y <= upper; y++){
            for (int x = lower; x <= upper; x++){
                std::cout << std::setw(3) << this->operator()({ x, y });
            }
            std::cout << std::endl;
        }
    }
};

class node{
public:
    coord_t pos;
    coord_t cameFrom;
    int gScore;
    int minDistance;

    node(coord_t pos, coord_t cameFrom, int gScore, int minDistance){
        this->pos = pos;
        this->cameFrom = cameFrom;
        this->gScore = gScore;
        this->minDistance = minDistance;
    }

    int fScore() const{ return gScore + minDistance; };

    bool operator< (const node &rhs) const{ return fScore() < rhs.fScore(); }
};

class EditablePriorityQueue{
private:
    //This is reversed so smallest are on top
    struct lesser{
        bool operator()(node *a, node *b) const{
            return (*b) < (*a);
        }
    };

    std::vector<node*> queue; // Use heap functions to maintain the priority queue ourself
    std::map<coord_t, node*> members;

public:
    EditablePriorityQueue(){};

    ~EditablePriorityQueue(){
        for (auto &m : members){
            delete m.second;
        }
    }

    bool empty(){ return members.empty(); }

    node *top(){
        auto top = this->queue.front();
        std::pop_heap(queue.begin(), queue.end(), lesser());
        queue.pop_back();
        members.erase(top->pos);
        return top;
    }

    void set(coord_t target, coord_t cameFrom, int gScore, int minDistance){
        auto targetLocation = members.find(target);

        //If the target isn't a member add it
        if (targetLocation == members.end()){
            auto *newNode = new node(target, cameFrom, gScore, minDistance);
            queue.push_back(newNode);
            std::push_heap(queue.begin(), queue.end(), lesser());
            members[target] = newNode;
        }
        //The target must be updated
        else{
            auto currentNode = targetLocation->second;
            if (currentNode->gScore > gScore){
                currentNode->gScore = gScore;
                currentNode->cameFrom = cameFrom;
                std::make_heap(queue.begin(), queue.end()); //More efficient way to do this?
            }
        }
    }
};

std::pair<coord_t, int> pathCost(ColorMap &m, coord_t start, const std::set<coord_t> &ends){
    EditablePriorityQueue openSet;
    std::set<coord_t> closedSet;
    std::map<coord_t, coord_t> cameFrom;

    openSet.set(start, start, 0, coordMinSetDistance(start, ends));
    while (openSet.empty() == false){
        auto current = openSet.top();
        closedSet.insert(current->pos);
        cameFrom[current->pos] = current->cameFrom;

        //Check if we're done
        if (ends.count(current->pos) != 0){
            //Recover the path
            coord_t path = current->pos;
            int finalScore = current->gScore;
            delete current;
            while (!(cameFrom[path] == start)){
                path = cameFrom[path];
            }

            return{ path, finalScore };
        }               

        //Examine current's neighbours
        for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++){
            coord_t neighbour = { current->pos.x + x, current->pos.y + y };

            if (x == 0 && y == 0){ continue; }

            closedSet.count(neighbour);
            if (closedSet.count(neighbour) != 0){ continue; }

            int neighbourScore = m(neighbour);
            if (neighbourScore == m.Blocked){ continue; }

            int tentativeScore = current->gScore + neighbourScore;
            openSet.set(neighbour, current->pos, tentativeScore, coordMinSetDistance(neighbour, ends));

        }
        delete current;
    }

    return{ { -1, 0 }, INT_MAX }; //Try to end it
}

coord_t myPlayer(dna_t d, view_t v) {
    auto ourMap = ColorMap(d, &v);

    std::set<coord_t> edges;
    for (coord_t edge = { VIEW_DIST, -1 * VIEW_DIST }; edge.y <= VIEW_DIST; edge.y++){
        edges.insert(edge);
    }

    //Move to the neighbor closest to a square on the right
    auto result = pathCost(ourMap, { 0, 0 }, edges);
    auto minMove = result.first;

    return minMove;
}

int main() {
    slog << "Geometric mean score: " << runsimulation(myPlayer) << std::endl;
}

うーん、これは私のためにコンパイルされませんg++ -std=c++11 .\wallguesser.cpp -O2 -o .\wallguesser.exe。私は多くのエラーを取得しますが、最初のエラーは.\wallguesser.cpp:47:19: error: 'dna_t' has no member named 'at' if (d.at(i) == true){
マーティン・エンダー

問題ありません。単に変更atして[]修正するだけです。
feersum

7

FITTEST-幾何平均スコア:〜922(2K実行)

私のアプローチは次のとおりです。

  1. 種を殺すものを見つけ、望ましい行動定義します(機能的)
  2. コードに目的の動作を実装する(技術的)
  3. それを与える優先順位を。それは他の望ましい行動よりも重要ですか、それとも重要ではありませんか。
  4. ソリューションのパラメーターを調整して、幾何平均スコアを最適化します。

同じ50シードで2000セット以上のパラメーターをテストしました。最も有望なセットが選択され、250の同一のシードを使用してスコアが付けられ、最高ランクのシードが次のテストラウンドの入力となりました。そこで、ユーザーmbomb007が示唆するように、この問題に最適な遺伝的アルゴリズムを見つけるための遺伝的アルゴリズム作成ました

望ましい動作:

  1. 種は、どの色が安全で、どれが悪いかを学ぶ必要があります
  2. 種は主に、直前の3つのセルに基づいて移動先の決定に焦点を当てる必要がありますが、適切な移動が利用できない場合は、垂直移動または後方移動を考慮する必要があります
  3. 種はまた、彼の周りの8個の細胞を超え何を見て、意思決定の情報でそれを使用する必要があります
  4. 種はわな特定することを学ぶべきです。
  5. 一部の種は、壁が良好であると誤って仮定し、常に壁に移動しようとするため、壁の前で立ち往生します。それらがその時点で最高の適合スコアを持つ種である場合、壁に関する誤った仮定を持つ彼らのDNAは新生児に何度も複製されます。しばらくすると、すべての種が壁の前で立ち往生し、それらのいずれもポイントを獲得する目標に到達しません。バカを止める方法は?

データ保存方法:

私たちは、種が物事を学び、その環境に適応し、適者になることを望んでいます。必然的にこれは、学習データを何らかの方法で保存できる場合にのみ機能します。学習は、100 DNAビットに「格納」されます。DNAの価値を変えることはできないため、これは奇妙な保存方法です。したがって、DNAにはすでに悪い動きと良い動きの情報が格納されていると想定しています。特定の種について正しい情報がそのDNAに保存されている場合、彼は早歩きしてそのDNAで多くの新しい種を生成します。

幾何平均スコアは、情報の保存方法に敏感であることがわかりました。100ビットのDNAの最初の4ビットを読み取り、これを整数変数に保存するとします。これにはいくつかの方法があります。

  1. 10進数データストレージ:「組み込み」dnarange機能を使用して、例:10114ビットは「1x2 ^ 3 + 0x2 ^ 2 + 1x2 ^ 1 + 1x2 ^ 0 = 15になります。可能な値(4ビットの場合):[0、1 、2、3、4、5、6、7、8、9、10、11、12、13、14、15]
  2. データストレージのストリーク:dnaStreakRange関数(以下で定義)を使用すると、例:4bits 1011はになり1x1 + 0x1 + 1x1+ 1x2 = 4ます。可能な値(4ビットの場合):[0、1、2、3、6、10]
int dnaStreakRange(dna_t &d, int start, int chunklen) {
    int score = 0;
    int streak = 0;
    for(int i = 0; i < chunklen; i++) {
        if(d[start + i])
            score += ++streak;
        else
            streak = 0;
    };  
    return score;
}
  1. ビットサムデータストレージ:dnaCountRange関数(以下で定義)を使用して、例:4bits 1011はになり1x1 + 0x1 + 1x1 + 1x1 = 3ます。可能な値(4ビットの場合):[0、1、2、3、4]
int dnaCountRange(dna_t &d, int start, int chunklen) {
    int score = 0;
    for(int i = 0; i < chunklen; i++) {
        if(d[start + i])
            score ++;
    };  
    return score;
}

保管方法の違いは次のとおりです。

  • 10進数の保存方法は、DNA に対する1ビットの変更に対して脆弱です。ビットサム値が1011から0011に変化すると、値は3から2に変化しますが、これはわずかな変化です。
  • 10進数の格納方法は同種です。可能な値のそれぞれには、発生する同じ変更があります。4ビットのストレージメモリブロックから15の値を読み取る可能性は、1/16 = 6%です。ストリーク保管方法は、均一ではありません。ストリーク4ビット値が6以下になる可能性は、(15-3)/ 16 = 81%(0111,1110,111を除く16の組み合わせすべて)です。分布の形状を示すビジュアルの下。青い矢印でわかるように、4ビットストリークが6以下になる可能性は81%です。 4,5および6ビット長の2進数のdecimal、streak、およびbitumストレージタイプの分布の視覚化

ソリューションに優先順位を付けます。

ColorScorePlayerが同一のスコアを持つ2つの前方への動きを識別した場合、任意の選択が行われます。私見、ランダム関数v.rng.rint()functionを使用しないください。代わりに、この同じスコアの機会をフックとして使用して、2次効果のソリューションを評価する必要があります。

一次効果が最優先されます。等しいスコアに達すると、優先度2のソリューションが優先されます。ソリューションのパラメーターを調整することにより、等しいスコアが発生する可能性に影響を与え、そのようにして優先度1および優先度2のソリューションの重みを変更できます。

望ましい動作の実装

安全な色をご覧ください。

  • 16色の33%が不良であるため、移動のスコアが63/3未満の場合、移動は許可されません。したがってthreshold = 63/3=21、63は6ビットの最大スコアであり、33%= 1/3です(上のグラフで調べることができます)。

適切な動きがない場合は、垂直または後方に移動します。

  • 前方への移動が許可されていない場合、垂直方向の移動は同じ方法で互いに比較されます。垂直方向の移動も許可されていない場合、後方への移動がランク付けされます。これはweightMove変数を介して実現されます。

向こうにあるものを見てください:

  • 2つまたは3つの動きのスコアが同じ場合、それらの動きを囲む3x3ボックスが(変数を介して)最適なオプションを(ループを介しx2y2)決定しmainSubScoreます。その3x3ボックスの一番右の列が先頭です。
coord_t adjustedColorPlayer(dna_t d, view_t v) {
    const int chunklen = 6,threshold = 63/3;
    int xBestScore=0, yBestScore=0;
    long bestScore=-1, weightMove, weightMove2, mainScore;
    for(int x = -1; x <= 1; x++) {
        if (x < 0) weightMove = 1000; // moving backward
        if (x== 0) weightMove = 10000; //moving vertical
        if (x > 0) weightMove = 100000; //moving forward
        for(int y = -1; y <= 1; y++) {
            if(v(x, y) == OUT_OF_BOUNDS || (x==0&&y==0) ) continue;
            mainScore = dnarange(d,v(x,y)*chunklen,chunklen);
            if (mainScore<threshold+1) {
                mainScore =  0; //not a suitable move because too low score
            }else{
                mainScore*= weightMove;
                // when equal score, use sub score by examining 5x5 box to rank moves
                for(int x2 = x-1; x2 <= x+1; x2++){     
                    if (x2 < x) weightMove2 = 1; // moving backward
                    if (x2== x) weightMove2 = 10; //moving vertical
                    if (x2 > x) weightMove2 = 100; //moving forward
                    for(int y2 = x-1; y2 <= y+1; y2++){     
                        if(v(x2, y2) != OUT_OF_BOUNDS){
                            long mainSubScore = dnarange(d,v(x2,y2)*chunklen,chunklen);
                            if (mainSubScore>=threshold+1) mainScore+=mainSubScore*weightMove2;
                        }
                    }
                 }
            }
            if(mainScore > bestScore) {
                bestScore = mainScore;              
                xBestScore = x;
                yBestScore = y;
            }
        }
    }
    return{xBestScore,yBestScore};
}

スコア:123(2Kラン)

最初の50スコア(18ゲームで1ポイントしか獲得していません):

1 10 1 79947 3 1 11 125 7333287 23701 310869 53744 1 2 2 2 2 1 1 57556 2 688438 60 1 2 2636261 26306 1 125369 1 1 1 61895 27 1 36 1 91100 87636 1 2 47497 53 16 1 11 222384 1 1 1

トラップを特定します。

任意のゲームがbitsum4ストレージを使用して終了したときに、スコアが最も高い種のDNAを調べました(したがって、カラースコアの範囲は[0,4]です)。

  • 0得点:後方へテレポート、両壁、1x安全
  • 得点1:後方へのトラップ(無害)、後方へのテレポート、1x安全
  • 得点2:前方へのトラップ(非常に危険)、1倍安全
  • 3得点:テレポートフォワード、5倍安全
  • 4得点:テレポートフォワード、1x安全

このことから、壁とテレポートが正しいスコアを獲得していると結論付けることができます。トラップは方向と発信元の色に依存しているため、トラップは識別されませんが、スコアリングは宛先の色で行われます。したがって、原点の色に関するデータも保存する必要がありv(0,0)ます。理想的な世界では、16色x 8方向x 3ビット= 384ビットの情報を保存します。

残念ながら、利用可能なビットは100ビットしかないため、上記で説明したソリューションにはメモリも必要なので、すべてを使用することはできません。したがって、4つのカラービンを作成します。

  • 0:色0-色3
  • 1:色4-色7
  • 2:色8-色11
  • 3:色12-色16

および4つの移動方向ビン

  • 0:垂直または後方に移動、
  • 1:上に進む、
  • 2:前進する、
  • 3:下に進む

小数スコアが4以上(100,101,110,111)の場合、トラップがこのセルに関連付けられていると想定されます。その結果、等しいスコアが生じたときにこの動きは選択されません。したがって、トラップの識別は二次的な効果であり、「それを超えたものを見る」ことが第三の優先順位のソリューションになります。

int dnaLookup2(dna_t &d, int start, int chunklen, int storageMethod) {
    // Definition of storageMethod: 0=decimal, 1=streak, 2=bitsum
    int score = 0, streak = 0;
    for(int i = start; i < start+chunklen; i++) {
        int value = d[i];
        if (storageMethod==0) {
            score = (score << 1) |value;
        }else{
            if (storageMethod==1){
                if(value) score += ++streak; else streak = 0;
            }else{
                if(value) score ++;         
            }
        }
    };  
    return score;
}

coord_t theTrapFighter(dna_t d, view_t v) {
    // Definition of storageMethod: 0=decimal, 1=streak, 2=bitsum
    const int colorMemStorageMethod = 1, colorMemBlockSize = 3;
    const int trapMemStorageMethod = 0, trapMemBlockSize = 3;
    const int trapMemTopThreshold = 4, nDirBins = 4, nColorBins = 4;

    int xBestScore=0, yBestScore=0;
    long bestScore=-1, weightMove, weightMove2, mainScore;
  for(int x = -1; x <= 1; x++) {
        if (x < 0) weightMove = 1000; // moving backward
        if (x== 0) weightMove = 10000; //moving vertical
        if (x > 0) weightMove = 100000; //moving forward
        for(int y = -1; y <= 1; y++) {          
            int color = v(x, y);
            if(color == OUT_OF_BOUNDS || (x==0&&y==0) ) continue;
            mainScore = dnaLookup2(d,color*colorMemBlockSize,
             colorMemBlockSize,colorMemStorageMethod);
            if (mainScore==0) {
                //not a suitable move because too low score
            }else{
                mainScore*= weightMove;
                //lookup trap likelihood
                int directionBin = 0;
                if (nDirBins==3) directionBin = x>0?y+1:-1;
                if (nDirBins==4) directionBin = x>0?y+2:0;
                // put 16 colors in nColorBins bins
                int colorBin = v(0,0)*nColorBins/N_COLORS; 
                colorBin = colorBin>(nColorBins-1)?(nColorBins-1):colorBin;
                if (directionBin >= 0 &&
                 dnaLookup2(
                   d,
                   colorMemBlockSize*16
                    +trapMemBlockSize*(nColorBins*directionBin+colorBin),
                   trapMemBlockSize,
                   trapMemStorageMethod
                 ) >=trapMemTopThreshold){
                  //suspect a trap therefore no sub score is added                  
                 }else{
                    // when equal score, use sub score by examining 5x5 box to rank moves
                    for(int x2 = x-1; x2 <= x+1; x2++){     
                        if (x2 < x) weightMove2 = 1; // moving backward
                        if (x2== x) weightMove2 = 10; //moving vertical
                        if (x2 > x) weightMove2 = 100; //moving forward
                        for(int y2 = x-1; y2 <= y+1; y2++){     
                            int color2 = v(x2, y2);
                            if(color2 != OUT_OF_BOUNDS){
                                mainScore+=weightMove2 * dnaLookup2(d,color2*colorMemBlockSize,
                                 colorMemBlockSize,colorMemStorageMethod);
                            }
                        }
                    }               
                 }
            }
            if(mainScore > bestScore) {
                bestScore = mainScore;              
                xBestScore = x;
                yBestScore = y;
            }
        }
    }
    return{xBestScore,yBestScore};
}

スコア:580(2K実行)

最初の50スコア(13ゲームで1ポイントしか獲得していません):

28,044 14,189 1 2,265,670 2,275,942 3 122,769 109,183 401,366 61,643 205,949 47,563 138,680 1 107,199 85,666 31 2 29 1 89,519 22 100,908 14,794 1 3,198,300 21,601 14 3,405,278 1 1 1 2 74,167 1 71、494 1948 94444

壁についての間違った仮定は、バカによって新生児に何度も複製されます:

一部の種は、壁が良好であると誤って仮定し、常に壁に移動しようとするため、壁の前で立ち往生します。また、テレポーターの無限ループに巻き込まれることもあります。どちらの場合も効果は同じです。

主な問題は、数百回の反復の後、いくつかの遺伝子が非常に支配的になることです。これらが「正しい」遺伝子である場合、非常に高いスコア(> 100万ポイント)を得ることができます。これらが間違っていると、「正しい」遺伝子を見つけるために多様性が必要になるため、行き詰まります。

バカの戦い:解決策1:色の反転

私が最初に試みた解決策は、未だに非常に多様な未使用メモリの一部を活用する努力でした。カラーメモリに84ビットを割り当て、メモリの検出をトラップしたと仮定します。残りの16ビットは非常に多様です。間隔[0,255]に値を持つ2つのdecimal8変数を埋めることができ、それらは同種です。つまり、各値には1/256のチャンスがあります。変数はとが呼び出さinInverseinReverseます。

inInverse255(1/256の可能性)に等しい場合、色スコアの解釈を逆にします。だから、バカが高得点だから安全だと思っている壁は低得点になり、したがって悪い動きになるだろう。欠点は、これが「権利」遺伝子にも影響するため、非常に高いスコアが得られないことです。さらに、このinInverse種は自分自身を再現する必要があり、その子も支配的なDNAの一部を取得します。最も重要な部分は、多様性を取り戻すことです。

inReverse255(1/256の可能性)に等しい場合、色スコアの格納位置の順序を逆にします。したがって、色0がビット0〜3に保存される前。これで、カラー15がその位置に保存されます。inInverseアプローチとの違いは、inReverseこれまでに行った作業を取り消すことです。私たちはスクエア1に戻りました。ゲーム開始時と同様の遺伝子を持つ種を作成しました(トラップ発見メモリを除く)

最適化により、inInverseinReverseを同時に使用するのが賢明かどうかがテストされます。最適化後、スコアは増加しませんでした。問題は、より多様な世代集団があることですが、これは「正しいDNA」にも影響します。別のソリューションが必要です。

バカの戦い:解決策2:ハッシュコード

種には15の開始位置があり、現在、同じ開始位置から開始した場合、まったく同じ経路をたどる可能性が大きすぎます。彼が壁を愛するバカなら、彼は同じ壁に何度も立ち往生するでしょう。運がよければ、彼ははるかに先の壁に到達することができた場合、彼は間違った仮定でDNAプールを支配し始めます。私たちが必要とするのは、彼の子孫がわずかに異なる道をたどり(彼にとっては遅すぎるため)、はるか前方の壁ではなく、より近くの壁で立ち往生することです。これは、ハッシュコードを導入することで実現できます

ハッシュコードは一意に識別し、ボード上の現在位置を標識する目的を持っている必要があります。目的は、(x、y)ポジションが何であるかを調べることではなく、この場所で私の先祖が以前にいた質問に答えることですか?

目の前に完全なボードがあり、5 x 5セルの各正方形のjpgを作成するとします。最終的には(53-5)x(15-5)= 380枚の画像になります。これらの画像に1から380の番号を付けましょう。ハッシュコード は1から330で実行されるのではなく、IDが欠落しているID、たとえば563、3424、9424、21245などのIDとして表示される必要があります。

unsigned long hashCode=17;
for(int x = -2; x <= 2; x++) {
    for(int y = -2; y <= 2; y++) {
        int color = v(x, y)+2;
        hashCode = hashCode*31+color;
    }
}       

素数1731は、ループの最初に追加された情報が消えないようにするためのものです。ハッシュコードをプログラムの残りの部分に統合する方法については、後で詳しく説明します

「先を見る」サブスコアリングメカニズムを別のサブスコアリングメカニズムに置き換えましょう。2つまたは3つのセルのメインスコアが等しい場合、上のセルが選択される確率は50%、下のセルが選択される確率は50%、中央のセルが選択される確率は0%です。チャンスはランダムジェネレーターではなく、メモリからのビットによって決定されます。そのようにして、同じ状況で同じ選択が行われることを確認します。

理想的な世界(メモリが無限にある場合)では、現在の状況に対して一意のハッシュコード( 25881など)を計算し、メモリ位置25881に移動して、上部または下部のセルを選択する必要がある場合にそこを読み取ります(等しいスコアです)。そのようにして、まったく同じ状況になります(たとえば、ボードを2回目に移動して同じ位置から開始する場合)、同じ決定を下します。無限のメモリがないので、利用可能なメモリのサイズのモジュロハッシュコードに適用します。現在のハッシュコードは、モジュロ演算後の分布が均一であるという意味で優れています。

子孫がDNAをわずかに変えて同じボードを移動すると、ほとんどの場合(> 99%)、まったく同じ決定を下します。しかし、彼が先に行くほど、彼のパスが彼の祖先と異なる可能性が大きくなります。そのため、彼がこのはるか先の壁に引っかかる可能性はわずかです。彼の祖先が比較的大きい同じ壁に引っかかっている間、彼は多くの子孫を生成しないので、これはそれほど悪くありません。ハッシュコードのアプローチがなければ、近くと遠くの壁に引っかかる可能性はほとんど同じです

最適化

最適化後、トラップ識別テーブルは不要であり、色ごとに2ビットで十分であると結論付けられました。メモリの残りの100-2x16 = 68ビットは、ハッシュコードを格納するために使用されます。と思われるハッシュコードメカニズムがトラップを避けることができます。

15のパラメーターに最適化しています。このコードには、調整されたパラメーターの最適なセットが含まれています(これまで)。

int dnaLookup(dna_t &d, int start, int chunklen, int storageMethod,int inInverse) {
    // Definition of storageMethod: 0=decimal, 1=streak, 2=bitsum
    int score = 0;
    int streak = 0;
    for(int i = start; i < start+chunklen; i++) {
        int value = d[i];
        if (inInverse) value = (1-d[i]);            
        if (storageMethod==0) {
            score = (score << 1) |value;
        }else{
            if (storageMethod==1){
                if(value) score += ++streak; else streak = 0;
            }else{
                if(value) score ++;         
            }
        }
    };  
    return score;
}

coord_t theFittest(dna_t d, view_t v) {
    // Definition of storageMethod: 0=decimal, 1=streak, 2=bitsum
    const int colorMemStorageMethod = 2, colorMemBlockSize = 2, colorMemZeroThreshold = 0;
    const int useTrapMem = 0, trapMemStorageMethod = -1, trapMemBlockSize = -1;
    const int trapMemTopThreshold = -1, nDirBins = -1, nColorBins = -1;
    const int reorderMemStorageMethod = -1, reorderMemReverseThreshold = -1;
    const int reorderMemInverseThreshold = -1;
    // Definition of hashPrority: -1: no hash, 0:hash when 'look beyond' scores equal,
    // 1: hash replaces 'look beyond', 2: hash replaces 'trap finder' and 'look beyond'
    // 3: hash replaces everything ('color finder', 'trap finder' and 'look beyond')
    const int hashPrority = 2;
    int inReverse = reorderMemReverseThreshold != -1 && 
     (dnaLookup(d,92,8,reorderMemStorageMethod,0) >= reorderMemReverseThreshold);
    int inInverse = reorderMemInverseThreshold != -1 && 
     (dnaLookup(d,84,8,reorderMemStorageMethod,0) >= reorderMemInverseThreshold);
    int trapMemStart=N_COLORS*colorMemBlockSize;
    unsigned long hashCode=17;
    int moveUp=0;
    if (hashPrority>0){
        for(int x = -2; x <= 2; x++) {
            for(int y = -2; y <= 2; y++) {
                int color = v(x, y)+2;
                hashCode = hashCode*31+color;
            }
        }       
        unsigned long hashMemStart=N_COLORS*colorMemBlockSize;
        if (useTrapMem==1 && hashPrority<=1) hashMemStart+=nDirBins*nColorBins*trapMemBlockSize;
        if (hashPrority==3) hashMemStart=0;
        int hashMemPos = hashCode % (DNA_BITS-hashMemStart);
        moveUp = dnaLookup(d,hashMemStart+hashMemPos,1,0,inInverse);
    }

    int xBestScore=0, yBestScore=0;
    long bestScore=-1, weightMove, weightMove2, mainScore;
    for(int x = -1; x <= 1; x++) {
        if (x < 0) weightMove = 1000; // moving backward
        if (x== 0) weightMove = 10000; //moving vertical
        if (x > 0) weightMove = 100000; //moving forward
        for(int y = -1; y <= 1; y++) {          
            int color = v(x, y);
            if (inReverse) color = 15-v(x, y);
            if(color == OUT_OF_BOUNDS || (x==0&&y==0) ) continue;
            //when MoveUp=1 -> give move with highest y most points (hashScore=highest)
            //when MoveUp=0 -> give move with lowest y most points (hashScore=lowest)
            int hashScore = (y+2)*(2*moveUp-1)+4; 
            mainScore = dnaLookup(
              d,
              color*colorMemBlockSize,
              colorMemBlockSize,
              colorMemStorageMethod,
              inInverse
             );
            if (mainScore<colorMemZeroThreshold+1) {
                mainScore =  0; //not a suitable move because too low score
            }else{
                mainScore*= weightMove;
                //lookup trap likelihood
                int directionBin = 0;
                if (nDirBins==3) directionBin = x>0?y+1:-1;
                if (nDirBins==4) directionBin = x>0?y+2:0;
                // put 16 colors in nColorBins bins
                int colorBin = v(0,0)*nColorBins/N_COLORS; 
                if (inReverse) colorBin = (15-v(0,0))*nColorBins/N_COLORS; 
                colorBin = colorBin>(nColorBins-1)?(nColorBins-1):colorBin;
                if (useTrapMem && directionBin >= 0 &&
                 dnaLookup(
                   d,
                   trapMemStart+trapMemBlockSize*(nColorBins*directionBin+colorBin),
                   trapMemBlockSize,
                   trapMemStorageMethod,
                   0
                 )>=trapMemTopThreshold){
                  //suspect a trap therefore no sub score is added                  
                 }else{
                    if (hashPrority>=1){
                        mainScore+=hashScore;
                    } else{
                        // when equal score, use sub score by examining 5x5 box to rank moves
                        for(int x2 = x-1; x2 <= x+1; x2++){     
                            if (x2 < x) weightMove2 = 1; // moving backward
                            if (x2== x) weightMove2 = 10; //moving vertical
                            if (x2 > x) weightMove2 = 100; //moving forward
                            for(int y2 = x-1; y2 <= y+1; y2++){     
                                int color2 = v(x2, y2);
                                if (inReverse) color2 = 15-v(x2, y2);
                                if(color2 != OUT_OF_BOUNDS){
                                    long mainSubScore = dnaLookup(
                                      d,
                                      color2*colorMemBlockSize,
                                      colorMemBlockSize,
                                      colorMemStorageMethod,
                                      inInverse
                                    );
                                    if (mainSubScore>=colorMemZeroThreshold+1){
                                        mainScore+=mainSubScore*weightMove2;
                                    }
                                }
                            }
                        }
                    }               
                 }
            }
            if (hashPrority==2 || (useTrapMem<=0 && hashPrority>=1)) mainScore+=hashScore*10;
            if (hashPrority==3) mainScore=hashScore*weightMove;         

            if(mainScore > bestScore) {
                bestScore = mainScore;              
                xBestScore = x;
                yBestScore = y;
            }
        }
    }
    return{xBestScore,yBestScore};
}   

スコア:922(2Kラン)

最初の50スコア(9ゲームで1ポイントしか獲得していません):

112,747 3 1 1,876,965 8 57 214,921 218,707 2,512,937 114,389 336,941 1 6,915 2 219,471 74,289 31116 133,162 1 5 633,066 166,473 515,204 1 86,744 17,360 2 190,697 1 6 122 126,399 399 1

これは私の最初のC ++プログラムです。私はあなたのほとんどがgnome分析のバックグラウンドを持っています。主催者に感謝したいと思います。私はこれに取り組むのを本当に楽しんでいました。

フィードバックがある場合は、下にコメントを残してください。長いテキストをおologiesびします。


あなたのトラップ分析は非常に興味深いと思います。

たとえば、12.5 16ビットワードとして見られる25のカラー値をxorし、モジュロを取るなど、別のハッシュ関数を試しましたか?素数の一致がより良い同質性を与えるとは思いませんが、私は大きな数学者ではありません。

また、パスアルゴリズムの追加を検討しましたか?これは、ゲノムに関係なく大きな改善要因であると思われます。これは、勝ちの地位につながる可能性が非常に高い経路に沿ってのみゲノムの能力をテストするものに移動を制限するためです。

黒井、ご意見ありがとうございます。C ++のバイナリ演算にそれほど馴染みがないので、xoringを試しませんでした。私はあなたが12.5 8ビットワードを意味すると思いますか?Xoringを使用していますか?
ルート

私の「熱心な信者」のコードを見て、私がどんな種類のハッシュ関数を使用しているかを見ることができます。基本的に、トラック外のセルをスキップし、トラック上の色を16ビットワードの高次および低次の部分と見なします。これらのワードはすべて、レジスタ内のXORで累積され、その後、ハッシュテーブルサイズで除算されます。ハッシュの最大値(65535)がテーブルサイズ(<100)よりもはるかに高い限り、モジュロの拡散力は良好です。ランダムに生成されたグリッドの幅広いセットでテストしましたが、均一性が良好なようです。

6

パスファインダー、C ++、予備スコア35.8504(50ラウンド)

完全なオーバーホール!アルゴリズムをC ++に移植して少し調整しましたが、おそらくラットが頭を壁にぶつけ続けているため、スコアはまだそれほど高くありません。これを改善しようとするのはうんざりしているので、今のところはそのままにしておきます。


int dnarange(dna_t &d, int start, int len) {
    int res = 0;
    for(int i = start; i < start+len; i++) {
        res = (res << 1) | d[i];
    }
    return res;
}

int dnasum(dna_t &d, int start, int len) {
    int res = 0;
    for(int i = start; i < start+len; i++) {
        res += d[i];
    }
    return res;
}

int dnaweight(dna_t &d, int start) {
    return d[start] + d[start+1] + 2*d[start+2] + 2*d[start+3] + 3*d[start+4];
}

int trap_d [16] = {1,0,1,1,0,1,-1,1,-1,0,-1,-1,0,-1,1,-1}; //immutable
int nhood [10] = {1,0,1,1,1,-1,0,1,0,-1}; //immutable

coord_t pathfinder(dna_t d, view_t v) {
  int is_trap[16] = {0};
  int pos_or_weight[16] = {0};
  int u_weight = dnaweight(d, 80);
  for (int i = 0; i < 16; i++) {
    int status = dnarange(d, 5*i, 2);
    if (status == 1) {
      is_trap[i] = 1;
      pos_or_weight[i] = dnarange(d, 5*i + 2, 3);
    } else {
      pos_or_weight[i] = dnaweight(d, 5*i);
    }
  }
  int w_area[7][4] = {0};
  for (int j = 0; j < 7; j++) {
    w_area[j][3] = u_weight;
  }
  for (int i = 0; i < 3; i++) {
    w_area[0][i] = u_weight;
    w_area[6][i] = u_weight;
  }
  int d_coeff = dnaweight(d, 85);
  for (int i = 0; i < 3; i++) {
    for (int j = 1; j < 6; j++) {
      int p_or_w, color = v(i, j-3);
      if (color != OUT_OF_BOUNDS) {
    p_or_w = pos_or_weight[color];
      } else {
    p_or_w = 1000;
      }
      if (color != OUT_OF_BOUNDS && is_trap[color] && i+trap_d[2*p_or_w] >= 0) {
    w_area[j + trap_d[2*p_or_w + 1]][i + trap_d[2*p_or_w]] += d_coeff;
      } else {
    w_area[j][i] += p_or_w;
      }
    }
  }
  for (int i = 3; i >= 0; i--) {
    for (int j = 0; j < 7; j++) {
      int min_w = 1000;
      for (int k = std::max(0, j-1); k <= std::min(6, j+1); k++) {
    min_w = std::min(min_w, w_area[k][i + 1]);
      }
      w_area[j][i] += min_w;
    }
  }
  int speed = dnasum(d, 90, 5);
  w_area[2][0] += 2 + speed;
  w_area[4][0] += 2 + speed;
  int goal = dnaweight(d, 95);
  int min_w = 10000;
  int sec_w = 10000;
  int min_x, min_y, sec_x, sec_y, w;
  for (int i = 0; i < 5; i++) {
    w = w_area[nhood[2*i + 1] + 3][nhood[2*i]];
    if (w < min_w) {
      sec_w = min_w;
      sec_x = min_x;
      sec_y = min_y;
      min_w = w;
      min_x = nhood[2*i];
      min_y = nhood[2*i + 1];
    } else if (w < sec_w) {
      sec_w = w;
      sec_x = nhood[2*i];
      sec_y = nhood[2*i + 1];
    }
  }
  if (min_w > goal) {
    int r = v.rng.rint(5);
    return {nhood[2*r], nhood[2*r+1]};
  } else if (sec_w <= goal && v.rng.rint(100) < 2*speed) {
    return {sec_x, sec_y};
  }
  return {min_x, min_y};
}

説明

一般的な考え方は、各色をトラップとして分類するかどうかで分類し、トラップへの方向と非トラップへの重みを割り当て、ビジョングリッドの右境界線への最小重みパスをたどることです。

ゲノムの最初の80ビットでは、各色は5ビットを使用して分類されますabcde。の場合ab = 01、色はトラップでありcde、その方向をエンコードします(8つの可能性)。の場合ab ≠ 01、色はトラップではなく、その重みはa + b + 2*(c + d + e)です。

次に、3x7グリッドを初期化します。これは、「未知の」色が埋め込まれたラットの視界を右側に表します。ビット80〜84は、トラップ以外の色と同様に未知のセルの重みをエンコードし、ビット85〜89はトラップの共通の重みをエンコードします。グリッドを重みで埋め、最短経路を計算し、サイドステッピングを防ぐために、ラットの真上と真下のセルに追加の重み(ビット90〜95でエンコード)を追加します。ビット95-99は目標の重みをエンコードします。パスの最小重量がそれより下の場合、ラットはおそらくどこかに引っかかっており、ランダムに移動します(ただし、後戻りすることはありません)。それ以外の場合、最小重量パスに従います。横抜け防止の重みに応じて小さな確率で、ラットは代わりに2番目から最小の重みの経路を選択します。これは、壁に引っかかるのを防ぐためです(しかし、今のところうまく機能していないようです)。


私のコンピューターで実装を実行しました。数時間かかりました。平均スコアは7.848433940863856ポイントです。pastebin.com/d50GcwnK
Jakube

@ジャクベありがとう!それは私が思っていたよりもはるかに悪いのですが、コードをもう一度見ると、いくつかのバグやその他の奇妙なことがわかります。これを後でC ++に移植して、自分で分析できるようにします。
ズガルブ

5

LookAheadPlayer C ++≈89.904

私の最初の考えは、探している色に一致する4ビットを探し、次の数ビットをスコアとして使用することでした。これは恐らく恐ろしいアイデアであることが判明しました。これはおそらく突然変異によるものです。

そこで、突然変異やクロスオーバーから保護する方法を考えました。それは、QRコードの解読で行ったことを思い出しました。QRコードでは、データがブロックに分割されてストライプ化され、データの特定の部分が大量に破壊されるのを防ぎます。

したがって、ColorScorePlayerのように、DNAを16のチャンクに切り分け、それらを所定のスコアとして使用します。ただし、各スコアの個々のビットが隣接しないように、スコアはストライプ化されます。次に、現在の可能な動きと次の潜在的な動きの両方のスコアを合計し、最適な動きを選択します。

注:これはMinGWでコード化/テストされました。最適化またはマルチスレッドではコンパイルされません。実際にLinuxをインストールしたり、Visual Studioを使用してこれらが機能するコンパイラを使用したりすることはできません。明日の朝すぐにテストしますが、問題が発生した場合はお知らせください。

// get striped color score, 6 bits per color. should be
// resistant to getting erased by a crossover
void mapColorsBitwise(dna_t &d, int* color_array) {
    for (int i=0; i<N_COLORS; i++) {
        int score = 0;
        for (int j=0; j<6; j++) {
            score = (score<<1) | d[ j*N_COLORS + i ];
        }
        color_array[i] = score;
    }
}

// label for the lookup tables
enum direction_lut {
    UP_RIGHT=0, RIGHT, DOWN_RIGHT
};

// movement coord_t's to correspond to a direction
static const coord_t direction_lut[3] = {
    { 1, -1 }, { 1, 0 }, { 1, 1 }
};

// indexes into the arrays to denote what should be summed
// for each direction.
static const int sum_lut[3][6] = {
    { 3, 4, 8, 8, 9, 14 }, { 9, 13, 13, 14, 14, 19 },
    { 14, 18, 18, 19, 23, 24 }
};

coord_t lookAheadPlayer(dna_t d, view_t v) {
    int scoreArray[25] = { 0 };
    int colorScores[N_COLORS] = { };

    // Get color mapping for this iteration
    mapColorsBitwise(d, colorScores);

    for (int y=-2; y<=2; y++) {
        for (int x=0; x<=2; x++) {
            // Get the scores for our whole field of view
            color_t color = v(x,y);
            if (color != OUT_OF_BOUNDS)
                scoreArray[ (x+2)+((y+2)*5) ] += colorScores[color];
        }
    }

    // get the best move by summing all of the array indices for a particular
    // direction
    int best = RIGHT;
    int bestScore = 0;
    for (int dir=UP_RIGHT; dir<=DOWN_RIGHT; dir++) {
        if (v(direction_lut[dir].x, direction_lut[dir].y) == OUT_OF_BOUNDS)
            continue;

        int score = 0;
        for (int i=0; i<6; i++) {
            score += scoreArray[ sum_lut[dir][i] ];
        }

        if (score > bestScore) {
            bestScore = score;
            best = dir;
        }
    }

    return direction_lut[best];
}

5

SlowAndSteady C ++(スコア9.7)

単一のビットフリップはその位置に応じて根本的に異なる効果を持つ可能性があるため、ゲノムのチャンクを数値として解釈することに頼ることはできません。だからこそ、単純に16個の6ビットセグメントを使用し、1s の数でスコアを付けます。最初は111111良かったし、000000悪い、と(ゲノムが完全に進化されれば)、それはDNAの初期設定では、長期的には問題does notの間、セグメントのほとんどは2-4のものを持っているので、私が使用してに切り替え9 - (#1 - 3)^2スコアリングのために、この最初のラウンドでより多くの動きの自由とより速い進化を可能にします。

今、私は7つの最も近い隣人だけを見て、カラースコアに方向バイアスを追加し、ランダムに最高の方向の1つに移動します。

スコア自体はそれほど高くはありませんが、私の生き物はフィニッシュラインに到達し、3/4のケースで1を超えています。

coord_t SlowAndSteadyPlayer(dna_t d, view_t v) {
    const int chunklen = 6;
    int color_scores[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    for(int i=0; i<16; i++){ //count ones
        for(int j=0; j<chunklen; j++){
            color_scores[i] += d[i*chunklen + j];
        }
    }

    int moves[7][2] = {
        {-1,1}, {0,1}, {1,1},
                       {1,0},
        {-1,-1},{1,-1},{-1,-1}
    };
    int movescores[7];
    int smax = -1;
    int nmax = 0;
    int best_moves[7];
    for(int m=0; m<7; m++){ //compute the score for each move
        int temp_color = v(moves[m][0], moves[m][1]);
        if(temp_color == OUT_OF_BOUNDS){
            movescores[m] = 0;
            continue;
        }
        int dir_bias[3] = {1,3,6};
        int temp_score = 9-(color_scores[temp_color]-3)*(color_scores[temp_color]-3) + dir_bias[moves[m][0]+1];
        movescores[m] = temp_score;

        if(temp_score > smax) {
            smax = temp_score;
            nmax = 0;
        }
        if(temp_score == smax) best_moves[nmax++] = m;
    }

    int best_chosen = v.rng.rint(nmax);
    return {moves[best_moves[best_chosen]][0], moves[best_moves[best_chosen]][1]};
}

そして、100枚のボードの採点サンプル

Scores: 5 4 13028 1 1 101 2 24 1 21 1 4 2 44 1 1 24 8 2 5 1 13 10 71 2 19528 6 1 69 74587 1 1 3 138 8 4 1 1 17 23 1 2 2 50 7 7 710 6 231 1 4 3 263 4 1 6 7 20 24 11 1 25 1 63 14 1 2 2 1 27 9 7 1 7 31 20 2 17 8 176 3 1 10 13 3 142 1 9 768 64 6837 49 1 9 3 15 32 10 42 8

幾何平均スコア:9.76557


1つのボードについて言及するスコアは、標準の突然変異率または調整値を使用していますか?
センモウヒラムシ

「私の生き物はフィニッシュラインに到達し、ケースの3/4で1を超えるスコアを獲得します」得点の指標がこれに報いることを願っています
Sparr

5

WeightChooser | C#| スコア:1520ゲームで220.8262

次の可能性のある動きの平均重量(青)に基づいて、次の可能性のある動きの重量(青)を計算します

using ppcggacscontroller;
using System.Linq;
using System;

public class WeightChooser
{
    public static ppcggacscontroller.Program.Coord[] cspcoords = new[] {
            new Program.Coord(1, -1),
            new Program.Coord(1, 0),
            new Program.Coord(1, 1),
        };

    const int dnaBits = 4;

    public static void move(GameLogic.IView v, GameLogic.IGenome g, Random rnd, out int ox, out int oy)
    {
        var gcrds = cspcoords.Where(c => viewVal(v, c) > -1)
            .OrderByDescending(p => getBitsSet(g, viewVal(v, p)))
            .ThenByDescending(gt => weight(v, g, gt));

        Program.Coord nextMove = gcrds.First();
        ox = nextMove.x;
        oy = nextMove.y;
    }

    private static uint getBitsSet(GameLogic.IGenome g, int vVal)
    {
        uint i = g.cutOutInt(dnaBits * vVal, dnaBits);
        i = i - ((i >> 1) & 0x55555555);
        i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
        return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    }

    private static int viewVal(GameLogic.IView v, Program.Coord c)
    {
        return v[c.x, c.y];
    }

    private static double weight(GameLogic.IView v, GameLogic.IGenome g, Program.Coord toGo)
    {
        double w = 0;

        int y = (toGo.y + v.yd) - 1;
        int i = 0;
        for (; i <= 2; i++)
        {
            int field = v[toGo.x + 1, (y + i) - v.yd];
            if (field > -1)
                w += getBitsSet(g, field);
        }

        return w / i;
    }
}

Scores: 32, 56103, 1361, 3351446, 33027, 23618, 22481, 1172713, 1, 3, 1, 1, 1, 2 88584, 106357, 1, 1232, 1, 1651280, 16690, 1, 1, 23732, 207554, 53, 69424, 1, 1,  79361, 1, 1, 51813, 229624, 25099, 2, 1, 234239, 362531, 1, 1, 19, 7295, 1, 7, 2, 196672, 1654208, 73453, 1, 23082, 1, 8, 5, 1685018, 4, 20, 1, 1, 1, 1, 1, 144 671, 122309, 10, 94752, 100895, 1, 54787, 54315, 252911, 79277, 1159, 241927, 94 347, 1, 318372, 37793, 1, 1, 1345310, 18934, 169700, 1, 1, 3, 186740, 83018, 121 758, 1, 358, 1935741, 88, 1, 1, 1, 1, 7, 21, 51144, 2, 1, 267638, 1, 1, 3, 1, 1,  1, 1, 674080, 47211, 8879, 7, 222766, 67214, 2, 89, 21038, 178463, 92846, 3, 14 0836, 1, 1, 111927, 1, 92165, 1, 192394, 1, 1, 2563722, 1, 42648, 1, 16, 1, 1, 2 85665, 1, 212653, 1, 4, 20513, 3, 135118, 13161, 2, 57, 78355, 3, 3, 44674, 8, 1 , 226472, 1, 1, 31588, 19619, 1, 2931870, 60814, 1, 1, 33867, 60740, 20558, 1, 1 5, 3, 5, 1, 1, 1, 60737, 450636, 468362, 1, 1, 347193, 91248, 551642, 1, 427215,  1, 57859, 17, 15, 66577, 24192, 1, 63560, 6568, 40279, 68216, 23098, 180732, 1,  1, 3041253, 1, 253488, 60535, 1, 1, 150838, 7361, 72855, 290699, 104644, 1, 763 01, 378, 1, 89220, 1, 262257, 2, 2, 1, 117, 105478, 33, 1, 65210, 1, 117588, 1, 1, 24320, 12, 3714568, 81152, 1, 1, 10125, 2, 1, 22, 1, 45201, 1, 1, 10518, 1, 1 , 1, 1, 34, 210021, 1, 1, 1, 65641, 6, 72, 1, 7, 2, 161578, 1, 1, 38378, 1, 4113 741, 1, 34450, 244212, 127660, 1, 256885, 46, 2, 1, 1, 103532, 1, 503965, 114774 , 52450, 124165, 73476, 50250, 1, 3, 3755352, 24928, 1, 1, 51, 11, 1, 210580, 1,  62375, 1, 1, 92745, 341232, 167675, 86, 242, 293710, 454841, 1, 49840, 4456758,  121378, 145323, 74904, 5048, 25459, 1, 57, 116999, 1, 1, 76074, 111447, 95706, 1, 1, 52631, 166756, 2159474, 161216, 1, 2, 3, 11904, 1, 22050, 6, 1, 1, 1, 41, 48908, 6, 80878, 28125, 28, 160516, 1, 4, 1, 8, 1, 1, 7, 362724, 1, 397193, 1, 2 5, 1, 59926, 3, 74548, 2320284, 470189, 1, 108, 1, 1, 16, 1, 496013, 1, 1, 1, 1,  107758, 1, 284144, 146728, 1, 70769, 94215, 1, 1, 9961, 97300, 7, 1, 76263, 1, 27, 294046, 40, 8, 2, 1, 57796, 2, 79800, 1043488, 470547, 1, 1, 1, 6, 69666, 8,  1, 1, 344011, 205325, 3963186, 1141527, 61598, 446029, 1, 1, 1, 1, 625247, 1877 92, 136391, 1, 72519, 1, 141168, 412, 98491, 103995, 297052, 1, 1, 1, 1, 3, 17, 9, 62899, 5, 47810, 254, 26789, 2, 1, 1, 3, 10361, 19615, 40430, 17288, 3, 71831 , 41374, 1, 91317, 409526, 1, 184305, 1, 192552, 3, 3587674, 39, 13, 134500, 41,  42, 672, 559835, 9, 39004, 51452, 1, 1, 12293, 11544, 265766, 8590, 1, 8632, 1,  1, 61849, 35155, 1, 74798, 72773, 1, 89, 37, 4, 4405882, 1, 99, 44397, 5, 4, 6,  1, 1, 1, 515818, 78383, 20, 127829, 1824801, 157, 1, 1, 268561, 19, 2, 230922, 1, 103, 98146, 5029789, 304324, 1, 5, 60516, 1, 139, 28982, 7, 20755, 187083, 1,  1, 143811, 37697, 1, 1, 269819, 83, 1, 202860, 13793, 16438, 113432, 1, 1, 2, 5 134384, 29, 84135, 39035, 2, 125, 1, 30, 129771, 41982, 13548, 61, 1, 2, 1, 82, 102, 2, 105581, 210399, 291204, 3012324, 1, 84763, 1, 1, 442067, 2, 1, 1, 1, 116 , 1, 3, 3, 56, 208807, 1, 2, 1, 14, 29, 31286, 1, 1, 162358, 28856, 46898, 1, 16 2698, 1, 1, 1, 65, 1, 1, 234566, 6, 1, 1, 128, 124, 2167692, 181946, 29, 1, 1, 1 , 1, 17, 162550, 179588, 4, 226480, 28, 1, 158512, 35084, 1, 26160, 17566, 1, 81 826, 2, 33, 1, 1, 11, 1, 230113, 1, 1, 1, 24405, 17, 1, 2, 1, 162365, 2, 1, 1, 8 5225, 1, 15016, 51509, 1, 5, 1, 93, 13, 59, 24548, 1, 3, 2, 2, 1, 64424, 1, 1, 4 , 1, 1, 1, 2, 267115, 139478, 52653, 96225, 1, 1, 35768, 3, 1, 1, 3280017, 8, 80 014, 43095, 112102, 1, 1, 1, 79594, 5, 1, 1, 4, 455714, 19, 15, 1, 233760, 55850 5, 2, 2, 1, 63672, 1, 3732951, 1, 135858, 134256, 452456, 151573, 79057, 638215,  88820, 1, 1, 76517, 13, 314006, 5, 1, 17704, 1, 79589, 1, 18371, 530793, 59020,  1, 1, 1, 4, 1, 1, 1, 71735, 1, 1, 1, 1, 1, 37894, 1, 2, 24054, 1, 8, 26471, 34,  1, 48033, 5, 3, 1, 25, 101, 1, 1, 5, 1, 1, 1, 97521, 1, 682817, 286486, 5, 1472 4, 1, 7805226, 6, 1, 1, 1, 7, 2, 1, 1, 1, 25, 233330, 1, 20899, 3417337, 92793, 23, 80821, 1, 1, 115948, 264191, 3, 79809, 1, 2, 59531, 2, 1, 1, 28684, 97, 1, 2 69433, 98769, 1, 76608, 138124, 1, 1, 325554, 122567, 1, 1, 3, 689604, 4, 85823,  66911, 138091, 169416, 21430, 1, 2, 486654, 108446, 93072, 1, 67907, 4, 1, 1, 5 2260, 67867, 210496, 25157, 1, 1, 1, 5477, 2, 2, 11907, 106, 48404, 1, 1, 1, 787 11, 190304, 112025, 1, 9313, 143055, 40189, 315537, 157581, 70714, 6, 180600, 38 594, 103658, 59444, 7, 31575, 1, 1, 581388, 370430, 1, 114446, 1, 1, 2, 3968, 1,  1, 1, 1, 1, 4523411, 1, 1, 270442, 1, 59, 235631, 3, 110196, 9, 1, 93724, 1, 22 917, 1, 6, 1, 2350266, 1, 1, 20, 4686858, 31, 1, 240180, 10, 470592, 3, 61051, 1 45372, 2831, 64052, 10, 120652, 255971, 479239, 1, 387659, 1, 1, 1, 378379, 7, 3 3218, 55914, 1, 1, 1667456, 6, 2, 74428, 3, 2, 1, 121582, 121274, 19651, 59899, 1, 11, 406670, 137835, 100269, 2, 164361, 98762, 44311, 25817, 178053, 31576, 1,  8, 2539307, 121430, 1, 41001, 1, 4, 1, 116258, 91101, 1, 126857, 1, 8, 49503, 1 , 489979, 12, 500332, 1, 52, 4, 8786, 4, 4878652, 12354, 27480, 89115, 87560, 11 793, 5, 1, 4702325, 301188, 1, 1, 1, 1, 1, 416520, 49357, 230103, 24497, 1, 3, 2 , 57366, 183021, 1, 1, 1, 1, 1, 2, 2, 2546229, 1, 2, 38665, 1, 6903, 1, 89519, 9 5119, 64879, 1, 1, 160380, 474336, 3107, 1, 7, 29099, 28667, 3, 196933, 35979, 1 2924, 7, 1, 99885, 6, 1, 1, 1, 7, 1, 1, 1, 1, 65727, 1, 1, 1, 1, 2108110, 3, 107 811, 23818, 701905, 1, 156034, 32, 1, 29, 143548, 1, 67665, 4612762, 1, 3, 20, 1 , 1, 9, 28543, 1, 1, 1, 30978, 9, 1, 19504, 79412, 15375, 763265, 1, 352373, 193 045, 1, 4570217, 9, 1, 6, 29180, 90030, 1, 1, 1, 1, 1, 93, 1, 100889, 1, 1, 37, 15, 17, 1, 81184, 1, 2, 272831, 1, 137, 1, 9, 42874, 679183, 1, 350027, 12, 1, 2 , 1, 26408, 1, 11182, 1, 30, 139590, 7, 3, 1, 1, 34729, 1, 2, 1, 1, 50343, 66873 , 3891, 1, 148952, 1, 1, 22322, 104176, 1, 3, 20549, 140266, 37827, 30504, 17, 6 8588, 120195, 1, 123353, 2, 64301, 11, 1, 109867, 4, 1, 1, 1, 28671, 1, 50963, 5 4584, 1, 1, 1, 33, 1, 381918, 1, 265823, 4771840, 155179, 314, 134086, 1, 1, 30,  1, 2, 1102665, 18, 132243, 3861, 1, 1, 208906, 60112, 1, 1, 1, 31273, 551, 3490 0, 2, 43606, 1, 1, 1, 1, 5, 2, 88342, 2, 1, 19, 3, 1, 1, 1, 1, 28507, 1, 491467,  1, 1, 22, 1, 1, 1, 1, 9345, 9, 18, 84343, 1, 2, 1, 18, 36816, 1, 1, 513028, 287 88, 5037383, 721932, 170292, 108942, 539115, 1, 575676, 20, 1, 31698, 99797, 205 21, 380986, 1, 1, 14, 2, 1, 201100, 30, 1, 119484, 1, 1, 1, 1, 2214252, 3, 4, 18 179, 9, 4, 542150, 1, 6, 157, 3182099, 4, 1, 1, 6140, 3339847, 498283, 52523, 1,  1, 1, 1, 1, 202054, 263324, 1, 6, 2, 1, 2, 72357, 12, 5, 66, 4, 7368, 1, 30706,  61936, 3945270, 138991, 1, 68247, 1, 1, 30482, 35326, 1, 1, 9, 1, 148, 1, 46985 , 1, 4325093, 1, 1, 2880384, 65173, 1, 56581, 179178, 372369, 56187, 3, 12, 8, 4 00743, 3, 28658, 1, 1, 9, 1, 4, 2, 34357, 1, 42596, 68840, 2, 62638, 158027, 617 34, 71263, 1, 1, 9, 1, 6830309, 3, 1, 1, 157253, 129837, 9, 5008187, 48499, 5981 3, 1, 40320, 233893, 5, 1383, 7732178, 16, 1, 13, 5686145, 84554, 1, 79442, 1, 1 , 256812, 127818, 31, 226113, 1, 4, 1, 1, 4506163, 1, 4, 1, 40176, 19107, 205, 2 7, 1, 448999, 1, 1, 2750, 62723, 1, 12, 1, 1, 79881, 1, 48, 13, 4, 1, 28765, 1, 33, 291330, 30817, 2, 1, 1, 1, 4170949, 16, 1, 1, 118781, 10473, 520797, 1, 8, 1 , 80215, 1, 21759, 5143209, 79141, 40229, 1, 17403, 71680, 1115694, 1, 1, 1, 10,  1, 77149, 382712, 1, 11, 84891, 47633, 1, 2, 39037, 1, 213148, 1607280, 127674,  1, 333207, 1, 78901, 1, 16203, 87580, 1, 1565571, 537902, 53000, 15, 1, 2, 1, 2 13127, 1, 338634, 2469990, 469479, 9519, 51083, 1, 42082, 33179, 1, 1, 32444, 3,  1, 201642, 99724, 377, 1, 2, 1, 36919, 1, 322707, 2, 164765, 82516, 1, 5274643,  1, 36421, 1, 8, 1, 117856, 1, 1, 493342, 1, 36289, 7, 1, 62, 2, 1, 38533, 1, 68 , 45754, 9, 102015, 312941, 1, 99 
Final score is 220.826222910756

5

RATS IN ACTION(答えではなく、C ++ボット用のグラフィックツール)

この挑戦が始まって以来、私はネズミが実際にコース上で直面しているものを理解するのに苦労しました。
最後に、コントローラーをハックし、トラックのグラフィック表現を得るためのサイドツールを作成しました。
最終的にはさらにハッキングを行い、特定のラットのDNAの可能な経路の視覚化を追加しました。

マップは非常に雑然としており、少し慣れる必要がありますが、ボットがどのように機能するかを理解することは非常に役立ちました。

以下に例を示します。

サンプルトラック

おそらく何かを見るためにズームインする必要があるので、ここは前半だけです:

ハーフトラック(しゃれなし)

まず、ネズミの道を見てみましょう。考えられる開始場所ごとに1つのパスがあります(通常は15、少し少ない場合があります)。通常、それらは合併する傾向があり、理想的には単一の勝利場所につながります。

パスは大きな直線の矢印で表されます。色は結果を説明します:

  • 緑:勝つ
  • 黄色:無限ループ
  • 茶色:壁をたたく
  • 赤:不運な事故

この例では、12の勝利開始位置があり、1つは無限ループにつながり、2つは厳しい死になります(表示されるとおり、トラップにテレポートされます)。

パスの不連続性はテレポーテーションによるものであり、対応する曲線矢印で追跡できます。

さて、色付きのシンボルについて。それらは16色の意味を表します(灰色はラットが見るものを表します)。

  • 壁:正方形
  • テレポーター:4分岐星
  • トラップ検出器:小さな八角形

空の色は...まあ...空です。

テレポーターには、目的地を指す外向きの矢印があります。

トラップ検出器には、トラップを示す矢印もあります。これは赤い円で示されています。
9個のうち1個の場合、トラップは検出器と同じセルにあります。その場合、赤い円の上に小さな八角形が表示されます。

この例の淡黄色トラップの場合です。
また、示されたトラップを指している藤色のトラップ検出器を見ることができます。

トラップの赤い円が壁の下に隠れることがあることに注意してください。どちらも致命的であるため、テレポーテーションの場合でも結果は同じです。
また、トラップがテレポーターに配置されている可能性があることに注意してください。この場合、テレポーターが優先されます(つまり、ネズミはトラップに落ちる前にテレポートされ、実際にトラップを無効にします)。

最後に、灰色のシンボルは、私のラットが見るものを表します(つまり、ゲノムの色の属性の意味)。

  • 壁:正方形
  • トラップ検出器:オクトゴン
  • トラップ:X

基本的に、灰色の正方形に座っているすべての細胞は、ラットによって壁と見なされます。
Big Xはトラップと見なされるセルを表し、対応するオクトゴンはそれらを報告した検出器を示します。

この例では、淡い黄色のトラップのように、両方の壁がそのように識別されています(実際に致命的なセルを示しているため、壁として正しいことを表します)。
モーブトラップ検出器はそのように識別されています(灰色の八角形の上にあります)が、トラップの位置は正しくありません(一部の赤い円の下に十字がないことがわかります)。

4つのテレポーターのうち、2つは壁(青緑色と黄褐色)と見なされ、2つは空のセル(赤と黄色)と見なされます。

いくつかの空のセルは、トラップ検出器または壁と見なされます。よく見ると、これらの「欠陥検出器」は、実際にラットに問題を引き起こすセルへの侵入を禁止しているため、実際の色と一致しなくても明確な目的を持っていることがわかります。

コード

まあそれは混乱ですが、かなりうまく機能します。

プレーヤーのコードから見ると、インターフェイスを1つだけ追加しました。特定のDNAの意味を報告するために使用されるトレース関数です。私の場合、3つのタイプ(壁、トラップ検出器、および空)を使用しましたが、基本的には色に関連するものを出力できます(ゲノム関連のグラフィックスが必要ない場合はまったく出力できません)。

コントローラーをハッキングして、トラックと色の説明を、すべての可能な場所からのラットのDNAの「ドライラン」と照合する巨大な文字列を生成しました。

これは、ボットがランダムな値を使用しない場合にのみ、結果が本当に意味を持つことを意味します。それ以外の場合、表示されるパスは1つの可能な結果のみを表します。

最後に、これらのトレースはすべて大きなテキストファイルに入れられ、後でグラフィック出力を生成するPHPユーティリティによって読み取られます。

現在のバージョンでは、新しい最大適応度に達するとラットが死亡するたびにスナップショットを撮ります(これは、あまりにも多くのスナップショットを必要とせずにゲノムの漸進的な改良を示しています)。最も成功したDNA)。

誰かが興味を持っているなら、コードを公開できます。

明らかに、これはC ++ボットでのみ機能しゲノム固有のデータ(私の場合は灰色の数字)を表示する場合は、トレース関数を作成し、PHPコードを変更する必要があります。
DNA固有の情報がなくても、ごくわずかな労力で特定のマップ上でDNAがたどるパスを確認できます。

なぜ中間出力なのか?

何よりもまず、C ++には、特にMSVCを使用する場合には、適切なポータブルグラフィックライブラリがありません。Win32ビルドが通常利用可能であるとしても、それらはしばしば後から付け加えられるものであり、必要な外部ライブラリ、パッケージ、およびその他のUnixに似た機能の数により、迅速でシンプルなグラフィカルアプリケーションの作成が人の体の一部のひどい痛みになります。ネーミングから。

私はシンプルでも、快適な作業、私見++ CでポータブルGUI /グラフィカルな開発を行うだけで環境についてのQtを(使用して考えられて-それは、メッセージングシステム追加、おそらくので、ラà Cが痛んで欠け++のObjective Cを、制限メモリの信じられないほどの仕事をしていませんしかし、これは手近なタスクのやりすぎのように見えました(そして、コードを使用したい人は誰でも大きなSDKをインストールする必要があります-努力の価値はほとんどないと思います)。

ポータブルなライブラリを想定していても、話す必要のある速度はありません(写真を作成するのに1秒程度で十分です)。

さらに、中間テキスト出力を使用すると、柔軟性が大幅に向上します。データがそこにあれば、それらを他の目的に使用できます(たとえば、ボットのパフォーマンスの分析)。

なぜPHPなのか?

この言語は非常にシンプルで順応性があり、プロトタイピングに非常に便利です。極端なパフォーマンスを必要としないコードチャレンジのために、それを私の母国語にしました。
しかし、ゴルフはひどい言葉ですが、ゴルフは決して私のお茶ではありませんでした。

私はpythonやRubyも同じ目的で使用するのと同じくらい楽しいと思いますが、私はそれらを使って真剣な仕事をする機会がなかったので、最近Webサイトで作業していました。

言語がわからなくても、ニーズに合わせてコードを変更するのはそれほど難しくないはずです。$古き良き基本的な日と同じように、変数の前にあるsを忘れないでください:)。


1
ツールを共有してください。あなたの答えにはコードもリンクもありません。
フランキー

5

SkyWalker-Python-50ゲームで231未満のスコア

したがって、最初にコーディングしてから、いくつかの説明を行います。コピー中に何も壊れないことを願っています。

class SkyWalker(Player):
    def __init__(self):
        Player.__init__(self)
        self.coords = [#Coordinate(-1,-1),
                       #Coordinate( 0,-1),
                       Coordinate( 1, 0),
                       Coordinate( 1,-1),
                       #Coordinate(-1, 0),
                       #Coordinate( 0, 0),
                       #Coordinate(-1, 1),
                       #Coordinate( 0, 1),
                       Coordinate( 1, 1)]

        self.n_moves = len(self.coords)

    def visionToMove(self, x, y):
        x = x - 2
        y = y - 2

        return (x, y)

    def trapToMove(self, x, y, offx, offy):
        x = x - 2 + (offx % 3) - 1
        y = y - 2 + (offy % 3) - 1
        return (x, y)

    def isNeighbour(self, x1, y1, x2, y2):
        if (x1 == x2) or (x1+1 == x2) or (x2+1 == x1):
            if (y1 == y2) or (y1+1 == y2) or (y2+1 == y1):
                return True
        return False

    def calcMove(self, donots, never, up):
        forwards = {(1, 0): 0, (1, 1): 0, (1, -1): 0, (0, 1): 10, (0, -1): 10}

        for key in forwards:
            if key in never:
                forwards[key] = 100
            for x in donots:
                if (key[0] == x[0]) and (key[1] == x[1]):
                    forwards[key] = 20

        min_value = min(forwards.itervalues())
        min_keys = [k for k in forwards if forwards[k] == min_value]

        return random.choice(min_keys)

    def turn(self):
        trap1 = self.bit_chunk(0, 4)
        trap1_offsetx = self.bit_chunk(4, 2)
        trap1_offsety = self.bit_chunk(6, 2)
        trap2 = self.bit_chunk(8, 4)
        trap2_offsetx = self.bit_chunk(12, 2)
        trap2_offsety = self.bit_chunk(14, 2)
        wall1 = self.bit_chunk(16, 4)
        wall2 = self.bit_chunk(20, 4)
        tel1 = self.bit_chunk(24, 4)
        tel1_good = self.bit_chunk(28, 3)
        tel2 = self.bit_chunk(31, 4)
        tel2_good = self.bit_chunk(35, 3)
        tel3 = self.bit_chunk(38, 4)
        tel3_good = self.bit_chunk(42, 3)
        tel4 = self.bit_chunk(45, 4)
        tel4_good = self.bit_chunk(49, 3)
        up = self.bit_at(100)

        donots = []
        never = []

        for y in range(0, 5):
            for x in range(0, 5):
                c = self.vision[y][x]
                if (c == -1):
                    never += self.visionToMove(x, y),
                elif (c == trap1):
                    donots += self.trapToMove(x, y, trap1_offsetx, trap1_offsety),
                elif (c == trap2):
                    donots += self.trapToMove(x, y, trap2_offsetx, trap2_offsety),
                elif (c == wall1):
                    donots += self.visionToMove(x, y),
                elif (c == wall2):
                    donots += self.visionToMove(x, y),
                elif (c == tel1):
                    if (tel1_good > 3):
                        donots += self.visionToMove(x, y),
                elif (c == tel2):
                    if (tel2_good > 3):
                        donots += self.visionToMove(x, y),
                elif (c == tel3):
                    if (tel3_good > 3):
                        donots += self.visionToMove(x, y),
                elif (c == tel4):
                    if (tel4_good > 3):
                        donots += self.visionToMove(x, y),

        coord = self.calcMove(donots, never, up)

        return Coordinate(coord[0], coord[1])

いくつかの説明

私の意見では、主な違いはすべての色をコーディングしているわけではないということです。代わりに、重要な色の数を保存しようとします。私の意見では、これらの色はtrap、壁、テレポーターです。標本は良い細胞の色を知る必要はありません。したがって、私のゲノムは次のように構成されています。

  • トラップ用の2 x 8ビット、最初の4ビットは色番号、他の4ビットはオフセット
  • 壁用の2 x 4ビット、色のみ
  • テレポーターの場合は4 x 7ビット、色の場合は4ビット、良いか悪いかを判断するには3ビット

これにより、合計52ビットが使用されます。ただし、3つのテレポーター決定者の最初のビットのみを使用します(数値が3より大きいかどうかを確認します)。したがって、残りの2つは削除され、44ビットが使用されたままになります。

各ターンで、視野のすべてのフィールドが悪い色(+ボード外-1)であるかどうかを確認し、標本が移動したくないフィールドのリストに追加します。トラップの場合、そのトラップカラーの保存済みオフセットにあるフィールドを追加します。

これらの不良フィールドのリストに基づいて、次の動きが計算されます。優先フィールドの順序は次のとおりです。

  1. 進む
  2. 上か下
  3. 後方に上下
  4. 後方に

カテゴリの2つのフィールドが該当する場合、1つがランダムに選択されます。

結果

Individual scores: [192, 53116, 5, 1649, 49, 2737, 35, 5836, 3, 10173, 4604, 22456, 21331, 445, 419, 2, 1, 90, 25842, 2, 712, 4, 1, 14, 35159, 13, 5938, 670, 78, 455, 45, 18, 6, 20095, 1784, 2, 11, 307853, 58171, 348, 2, 4, 190, 7, 29392, 15, 1158, 24549, 7409, 1]
On average, your bot got 231.34522696 points

考え

  • 50回のランでラッキーになったのか、実際に私の戦略に何らかの知恵があるのか​​、私にはわかりません。

  • 私のランニングは決して離陸して超ハイスコアを獲得することはないようですが、少なくとも数回はゴールを見つける傾向があります

  • いくつかの小さなランダム性は、レースの終わり近くでトラップに巻き込まれないようにするのに適しています

  • 特別な色は決して悪くないと思います。ただし、トラップのオフセット上にある場合、それらのインスタンスは不良になる可能性があります。したがって、トラップ、壁、またはテレポーターでない場合、色に悪いラベルを付けても意味がありません。

  • 壁は最大の敵です

改善点

まず、目標に近づくにつれて黒い四角が見えなくなってしまいますが、より多くのテストを実行し、より意味のある結果を得るには、C ++ポートが必要です。

主な問題の1つは、ラットの前に悪い細胞(または標本が悪いと思う細胞)があると、簡単に円を描いて上下に動き始めることです。これらの場合、前方に2移動することにより、これを停止または削減し、再び戻るだけのフィールドに移動しないようにすることができます。

多くの場合、良い遺伝子を持つラットが目標に到達し、遺伝子を広め始めるまでにはかなり時間がかかります。そのような場合に多様性を高めるための戦略が必要かもしれません。

テレポーターは計算するのが難しいので、リスクのある人と常に良いテレポーターを使用する人と、他の選択肢がない場合にのみそれらを使用する人に人口を分割する必要があります。

どういうわけか私のゲノムの後半を使うべきです。


私も色を保存しようとしますが、最終的には倍になるので機能しないと結論付けました。たとえばself.bit_chunk(16, 4)self.bit_chunk(20, 4)値の両方持っている0010あなたが効果的に2つのだけのトラップの1に関する情報を格納しています。
ルート

これを実行するには、1行にインデントを追加する必要がありました-コピーアンドペースト中にインデントが失われたと思います。ここでもコードに追加しました。
trichoplax

これを実行したい人は誰でも:Python 2で実行され、Python 3で単一のオカレンスを変更することで実行できます itervaluesvalues
-trichoplax

私は次の結果を得ました:[6155、133、21、12194、8824、3、3171、112、111425、3026、1303、9130、2680、212、28、753、2923、1、1、4140、107、1256 、90、11、104、1538、63、917、8、1、709、11、304、212、2、43、5、4、206、8259、75、28、7、1、11、5、1 、1244、1398、13]幾何平均122.9220309940335
trichoplax

信頼できるスコアを得るには、50以上のゲームを実行する必要があるようです。
-trichoplax

3

Python、NeighborsOfNeighbors、スコア= 259.84395、100ゲーム以上

これはColorScorePlayerのバリエーションです。6ビットごとに正方形の品質スコアが格納されます。ボットが移動するとき、3つの前方の正方形(斜め上、前方、斜め下)のそれぞれにスコアを付けます。スコアは、正方形の品質に次の3つの正方形の平均品質の半分を加えたものです。これにより、最初の正方形の品質を圧倒することなく、ボットにいくつかの先を見越せます。アルゴリズムはLookAheadPlayerに似ていますが、このソリューションを書く前には見ていませんでした。

class NeighborsOfNeighbors(Player):
  def __init__(self):
    Player.__init__(self)
    self.coords = [ Coordinate( 1, 0),
                    Coordinate( 1,-1),
                    Coordinate( 1, 1)
                    ]

  def turn(self):
    scores=[self.score(c.x,c.y)+0.5*self.adjacentScore(c.x,c.y) if self.vision_at(c.x,c.y)>-1 else None for c in self.coords ]
    max_score = max(scores)
    return random.choice( [c for s,c in zip(scores,self.coords) if s==max_score] )

  def adjacentScore(self,x,y):
    adjacent = [(x+1,y)]
    if self.vision_at(x,y+1)>-1:
      adjacent+=[(x+1,y+1)]
    if self.vision_at(x,y-1)>-1:
      adjacent+=[(x+1,y-1)]
    adjscores=[self.score(a,b) for a,b in adjacent]
    return sum(adjscores)/float(len(adjscores))

  def score(self,x,y):
    return -1 if self.vision_at(x,y) == -1 else self.bit_chunk(6*self.vision_at(x,y),6)

1行にインデントがありません。貼り付けたときに失われたと思います。追加しました。
trichoplax

Python 3で実行すると、max(scores)を計算するときにNoneを比較することについて不平を言いました。そこで、前の行に変更else Noneelse 0てスコアを計算しました。願わくば、これでロジックが変更されないことを願っています(失われたインデントを追加する以外、SEのコードは変更していません)。
-trichoplax

Python 3で実行すると、この回答に対して次のスコアが得られました:[1、13085、360102、1、73713、1、189、1、1、193613、34、195718、199、8、1、1、60006、66453、 2、2、53、425206、1、4、1、1、16、153556、1、18134、35655、1、4211684、2、1、26451、8、1、724635、69242、38469、796553、111340、 1、25、40017、76064、66478、209365、3925393]
-trichoplax

428.3750848244933の幾何平均
trichoplax

2

ROUS(異常なサイズのRo歯類)、Java、スコア= 0

これは周囲を急ぎ、どこへ行くかを決定します。 Javaコントローラーが機能しないため、このスコアはありません。これは、それを助けるテレポーターを数人見つけた場合にのみ非常に遠くなります。これは絶滅する傾向があり、時々コントローラーをクラッシュさせます。これはおそらく、自然環境が火の沼であるという事実によるものです。

import java.awt.*;
import java.util.Map;

public class ROUS extends Player{

    private static final int NUMBER_OF_GENES = 33;
    private static final int GENE_SIZE = 3;
    private static final Point[] coords = new Point[]{
        new Point(-1, -1),
        new Point(-1, 0),
        new Point(-1, 1),
        new Point(0, -1),
        new Point(0, 1),
        new Point(1, -1),
        new Point(1, 0),
        new Point(1, 1)
    };

    public Point takeTurn(String dna, Map<Point, Integer> vision){
        Point[] table = decode(dna);
        int hash = hash(vision);
        return table[hash];
    }

    private int hash(Map<Point, Integer> surroundings) {
        return Math.abs(surroundings.hashCode()) % NUMBER_OF_GENES;
    }

    private Point[] decode(String dna) {
        Point[] result = new Point[NUMBER_OF_GENES];

        for (int i = 0; i < NUMBER_OF_GENES; i++){
            int p = Integer.parseInt(dna.substring(i * GENE_SIZE, (i + 1) * GENE_SIZE), 2);
            int x;
            int y;

            result[i] = coords[p];
        }
        return result;
    }
}

1
Javaコントローラは現在機能しています。
マーティンエンダー

3
最初はあなたが古代ロシアに敬意を払っていると思っていましたが、それはロブ・ライナーに見えたようです。

可能な最小スコアは1
trichoplax

@trichoplax ...コントローラーをクラッシュ
...-TheNumberOne

なるほど-それは頻繁に起こるので、あなたはランの終わりに達することができませんか?
trichoplax

2

グレーカラー先読み(C ++、〜1.35)

これは平均してあまりうまくいっていませんが、まれに見事に動作します。残念ながら、最大スコア(20077)ではなく、幾何平均(1.35)でスコアリングされています。

このアルゴリズムは、4ビットのグレーコードを使用して各色のスコアを-2から2の範囲にマッピングし(範囲[-1..1]にバイアスをかけます)、各ムーブのタイルと次のムーブのスコアを計算します。 。また、2ビットグレーコードを使用して、タイル自体の乗数と右に移動するためのバイアス係数を決定します。(グレーコードは、突然変異による大きなジャンプの影響をはるかに受けにくいですが、ミッドコードポイントのクロスオーバーには実際には何の利点もありません...)

また、トラップを特別に処理しようとすることはまったくありません。これが失敗の可能性があると思われます(ただし、この理論をテストするためにコントローラーにインストルメンテーションを追加していません)。

可能な動きごとにスコアを決定し、スコアが最も高いすべての動きの中からランダムに選択します。

coord_t colorTileRanker(dna_t d, view_t v) {
    const int COLOR_OFFSET = 0; // scores for each color (4 bits each)
    const int SELF_MUL_OFFSET = 96; // 2 bits for self-color multiplier
    const int MOVE_MUL_OFFSET = 98; // 2 bits for move-forward multiplier

    static const int gray2[4] = {0, 1, 3, 2};
    static const int gray3[8] = {0, 1, 3, 2, 7, 6, 4, 5};

    // bias factor table
    const int factorTable[4] = {0, 1, 2, 1};

    const int selfMul = factorTable[gray2[dnaRange(d, SELF_MUL_OFFSET, 2)]]*2 + 9;
    const int moveMul = factorTable[gray2[dnaRange(d, MOVE_MUL_OFFSET, 2)]] + 1;

    // scoring table for the color scores
    static const int scoreValue[8] = {0, 1, 2, 3, 4, 3, 2, 1};

    std::vector<coord_t> bestMoves;
    int bestScore = 0;

    for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= -1; y++) {
            const int color = v(x, y);
            if ((x || y) && (color >= 0)) {
                int score = 0;

                // score for the square itself
                score += selfMul*(scoreValue[gray3[dnaRange(d, COLOR_OFFSET + color*3, 3)]] - 2);

                // score for making forward progress;
                score += moveMul*(x + 1);

                // score for the resulting square's surrounding tiles
                for (int a = -1; a <= 1; a++) {
                    for (int b = -1; b <= 1; b++) {
                        const int color2 = v(x + a, y + b);
                        if (color2 >= 0) {
                            score += scoreValue[gray3[dnaRange(d, COLOR_OFFSET + color2*3, 3)]] - 2;
                        }
                    }
                }

                if (score > bestScore) {
                    bestMoves.clear();
                    bestScore = score;
                }
                if (score >= bestScore) {
                    bestMoves.push_back({x, y});
                }
            }
        }
    }

    if (bestMoves.empty()) {
        return {v.rng.rint(2), v.rng.rint(3) - 1};
    }
    return bestMoves[v.rng.rint(bestMoves.size())];
}

私の最新の実行では、スコアを取得しました:1 1 1 1 1 1 1 1 46 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 20077 1 1 1 2 1 1 1 1 1 1

20077の数を増やし、1の数を減らしたいと思います。:)


1
グレイコードを使用することは、グレイトアイデアです!;)
マトビッチ

1
グレーコードの場合は+1。しかし、完全に変異耐性のゲノムは、多様性をかなり傷つけます。また、20.000のスコアは、達成できる最大値に近づきません。一部のラットが可能な開始位置からトラックを実行する機能を進化させた場合、実質的に不死になり、巨大なフィットネススコアを獲得します。そのゲノムはすぐに優勢になり、最大5万匹近くのラットの個体群と数百万のスコアをもたらします。

2

C ++、TripleScore、スコア:100〜400

まず第一に、私のスコアは複数の実行で大きく異なります(主に1の数のため)。

コアは、上方向、下方向、上方向、順方向、下方向の5つの方向のスコアを計算します。最初に上下のスコアが計算され、結果が所定の位置にとどまることの値と比較されます。所定の位置にとどまることが、上下に移動するよりも優れている場合、これらの方向は選択されません(したがって、前進する必要があります)。これは、2つのスポット間のバウンス(上、下、上、下、...)を防ぐためです。

これで、他の3つの方向、つまり、上向き、まっすぐ、および下向きがスコアリングされます。調査したすべての方向から、最高スコアの方向が保持され、そのうちの1つがランダムに選択されます。

方向のスコアリング:TripleScoreは、3つのサブスコアを使用して動きのスコアを計算します。

  • 宛先の色のスコア(colorScorePlayerのようにdnaに依存)
  • 今後のスコア(DNAに依存)
  • 宛先から前方へ移動する最大スコア(dnaに格納されている係数を乗算)

他の回答と同様に、スコアは返される1スコアの数に大きく依存します。

#define CHUNKSIZE 5 //We have 20 values so 5 bits/value
#define MAXVALUE 32 //2^CHUNKSIZE
#define AVGVALUE MAXVALUE/2

#define DNASEGMENT(dna, i) dnarange(dna, i*CHUNKSIZE, CHUNKSIZE)
#define DNA_COLOR 0
#define DNA_FORWARD 16
#define DNA_LOOKAHEAD 17

//Get the score for a specific move
int calcscore(dna_t dna, view_t view, int x, int y, bool final){
  if (view(x,y) == OUT_OF_BOUNDS){
    //We cant go there
    return -MAXVALUE;
  }
  //The score of the color
  int s = DNASEGMENT(dna, DNA_COLOR+view(x,y))-AVGVALUE;
  //The score of going forward
  s += x*DNASEGMENT(dna, DNA_FORWARD);

  //Get the children or not
  if (!final){
    int max=-MAXVALUE;
    int v;
    //Get the maximum score of the children
    for (int i=-1; i<2; ++i){
        v = calcscore(dna, view, x+1, y+i, true);
        if (v>max){
            max=v;
        }
    }
    //Apply dna factor to the childs score
    s += (max * DNASEGMENT(dna, DNA_LOOKAHEAD))/AVGVALUE;
  }
  return s;
}

coord_t TripleScore(dna_t dna, view_t view) {
  int maxscore = -100;
  int score;
  coord_t choices[5]; //Maximum 5 possible movements
  int maxchoices = 0;
  int zeroscore = calcscore(dna, view, 0, 0, false);

  //Go over all possible moves and keep a list of the highest scores
  for (int x=0; x<2; ++x){
    for (int y=-1; y<2; ++y){
        if (x | y){
            score = calcscore(dna, view, x, y, false);
            if (score > maxscore){
                maxscore = score;
                choices[0] = {x, y};
                maxchoices = 1;
            }else if (score == maxscore){
                choices[maxchoices++] = {x, y};
            }
        }
    }
    if (!x && maxscore <= zeroscore){
        //I will NOT bounce!
        maxscore = -100;
    }
  }

  return choices[view.rng.rint(maxchoices)];
}

2

Ruby-ProbabilisticScorePlayer

class ProbabilisticScorePlayer < Player
    Here = Vector2D.new( 0, 0)
    Forward = Vector2D.new( 1, 0)
    Right = Vector2D.new( 0, 1)
    Left = Vector2D.new( 0,-1)

    def vision_at(vec2d)
        v = @vision[vec2d.x+2][vec2d.y+2]
        v==-1?nil:v
    end

    def turn
        coords = [Forward]
        [Here,Forward].each{|x|
            [Here,Right,Left].each{|y|
                c = x+y
                if x!=y && vision_at c > -1
                  coords.push c if bit_at(vision_at c)==1
                  coords.push c if bit_at(vision_at(c+Forward)+16)==1
                  coords.push c if bit_at(vision_at(c+Right)+32)==1
                  coords.push c if bit_at(vision_at(c+Left)+48)==1
                  coords.push c if bit_at(vision_at(c+Forward+Right)+64)==1
                  coords.push c if bit_at(vision_at(c+Forward+Left)+80)==1
                end
            }
        }
        coords.sample(random: @rng)
    end
end

この非常に非決定的なラットは、その近傍によって空間を進む確率を計算します。ゲノムの最初の16スロットは16色を表します。スロット内の1は色が踏むのに適していることを意味し、0は悪いことを意味します。次の16個は、ターゲットの前のスペースについても同じように保持されます。

確率論的アプローチの主な利点は、長い間壁に隠れることがほぼ不可能であることです。欠点は、ほぼ完璧なネズミがほとんど得られないことです。


独創性のために+1。どのようなスコアを獲得しましたか?

まだ実際にテストしたことはありません
...-MegaTom

c初期値を与えるのを忘れましたか?最初に使用するときは定義されていないようですif
マーティンエンダー

@MartinBüttnerはい、忘れました。今すぐ修正します。
メガトム

Rubyについてはよく知りませんが、Ruby2.1.5ではコードが実行されません。coordsはリストではなく、括弧の&&代わりに使用し、and括弧を忘れました。これをすべて修正した後でも、RNG値をバインドしていないため、空の方向を取得しています。この擬似コード、または何らかのRubyの方言で実行することを意図したものですか?

2

Java、RunningStar、スコア= 1817.050970291959 1000ゲーム以上

このボットは、StarPlayerの手法でRun-Bonusのカラーコーディングを使用します

更新:Javaコントローラーが修正されました。

Scores: 6, 81533, 1648026, 14, 5, 38841, 1, 76023, 115162, 3355130, 65759, 59, 4, 235023, 1, 1, 1, 3, 2, 1, 1, 14, 50, 1, 306429, 68, 3, 35140, 2, 1, 196719, 162703, 1, 1, 50, 78233, 5, 5, 5209, 1, 2, 60237, 1, 14, 19710, 1528620, 79680, 33441, 58, 1, 4, 45, 105227, 11, 4, 40797, 2, 22594, 9, 2192458, 1954, 294950, 2793185, 4, 1, 1, 112900, 30864, 23839, 19330, 134178, 107920, 5, 122894, 1, 1, 2721770, 8, 175694, 25235, 1, 3109568, 4, 11529, 1, 8766, 319753, 5949, 1, 1856027, 19752, 3, 99071, 67, 198153, 18, 332175, 8, 1524511, 1, 159124, 1, 1917181, 2, 1, 10, 276248, 1, 15, 1, 52, 1159005, 43251, 1, 536150, 75864, 509655, 1126347, 250730, 1548383, 17, 194687, 27301, 2, 1, 207930, 621863, 6065, 443547, 1, 6, 1, 1, 1, 1, 556555, 436634, 25394, 2, 61335, 98076, 1, 190958, 2, 18, 67981, 3, 8, 119447, 1, 1, 1, 19, 28803, 23, 33, 60281, 613151, 1, 65, 20341, 799766, 476273, 105018, 357868, 3, 92325, 2062793, 18, 72097, 30229, 1, 1, 3, 610392, 1, 202149, 887122, 56571, 1, 77788, 61580, 4, 72535, 381846, 148682, 26676, 1, 210, 3556343, 212550, 650316, 33491, 180366, 1, 295685, 46255, 43295, 1006367, 63606, 1, 1, 1, 1, 3094617, 21, 10, 3, 1, 1, 14730, 1585801, 102, 2, 410353, 1570, 1, 17423, 1, 1849366, 5, 1, 357670, 1, 1, 1, 1, 89936, 349048, 15, 7, 6, 2, 121654, 1852897, 19, 1, 103275, 1, 1, 771797, 23, 19, 6700, 1, 135844, 2966847, 3, 2356708, 101515, 1, 17, 1, 996641, 22, 16, 657783, 171744, 9604, 1, 1335166, 1739537, 2365309, 1, 3378711, 11332, 3980, 182951, 609339, 8, 10, 1746504, 61895, 386319, 24216, 331130, 12193, 1, 284, 1, 2, 50369, 38, 8, 1, 1238898, 177435, 124552, 22370, 1418184, 20132, 6, 2, 730842, 1, 1341094, 141638, 534983, 1551260, 31508, 96196, 434312, 3012, 715155, 1, 276172, 214255, 1, 208948, 4, 1631942, 512293, 37, 64474, 1342713, 1, 132634, 13, 2, 61876, 1081704, 160301, 2, 488156, 2414109, 1809831, 5, 74904, 6, 11, 5, 1, 79856, 96, 35421, 229858, 238507, 3838897, 18, 44, 1, 1659126, 9, 33708, 12, 1, 758381, 162742, 256046, 3, 15, 142673, 70953, 58559, 6, 2, 1, 984066, 290404, 1072226, 66415, 4465, 924279, 48133, 319765, 519401, 1, 1, 1201037, 418362, 17022, 68, 213072, 37, 1039025, 1, 2, 6, 4, 45769, 1, 5, 1061838, 54614, 21436, 7149, 1, 1, 1, 35950, 2199045, 1, 379742, 3, 2008330, 238692, 181, 7, 140483, 92278, 214409, 5179081, 1, 1, 334436, 2, 107481, 1142028, 1, 31146, 225284, 1, 14533, 4, 3963305, 173084, 102, 1, 4732, 14, 1, 25, 11032, 224336, 2, 131110, 175764, 81, 5630317, 1, 42, 1, 89532, 621825, 2291593, 210421, 8, 44281, 4, 303126, 2895661, 2672876, 3, 436915, 21025, 1, 4, 49227, 1, 39, 3, 1, 103531, 256423, 2, 1600922, 15, 1, 2, 58933, 1114987, 1, 4, 3, 1, 1544880, 285673, 240, 2, 128, 214387, 3, 1327822, 558121, 5, 2718, 4, 1258135, 7, 37418, 2729691, 1, 346813, 385282, 2, 35674, 513070, 13, 1930635, 117343, 1929415, 52822, 203219, 1, 52407, 1, 1, 1, 3, 2, 37121, 175148, 136893, 2510439, 2140016, 437281, 53089, 40647, 37663, 2579170, 83294, 1597164, 206059, 1, 9, 75843, 773677, 50188, 12, 1, 1067679, 105216, 2452993, 1813467, 3279553, 280025, 121774, 62, 5, 113, 182135, 1, 16, 71853, 4, 557139, 37803, 228249, 6, 32420, 8, 410034, 73889, 1, 2, 96706, 48515, 1, 3, 1314561, 137, 966719, 692314, 80040, 85147, 75291, 1, 1, 30, 38119, 182723, 42267, 3836110, 22, 986685, 2, 37, 1, 3, 26, 43389, 2679689, 1, 1, 57365, 1, 2662599, 2, 72055, 1, 141247, 1, 1, 1122312, 1, 1080672, 4, 266211, 1, 34163, 1490610, 256341, 1, 627753, 32110, 1, 42468, 1, 10746, 1, 9, 1, 46, 1714133, 5, 117, 1, 104340, 218338, 151958, 122407, 211637, 223307, 57018, 74768, 582232, 2, 621279, 4, 1, 11, 196094, 1839877, 167117, 8, 42991, 2199269, 124676, 1, 1, 1, 5, 1, 1, 698083, 1, 76361, 1564154, 67345, 1398411, 9, 11, 105726, 1197879, 1, 2, 62740, 39, 2, 397236, 17057, 267647, 13, 57509, 22954, 1, 12, 747361, 4325650, 21425, 2160603, 144738, 1, 204054, 3113425, 6, 3019210, 30, 3359, 1, 89117, 489245, 1, 218068, 1, 1, 14718, 222722, 1, 1, 216041, 72252, 279874, 183, 89224, 170218, 1549362, 2, 1, 953626, 32, 130355, 30460, 121028, 20, 159273, 5, 2, 30, 1, 76215, 1654742, 2326439, 1, 53836, 1, 6, 4, 72327, 9, 285883, 1, 908254, 698872, 47779, 3, 2293485, 265788, 3766, 1, 1, 83151, 36431, 307577, 256891, 29, 1, 1, 1093544, 145213, 5, 2, 581319, 2911699, 1, 213061, 1359700, 2, 1, 343110, 1, 157592, 1708730, 1, 22703, 32075, 1, 1, 87720, 159221, 2313143, 10, 2266815, 2106917, 1345560, 3146014, 4, 551632, 1066905, 550313, 4069794, 1, 1406178, 38981, 1, 3, 1, 3039372, 241545, 35, 63325, 85804, 1365794, 2, 2143204, 48, 1, 99, 3225633, 7, 4074564, 1023899, 3209940, 2054326, 70880, 2, 1, 284192, 1944519, 84682, 2, 867681, 90022, 378115, 1, 15, 602743, 1337444, 131, 1, 229, 161445, 3, 2, 5591616, 195977, 92415, 637936, 142928, 1, 2310569, 923, 1, 230288, 1300519, 398529, 2233, 100261, 4323269, 81362, 37300, 1, 233775, 32277, 434139, 323797, 19214, 782633, 2881473, 1, 1, 9, 337016, 1, 515612, 44637, 17, 1, 25, 67758, 1737819, 16454, 30613, 692963, 62216, 222062, 344596, 3, 33782, 19, 180441, 23552, 20462, 70740, 10298, 109691, 1, 1729427, 33714, 1770930, 1, 1, 1, 1, 290766, 136688, 688231, 3250223, 30703, 1985963, 527128, 3, 226340, 195576, 30, 1, 3, 1, 793085, 5527, 5, 1, 2188429, 1327399, 5, 6192537, 1445186, 2478313, 2, 16892, 3, 1, 1, 15, 12, 1361157, 4, 1241684, 1, 45008, 1, 505095, 4037314, 14, 8, 1, 16740, 69906, 45, 1, 240949, 3975533, 212705, 2617552, 278884, 1, 24966, 958059, 231886, 22929, 4052071, 51259, 67791, 78739, 1, 165787, 67, 518191, 86923, 437, 1271004, 135941, 244766, 1, 1, 1, 1152745, 1, 3, 406365, 3847357, 476636, 135097, 304368, 8, 1578276, 1, 1, 375, 1, 1, 1298206, 1860743, 2, 35311, 834516, 421428, 2, 66629, 1, 309845, 398756, 33, 907277, 384475, 2267460, 1, 269300, 124525, 34399, 93584, 362186, 811260, 426109, 1, 1009323, 109986, 122181, 1, 1, 3626487, 11452, 1092410, 57233, 6, 2009226, 1, 83333, 4, 1338631, 79114, 2140249, 51813, 1118986, 43514, 1529365, 1, 101, 1, 1,
package game.players;

import java.awt.Point;
import java.util.*;

public class RunningStar extends Player{

    @Override
    public Point takeTurn(String genome, Map<Point, Integer> vision) {
        Map<Integer, Integer> squareCosts = decode(genome);
        Path path = astar(vision, squareCosts);
        return path.get(1);
    }

    private Path astar(Map<Point, Integer> vision, Map<Integer, Integer> squareCosts) {
        Set<Path> closed = new HashSet<>();
        PriorityQueue<Path> open = new PriorityQueue<>();
        open.add(new Path(new Point(0, 0), 0));
        while (!open.isEmpty()){
            Path best = open.remove();
            if (best.head().x == 2 || (best.head().x > 0 && (best.head().y == 2 || best.head().y == -2))){
                return best;
            }
            for (Path path : pathsAround(best, vision, squareCosts)){
                if (!closed.contains(path) && !open.contains(path)){
                    open.add(path);
                }
            }
            closed.add(best);
        }

        Path p = new Path(new Point(0,0), 0);
        return p.add(new Point((int)(random.nextDouble() * 3 - 1), (int)(random.nextDouble() * 3 - 1)), 0);
    }

    private List<Path> pathsAround(Path path, Map<Point, Integer> vision, Map<Integer, Integer> costs) {
        Point head = path.head();
        List<Path> results = new ArrayList<>();
        for (int i = -1; i <= 1; i++){
            for (int j = -1; j <= 1; j++){
                if (i == 0 && j == 0){
                    continue;
                }
                Point p = new Point(head.x + i, head.y + j);
                if (!vision.containsKey(p) || vision.get(p) == -1){
                    continue;
                }
                results.add(path.add(p, costs.get(vision.get(p))));
            }
        }
        return results;
    }

    private Map<Integer, Integer> decode(String genome) {
        int chunkLength = genome.length()/16;
        Map<Integer, Integer> costs = new HashMap<>();
        for (int i = 0; i < 16; i++){
            int runSize = 0;
            int cost = 0;
            for (int j = i * chunkLength; j < (i + 1) * chunkLength; j++){
                switch (genome.charAt(j)){
                    case '0':
                        runSize = 0;
                        break;
                    case '1':
                        cost += ++runSize;
                }
            }
            costs.put(i, cost);
        }
        return costs;
    }

    private class Path implements Comparable<Path>{

        Point head;
        Path parent;
        int length;
        int totalCost;

        private Path(){}

        public Path(Point point, int cost) {
            length = 1;
            totalCost = cost;
            head = point;
            parent = null;
        }

        public Point get(int index) {
            if (index >= length || index < 0){
                throw new IllegalArgumentException(index + "");
            }
            if (index == length - 1){
                return head;
            }
            return parent.get(index);
        }

        public Point head() {
            return head;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Path path = (Path) o;

            if (!head.equals(path.head)) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return head.hashCode();
        }

        @Override
        public int compareTo(Path o) {
            return totalCost - o.totalCost;

        }

        public Path add(Point point, int cost) {
            Path p = new Path();
            p.head = point;
            p.totalCost = totalCost + cost;
            p.length = length + 1;
            p.parent = this;
            return p;
        }
    }
}

2

LeapForward、Python 2

特に画期的ではありませんが、OKを実行したのは私の唯一の試みです。

class LeapForward(Player):
  def __init__(self):
    Player.__init__(self)
    self.coords = [Coordinate( 1, 0),
                   Coordinate( 1,-1),
                   Coordinate( 1, 1)]
    self.n_moves = len(self.coords)

  def turn(self):
    notOKColors = [self.bit_chunk(4*n,4) for n in range(4,8)]
    notOKMap = [Coordinate(x-2,y-2) for x in range(0,5) for y in range(0,5) if self.vision[y][x] not in notOKColors]
    goTo = [c for c in self.coords if c in notOKMap]
    if not goTo:
      goTo = [Coordinate(1,0)]
    return random.choice(goTo)

基本的に、ゲノム内で回避するために4色(各4ビット)をコーディングします。次に、そのリストにない色に進みます。すべての色が悪い場合、それはまだ未知へと飛び出します。


おそらくそれを「RedQueen」と呼ぶべきでした:)
plannapus

1

Java-IAmARobotPlayer-スコア3.7

私が作った別の(これまでのところあまり面白くない)プログラムと比較するために、このロボットラットを作成しました。全体的には得点はよくありませんが、どこかで得点すると、多くのラットが通過します。アイデアは、その前の3つのセルのみを見るというもので、各セルは良いか悪いかです。これにより、2進数が得られます。次に、その番号をゲノムで検索し、3つの連続したビットを取得し、それらを番号に変換して、この番号の下に格納されているアクションを実行します。そのため、同じ状況が発生しても常に同じ動作をします。

package game.players;
import java.awt.*;
import java.util.Map;
public class IAmARobotPlayer extends Player{
    private static final Point[] possibleMoves = {new Point(1,-1), new Point(1,0), new Point(1,1), new Point(0,-1), new Point(0,1), new Point(1,-1), new Point(1,0), new Point(1,1)};
    private int isGood(int pos,Map<Point,Integer> vision, char[] genomeChar){
        int value = vision.get(new Point(1,pos));
        if(value ==-1){
            return 0;
        } else {
            return genomeChar[84+value]-'0';
        }
    }

    @Override
    public Point takeTurn(String genome, Map<Point, Integer> vision) {

        char[] genomeChar = genome.toCharArray();
        int situation = 4*isGood(1,vision,genomeChar)+2*isGood(0,vision,genomeChar)+1*isGood(-1,vision,genomeChar);
        int reaction = 4*(genomeChar[3*situation+0]-'0')+2*(genomeChar[3*situation+1]-'0')+1*(genomeChar[3*situation+2]-'0');
        return possibleMoves[reaction];

    }
}

結果:

Individual scores: 1, 1, 332, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 47560, 15457, 1, 
Your final score is 3.7100115087136234

1

慎重な標本-C ++-200回以上の実行で2030程度のスコア

これは、Blind FaithからエンコードされたDNAの色部分(16x4ビット)を使用しますが、DNAの残り(36ビット)は完全に未使用のままです。

色のエンコードは次のいずれかです。

  • 10XX-安全な正方形の場合;
  • 11XX-致命的な正方形の場合。そして
  • 0000〜0111-8種類のトラップスクエアの場合。

Xは未使用ビットを示します。16の2色のみが4つのビットすべてを使用するトラップである場合(トラップが9の8倍になる場合のみ)、通常64個の未使用ビットがあります。 -理論は、これらの未使用ビットのいずれかに影響を与える変異はゲノムを破壊することはなく、安定性はそれらの残りのビットを使用できる空想的なソリューションよりも優れているということです。

標本はこれを使用して、自身を中心とする7x7グリッド内の安全なルートを計画します(視界が許可される5x5に加えて、オフセットトラップを可能にするために各側に1正方形が追加されます)。

私は最初にいくつかのチェックで構築を開始し、現在標本の色が致命的ではないという事実がゲノムと一致しないことを確認し、エラーのある色にUNSURE安全性の正方形(および隣接する正方形)としてフラグを立てましたが、それは重要なことですこれらの正方形を安全とマークし、いくつかの追加の標本を殺すのに比べて、ほとんどまたはまったく利益が得られないという複雑さ。時間があればこれに戻ります。

#include <initializer_list>
#include <vector>

enum class D { SAFE, LETHAL,TRAP_N, TRAP_NE, TRAP_E, TRAP_SE, TRAP_S, TRAP_SW, TRAP_W, TRAP_NW, UNSURE };
enum class X { SAFE, LETHAL, UNSURE };

inline void checkLocation( color_t color, D (&dna)[16], D check )
{
    if ( color != OUT_OF_BOUNDS && dna[color] == check )
        dna[color] = D::UNSURE;
}

inline void updateMapLocation( X (&map)[7][7], unsigned int x, unsigned int y, const X& safety ){
    if (        ( safety == X::LETHAL && map[x][y] != X::LETHAL )
            || ( safety == X::UNSURE && map[x][y] == X::SAFE ) )
        map[x][y] = safety;
}

inline unsigned int isSafePath( X (&map)[7][7], coord_t p )
{
    return map[p.x][p.y] == X::SAFE ? 1 : 0;
}
inline unsigned int isSafePath(X (&map)[7][7],coord_t p,coord_t q,coord_t r){
    if ( isSafePath( map,p ) )
        if ( isSafePath( map, q ) )
            return isSafePath( map, r );
    return 0;
}

inline unsigned int isSafeEast( X (&map)[7][7], coord_t p )
{
    if ( !isSafePath( map, p ) )
        return 0;
    if ( p.x == 6 )
        return 1;
    return isSafeEast(map,{p.x+1,p.y-1})
            +isSafeEast(map,{p.x+1,p.y+0})
            +isSafeEast(map,{p.x+1,p.y+1});
}

template<typename T> inline T max(T a,T b){return a>=b?a:b;}
template<typename T, typename... A> inline T max(T a,T b,A... c){return max(max(a,b),c...); }

coord_t cautiousSpecimins( dna_t d, view_t v ) {
    X map[7][7] = { { X::SAFE } };
    D dna[16] = { D::UNSURE };
    for ( color_t i = 0; i < 16; i++ )
    {
        if ( d[4*i] == 1 )
        {
            dna[i] = d[4*i + 1] == 1 ? D::LETHAL : D::SAFE;
        }
        else
        {
            switch ( dnarange( d, 4*i + 1, 3 ) )
            {
                case 0: dna[i] = D::TRAP_N; break;
                case 1: dna[i] = D::TRAP_NE; break;
                case 2: dna[i] = D::TRAP_E; break;
                case 3: dna[i] = D::TRAP_SE; break;
                case 4: dna[i] = D::TRAP_S; break;
                case 5: dna[i] = D::TRAP_SW; break;
                case 6: dna[i] = D::TRAP_W; break;
                case 7: dna[i] = D::TRAP_NW; break;
                default: dna[i] = D::UNSURE; break;
            }
        }
    }
    if ( v(-1, 0) != OUT_OF_BOUNDS )
        checkLocation( v( 0, 0), dna, D::LETHAL );

    if ( v(-1, 0) != OUT_OF_BOUNDS )
        for ( unsigned int y = 0; y < 7; ++ y )
            map[2][y] = X::LETHAL;

    if ( v(-2, 0) != OUT_OF_BOUNDS )
        for ( unsigned int x = 0; x < 2; ++x )
            for ( unsigned int y = 0; y < 7; ++ y )
                map[x][y] = X::LETHAL;

    if ( v( 0, 1) == OUT_OF_BOUNDS )
        for ( unsigned int x = 0; x < 7; ++x )
                map[x][4] = X::LETHAL;

    if ( v( 0, 2) == OUT_OF_BOUNDS )
        for ( unsigned int x = 0; x < 7; ++x )
            for ( unsigned int y = 5; y < 7; ++ y )
                map[x][y] = X::LETHAL;

    if ( v( 0,-1) == OUT_OF_BOUNDS )
        for ( unsigned int x = 0; x < 7; ++x )
                map[x][2] = X::LETHAL;

    if ( v( 0,-2) == OUT_OF_BOUNDS )
        for ( unsigned int x = 0; x < 7; ++x )
            for ( unsigned int y = 0; y < 2; ++ y )
                map[x][y] = X::LETHAL;

    checkLocation( v( 1, 1), dna, D::TRAP_SW );
    checkLocation( v( 1, 0), dna, D::TRAP_W  );
    checkLocation( v( 1,-1), dna, D::TRAP_NW );
    checkLocation( v( 0,-1), dna, D::TRAP_N  );
    checkLocation( v(-1,-1), dna, D::TRAP_NE );
    checkLocation( v(-1, 0), dna, D::TRAP_E  );
    checkLocation( v(-1, 1), dna, D::TRAP_SE );
    checkLocation( v( 0, 1), dna, D::TRAP_S  );

    for ( int x = 1; x <= 5; ++x )
    {
        for ( int y = 1; y <= 5; ++y )
        {
            switch( dna[v(x-3,y-3)] )
            {
                case D::LETHAL : updateMapLocation( map, x+0, y+0, X::LETHAL ); break;
                case D::TRAP_N : updateMapLocation( map, x+0, y+1, X::LETHAL ); break;
                case D::TRAP_NE: updateMapLocation( map, x+1, y+1, X::LETHAL ); break;
                case D::TRAP_E : updateMapLocation( map, x+1, y+0, X::LETHAL ); break;
                case D::TRAP_SE: updateMapLocation( map, x+1, y-1, X::LETHAL ); break;
                case D::TRAP_S : updateMapLocation( map, x+0, y-1, X::LETHAL ); break;
                case D::TRAP_SW: updateMapLocation( map, x-1, y-1, X::LETHAL ); break;
                case D::TRAP_W : updateMapLocation( map, x-1, y+0, X::LETHAL ); break;
                case D::TRAP_NW: updateMapLocation( map, x-1, y+1, X::LETHAL ); break;
//              case D::UNSURE : updateMapLocation( map, x+0, y+0, X::SAFE );
//                               updateMapLocation( map, x+0, y+1, X::UNSURE );
//                               updateMapLocation( map, x+1, y+1, X::UNSURE );
//                               updateMapLocation( map, x+1, y+0, X::UNSURE );
//                               updateMapLocation( map, x+1, y-1, X::UNSURE );
//                               updateMapLocation( map, x+0, y-1, X::UNSURE );
//                               updateMapLocation( map, x-1, y-1, X::UNSURE );
//                               updateMapLocation( map, x-1, y+0, X::UNSURE );
//                               updateMapLocation( map, x-1, y+1, X::UNSURE );
//                               break;
                default        : break;
            }           
        }
    }

    unsigned int north = isSafeEast(map,{4,4});
    unsigned int east  = isSafeEast(map,{4,3});
    unsigned int south = isSafeEast(map,{4,2});
    unsigned int mx    = max( north, east, south );
    unsigned int sz;
    std::vector<coord_t> dir;
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+1,+1} );
        if ( east  == mx ) dir.push_back( {+1,+0} );
        if ( south == mx ) dir.push_back( {+1,-1} );

        return dir[v.rng.rint(dir.size())];
    }


    north = isSafePath(map,{4,4},{5,5},{5,6})
            + isSafePath(map,{4,4},{4,5},{5,6});
    south = isSafePath(map,{4,2},{5,1},{5,0})
            + isSafePath(map,{4,2},{4,1},{5,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+1,+1} );
        if ( south == mx ) dir.push_back( {+1,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = isSafePath(map,{3,4},{4,5},{5,6});
    south = isSafePath(map,{3,2},{4,1},{5,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+0,+1} );
        if ( south == mx ) dir.push_back( {+0,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = 2*isSafePath(map,{4,4},{4,5},{4,6})
            + 1*isSafePath(map,{4,4},{3,5},{4,6});
    south = 2*isSafePath(map,{4,2},{4,1},{4,0})
            + 1*isSafePath(map,{4,2},{3,1},{4,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+1,+1} );
        if ( south == mx ) dir.push_back( {+1,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = isSafePath(map,{3,4},{4,5},{4,6})
            + isSafePath(map,{3,4},{3,5},{4,6});
    south = isSafePath(map,{3,2},{4,1},{4,0})
            + isSafePath(map,{3,2},{3,1},{4,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+0,+1} );
        if ( south == mx ) dir.push_back( {+0,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = isSafePath(map,{2,4},{3,5},{4,6});
    south = isSafePath(map,{2,2},{3,1},{4,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {-1,+1} );
        if ( south == mx ) dir.push_back( {-1,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = isSafePath(map,{3,4},{3,5},{3,6})
            + isSafePath(map,{3,4},{2,5},{3,6});
    south = isSafePath(map,{3,2},{3,1},{3,0})
            + isSafePath(map,{3,2},{2,1},{3,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {+0,+1} );
        if ( south == mx ) dir.push_back( {+0,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    north = isSafePath(map,{2,4},{3,5},{4,6});
    south = isSafePath(map,{2,2},{3,1},{4,0});
    mx = max( north, south );
    if ( mx > 0 )
    {
        if ( north == mx ) dir.push_back( {-1,+1} );
        if ( south == mx ) dir.push_back( {-1,-1} );

        return dir[v.rng.rint(dir.size())];
    }

    return {-1,-1};
}

サンプルスコア:

Scores: 421155 2 129418 71891 90635 1 211 1111987 29745 7 2200750 41793 50500 45 2012072 2 485698 1 110061 1554720 210308 249336 2 1 262110 17 3 19 1719139 23859 45118 3182784 318 2 1 15572 14 2822954 18 11 2 3 15954 1331392 2296280 135015 1 360826 1 692367 4 244775 4814645 3749144 3 1 660000 1 11 3688002 3920202 3428464 123053 1 243520 86 9 6 289576 195966 549120 220918 9 1 43 71046 5213 118177 150678 54639 3 200839 1 3 6 1978584 1514393 119502 1 1 137695 184889 337956 1 1 441405 133902 991 1 4137428 1 1427115 3340977 1 2 1 55559 11 1 94886 30270 1 6 3 69394 264780 6877 47758 128568 1 116672 130539 163747 96253 1 2654354 1 141 58212 1613661 27 9504 1 2474022 843890 1 59 3110814 2353731 150296 313748 2590241 6 5970407 1434171 2 334715 141277 1 56810 2964306 51544 61973 715590 1 106 900384 50948 2 34652 108096 391006 1 2969764 47625 1 24 30481 44 8 1 18 2094036 106461 3080432 75 620651 16 71730 282145 275031 17 1 8 15 121731 18 2 1 1 495868 3252390 6 1 63712 7 3733149 13380 1 1
Geometric mean score: 2030.17

テスト中の最大スコア:8,150,817標本が保存されました。


さて、あなたはそれをしました...後のためにパスを保存したかったのですが、慎重なents歯類に挑戦することはできませんでした:) パス領域を7x7に拡張するというあなたのアイデアも有望なようです。それを使用できるかどうかを確認します。

私は現在、これのために2000回実行しています...最初の900回の後、平均は約600に落ち着いているようです。これは2000年からかなり離れています。単なるまぐれ?
マーティンエンダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.