Asimetrik KOTH: Kediyi Yakala (Yakalayıcı İplik)


17

Asimetrik KOTH: Kediyi Yakala

GÜNCELLEME : Controller.java özel durumları yakalamadığından (yalnızca hatalar) gist dosyaları güncellenir (yeni alt bölümler dahil). Artık hataları ve istisnaları yakalar ve yazdırır.

Bu zorluk iki iplikten oluşur, bu yakalama ipliği, kedi ipliği burada bulunabilir .

Kontrolör indirilebilir burada .

Bu asimetrik bir KOTH: Her başvuru ya bir kedi ya da bir avcıdır . Her bir kedinin her çifti ve bir avcı arasında oyunlar var. Kediler ve avcıların ayrı sıralamaları vardır.

yakalayan şey

Altıgen ızgarada bir kedi var. Göreviniz onu mümkün olduğunca hızlı yakalamak. Her turda, kedinin oraya gitmesini önlemek için bir ızgara hücresine bir su kovası yerleştirebilirsiniz. Ancak kedi (belki de) o kadar aptal değildir ve bir kova yerleştirdiğinizde kedi başka bir ızgara hücresine hareket eder. Izgara altıgen olduğundan, kedi 6 farklı yöne gidebilir. Amacınız kediyi su kovalarıyla çevrelemek, ne kadar hızlı o kadar iyi.

Kedi

Yakalayıcının, etrafınıza su kovaları koyarak sizi yakalamak istediğini biliyorsunuz. Elbette kaçmaya çalışıyorsunuz, ama tembel bir kedi olduğunuzda (kediler gibi) o anda tam olarak bir adım atıyorsunuz. Bu, sizinle aynı yerde kalamayacağınız anlamına gelir, ancak çevredeki altı noktadan birine taşınmanız gerekir. Yakalayıcının yeni bir su kovası yerleştirdiğini her gördüğünüzde başka bir hücreye gidersiniz. Tabii ki mümkün olduğunca uzun süre kaçmaya çalışıyorsunuz.

Kafes

Izgara altıgen, ancak altıgen veri yapılarımız olmadığından, 11 x 11kare 2d dizisi alıyoruz ve kedinin sadece 6 yönde hareket edebileceği altıgen 'davranışı' taklit ediyoruz :

resim açıklamasını buraya girin

Topoloji toroidaldir, yani dizinin 'dışında' bir hücreye basarsanız, dizinin diğer tarafındaki ilgili hücreye aktarılırsınız.

oyun

Kedi ızgarada belirli bir pozisyonda başlar. Yakalayıcı ilk hareketi yapabilir, sonra kedi ve yakalayıcı kedi yakalanana kadar alternatif olarak hareket eder. Adım sayısı o oyunun skorudur. Kedi mümkün olduğunca büyük bir puan almaya çalışır, yakalayıcı mümkün olduğunca düşük bir puan almaya çalışır. Katıldığınız tüm oyunların ortalama toplamı, başvurunuzun puanı olacaktır. Biri kedi, diğeri yakalayıcılar için olmak üzere iki ayrı sıralama vardır.

kontrolör

Verilen denetleyici Java ile yazılmıştır. Bir yakalayıcı ya da kedi olarak, her biriniz bir Java sınıfını (zaten bazı ilkel örnekler vardır) uygulamanız ve playerspakete yerleştirmeniz (ve Controller sınıfındaki kedi / yakalayıcıların listesini güncellemeniz) gerekir, ancak ayrıca yazabilirsiniz. bu sınıf içindeki ek işlevler. Kontrolör, basit kediler / yakalayıcı sınıflarının her iki çalışma örneğiyle birlikte gelir.

Alan, hücrelerin geçerli durumlarının değerlerini depolayan bir 11 x 112D intdizisidir. Bir hücre boşsa, değeri 0vardır, bir kedi varsa değeri vardır -1ve bir kova varsa bir vardır 1.

Kullanabileceğiniz birkaç işlev vardır: isValidMove()/ isValidPosition()hamle (cat) / pozisyonunuzun (catcher) geçerli olup olmadığını kontrol etmek içindir.

