KOTH asymétrique: Attrapez le chat (fil de capture)


17

KOTH asymétrique: Attrapez le chat

MISE À JOUR : Les fichiers gist sont mis à jour (y compris les nouvelles submisisons) car Controller.java n'a pas détecté d'exceptions (seulement des erreurs). Il détecte désormais les erreurs et les exceptions et les imprime également.

Ce défi consiste en deux threads, c'est le thread catcher, le thread cat peut être trouvé ici .

Le contrôleur peut être téléchargé ici .

Il s'agit d'un KOTH asymétrique: chaque soumission est soit un chat, soit un receveur . Il y a des jeux entre chaque paire de chacun un chat et un receveur. Les chats et les attrapeurs ont des classements séparés.

Catcher

Il y a un chat sur une grille hexagonale. Votre tâche consiste à l'attraper le plus rapidement possible. Chaque tour, vous pouvez placer un seau d'eau sur une cellule de la grille afin d'empêcher le chat de pouvoir s'y rendre. Mais le chat n'est pas (peut-être) aussi stupide, et chaque fois que vous placez un seau, le chat se déplace vers une autre cellule de la grille. La grille étant hexagonale, le chat peut aller dans 6 directions différentes. Votre objectif est d'entourer le chat de seaux d'eau, le plus vite sera le mieux.

Chat

Vous savez que le receveur veut vous attraper en plaçant des seaux d'eau autour de vous. Bien sûr, vous essayez de vous soustraire, mais comme vous êtes un chat paresseux (comme les chats), vous faites exactement un pas à la fois. Cela signifie que vous ne pouvez pas rester au même endroit que vous, mais vous devez vous déplacer vers l'un des six endroits environnants. Chaque fois que vous voyez que le receveur a placé un nouveau seau d'eau, vous allez dans une autre cellule. Bien sûr, vous essayez d'éviter le plus longtemps possible.

la grille

La grille est hexagonale, mais comme nous n'avons pas de structures de données hexagonales, nous prenons un 11 x 11tableau carré 2d et imitons le `` comportement '' hexagonal que le chat ne peut déplacer que dans 6 directions:

entrez la description de l'image ici

La topologie est toroïdale, ce qui signifie que si vous marchez sur une cellule «à l'extérieur» de la matrice, vous serez simplement transféré vers la cellule correspondante de l'autre côté de la matrice.

Jeu

Le chat commence à une position donnée dans la grille. Le receveur peut effectuer le premier mouvement, puis le chat et son receveur alternent les mouvements jusqu'à ce que le chat soit attrapé. Le nombre de pas est le score de ce match. Le chat essaie d'obtenir un score aussi élevé que possible, le receveur essaie d'obtenir un score aussi bas que possible. La somme moyenne de tous les jeux auxquels vous avez participé sera le score de votre soumission. Il y a deux classements distincts, un pour le chat, un pour les attrapeurs.

Manette

Le contrôleur donné est écrit en Java. En tant que receveur ou chat, vous devez chacun implémenter une classe Java (il existe déjà quelques exemples primitifs) et la placer dans le playerspackage (et mettre à jour la liste des chats / catchers dans la classe Controller), mais vous pouvez également écrire fonctions supplémentaires au sein de cette classe. Le contrôleur est livré avec chacun deux exemples pratiques de classes simples chats / catcher.

Le champ est un tableau 11 x 112D intqui stocke les valeurs des états actuels des cellules. Si une cellule est vide, elle a de la valeur 0, s'il y a un chat, elle a de la valeur -1et s'il y a un seau, il y en a un 1.

Il y a quelques fonctions données que vous pouvez utiliser: isValidMove()/ isValidPosition()sont pour vérifier si votre mouvement (chat) / position (receveur) est valide.

Chaque fois que c'est votre tour, votre fonction takeTurn()est appelée. L'argument contient une copie de la grille actuelle et des méthodes telles read(i,j)que la lecture de la cellule (i,j), ainsi isValidMove()/ isValidPosition()que la vérification de la validité de votre réponse. Cela gère également le recouvrement de la topologie toroïdale, ce qui signifie que même si la grille n'est que de 11 x 11, vous pouvez toujours accéder à la cellule (-5,13).

La méthode doit renvoyer un inttableau de deux éléments, qui représentent des mouvements possibles. Pour les chats, ce sont ceux {-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}qui représentent la position relative de l'endroit où le chat veut aller, et les capteurs renvoient les coordonnées absolues de l'endroit où ils veulent placer un seau {i,j}.

Si votre méthode produit un mouvement invalide, votre soumission sera disqualifiée. Le déplacement est considéré comme invalide, si à votre destination est déjà un seau ou le déplacement n'est pas autorisé / destination déjà occupée (comme un chat), ou s'il y a déjà un seau / chat (comme un receveur). Vous pouvez vérifier cela à l'avance avec les fonctions données.

Votre soumission devrait fonctionner assez rapidement. Si votre méthode dure plus de 200 ms pour chaque étape, elle sera également disqualifiée. (De préférence beaucoup moins ...)

