非対称KOTH:Catch the Cat(Catスレッド)


14

非対称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       191962     8      flawr   
StupidFill        212688     9      flawr
Achilles          77214      6      The E
Agamemnon         74896      5      The E
CloseCatcher      54776      4      randomra
ForwordCatcher    93814      7      MegaTom  
Dijkstra          47558      2      TheNumberOne
HexCatcher        48644      3      randomra
ChoiceCatcher     43834      1      randomra

RandCat            77490     9      flawr
StupidRightCat     81566     6      flawr
SpiralCat          93384     5      CoolGuy
StraightCat        80930     7      CoolGuy
FreeCat           106294     3      randomra
RabidCat           78616     8      cain
Dijkstra's Cat    115094     1      TheNumberOne
MaxCat             98400     4      Manu
ChoiceCat         113612     2      randomra

1
私はこの種の挑戦が警官と強盗のタグの目的だと思います。
SuperJedi224

4
@flawr 2つの敵のサブチャレンジを含むすべてのチャレンジにCnRタグを拡張することに賛成します(そして、このタグとKotHの両方をタグとして使用します)。CnRタグwikiは、そのジャンルでの最初の2、3の課題の影響を大きく受けています。(また、あなたは警官と強盗を間違った方向に持っています;))
マーティン・エンダー

1
猫がメソッドを介してキャッチャーの応答をインポートmain.Controller、呼び出しgetCatchers()、シミュレート/妨害することを防ぐものは何takeTurnですか?
LegionMammal978

12
@ LegionMammal978スポーツマンシップ。
マーティンエンダー

2
@feersumはこれを助けますか?(黒(または青)のドットは同じセルを表します。)
flawr

回答:


5

FreeCat

フィールドが変更されない場合、3つのステップの後、最も可能性のあるパスを与える移動を選択します。

FreeCat対Achilles:

FreeCat vsアキレス

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

import java.util.Arrays;

import main.Field;

public class FreeCat implements Cat {

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

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

    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;
            }
        }
        return bestMove;
    }

    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;
    }
}

3

ダイクストラの

彼はマスターのマスターアルゴリズムを学び、適用しました。彼は、対応するキャッチャーのクラスのメソッドのいくつかに依存していることに注意してください。

ダイクストラの猫とヘックスキャッチャー(更新が必要):

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

package players;

import main.Field;
import players.Dijkstra; //Not needed import. Should already be available.

/**
 * @author TheNumberOne
 *
 * Escapes from the catcher.
 * Uses Dijkstras methods.
 */

public class DijkstrasCat implements Cat{

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

    @Override
    public int[] takeTurn(Field f) {
        int[] me = f.findCat();
        int[] bestMove = {-1,1};
        int bestOpenness = Integer.MAX_VALUE;
        for (int[] move : possibleMoves){
            int[] newPos = Dijkstra.normalize(new int[]{me[0]+move[0],me[1]+move[1]});
            if (!f.isValidMove(move)){
                continue;
            }
            int openness = Dijkstra.openness(newPos, f, true)[1];
            if (openness < bestOpenness || (openness == bestOpenness && Math.random() < .5)){
                bestOpenness = openness;
                bestMove = move;
            }
        }
        return bestMove;
    }
}

彼の働き:

彼は自分との関係でボードのストリンジェンシーを最小限に抑える動きを見つけようとします。詳細については、対応するキャッチャーの投稿を参照してください。

更新あり:

彼は今、水の入ったバケツが時々形成する奇妙な幾何学的形状を避けています。


3

マックスキャット

Minimaxアルゴリズムを実装してみました。ただし、時間が限られているため、パフォーマンスはあまりよくありません。編集:マルチスレッドを使用するようになりましたが、(少なくとも私のコンピューターでは)これ以上深さを設定することはできません。そうでない場合、タイムアウトが発生します。6個以上のコアを搭載したPCを使用すると、この提出ははるかに優れたものになります:)

MaxCat対ダイクストラ:

MaxCat対ダイクストラ

package players;

import java.util.ArrayList;
import java.util.List;

import main.Field;

