非対称KOTH:Catch the Cat(キャッチャースレッド)


17

非対称KOTH:猫を捕まえる

UPDATE Controller.javaが例外(エラーのみ)をキャッチしなかったため、gistファイルが更新されます(新しいサブミッションを含む)。現在、エラーと例外をキャッチし、それらも出力します。

このチャレンジは2つのスレッドで構成されています。これはキャッチャースレッドです。catスレッドはここにあります

コントローラーはここからダウンロードできます

これは非対称のKOTHです。各サブミッションはまたはキャッチャーです。それぞれの猫とキャッチャーの各ペアの間にゲームがあります。猫とキャッチャーは別々のランキングを持っています。

キャッチャー

六角形のグリッドに猫がいます。あなたの仕事は、できるだけ早くそれをキャッチすることです。猫がそこに行くのを防ぐために、毎ターン、1つのグリッドセルに水バケツを置くことができます。しかし、猫は(おそらく)愚かではなく、バケツを置くたびに、猫は別のグリッドセルに移動します。グリッドは六角形であるため、猫は6つの異なる方向に進むことができます。あなたの目標は、猫を水バケツで囲むことです。

ネコ

あなたは、キャッチャーがあなたの周りに水バケツを置くことによってあなたを捕まえたいことを知っています。もちろん、あなたは逃げようとしますが、あなたが怠catな猫であるように(猫はそうです)、あなたはまさにその時一歩を踏み出します。つまり、同じ場所に滞在することはできませんが、周囲の6つのスポットのいずれかに移動する必要があります。キャッチャーが新しいバケツを置いたのを見るたびに、別のセルに行きます。もちろん、できるだけ長く回避しようとします。

グリッド

グリッドは六角形ですが、六角形のデータ構造がないため、11 x 11正方形の2D配列を取り、猫が6方向にしか移動できない六角形の「動作」を模倣します。

ここに画像の説明を入力してください

トポロジはトロイダルです。つまり、アレイの「外側」のセルを踏むと、アレイの反対側の対応するセルに転送されます。

ゲーム

猫はグリッドの指定された位置から始まります。キャッチャーは最初の動きをすることができ、猫とキャッチャーは猫が捕まるまで交互に動きます。ステップ数は、そのゲームのスコアです。猫は可能な限り大きなスコアを取得しようとし、キャッチャーは可能な限り低いスコアを取得しようとします。参加したすべてのゲームの平均合計が提出のスコアになります。猫用とキャッチャー用の2つの別々のランキングがあります。

コントローラ

指定されたコントローラーはJavaで作成されています。キャッチャーまたは猫として、それぞれJavaクラスを実装し(既にいくつかの基本的な例があります)、playersパッケージに配置する必要があります(コントローラークラスの猫/キャッチャーのリストを更新します)。そのクラス内の追加機能。コントローラーには、単純なcats / catcherクラスの2つの実例がそれぞれ付属しています。

フィールドは、セルの現在の状態の値を格納する11 x 112D int配列です。セルが空の場合は値0があり、猫がいる場合は値-1があり、バケットがある場合はがあり1ます。

あなたが使用できるいくつかの特定の機能がありますisValidMove()/ isValidPosition()あなたの移動(猫)/位置(キャッチャー)が有効であるかどうかをチェックするためのものです。

自分の番になるたびに、関数takeTurn()が呼び出されます。引数は次のような方法がある現在のグリッドのコピーが含まread(i,j)でセルを読み出すために(i,j)、だけでなく、isValidMove()/ isValidPosition()あなたの答えの妥当性をそのチェックを。これは、トロイダルトポロジのラッピングも管理します。つまり、グリッドが11 x 11のみの場合でも、セル(-5,13)にアクセスできます。

このメソッドはint、可能な動きを表す2つの要素の配列を返す必要があります。猫の場合、これらは{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}猫が行きたい場所の相対的な位置を表し、キャッチャーはバケツを置きたい場所の絶対座標を返します{i,j}

メソッドが無効な移動を生成する場合、提出は失格となります。移動先がすでにバケットであるか、移動が許可されていない/移動先が既に占有されている場合(猫として)、またはバケット/猫が既に存在する場合(キャッチャーとして)、移動は無効と見なされます。あなたは、与えられた関数で事前にそれをチェックすることができます。