Les programmes sont autorisés à stocker des informations entre les étapes.

Soumissions

  • Vous pouvez faire autant de soumissions que vous le souhaitez.
  • Veuillez ne pas modifier de manière significative les soumissions que vous avez déjà soumises.
  • Veuillez chaque soumission dans une nouvelle réponse.
  • Chaque soumission doit de préférence avoir son nom unique.
  • La soumission doit comprendre le code de votre classe ainsi qu'une description qui nous indique comment fonctionne votre soumission.
  • Vous pouvez écrire la ligne <!-- language: lang-java -->avant votre code source afin d'obtenir une coloration syntaxique automatique.

Notation

Tous les chats rivaliseront avec tous les attrapeurs le même nombre de fois. J'essaierai de mettre à jour fréquemment les scores actuels, les gagnants seront déterminés lorsque l'activité aura diminué.

Ce défi est inspiré de ce vieux jeu flash

Merci @PhiNotPi pour les tests et les commentaires constructifs.

Scores actuels (100 matchs par paire)

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

Quel programme fait les animations?
MegaTom

L'animation n'est que l'interface graphique (lors du démarrage du contrôleur, vous devez définir PRINT_STEPS = truedes paramètres plus détaillés dans le fichier MyFrame.java). Ensuite, j'ai enregistré cela avec LICEcap et l' ai édité avec GIMP . Si vous avez d'autres questions, n'hésitez pas!
flawr

Si vous ajoutez une entrée utilisateur au contrôleur, cela pourrait faire un bon logiciel avec l'interface graphique et les robots déjà écrits. Il serait également intéressant de voir dans quelle mesure les humains peuvent casser / abuser des stratégies spécifiques des bots.
randomra

De plus, mon bot peut-il conserver les informations du match précédent pour essayer de trouver une meilleure séquence de mouvements contre le même bot? Je suppose que non, car cela s'améliore au fur et à mesure que vous tournez. Il devrait également deviner s'il joue contre un nouveau bot, donc l'ordre de fonctionnement importerait aussi.
randomra

1
Pourquoi les scores des chats sont-ils désordonnés?
Spikatrix

Réponses:


6

Achille

Achille n'est pas trop brillant mais il est impitoyablement efficace. D'abord, il empêche le chat d'utiliser l'enveloppe autour de la planche, puis il divise la planche en deux. Ensuite, il continue de diviser la partie de la planche dans laquelle le chat est en deux jusqu'à ce que le chat soit piégé.

Démonstration RandCat vs Achilles

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



}

Eh bien, lequel est-ce maintenant, Achille ou Hector? (Ou quelqu'un avec un trouble d'identité dissiociatif? =)
flawr

@flawr Achilles, lol j'ai changé le nom à mi-chemin (c'est plus apte à nommer le receveur Achilles et le chat Hector) mais j'ai oublié de changer le java - c'est ce qui se passe lorsque vous programmez après le thé :(
euanjt

Mais Hector préfère être un nom de chien =) Merci pour votre soumission qui fonctionne très bien. J'espère que cela ne vous dérange pas que j'inclus également le «préambule» dans votre code.
flawr

Oui Aucun problème. Hector sonne comme un nom de chien ...
euanjt

Je viens de lancer une simulation (10000 jeux pour chaque appariement) et Achilles a été disqualifié, en raison de StackOverflowError répété. Je pense que la récursivité n'a pas pris fin: pastebin.com/9n6SQQnd
flawr

5

Agamemnon

Agamemnon divise la zone du chat en deux avec une ligne verticale jusqu'à ce que le chat n'ait qu'une bande de largeur 2 pour se déplacer, à quel point il piège le chat.

Agamemnon vs RandCat:

entrez la description de l'image ici

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

Ce receveur fait toujours mieux qu'Achille et je pense qu'il est suffisamment différent pour justifier une nouvelle réponse.


Très belle solution, j'étais sûr qu'Achille était presque optimal, mais maintenant je pense que même Agamemnon pourrait être légèrement amélioré =)
flawr

Oui, Agamemnon a un algorithme de piégeage de fin de jeu bien meilleur qu'Achille, mais je suis sûr qu'il y a quelques ajustements ... Maintenant, je vais essayer de travailler sur un chat :)
euanjt

