Asymmetrical KOTH: Catch the Cat (Cat Thread)

14

Asymmetrical KOTH: Catch the Cat

UPDATE : File inti diperbarui (termasuk submisisons baru) karena Controller.java tidak menangkap Pengecualian (hanya kesalahan). Itu sekarang menangkap kesalahan dan pengecualian dan juga mencetaknya.

Tantangan ini terdiri dari dua utas, ini adalah utas kucing, utas penangkap dapat ditemukan di sini .

Pengontrol dapat diunduh di sini .

Ini adalah KOTH asimetris: Setiap pengiriman adalah kucing atau penangkap . Ada permainan antara masing-masing pasangan masing-masing kucing dan penangkap. Kucing dan penangkap memiliki peringkat terpisah.

Penangkap

Ada kucing di kisi heksagonal. Tugas Anda adalah menangkapnya secepat mungkin. Setiap belokan, Anda dapat menempatkan ember air di satu sel kisi untuk mencegah kucing masuk ke sana. Tapi kucing itu (mungkin) tidak sebodoh itu, dan setiap kali Anda meletakkan ember, kucing itu akan pindah ke sel kisi lain. Karena kisi-kisi itu heksagonal, kucing dapat pergi ke 6 arah yang berbeda. Tujuan Anda adalah mengelilingi kucing dengan ember air, semakin cepat semakin baik.

Kucing

Anda tahu penangkap ingin menangkap Anda dengan menempatkan ember air di sekitar Anda. Tentu saja Anda mencoba menghindar, tetapi karena Anda adalah kucing malas (seperti kucing), Anda justru mengambil satu langkah pada saat itu. Ini berarti Anda tidak dapat tinggal di tempat yang sama dengan Anda, tetapi Anda harus pindah ke salah satu dari enam tempat di sekitarnya. Setiap kali Anda melihat bahwa penangkap menempatkan ember air baru Anda pergi ke sel lain. Tentu saja Anda berusaha menghindar selama mungkin.

Kisi

Kisi-kisi adalah heksagonal, tetapi karena kami tidak memiliki struktur data heksagonal, kami mengambil 11 x 11larik 2d persegi dan meniru 'perilaku' heksagonal yang kucing hanya bisa bergerak dalam 6 arah:

masukkan deskripsi gambar di sini

Topologi adalah toroidal, itu berarti jika Anda menginjak sel 'luar' dari array, Anda hanya akan ditransfer ke sel yang sesuai di sisi lain array.

Permainan

Kucing mulai keluar pada posisi yang diberikan di grid. Penangkap dapat melakukan langkah pertama, kemudian kucing dan penangkapnya bergantian bergerak sampai kucing ditangkap. Jumlah langkah adalah skor untuk game itu. Kucing berusaha mendapatkan skor sebesar mungkin, penangkap mencoba mendapatkan skor serendah mungkin. Jumlah rata-rata dari semua game yang Anda ikuti akan menjadi skor pengajuan Anda. Ada dua peringkat yang terpisah, satu untuk kucing, satu untuk penangkap.

Pengendali

Kontroler yang diberikan ditulis dalam Java. Sebagai penangkap atau kucing, Anda masing-masing harus menyelesaikan masing-masing kelas Java (sudah ada beberapa contoh primitif) dan letakkan dalam playerspaket (dan perbarui daftar kucing / penangkap di kelas Pengontrol), tetapi Anda juga dapat menulis fungsi tambahan di dalam kelas itu. Controller dilengkapi dengan masing-masing dua contoh kerja dari kelas kucing / penangkap sederhana.

Bidang ini adalah array 11 x 112D intyang menyimpan nilai status sel saat ini. Jika sebuah sel kosong, ia memiliki nilai 0, jika ada kucing ia memiliki nilai -1dan jika ada sebuah ember ada sebuah 1.

Ada beberapa fungsi yang dapat Anda gunakan: isValidMove()/ isValidPosition()untuk memeriksa apakah gerakan (kucing) / posisi (penangkap) Anda valid.

Setiap kali giliran Anda, fungsi Anda takeTurn()dipanggil. Argumen tersebut berisi salinan kisi saat ini dan memiliki metode seperti read(i,j)membaca sel di (i,j), serta isValidMove()/ isValidPosition()memeriksa validitas jawaban Anda. Ini juga mengelola pembungkus topologi toroidal, yang berarti bahkan jika grid hanya 11 x 11, Anda masih dapat mengakses sel (-5,13).