Sıra size geldiğinde, fonksiyonunuz takeTurn()çağrılır. Argüman read(i,j), hücrenin okunması gibi yöntemlerin (i,j)yanı sıra isValidMove()/ isValidPosition()cevabınızın geçerliliğini kontrol eden mevcut ızgaranın bir kopyasını içerir . Bu, toroidal topolojinin sarılmasını da yönetir, yani ızgara sadece 11 x 11 olsa bile, hücreye erişebilirsiniz (-5,13).

Yöntem int, olası hareketleri temsil eden iki öğeden oluşan bir dizi döndürmelidir . Kediler için bunlar {-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}kedinin nereye gitmek istediği göreceli konumunu temsil eder ve yakalayıcılar bir kova yerleştirmek istedikleri yerin mutlak koordinatlarını döndürür {i,j}.

Metodunuz geçersiz bir hamle üretirse, gönderiminiz diskalifiye edilecektir. Hedefiniz zaten bir kova ise veya harekete izin verilmiyorsa / hedef zaten işgal edilmişse (kedi olarak) veya zaten bir kova / kedi (yakalayıcı olarak) varsa, taşıma geçersiz kabul edilir. Verilen fonksiyonlarla elden önce kontrol edebilirsiniz.

Gönderiminiz oldukça hızlı olmalıdır. Metodunuz her adım için 200 ms'den uzun sürerse, diskalifiye edilir. (Tercihen çok daha az ...)

Programların adımlar arasında bilgi depolamasına izin verilir.

gönderimler

  • İstediğiniz sayıda başvuru yapabilirsiniz.
  • Lütfen daha önce gönderdiğiniz gönderileri önemli ölçüde değiştirmeyin.
  • Lütfen her bir gönderiyi yeni bir yanıtla gönderin.
  • Her gönderinin tercihen benzersiz bir adı olmalıdır.
  • Gönderme, sınıfınızın kodunun yanı sıra gönderiminizin nasıl çalıştığını bize açıklayan bir açıklamadan oluşmalıdır.
  • <!-- language: lang-java -->Otomatik sözdizimi vurgulaması için kaynak kodunuzdaki satırı yazabilirsiniz .

puanlama

Tüm kediler tüm avcılara aynı sayıda yarışır . Mevcut puanları sık sık güncellemeye çalışacağım, etkinlik azaldığında kazananlar belirlenecektir.

Bu meydan okuma bu eski flash oyundan esinlenmiştir

Test ve yapıcı geri bildirimde bulunduğunuz için @PhiNotPi'ye teşekkür ederiz.

Güncel Skorlar (Maç başına 100 oyun)

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

Animasyonları hangi program yapar?
MegaTom

Animasyon sadece GUI'dir (ayarlamanız gereken kontrolörü başlatırken PRINT_STEPS = true, dosyada daha ayrıntılı ayarlar MyFrame.java). Sonra bunu LICEcap ile kaydettim ve GIMP ile düzenledim . Başka sorularınız varsa sorun!
flawr

Denetleyiciye kullanıcı girişi eklerseniz, GUI ve önceden yazılmış botlar ile güzel bir yazılım yapabilir. İnsanların belirli bot stratejilerini ne kadar kırdığını / kötüye kullanabileceğini görmek de ilginç olacaktır.
randomra

Ayrıca, botum aynı botta daha iyi bir hareket sırası bulmaya çalışmak için önceki maçtaki bilgileri tutabilir mi? Sanırım daha fazla mermi daha iyi hale geldiğinden değil. Ayrıca yeni bir bota karşı oynayıp oynamadığını tahmin etmek zorunda kalacak, bu yüzden koşu düzeni de önemli olacaktır.
randomra

1
Kedilerin puanları neden sıralanmamış?
Spikatrix

Yanıtlar:


6

Aşil

Aşil çok parlak değil ama acımasızca etkili. Önce kedinin tahtanın etrafındaki sargıyı kullanmasını durdurur, daha sonra tahtayı ikiye böler. Daha sonra kedinin tuzağa düşmesine kadar kedinin içinde bulunduğu tahta parçasını ikiye böler.