あなたの提出は合理的に速く動作するはずです。メソッドが各ステップで200ミリ秒以上かかる場合、失格となります。(できればもっと少ない...)

プログラムは、ステップ間で情報を保存できます。

提出

  • 必要な数だけ提出できます。
  • 既に提出した提出物を大幅に変更しないでください。
  • 新しい回答の各提出をお願いします。
  • 各提出には、できれば一意の名前を付ける必要があります。
  • 提出物は、クラスのコードと、提出物がどのように機能するかを示す説明で構成される必要があります。
  • <!-- language: lang-java -->自動構文強調表示を得るために、ソースコードの前に行を書くことができます。

得点

すべてのはすべてのキャッチャーと同じ回数だけ競争します。現在のスコアを頻繁に更新するようにします。アクティビティが減少したときに勝者が決定されます。

この挑戦はこの古いフラッシュゲームに触発されています

テストと建設的なフィードバックを提供してくれた@PhiNotPiに感謝します。

現在のスコア(ペアリングごとに100ゲーム)

Name              Score      Rank   Author

RandCatcher       191674     8      flawr   
StupidFill        214246     9      flawr
Achilles          76820      6      The E
Agamemnon         74844      5      The E
CloseCatcher      54920      4      randomra
ForwordCatcher    94246      7      MegaTom  
Dijkstra          46500      2      TheNumberOne
HexCatcher        48832      3      randomra
ChoiceCatcher     43828      1      randomra

RandCat           77928      7      flawr
StupidRightCat    81794      6      flawr
SpiralCat         93868      5      CoolGuy
StraightCat       82452      9      CoolGuy
FreeCat           106304     3      randomra
RabidCat          77770      8      cain
Dijkstra's Cat    114670     1      TheNumberOne
MaxCat            97768      4      Manu
ChoiceCat         113356     2      randomra

どのプログラムがアニメーションを作成しますか?
メガトム

アニメーションは単なるGUIです(コントローラーを起動するときPRINT_STEPS = trueは、ファイルでより詳細な設定を設定する必要がありますMyFrame.java)。次に、これをLICEcapで記録し、GIMPで編集しました。さらに質問がある場合は、質問してください!
フレイ

コントローラーにユーザー入力を追加すると、GUIとボットが既に記述された素晴らしいソフトウェアを作成できます。人間が特定のボット戦略をどれだけクラック/悪用できるかを見るのも興味深いでしょう。
randomra

また、私のボットは以前の試合の情報を保持して、同じボットに対するより良い移動シーケンスを見つけようとすることができますか?ラウンドを重ねるほど良くなるからではないでしょう。また、新しいボットと対戦しているかどうかを推測する必要があるため、実行順序も重要になります。
ランダラ

1
猫のスコアが順序付けられていないのはなぜですか?
Spikatrix

回答:


6

アキレス

アキレスはあまり明るくはありませんが、容赦なく効率的です。まず、猫がボードのラップアラウンドを使用するのを止め、次にボードを2つに分割します。それから彼は、ネコが閉じ込められるまで、ネコがいるボードの部分を半分に分割し続けます。

デモンストレーションRandCat対Achilles

ランドキャットvsアキレス

package players;
/**
 * @author The E
 */
import main.*;



public class Achilles implements Catcher
{
    public Achilles() {

    }
    @Override
    public String getName() {

        return "Achilles";
    }