Metode harus mengembalikan intarray dari dua elemen, yang mewakili kemungkinan pergerakan. Untuk kucing ini adalah {-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}yang mewakili posisi relatif dari mana kucing ingin pergi, dan para penangkap mengembalikan koordinat absolut di mana mereka ingin menempatkan ember {i,j}.

Jika metode Anda menghasilkan langkah yang tidak valid, kiriman Anda akan didiskualifikasi. Langkah tersebut dianggap tidak valid, jika di tempat tujuan Anda sudah menjadi ember atau langkah tersebut tidak diperbolehkan / tujuan sudah ditempati (sebagai kucing), atau jika sudah ada ember / kucing (sebagai penangkap). Anda dapat memeriksa itu sebelumnya dengan fungsi yang diberikan.

Kiriman Anda harus bekerja cukup cepat. Jika metode Anda membutuhkan waktu lebih dari 200 ms untuk setiap langkah, itu juga akan didiskualifikasi. (Lebih disukai jauh lebih sedikit ...)

Program diizinkan untuk menyimpan informasi di antara langkah-langkah.

Pengajuan

  • Anda dapat membuat kiriman sebanyak yang Anda inginkan.
  • Tolong jangan secara signifikan mengubah kiriman yang sudah Anda kirim.
  • Silakan setiap pengiriman dalam jawaban baru.
  • Setiap pengajuan sebaiknya memiliki nama yang unik.
  • Kiriman harus terdiri dari kode kelas Anda serta deskripsi yang memberi tahu kami bagaimana kiriman Anda bekerja.
  • Anda dapat menulis baris <!-- language: lang-java -->sebelum kode sumber Anda untuk mendapatkan penyorotan sintaksis otomatis.

Mencetak gol

Semua kucing akan bersaing melawan semua penangkap dalam jumlah yang sama beberapa kali. Saya akan mencoba memperbarui skor saat ini sering, pemenang akan ditentukan ketika aktivitas telah menurun.

Tantangan ini terinspirasi oleh game flash lama ini

Terima kasih @PhiNotPi untuk pengujian dan memberikan umpan balik yang membangun.

Skor Saat Ini (100 Game per pasangan)

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
cacat
sumber
1
Saya pikir tantangan semacam ini untuk apa gunanya polisi dan perampok.
SuperJedi224
4
@ flawr Saya akan mendukung untuk memperluas tag CnR ke semua tantangan yang melibatkan dua sub-tantangan musuh (dan menggunakan keduanya dan KotH sebagai tag untuk ini). Tag CnR wiki sangat dipengaruhi oleh beberapa tantangan pertama yang kami alami dalam genre itu. (Juga, polisi dan perampok Anda salah jalan;;))
Martin Ender
1
Apa yang mencegah kucing mengimpor main.Controller, memanggil getCatchers(), dan mensimulasikan / menyabot respons para penangkap melalui takeTurnmetode mereka ?
LegionMammal978
12
@ LegionMammal978 Sportivitas.
Martin Ender
2
@feersum apakah ini membantu? (Titik hitam (resp. Biru) mewakili sel yang sama.)
flawr

Jawaban:

5

FreeCat

Pilih langkah yang akan memberinya jalur paling mungkin setelah 3 langkah jika bidang tidak berubah.

FreeCat vs Achilles:

FreeCat vs Achilles

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;
    }
}
randomra
sumber
3

Kucing Dijkstra

Dia belajar dan menerapkan algoritma master masternya. Perhatikan bahwa ia bergantung pada beberapa metode di kelas penangkap yang sesuai.

Dijkstra's Cat vs Hexcatcher (perlu diperbarui):

masukkan deskripsi gambar di sini

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

Bagaimana dia bekerja:

Dia mencoba menemukan langkah yang meminimalkan kekasaran dewan sehubungan dengan dirinya sendiri. Untuk informasi lebih lanjut, lihat pos penangkap yang sesuai.

Dengan pembaruan:

Dia sekarang menghindari bentuk geometris aneh yang kadang-kadang terbentuk oleh ember air.

TheNumberOne
sumber
3

MaxCat