public class MaxCat implements Cat {
    final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, { 0, -1 }, { 1, -1 } };

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

    public int[] takeTurn(Field f) {
        List<CatThread> threads = new ArrayList<>();
        int[] pos = f.findCat();
        for (int[] turn : turns) {
            if(f.read(pos[0]+turn[0], pos[1]+turn[1]) == Field.EMPTY){
                CatThread thread = new CatThread();
                thread.bestMove = turn;
                thread.field = new Field(f);
                thread.start();
                threads.add(thread);
            }
        }
        for (CatThread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {}
        }
        int best = Integer.MIN_VALUE;
        int[] bestMove = { -1, 1 };
        for (CatThread thread : threads) {
            if (thread.score > best) {
                best = thread.score;
                bestMove = thread.bestMove;
            }
        }
        return bestMove;
    }

    class CatThread extends Thread {
        private Field field;
        private int[] bestMove;
        private int score;
        private final int DEPTH = 3;

        @Override
        public void run() {
            score = max(DEPTH, Integer.MIN_VALUE, Integer.MAX_VALUE);       
        }

        int max(int depth, int alpha, int beta) {
            int pos[] = field.findCat();
            if (depth == 0 || field.isFinished()) {
                int moveCount = 0;
                for (int[] turn : turns) {
                    if(field.read(pos[0]+turn[0], pos[1]+turn[1]) == Field.EMPTY)
                        moveCount++;
                }
                return DEPTH-depth + moveCount;
            }
            int maxValue = alpha;
            for (int[] turn : turns) {
                if(field.read(pos[0]+turn[0], pos[1]+turn[1]) == Field.EMPTY) {
                    field.executeMove(turn);
                    int value = min(depth-1, maxValue, beta);
                    field.executeMove(new int[]{-turn[0], -turn[1]});
                    if (value > maxValue) {
                        maxValue = value;
                        if (maxValue >= beta)
                            break;
                    }
                }
            }
            return maxValue;
        }

        int min(int depth, int alpha, int beta) {
            if (depth == 0 || field.isFinished()) {
                int moveCount = 0;
                for (int[] turn : turns) {
                    int pos[] = field.findCat();
                    if(field.read(pos[0]+turn[0], pos[1]+turn[1]) == Field.EMPTY)
                        moveCount++;
                }   
                return -depth - moveCount;
            }
            int[][] f = field.field;
            int minValue = beta;
            List<int[]> moves = generateBucketMoves();
            for (int[] move : moves) {
                f[move[0]][move[1]] = Field.BUCKET;
                int value = max(depth-1, alpha, minValue);
                f[move[0]][move[1]] = Field.EMPTY;
                if (value < minValue) {
                    minValue = value;
                    if (minValue <= alpha)
                        break;
                }
            }
            return minValue;
        }

        private List<int[]> generateBucketMoves() {
            int[][] f = field.field;
            List<int[]> list = new ArrayList<>();
            for (int i = 0; i < f.length; i++) {
                for (int j = 0; j < f[i].length; j++) {
                    if (f[i][j] == Field.EMPTY) {
                        list.add(new int[]{i,j});
                    }
                }
            }
            return list;
        }
    }
}

実際には、Fieldpublic のコンストラクタを作成できます。ファイルをまだ更新していないのが残念ですが、これについては以前に説明しました。
フレイ

@flawrかっこいい、ありがとう!
CommonGuy

2

スパイラルキャット

らせん状に移動します。それ

  • 左上の円への移動を試みます
  • 可能でない場合は、右上の円に移動しようとします
  • 可能でない場合は、右の円に移動しようとします
  • 可能でない場合は、右下の円に移動しようとします
  • 可能でない場合は、左下の円に移動しようとします

SpiralCat vsアガメムノン:

スパイラルキャットvsアガメムノン

package players;
/**
 * @author Cool Guy
 */

import main.Field;

public class SpiralCat implements Cat{
    public String getName(){
        return "SpiralCat";
    }
    public int[] takeTurn(Field f){
        int[][] turns = {{-1,1},{0,1},{1,0},{1,-1},{0,-1},{-1,0}};//all valid moves
        int[] move;
        int i = -1;
        do {
            i++;
            move = turns[i];
        } while(f.isValidMove(move) == false);
        return move;
    }
}

あなたが遭遇したバグを知っていますか?私が変更したいのは、範囲外を避けるために変更turns[i]するturns[i%6]ことです(この状況では発生しません)。
-flawr

@flawr、くそー。言葉の選択が悪い。私はこの猫があまり知的ではないことを意味しました。時には、この猫は、
出口

@flawr、使用する必要がありますturns[i%6]か?私が意味する、takeTurn猫がブロックされている場合は、右、呼び出されないのだろうか?
Spikatrix

いいえ、あなたはプログラムのバグに遭遇したと思っていたので、考えられる理由を探していました。しかし、あなたは正しいです、明らかに(すべて正しければ)i>=6決して起こらないはずです。
-flawr

2

ラビッドキャット

RabidCatは疎水性なので、水のバケツを恐れています。彼は最も近いものを見つけ、反対方向に走ります。

RabidCat対ForwordCatcher:

rabidcat_vs_forwordcatcher

package players;

import java.util.Random;

import main.Field;

/**
* Run away from water buckets
* @author cain
*
*/

public class RabidCat implements Cat {

public RabidCat() {
}

@Override
public String getName() {
    return "RabidCat";
}

@Override
public int[] takeTurn(Field f) {
    int[][] directions = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};