    @Override
    public int[] takeTurn(Field f) {
        try{
        if(f.read(0, f.SIZE-1)!=Field.BUCKET)
        {
            //Make the first line

            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j) == Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            return WasteGo(f);

        }
        else if (f.read(f.SIZE-1, 0)!=Field.BUCKET)
        {
            //Make the second line
            for(int i = 0; i<f.SIZE; i++)
            {
                if(f.read(i, 0) == Field.EMPTY)
                {
                    return new int[]{i,0};
                }
            }
            //The cat got in the way
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(1, j) == Field.EMPTY)
                {
                    return new int[]{1,j};
                }
            }
            return WasteGo(f);
        }
        else
        {
            return TrapCat(1,1,f.SIZE-1, f.SIZE-1, false, f);

        }
        }
        catch (Exception e)
        {
            return WasteGo(f);
        }
    }
    private int[] TrapCat(int i1, int j1, int i2, int j2, Boolean direction, Field f) {
        for(int a = 0; a<f.SIZE+10; a++)
        {
            if(direction)
            {

                int height = j2-j1+1;
                int row = j1 + height/2;
                for(int i = i1; i<=i2; i++)
                {
                    if(f.read(i, row)==Field.EMPTY)
                    {
                        return new int[]{i,row};
                    }
                }

                    //Done that Row
                    //Find cat
                    if(f.findCat()[1]>row)
                    {
                        //he's above the line
                        j1 = row+1;
                        direction = !direction;
                        //return TrapCat(i1, row+1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's below the line
                        j2 = row - 1;
                        direction = !direction;
                        //return TrapCat(i1, j1, i2, row-1, !direction, f);
                    }


            }
            else
            {
                int bredth = i2-i1+1;
                int column = i1 + bredth/2;
                //Continue making the line
                for(int j = j1; j<=j2; j++)
                {
                    if(f.read(column,j)==Field.EMPTY)
                    {
                        return new int[]{column,j};
                    }
                }

                    //Done that Column
                    //Find cat
                    if(f.findCat()[0]>column)
                    {
                        //he's right of the line
                        i1 = column + 1;
                        direction = !direction;
                        //return TrapCat(column+1, j1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's left of the line
                        i2 = column -1;
                        direction = !direction;
                        //return TrapCat(i1, j1, column-1, j2, !direction, f);
                    }

            }
        }
        return WasteGo(f);
    }
    private int[] WasteGo(Field f) {
        for (int i = 0; i<f.SIZE;i++)
        {
            for(int j=0;j<f.SIZE;j++)
            {
                if(f.read(i,j)==Field.EMPTY)
                {
                    return new int[]{i,j};
                }
            }
        }
        //Something drastic happened
        return new int[]{0,0};
    }



}

さて、アキレスとヘクターのどちらですか?(または、解離性同一性障害を持つ人?=)
flawr

アキレス@flawr、笑私は(それがキャッチャーアキレスと猫ヘクターに名前を付けるしやすいです)を介して名前の半分の方法を変更が、Javaを変更するのを忘れて-それは:(お茶の後にするとき、あなたのプログラムに何が起こるかだ
euanjt

しかし、ヘクターはむしろ犬になります=)あなたの提出作品が素晴らしいことに感謝します。コードに「プリアンブル」を含めることを気にしないでください。
-flawr

ええ、問題ありません。ヘクターは犬の名前のように
聞こえ

StackOverflowErrorが繰り返し発生したため、シミュレーション(ペアリングごとに10000ゲーム)を実行しましたが、アキレスは失格となりました。:私は、再帰が終了しなかったと思いますpastebin.com/9n6SQQnd
flawr

5

アガメムノン

アガメムノンは、猫が動く幅2のストリップを持つまで猫のエリアを縦線で半分に分割し、その時点で猫を捕まえます。

アガメムノン対ランドキャット:

ここに画像の説明を入力してください

package players;
/**
 * @author The E
 */