Saya mencoba menerapkan algoritma Minimax. Namun, itu tidak berkinerja sangat baik karena keterbatasan waktu. Sunting: Sekarang menggunakan multithreading, tetapi (minimal di komputer saya) saya tidak dapat mengatur kedalaman lebih tinggi. Kalau tidak, timeout terjadi. Menggunakan PC dengan 6 inti atau lebih, pengiriman ini akan jauh lebih baik :)

MaxCat vs Dijkstra:

MaxCat vs Dijkstra

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;
        }
    }
}
CommonGuy
sumber
Sebenarnya Anda dapat membuat konstruktor Fieldpublik. Saya minta maaf saya belum memperbarui file, tetapi kami membahas ini sebelumnya!
flawr
@ flawr Oh keren, terima kasih!
CommonGuy
2

SpiralCat

Bergerak dengan cara spiral. Itu

  • Mencoba untuk pindah ke lingkaran kiri atas
  • Jika tidak memungkinkan, cobalah untuk pindah ke lingkaran kanan atas
  • Jika tidak memungkinkan, cobalah untuk pindah ke lingkaran kanan
  • Jika tidak memungkinkan, cobalah untuk pindah ke lingkaran kanan bawah
  • Jika tidak memungkinkan, cobalah untuk pindah ke lingkaran kiri bawah

SpiralCat vs Agamemnon:

SpiralCat vs Agamemnon

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;
    }
}
Spikatrix
sumber
Apakah Anda tahu bug apa yang Anda temui? Satu-satunya hal yang saya akan mengubah akan mengubah turns[i]untuk turns[i%6]untuk menghindari keluar batas (yang seharusnya tidak terjadi di stuation ini).
flawr
@ flawr, Sial. Pilihan kata yang buruk. Maksud saya, kucing ini tidak terlalu pintar. Kadang-kadang, kucing ini hanya berganti-ganti antara lingkaran kiri atas dan lingkaran kanan bawah bahkan ketika ada jalan keluar ...
Spikatrix
@ flawr, Apakah saya harus menggunakan turns[i%6]? Maksudku,takeTurn tidak akan dipanggil jika kucingnya diblokir, kan?
Spikatrix
Tidak, saya pikir maksud Anda Anda menemukan bug dalam program ini, jadi saya mencari kemungkinan alasannya. Tapi kau benar, jelas (jika semuanya adalah benar) i>=6seharusnya tidak pernah terjadi.
flawr
2

RabidCat

RabidCat memiliki hidrofobia, jadi dia takut dengan ember air. Dia menemukan yang terdekat dan berlari ke arah yang berlawanan.

RabidCat vs 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];
}

}
Kain
sumber
Wow, benar-benar rusak oleh CloseCatcher
Cain
2

ChoiceCat

Untuk setiap posisi kucing baru yang mungkin, kami memeriksa kebaikannya dan memilih yang terbaik. Kebaikan adalah fungsi dari dua sel tetangga terbaik yang lebih jauh dari posisi kucing daripada posisi yang skornya kita hitung. Kami hanya menggunakan dua sel karena satu dapat diblokir dan kucing hanya perlu satu lagi untuk lolos. Fungsi kami lebih suka dua sel yang cukup baik daripada satu besar dan satu buruk. Posisi dengan bucket memiliki skor 0 dan sel bebas terjauh memiliki skor 1.

ChoiceCat tampaknya mendapat skor lebih baik daripada kucing saat ini.

ChoiceCat vs ChoiceCatcher:

ChoiceCat vs 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;
    }
}
randomra
sumber
1

StupidRightCat

Ini dibuat hanya untuk menguji controller. Kucing itu bergerak ke kanan kapan pun memungkinkan, jika tidak bergerak ke arah acak.

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
        }
    }
}
cacat
sumber
1

RandCat

Ini dibuat hanya untuk menguji controller. Kucing itu hanya bergerak secara acak.

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
    }
}
cacat
sumber
1

StraightCat

Kucing ini bergerak lurus.

Pada awalnya, ia memilih arah acak dan terus bergerak ke arah ini sampai tidak bisa dalam hal ini, itu menggeser arah dengan cara searah jarum jam ke arah yang valid berikutnya dan mengulangi proses ini.

StraightCat vs Agamemnon:

StraightCat vs Agamemnon

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