    //where am I?
    int[] position = {0,0};
    for(int i = 0; i < 12; i++){
        for(int j = 0; j < 12; j++){
            if(f.read(i,j) == -1){
                position[0] = i;
                position[1] = j;
            }
        }
    }

    //Find the closest water
    int direction = 0;
    for(int d = 0; d < 10; d++){
        if(f.read(position[0] + d, position[1] - d) == 1 && f.isValidMove(directions[0])){
            direction = 1;
            break;
        }
        if(f.read(position[0], position[1] - d) == 1 && f.isValidMove(directions[1])){
            direction = 2;
            break;
        }
        if(f.read(position[0] + d, position[1]) == 1 && f.isValidMove(directions[2])){
            direction = 3;
            break;
        }
        if(f.read(position[0] - d, position[1]) == 1 && f.isValidMove(directions[3])){
            direction = 4;
            break;
        }
        if(f.read(position[0], position[1] + d) == 1 && f.isValidMove(directions[4])){
            direction = 5;
            break;
        }
        if(f.read(position[0] - d, position[1] + d) == 1 && f.isValidMove(directions[5])){
            direction = 6;
            break;
        }
    }

    //If there is no water near, wander
    while(direction == 0){
        Random rand = new Random();
        direction = rand.nextInt(6) + 1;
        if(!f.isValidMove(directions[direction - 1])){
            direction = 0;
        }
    }
    return directions[direction - 1];
}

}

うわー、CloseCatcherによって本当に破壊されます
ケイン

2

ChoiceCat

すべての新しい猫の位置について、その良さを確認し、最適なものを選択します。良さは、スコアを計算する位置よりも猫の位置から離れている2つの最良の隣接セルの関数です。1つはブロックでき、猫は逃げるためにもう1つしか必要としないため、2つのセルのみを使用します。私たちの機能は、1つの大きなセルと1つの悪いセルよりも、2つのかなり良いセルを好みます。バケットのあるポジションのスコアは0で、最も遠いフリーセルのスコアは1です。

ChoiceCatは、現在の猫よりもスコアが高いようです。

ChoiceCatとChoiceCatcher:

ChoiceCatとChoiceCatcher

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

import main.Field;

public class ChoiceCat implements Cat {

    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 "ChoiceCat";
    }

    public int[] takeTurn(Field f) {

        int[] pos = f.findCat();
        int[] bestMove = { 0, 1 };
        double bestMoveValue = -1;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            double moveValue = movePosValue(currPos, f);
            if (moveValue > bestMoveValue) {
                bestMoveValue = moveValue;
                bestMove = t;
            }
        }
        return bestMove;
    }

    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;
        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,2); i++) {
            fp *= product[5-i];
        }
        double retValue = Math.min(count,2) + fp;
        return -retValue;
    }
}

1

StupidRightCat

これは、コントローラーをテストするためだけに作成されました。猫は可能な限り右に移動し、そうでなければランダムな方向に移動します。

package players;

import main.Field;

public class StupidRightCat implements Cat{
    public String getName(){
        return "StupidRightCat";
    }
    public int[] takeTurn(Field f){
        int[][] turns = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};//all valid moves
        int[] move;

        if(f.isValidMove(turns[3])){
            return turns[3];
        } else {
            do {
                move = turns[(int) (turns.length * Math.random())];
            } while(f.isValidMove(move)==false);
            return move;//chose one at random
        }
    }
}

1

ランドキャット

これは、コントローラーをテストするためだけに作成されました。猫はただランダムに動きます。

package players;

import main.Field;

public class RandCat implements Cat{
    public String getName(){
        return "RandCat";
    }
    public int[] takeTurn(Field f){
        int[][] turns = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};//all valid moves
        int[] move;
        do {
            move = turns[(int) (turns.length * Math.random())];
        } while(f.isValidMove(move)==false);
        return move;//chose one at random
    }
}

1

StraightCat

この猫は直進します。

開始時に、ランダムな方向を選択し、それが不可能になるまでこの方向に移動し続けます。その場合、次の有効な方向に時計回りに方向をシフトし、このプロセスを繰り返します。

StraightCat対Agamemnon:

StraightCat対アガメムノン

package players;
/**
 * @author Cool Guy
 */

import main.Field;

public class StraightCat implements Cat{

    int lastDirection = -1; //Holds the last direction the cat moved
    public String getName(){
        return "StraightCat";
    }
    public int[] takeTurn(Field f){
        int[][] turns = {{-1,1},{0,1},{1,0},{1,-1},{0,-1},{-1,0}};//all valid moves

        if(lastDirection == -1)
          lastDirection = (int) (turns.length * Math.random());

        int[] move = turns[lastDirection];
        int i = lastDirection;

        while(true)
        {
            if(f.isValidMove(move))
                break;
            i = (i+1)%6;
            lastDirection = i;
            move = turns[i];
        }
        return move;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.