import main.*;



    public class Agamemnon implements Catcher {
        boolean up = true;
        @Override
        public String getName() {
            return "Agamemnon";
        }

        @Override
        public int[] takeTurn(Field f) {
            //First Make Line in column 1
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j)==Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            //Then in column SIZE/2
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(f.SIZE/2, j)==Field.EMPTY)
                {
                    return new int[]{f.SIZE/2,j};
                }
            }
            //Then work out where the cat is
            int left, right;
            int cati = f.findCat()[0];
            if(cati<f.SIZE/2)
            {
                left = 1;
                right = f.SIZE/2-1;
            }
            else
            {
                left = f.SIZE/2+1;
                right = f.SIZE-1;
            }
            while(right-left>1)
            {
                //If the cat is not in a two width column
                //Split the area the cat is in in half
                int middleColumn = (left+right)/2;
                for(int j = 0; j<f.SIZE; j++)
                {
                    if(f.read(middleColumn, j)==Field.EMPTY)
                    {
                        return new int[]{middleColumn,j};
                    }
                }
                //If we got here we had finished that column
                //So update left and/or right
                if(cati<middleColumn)
                {
                    //he's left of the middle Column
                    right = middleColumn - 1;
                }
                else
                {
                    //he's right of the middle Column
                    left = middleColumn+1;
                }
                //Repeat
            }
            //Otherwise try to trap the cat
            //Make a line up and down on the opposite side of the cat
            int catj = f.findCat()[1];
            if(left!=right){
                if(cati==left)
                {
                    if(f.read(right, catj)==Field.EMPTY)
                    {
                        return new int[]{right, catj};
                    }
                    if(f.read(right, catj-1)==Field.EMPTY)
                    {
                        return new int[]{right, catj-1};
                    }
                    if(f.read(right, catj+1)==Field.EMPTY)
                    {
                        return new int[]{right, catj+1};
                    }


                }
                else
                {
                    if(f.read(left, catj)==Field.EMPTY)
                    {
                        return new int[]{left, catj};
                    }
                    if(f.read(left, catj-1)==Field.EMPTY)
                    {
                        return new int[]{left, catj-1};
                    }
                    if(f.read(left, catj+1)==Field.EMPTY)
                    {
                        return new int[]{left, catj+1};
                    }

                }
            }
            //Alternate between above and below
            if(up)
            {
                up = !up;
                if(f.read(cati, catj+1)==Field.EMPTY)
                {

                    return new int[]{cati, catj+1};
                }
            }
            up = !up;
            if(f.read(cati, catj-1)==Field.EMPTY)
            {

                return new int[]{cati, catj-1};
            }
            return WasteGo(f);
        }

        private int[] WasteGo(Field f) {
            for (int i = 0; i<f.SIZE;i++)
            {
                for(int j=0;j<f.SIZE;j++)
                {
                    if(f.read(i,j)==Field.EMPTY)
                    {
                        return new int[]{i,j};
                    }
                }
            }
            //Something drastic happened
            return new int[]{0,0};
        }
    }

このキャッチャーは、アキレスより一貫して優れており、私は彼が新しい答えを正当化するのに十分異なると思います。


非常に素晴らしい解決策、アキレスは最適に近いと確信していましたが、今ではアガメムノンでさえわずかに改善できると思います=)
flawr

はい、アガメムノンはアキレスよりもはるかに優れたエンドゲームトラップアルゴリズムを持っていますが、いくつかの調整があると確信しています...今、猫を試してみます:)
euanjt

(私はそれがSpiralCatのアニメーションに影響を与えるかもしれないと思うelthough)@flawr、いくつかの特別な場合に引くスピードアップするために追加の非常に小さな微調整が、これはここにアニメーションには影響しません
-euanjt

質問!ラインを閉じようとしているが、猫が最後の場所に立っている場合はどうなりますか?
ラマ氏

@ Mr.Llamaそれは次の行をその行がいっぱいになったように開始します(つまり、猫は実際にはバケツでした)-ターンの最も効果的な使用ではありませんが、それは本当に重要ではありません-猫はその次のターンに移動しなければならないので、そこにバケツを置くことができます
-euanjt

5

HexCatcher

キャッチャーが、六角形の角がすでにバケツで占められている3ユニットの側面を持つ大きな六角形の内側に猫を捕まえることができる場合、キャッチャーは猫をこのエリアに留めて捕まえることができます。六角形は次のようになります。

ここに画像の説明を入力してください

これは、HexCatcherが達成しようとするものです。各コーナーセルが3つの大きな六角形の一部になるように、これらの大きな六角形でフィールドを精神的にタイル張りします。

猫の隣にある2つのコーナーを接続して、猫を現在のエリアに留める機会がある場合、ボットはそれを行います。(たとえば、猫が7,5にいる場合、6,6と8,5のセルだけがまだ占有されている場合でも、7,6を選択します。)

前のものがオプションではない場合、猫がいるエリアの一部であるコーナーをプレイすることを選択します。そのようなすべての角がすでに選択されている場合(画像のように)、猫の隣のセルを選択します。

ラップアラウンドをより適切に処理する(タイリングが壊れる)、最後のカップルの移動を最適に行うなど、複数の小さな改善が可能です。私はこれらのいくつかをするかもしれません。許可されていない場合は、興味のある人のために(競合していない)追加します。

DijkstrasCat対HexCatcher:

ここに画像の説明を入力してください

package players;
/**
 * @author randomra
 */
import main.Field;

public class HexCatcher implements Catcher {
    public String getName() {
        return "HexCatcher";
    }

    final int[][] o = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, { 0, -1 },
            { 1, -1 } };// all valid moves
    final int[][] t = { { -2, 2 }, { 0, 2 }, { -2, 0 }, { 2, 0 }, { 0, -2 },
            { 2, -2 } };// all valid double moves in one direction
    final int[][] h = { { -1, 2 }, { -2, 1 }, { -1, -1 }, { 1, -2 }, { 2, -1 },
            { 1, 1 } };// all valid moves in not one direction
    int opp = 0;

    public int[] takeTurn(Field f) {
        int[] p = f.findCat();
        // center of the hexagon the cat is in
        int[] c = { ((int) p[0] / 3) * 3 + 1, ((int) p[1] / 3) * 3 + 1 };
        // change priority of catching direction at every turn
        opp = 1 - opp;

        // check missing corner piece next to cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            boolean close = false;
            for (int k = 0; k < 6; k++) {
                if (c[0] + h[ind][0] == p[0] + o[k][0]
                        && c[1] + h[ind][1] == p[1] + o[k][1]) {
                    close = true;
                }
            }
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0 && close) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // cut off escape route if needed
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + o[ind][0], c[1] + o[ind][1]) == -1
                    && f.read(c[0] + t[ind][0], c[1] + t[ind][1]) == 0) {
                return new int[] { c[0] + t[ind][0], c[1] + t[ind][1] };
            }
        }
        // check any missing corner piece in the area
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // choose an empty cell next to the cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(p[0] + o[ind][0], p[1] + o[ind][1]) == 0) {
                return new int[] { p[0] + o[ind][0], p[1] + o[ind][1] };
            }
        }
        return null;
    }
}

3

キャッチャー

猫が次のステップに進むことができる位置の1つを選択します。猫がそこに移動し、フィールドが変更されない場合、猫のために3つのステップの後に最も可能性のあるパスを与えるものを選択します。

コードは、非常に似た方法で方向を選択する私の猫のエントリFreeCatとほとんど同じです。

SpiralCat対CloseCatcher:

SpiralCatとCloseCatcher

package players;
/**
 * @author randomra
 */

import main.Field;
import java.util.Arrays;

public class CloseCatcher implements Catcher {
    public String getName() {
        return "CloseCatcher";
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 },
            { 0, -1 }, { 1, -1 } };// all valid moves
    final int turnCheck = 3;

    public int[] takeTurn(Field f) {

        int[] pos = f.findCat();
        int[] bestMove = { 0, 1 };
        int bestMoveCount = -1;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            int moveCount = free_count(currPos, turnCheck, f);
            if (moveCount > bestMoveCount) {
                bestMoveCount = moveCount;
                bestMove = t;
            }
        }
        int[] bestPos = { pos[0] + bestMove[0], pos[1] + bestMove[1] };
        return bestPos;
    }

    private int free_count(int[] pos, int turnsLeft, Field f) {
        if (f.isValidPosition(pos) || Arrays.equals(pos, f.findCat())) {
            if (turnsLeft == 0) {
                return 1;
            }
            int routeCount = 0;
            for (int[] t : turns) {
                int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
                int moveCount = free_count(currPos, turnsLeft - 1, f);
                routeCount += moveCount;
            }
            return routeCount;
        }
        return 0;
    }

}

素敵な+1。CloseCatcherは簡単にStraightCat
Spikatrix

3

ダイクストラ