Gösteri RandCat vs Aşil

randcat vs achilles

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



}

Şimdi hangisi şimdi, Aşil veya Hector? (Ya da dağıtıcı bir kimlik bozukluğu olan biri? =)
kusur

@flawr Aşil, lol Adı yarıya kadar değiştirdim (avcısı Aşil ve kedi Hector'u adlandırmaya daha yatkın) ama java'yı değiştirmeyi unuttum
çaydan

Ama Hector bir köpek ismi olmayı tercih eder =) Gönderdiğiniz işler için teşekkür ederiz. Umarım kodunuza 'önsözü' de dahil etmemi umursamazsınız.
Kusur

Evet sorun değil. Hector bir köpek ismi gibi geliyor ...
euanjt

Ben sadece bir simülasyon (her eşleştirme için 10000 oyun) koştum ve Aşil tekrarlanan StackOverflowError nedeniyle diskalifiye edildi. Ben özyineleme sona ermedi düşünüyorum: pastebin.com/9n6SQQnd
flawr

5

Agamemnon

Agamemnon, kedinin hareket etmesi için sadece genişlik 2 bir şeride sahip olana kadar kedilerin alanını dikey bir çizgiyle ikiye böler, bu noktada kediyi hapseder.

Agamemnon vs RandCat:

resim açıklamasını buraya girin

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

Bu avcı sürekli Aşil'den daha iyi ve bence yeni bir cevap verebilecek kadar farklı.


Çok güzel bir çözüm, Aşil'in
optimale

Evet, Agamemnon, Aşil'den çok daha iyi bir oyun yakalama algoritmasına sahip, ancak bazı ince
ayarlar