@flawr très petit ajustement ajouté pour accélérer la capture dans certains cas spéciaux, cela n'affecte pas l'animation ici (bien que je pense que cela pourrait affecter l'animation de SpiralCat)
euanjt

Question! Que se passe-t-il si vous êtes sur le point de fermer une ligne, mais que le chat se tient au dernier endroit?
M. Llama

@ Mr.Llama, il commence à faire la ligne suivante comme si cette ligne avait été remplie (c'est-à-dire que le chat était en fait un seau) - pas l'utilisation la plus efficace d'un tour mais arrive très rarement que cela n'a pas vraiment d'importance - le le chat doit ensuite s'éloigner à son prochain tour pour que je puisse y placer mon seau
euanjt

5

HexCatcher

Si le receveur peut mettre le chat à l'intérieur d'un grand hexagone avec 3 unités de côtés où les coins de l'hexagone sont déjà occupés par des seaux, le receveur peut garder le chat dans cette zone et l'attraper. L'hexagone ressemble à ceci:

entrez la description de l'image ici

C'est ce que HexCatcher essaie de réaliser. Il tuile mentalement le champ avec ces gros hexagones de manière à ce que chaque cellule d'angle fasse partie de 3 gros hexagones.

S'il y a une chance de garder le chat dans la zone actuelle en connectant deux coins à côté du chat, le bot le fera. (Par exemple, dans l'image si le chat est à 7,5, nous choisissons 7,6 même si seules les cellules 6,6 et 8,5 sont encore occupées.)

Si le précédent n'est pas une option, nous choisissons de jouer un coin qui fait partie de la zone où se trouve le chat. Si tous ces coins sont déjà choisis (comme dans l'image), nous choisissons une cellule à côté du chat.

Plusieurs petites améliorations sont possibles, telles que la meilleure gestion de l'enroulement (le carrelage se casse là-bas) ou l'exécution optimale des derniers mouvements de couple. Je pourrais en faire certaines. Si ce n'est pas permis, je vais juste l'ajouter (hors compétition) pour les intéressés.

DijkstrasCat vs HexCatcher:

entrez la description de l'image ici

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

Choisit l'une des positions où le chat pourrait passer à l'étape suivante. Il choisit celui qui donnerait le plus de chemins possibles après 3 étapes au chat s'il se déplaçait là et que le champ ne changeait pas.

Le code est presque identique à mon entrée Cat, FreeCat , qui choisit la direction de manière très similaire.

SpiralCat vs CloseCatcher:

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

}

Nice +1. CloseCatcher capture facilement StraightCat
Spikatrix

3

Dijkstra

Il n'aime pas beaucoup les chats (:v{ >

FreeCat vs Dijkstra (besoins mis à jour) :

entrez la description de l'image ici

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

Comment il essaie d'attraper le chat:

Il analyse tous les carrés du tableau et essaie de trouver le carré qui minimise l'ouverture du tableau et maximise l'étendue du tableau; par rapport au chat. L'ouverture et la rigidité d'une planche sont calculées à l'aide d'une modification de son célèbre algorithme .

Ouverture:

L'ouverture d'un tableau par rapport à une position est le nombre de positions accessibles depuis cette position.

Stringiness:

La rigidité d'une planche par rapport à une position est la somme des distances entre les positions accessibles et la position.

Avec la dernière mise à jour:

Maintenant, il est bien meilleur pour attraper FreeCat et son propre chat tous les chats.Malheureusement, il est également bien pire pour attraper les chats fous et non coopératifs. Il pourrait être amélioré en détectant si le chat est l'un des fous et en agissant ensuite comme CloseCatcher.

Bug réparé.


Peut confirmer que cela fonctionne jusqu'à présent, mais de loin le plus lent mais l'un des meilleurs jusqu'à présent, je pense. A besoin de 134 secondes pour 100 matchs contre RandCat tout en effectuant un total de seulement 4406 coups! Je pense que je vais devoir laisser mon ordinateur fonctionner pendant la nuit dans un des prochains jours ... Pouvez-vous nous en dire un peu plus sur son fonctionnement?
flawr

@flawr Ajout d'une description.
TheNumberOne

Ça ne marche toujours pas pour moi. Me donne une erreur: error: cannot infer type arguments for PriorityQueue<>sur cette ligne PriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {.
Spikatrix

@CoolGuy Utilisez-vous java 6? Je pense que vous devez mettre à jour votre JDK.
TheNumberOne

@CoolGuy Vous pouvez également mettre un int[]entre les deux diamants vides après PriorityQueue.
TheNumberOne

2

ForwordCatcher

Place un seau devant le chat, ou si cela est pris, place derrière.

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
Il y a pas mal d'erreurs, ce qui m'amène à supposer que vous n'avez pas testé votre programme. Veuillez corriger ces ...
flawr

@flawr fixe. désolé pour les erreurs. Je ne l'ai pas testé et mon Java n'est pas trop bon.
MegaTom

Bien, jusqu'à présent, tout se passe bien, mais je ne sais toujours pas si cela produira toujours des mouvements valides =)
flawr

1
@flawr L'espace derrière un chat sera toujours vide pour le receveur :)
TheNumberOne

2

ChoiceCatcher

Utilise le même mécanisme de notation que mon entrée ChoiceCat . Il y a une petite modification qui aide à choisir les cellules pertinentes lors des premières étapes car ChoiceCat ne se soucie pas des premiers compartiments car il ne les considère pas comme une menace.

ChoiceCatcher semble marquer considérablement mieux que les capteurs actuels.

ChoiceCat vs ChoiceCatcher:

ChoiceCat vs 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

RandCatcher

Cela a été fait juste pour tester le contrôleur et place juste au hasard les seaux (très inefficacement).

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

Cela a été fait juste pour tester le contrôleur. Il remplit juste colonne par colonne jusqu'à ce que le chat soit attrapé.

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

}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.