彼は猫があまり好きではありません(:v{ >

FreeCat対Dijkstra (更新が必要)

ここに画像の説明を入力してください

package players;

import main.Controller;
import main.Field;

import java.util.*;

/**
 * @author TheNumberOne
 *
 * Catches the cat.
 */

public class Dijkstra implements Catcher{

    private static final int[][][] CACHE;

    static {
        CACHE = new int[Controller.FIELD_SIZE][Controller.FIELD_SIZE][2];
        for (int x = 0; x < Controller.FIELD_SIZE; x++){
            for (int y = 0; y < Controller.FIELD_SIZE; y++){
                CACHE[x][y] = new int[]{x,y};
            }
        }
    }

    private static final int[][] possibleMoves = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};
    @Override
    public String getName() {
        return "Dijkstra";
    }

    @Override
    public int[] takeTurn(Field f) {
        long startTime = System.nanoTime();

        final int[] theCat = f.findCat();
        int[] bestMove = {-1,1};
        int[] bestOpenness = {Integer.MAX_VALUE, 0};
        List<int[]> possiblePositions = new ArrayList<>();
        for (int x = 0; x < 11; x++){
            for (int y = 0; y < 11; y++){
                int[] pos = {x,y};
                if (f.isValidPosition(pos)){
                    possiblePositions.add(pos);
                }
            }
        }
        Collections.sort(possiblePositions, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return distance(o1, theCat) - distance(o2, theCat);
            }
        });
        for (int i = 0; i < possiblePositions.size() && System.nanoTime() - startTime < Controller.MAX_TURN_TIME/2; i++){
            int[] pos = possiblePositions.get(i);
            int before = f.field[pos[0]][pos[1]];
            f.placeBucket(pos);
            int[] openness = openness(theCat, f, true);
            if (openness[0] < bestOpenness[0] ||
                    (openness[0] == bestOpenness[0] &&
                            (openness[1] > bestOpenness[1])
                    )
                    ){
                bestOpenness = openness;
                bestMove = pos;
            }
            f.field[pos[0]][pos[1]] = before;
        }
        return bestMove;
    }


    /**
     *
     * @param pos The pos to calculate the openness of.
     * @param f The field to use.
     * @return Two integers. The first integer represents the number of reachable hexagons.
     * The second integer represents how strung out the squares are relative to the pos.
     */
    public static int[] openness(int[] pos, Field f, boolean catZeroWeight){
        Map<int[], Integer> lengths = new HashMap<>();
        PriorityQueue<int[]> open = new PriorityQueue<>(10,new Comparator<int[]>() {
            Map<int[], Integer> lengths;
            @Override
            public int compare(int[] o1, int[] o2) {
                return lengths.get(o1) - lengths.get(o2);
            }
            public Comparator<int[]> init(Map<int[], Integer> lengths){
                this.lengths = lengths;
                return this;
            }
        }.init(lengths));
        Set<int[]> closed = new HashSet<>();
        lengths.put(pos, catZeroWeight ? 0 : 6 - pointsAround(pos, f).size());
        open.add(pos);
        while (open.size() > 0){
            int[] top = open.remove();
            if (closed.contains(top)){
                continue;
            }
            closed.add(top);
            int l = lengths.get(top);
            List<int[]> pointsAround = pointsAround(top, f);

            for (ListIterator<int[]> iter = pointsAround.listIterator(); iter.hasNext();){
                int[] point = iter.next();
                if (closed.contains(point)){
                    iter.remove();
                }
            }

            for (int[] p : pointsAround){
                int length = l + 7 - pointsAround(p, f).size();
                if (lengths.containsKey(p)){
                    length = Math.min(length, lengths.get(p));
                }
                lengths.put(p, length);
                open.add(p);
            }
        }
        int sum = 0;
        for (int integer : lengths.values()){
            sum += integer;
        }
        return new int[]{lengths.size(),sum};
    }

    public static int distance(int[] p1, int[] p2){
        p2 = Arrays.copyOf(p2, 2);
        while (p2[0] < p1[0]){
            p2[0] += 11;
        }
        while (p2[1] < p2[0]){
            p2[1] += 11;
        }
        int lowestDistance = 0;
        for (int dx = 0; dx == 0; dx -= 11){
            for (int dy = 0; dy == 0; dy -= 11){
                lowestDistance = Math.min(lowestDistance,Math.min(Math.abs(p1[0]-p2[0]-dx),Math.min(Math.abs(p1[1]-p2[1]-dy),Math.abs(p1[0]+p1[1]-p2[0]-dx-p2[1]-dy))));
            }
        }
        return Math.min(Math.abs(p1[0]-p2[0]),Math.min(Math.abs(p1[1]-p2[1]),Math.abs(p1[0]+p1[1]-p2[0]-p2[1])));
    }

    public static int[] normalize(int[] p){
        return CACHE[(p[0]%11+11)%11][(p[1]%11+11)%11];
    }

    public static List<int[]> pointsAround(int[] p, Field f){
        int[] cat = f.findCat();
        List<int[]> locations = new ArrayList<>();
        for (int[] move : possibleMoves){
            int[] location = normalize(new int[]{p[0]+move[0], p[1] + move[1]});
            if (f.isValidPosition(location) || Arrays.equals(cat, location)){
                locations.add(location);
            }
        }
        return locations;
    }
}