@flawr bazı özel durumlarda yakalamayı hızlandırmak için çok küçük bir tweak eklendi, buradaki animasyonu etkilemez (her ne kadar SpiralCat'ın animasyonunu etkileyebileceğini düşünüyorum)
euanjt

Soru! Bir çizgiyi kapatmak üzereyseniz, ama kedi son noktada duruyorsa ne olur?
Bay Llama

@ Mr.Llama, bir sonraki çizgiyi o çizginin doldurulmuş gibi (yani kedi aslında bir kova) yapmaya başlıyor - bir dönüşün en etkili kullanımı değil, ancak nadiren gerçekten önemli olmadığı- o zaman
kepçemi

5

HexCatcher

Yakalayıcı kediyi altıgenin köşelerinin zaten kovalarla dolu olduğu 3 birim kenarlı büyük bir altıgenin içine sokabilirse, yakalayıcı kediyi bu alanda tutabilir ve onu yakalayabilir. Altıgen şöyle görünür:

resim açıklamasını buraya girin

HexCatcher bunu başarmaya çalışır. Zihinsel olarak bu büyük altıgenlerle alanı her köşe hücresinin 3 büyük altıgenin parçası olacağı şekilde döşer.

Kedinin yanındaki iki köşeyi bağlayarak kediyi mevcut alanda tutma şansı varsa, bot bunu yapacaktır. (Örneğin, görüntüde kedi 7,5 ise, sadece 6,6 ve 8,5 hücre dolu olsa bile 7,6'yı seçeriz.)

Bir önceki seçenek bir seçenek değilse, kedinin bulunduğu alanın bir parçası olan bir köşe oynamayı seçeriz. Tüm bu köşeler zaten seçilmişse (resimde olduğu gibi) kedinin yanında bir hücre seçeriz.

Sarmayı daha iyi idare etme (oradaki fayans kırılır) veya son çifti yapmak gibi birçok küçük iyileştirme mümkündür. Bunlardan bazılarını yapabilirim. İzin verilmiyorsa, ilgilenenler için (rekabet dışında) ekleyeceğim.

DijkstrasCat vs HexCatcher:

resim açıklamasını buraya girin

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

CloseCatcher

Kedinin bir sonraki adımda basabileceği konumlardan birini seçer. Kedinin oraya hareket etmesi ve alanın değişmemesi için 3 adımdan sonra mümkün olan en fazla yolu verecek olanı seçer.

Kod, yönü çok benzer bir şekilde seçen Cat girişim FreeCat ile neredeyse aynı .

SpiralCat vs CloseCatcher:

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

}

Güzel +1. CloseCatcher StraightCat'i
Spikatrix

3

Dijkstra

Kedileri çok sevmez (:v{ >

FreeCat vs Dijkstra (güncellenmesi gerekiyor) :

resim açıklamasını buraya girin

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

Kediyi nasıl yakalamaya çalışır:

Tahtanın tüm karelerini analiz eder ve tahtanın açıklığını en aza indiren kareyi bulmaya çalışır ve tahtanın ne kadar çıkarıldığını en üst düzeye çıkarır; kedi ile ilgili olarak. Bir tahtanın açıklığı ve sıkılığı, ünlü algoritmasının bir modifikasyonu kullanılarak hesaplanır .

açıklık:

Bir tahtanın bir pozisyona göre açıklığı, o pozisyondan ulaşılabilir pozisyonların sayısıdır.

tel tel:

Bir tahtanın bir konuma göre sıkılığı, ulaşılabilir konumlar ve konum arasındaki mesafelerin toplamıdır.

Son güncelleme ile:

Şimdi, FreeCat ve kendi kedisini tüm kedileri yakalamakta çok daha iyidir . Ne yazık ki, çılgın işbirliği yapmayan kedileri yakalamakta da çok daha kötü. Kedinin çılgınlardan biri olup olmadığını tespit edip CloseCatcher gibi davranarak geliştirilebilir.

Hata çözüldü.


Şimdiye kadar çalıştığını teyit edebilir, ama bugüne kadar en yavaş ama şimdiye kadar en iyi biri düşünüyorum. Toplamda sadece 4406 hamle yaparken RandCat'a karşı 100 oyun için 134 saniye gerekiyor! Bence önümüzdeki günlerden birinde bir gece bilgisayarımın çalışmasına izin vermeliyim ... Bize nasıl çalıştığından biraz daha bahsedebilir misin?
flawr

@flawr Bir açıklama ekledi.
TheNumberOne

Hala benim için çalışmıyor. Bana bir hata veriyor: error: cannot infer type arguments for PriorityQueue<>bu satırda PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {.
Spikatrix

@CoolGuy Java 6 mı kullanıyorsunuz? Bence JDK'nızı güncellemeniz gerekiyor.
TheNumberOne

@CoolGuy Sonra int[]iki boş elmas arasına bir de koyabilirsiniz PriorityQueue.
TheNumberOne

2

ForwordCatcher

Kedinin önüne bir kova yerleştirir veya eğer alınırsa, arkasına yerleştirir.

RabidCat vs ForwordCatcher:

RabidCat vs 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
Beni programınızı test etmediğiniz varsayımına götüren birkaç hata var. Lütfen bunları düzeltin ...
Kusur

@flawr düzeltildi. hatalar için özür dilerim. Test etmedim ve Java'm iyi değil.
MegaTom

Güzel, şu ana kadar her şey sorunsuz çalışıyor, ama yine de her zaman geçerli hamleler üretip üretmeyeceğinden emin değilim =)
flawr

1
@flawr Bir kedinin arkasındaki alan her zaman alıcı için boş olacak :)
TheNumberOne

2

ChoiceCatcher

ChoiceCat girişimle aynı puanlama mekanizmasını kullanır . ChoiceCat'in tehdit olarak görmediği için ilk birkaç kovayı önemsemediğinden, ilk birkaç adımda ilgili hücreleri seçmeye yardımcı olan küçük bir değişiklik var.

ChoiceCatcher, mevcut yakalayıcılardan önemli ölçüde daha iyi puan alıyor gibi görünüyor.

ChoiceCat ve ChoiceCatcher karşılaştırması:

ChoiceCat ve ChoiceCatcher karşılaştırması

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

RandCatcher

Bu sadece kontrolörü test etmek için yapıldı ve kovaları rastgele yerleştirdi (çok verimsiz).

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

Bu sadece kontrolörü test etmek için yapıldı. Kedi yakalanana kadar sadece sütun sütun doldurur.

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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.