彼が猫を捕まえようとする方法:

彼は、ボードのすべての正方形を分析し、ボードの開放性を最小化し、ボードの張り出し量を最大化する正方形を見つけようとします。猫に関連して。ボードの開放性とストリング性は、有名なアルゴリズムの修正を使用して計算されます

開放性:

位置に対するボードの開放性は、その位置から到達可能な位置の数です。

ストリングネス:

位置に対するボードの糸引きは、到達可能な位置と位置の間の距離の合計です。

最終更新:

今、彼はFreeCatと彼自身の猫をすべての猫で捕まえるのがずっと上手です。残念なことに、彼は狂った非協力的な猫を捕まえるのがはるかに悪いです。彼は、猫が狂ったものの1つであるかどうかを検出し、CloseCatcherとして行動することで改善できます。

不良動作修正済。


これまでのところ機能することを確認できますが、これまでのところ最も遅いが、これまでで最高の1つだと思います。RandCatとの100ゲームに134秒かかりますが、合計で4406移動します!次の日のいずれかで、PCを一晩実行する必要があると思います...どのように機能するかについて少しお話いただけますか?
flawr

@flawr説明を追加しました。
TheNumberOne

まだうまくいきません。エラーが1つあります:error: cannot infer type arguments for PriorityQueue<>この行にPriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {
-Spikatrix

@CoolGuy Java 6を使用していますか?JDKを更新する必要があると思います。
TheNumberOne

@CoolGuyまた、int[]後に2つの空のダイヤモンドの間に置くことができPriorityQueueます。
TheNumberOne

2

ForwordCatcher

猫の前にバケツを置きます。それが取られる場合は後ろに置きます。

RabidCat対ForwordCatcher:

RabidCat対ForwordCatcher:

package players;

import main.Field;
import java.util.Arrays;

public class ForwordCatcher implements Catcher {
    public String getName() {
        return "ForwordCatcher";
    }

    private int[] lastPos = {0,0};

    public int[] takeTurn(Field f) {
        int[] temp = lastPos;
        int[] pos = f.findCat();
        lastPos = pos;
        int[] Move = {pos[0]*2-temp[0], pos[1]*2-temp[1]};
        if(f.isValidPosition(Move)){return Move;}
        if(f.isValidPosition(temp)){return temp;}
        Move[0] = pos[0];Move[1] = pos[1]+1;
        return Move;
    }
}

1
かなりの数のエラーがあるため、プログラムをテストしなかったという仮定に至ります。それらを修正してください
...-flawr

@flawrが修正されました。エラーについては申し訳ありません。私はそれをテストしませんでしたし、私のJavaは良くありません。
メガトム

ナイス、これまでのところすべてがスムーズに実行されますが、それが常に有効な動きを生成するかどうかはまだ
わかりません

1
@flawrキャッチャーにとって猫の後ろのスペースは常に空です:)
TheNumberOne

2

ChoiceCatcher

ChoiceCatエントリと同じスコアリングメカニズムを使用します。ChoiceCatは最初の数個のバケットを脅威と見なさないため、最初の数個のバケットを気にしないため、最初の数ステップで関連するセルを選択するのに役立つ小さな変更があります。

ChoiceCatcherは、現在のキャッチャーよりもかなり良いスコアを獲得しているようです。

ChoiceCatとChoiceCatcher:

ChoiceCatとChoiceCatcher

package players;
/**
 * @author randomra
 */
import java.util.Arrays;

import main.Field;

public class ChoiceCatcher implements Catcher {

    private class Values {
        public final int size;
        private double[][] f;

        Values(int size) {
            this.size = size;
            f = new double[size][size];
        }

        public double read(int[] p) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j];
        }

        private double write(int[] p, double v) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j] = v;
        }
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { 1, 0 }, { 1, -1 },
            { 0, -1 }, { -1, 0 } };// all valid moves CW order
    final int stepCheck = 5;

    public String getName() {
        return "ChoiceCatcher";
    }

    @Override
    public int[] takeTurn(Field f) {
        int[] bestPos = null;
        double bestPosValue = Double.MAX_VALUE;
        for (int i = 0; i < f.SIZE; i++) {
            for (int j = 0; j < f.SIZE; j++) {
                if (f.read(i, j) == Field.EMPTY) {
                    Field myField = new Field(f);
                    myField.placeBucket(new int[] { i, j });
                    double posValue = catTurnValue(myField);
                    if (posValue < bestPosValue) {
                        bestPosValue = posValue;
                        bestPos = new int[] { i, j };
                    }
                }
            }
        }
        return bestPos;
    }

    private double catTurnValue(Field f) {

        int[] pos = f.findCat();
        double[] values = new double[6];
        int count=0;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            double moveValue = movePosValue(currPos, f);
            values[count++]=moveValue;
        }
        Arrays.sort(values);
        return values[5];
    }

    private double movePosValue(int[] pos, Field f) {

        Values v = new Values(f.SIZE);

        for (int ring = stepCheck; ring >= 0; ring--) {
            for (int phase = 0; phase < 2; phase++) {
                for (int sidepos = 0; sidepos < Math.max(1, ring); sidepos++) {
                    for (int side = 0; side < 6; side++) {
                        int[] evalPos = new int[2];
                        for (int coord = 0; coord < 2; coord++) {
                            evalPos[coord] = pos[coord] + turns[side][coord]
                                    * sidepos + turns[(side + 1) % 6][coord]
                                    * (ring - sidepos);
                        }
                        if (phase == 0) {
                            if (ring == stepCheck) {
                                // on outmost ring, init value
                                v.write(evalPos, -1);
                            } else {
                                v.write(evalPos, posValue(evalPos, v, f));
                            }
                        } else {
                            // finalize position value for next turn
                            v.write(evalPos, -v.read(evalPos));
                        }
                    }
                }
            }
        }

        return -v.read(pos);
    }

    private double posValue(int[] pos, Values v, Field f) {
        if (f.read(pos[0], pos[1]) == Field.BUCKET) {
            return 0;
        }
        int count = 0;
        int maxRoutes = 2;
        double[] product = new double[6];
        for (int[] t : turns) {
            int[] tPos = new int[] { pos[0] + t[0], pos[1] + t[1] };
            if (v.read(tPos) > 0) {
                product[count] = 1 - 1 / (v.read(tPos) + 1);
                count++;
            }
        }
        Arrays.sort(product);
        double fp = 1;
        for (int i = 0; i < Math.min(count, maxRoutes); i++) {
            fp *= product[5 - i];
        }
        double fp2 = 1;
        for (int i = 0; i < Math.min(count, 6); i++) {
            fp2 *= product[5 - i];
        }
        double retValue = Math.min(count, maxRoutes) + fp;
        double retValue2 = Math.min(count, 6) + fp2;
        return -retValue - retValue2 / 1000000;
    }

}

1

ランドキャッチャー

これは、コントローラーをテストするためだけに行われ、バケットをランダムに配置するだけです(非常に非効率的です)。

package players;

import main.Field;

public class RandCatcher implements Catcher {
    public String getName(){
        return "RandCatcher";
    }
    public int[] takeTurn(Field f){
        int[] pos = {0,0};
        do {
            pos[0] = (int) (Math.random()*f.SIZE);
            pos[1] = (int) (Math.random()*f.SIZE);
        } while( f.isValidPosition(pos)==false );
        return pos;
    }

}

1

StupidFillCatcher

これは、コントローラーをテストするためだけに作成されました。猫が捕まるまで、列ごとに埋めていきます。

package players;

import main.Field;

public class StupidFillCatcher implements Catcher {
    public String getName(){
        return "StupidFillCatcher";
    }
    public int[] takeTurn(Field f){
        for(int i=0; i < f.SIZE; i++){
            for(int j=0; j < f.SIZE; j++){
                if(f.isValidPosition(new int[] {i,j})){
                    return new int[] {i,j};
                }
            }
        }
        return new int[] {0,0};
    }

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.