Splix.io - roi de la terre


37

Vous êtes un point entreprenant qui souhaite augmenter les terres sous son contrôle. C’est très simple: quittez votre territoire actuel et revenez dans votre pays. Tous les éléments de cette boucle vous appartiennent maintenant. Mais il ya un hic. Si un autre point trouve votre boucle et la traverse, vous mourrez.

Si vous ne l'avez pas déjà essayé, allez à Splix.io et essayez un jeu. Utilisez les touches fléchées pour contrôler votre mouvement.

GIF

entrez la description de l'image ici

Crédit: http://splix.io/

Détails

Tous les joueurs commencent à des positions aléatoires sur un tableau 200x200. (Je me réserve le droit de changer cela :). Vous aurez un certain nombre de mouvements pour accumuler le plus grand nombre de points possible. Les points sont comptés par:

  • Le nombre de joueurs que vous avez tués fois 300
  • La quantité de terre que vous possédez à la fin du tour

Cela soulève le point que d'autres peuvent voler votre terre. S'ils commencent une boucle qui coupe une partie de votre terre, ils peuvent la réclamer. Si vous mourez pendant le tour, vous perdez tous les points pour ce tour.

Chaque tour a un groupe de joueurs choisi au hasard (maximum 5 joueurs uniques) (sujet à changement). Chaque joueur participe à un nombre égal de tours. Le score final de votre bot est déterminé par son score moyen par match. Chaque jeu consiste en 2000 tours (également sujets à changement). Tous les robots bougent en même temps.

Cas de décès

Tête mégot

coup de tête

Les deux joueurs meurent quand ils se font la tête. Cela reste vrai même lorsque les deux joueurs sont au bord de leur espace.

coup de tête

Cependant, lorsqu'un seul joueur est sur son terrain, l'autre joueur meurt.

entrez la description de l'image ici

Ligne croisée

entrez la description de l'image ici

Dans ce cas, seul le joueur violet meurt.

Vous ne pouvez pas franchir votre propre ligne.

entrez la description de l'image ici

Sortir du tableau

joueur sortant du plateau

Si un joueur tente de quitter le tableau, il mourra et perdra tous les points.

Zone de capture

Un joueur capturera une zone quand il aura une piste et qu'il rentrera dans son propre pays.

entrez la description de l'image ici

Le rouge remplit entre les deux lignes rouges. Le seul cas où un joueur ne remplit pas est lorsqu'un autre joueur est dans la boucle. Pour être clair, cela ne s'applique que lorsque l'autre joueur est lui-même dans la boucle, pas seulement la terre qui lui appartient. Un joueur peut capturer un terrain d'une autre personne. Si un joueur ne peut pas remplir la zone entourée par sa piste, la piste est convertie directement en terrain normal. Si le joueur à l'intérieur de la boucle d'atterrissage d'un autre joueur meurt, la zone dans cette boucle est remplie. Chaque fois qu'un joueur meurt, le tableau est réexaminé pour une zone pouvant être remplie.

Détails du contrôleur

Le contrôleur est ici . Il est très similaire au jeu original, mais de petites modifications ont été apportées pour que cela corresponde mieux à KotH et pour des raisons techniques. Il est construit avec @NathanMerrill de bibliothèque KotHComm , et avec une aide substantielle de @NathanMerrill ainsi. S'il vous plaît laissez-moi savoir de tous les bugs que vous trouverez dans le contrôleur dans la salle de discussion . Pour être cohérent avec KotHComm, j'ai utilisé des collections Eclipse dans tout le contrôleur, mais les robots peuvent être écrits en utilisant uniquement la bibliothèque Java Collections.

Tout est emballé dans un uberjar sur la page des versions de github . Pour l'utiliser, téléchargez-le et joignez-le à votre projet afin de pouvoir l'utiliser automatiquement (instructions pour IntelliJ , Eclipse ). Pour tester vos soumissions, vous exécutez le pot avec java -jar SplixKoTH-all.jar -d path\to\submissions\folder. Assurez-vous qu’un sous path\to\submissions\folder-dossier est nommé javaet placez-y tous vos fichiers. N'utilisez pas de noms de paquet dans vos robots (bien que cela puisse être possible avec KotHComm, c'est juste un peu plus compliqué). Pour voir toutes les options, utilisez --help. Pour charger tous les robots, utilisez --question-id 126815.

Écrire un bot

Pour commencer à écrire un bot, vous devez faire une extension SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • C'est ici que vous décidez quel mouvement vous voulez que votre bot fasse. Ne doit pas retourner null.
  • HiddenPlayer getThisHidden()
    • Obtenez la HiddenPlayerversion de this. Utile pour comparer votre bot au tableau.

enum Direction

  • Valeurs
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Obtenez le Directionque vous obtiendriez si vous faites un virage à gauche.
  • Direction RightTurn()
    • Obtenez ce Directionque vous obtiendriez si vous faisiez un virage à droite.

ReadOnlyBoard

C'est la classe où vous accédez au tableau. Vous pouvez soit obtenir une vue locale (20x20) du tableau avec les positions des joueurs affichées, soit une vue globale (le tableau entier) avec uniquement les informations sur les détenteurs et les positions sur le plateau. C'est aussi où vous obtenez votre position.

  • SquareRegion getBounds()
    • Récupère la taille du tableau.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • Obtenez une carte globale du conseil.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • Identique à getGlobal(), sauf qu’il est limité à une zone de 20x20 autour de votre lecteur et qu’il indique les positions du joueur.
  • Point2D getPosition(SplixPlayer me)
    • Obtenez la position de votre joueur. Utiliser comme board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • Obtenez votre position sur le tableau. Usage:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGamene donne accès qu’au nombre de tours restants dans le jeu int getRemainingIterations().

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • Obtenir la HiddenPlayerversion de qui revendique un point - réclamant = une traînée.
  • HiddenPlayer getOwner()
    • Obtenez qui possède un point.
  • HiddenPlayer getWhosOnSpot()
    • Si le joueur est positionné sur ce point, retournez la version cachée de celui-ci. Ne fonctionne que dans getLocal().

Point2D

Contrairement aux autres classes ici, Point2Dest contenu dans la bibliothèque KotHComm.com.nmerrill.kothcomm.game.maps.Point2D

  • Point2D(int x, int y)
  • int getX()
  • int getY()
  • Point2D moveX(int x)
  • Point2D moveY(int y)
  • Point2D wrapX(int maxX)
    • Enveloppez la xvaleur pour qu'elle soit dans la plage de maxX.
  • Point2D wrapY(int maxY)
    • Enveloppez la yvaleur pour qu'elle soit dans la plage de maxY.
  • int cartesianDistance(Point2D other)
    • Cela se traduit par le nombre de tours qu'il faudrait au joueur pour passer d'un point a à un point b.

Soutien Clojure

Le compilateur Clojure est fourni avec le SplixKoTH-all.jar, vous pouvez donc utiliser Clojure pour votre bot! Reportez-vous à mon random_botpour voir comment l'utiliser.

Déboguer un bot

Le contrôleur est livré avec un débogueur pour aider à tester les stratégies. Pour le démarrer, lancez le pot avec le--gui option.

Pour attacher le débogueur à votre pot, suivez ces instructions pour IntelliJ, ou ces instructions pour Eclipse (version Eclipse non testé).

entrez la description de l'image ici

Si vous utilisez un débogueur avec votre code, vous pouvez l'utiliser pour visualiser ce que votre bot voit. Définissez un point d'arrêt au début de makeMovevotre bot et assurez-vous qu'il ne met en pause que le thread en cours. Ensuite, cliquez sur le bouton de démarrage de l'interface utilisateur et parcourez votre code.

entrez la description de l'image ici

Maintenant, pour tout mettre ensemble:

Running Bots

Pour exécuter vos robots avec d'autres, vous devez exécuter le fichier jar sur la page des versions. Voici une liste de drapeaux:

  • --iterations( -i) <= int(par défaut 500)
    • Spécifiez le nombre de jeux à exécuter.
  • --test-bot( -t) <=String
    • Exécutez uniquement les jeux dans lesquels le bot est inclus.
  • --directory( -d) <= Chemin
    • Le répertoire dans lequel exécuter les soumissions. Utilisez ceci pour lancer vos robots. Assurez-vous que vos robots sont dans un sous-dossier du chemin nommé java.
  • --question-id( -q) <= int(utiliser seulement126815 )
    • Téléchargez et compilez les autres soumissions à partir du site.
  • --random-seed( -r) <=int (la valeur par défaut est un nombre aléatoire)
    • Donnez une graine au coureur afin que les robots qui utilisent aléatoire puissent voir les résultats reproduits.
  • --gui (-g )
    • Exécutez le débogueur ui au lieu de lancer un tournoi. Mieux utilisé avec --test-bot.
  • --multi-thread( -m) <= boolean(défauttrue)
    • Exécuter un tournoi en mode multi-thread. Cela permet d'obtenir un résultat plus rapide si votre ordinateur possède plusieurs cœurs.
  • --thread-count( -c) <= int(défaut4)
    • Nombre de threads à exécuter si le multi-thread est autorisé.
  • --help( -h)
    • Imprimez un message d'aide semblable à celui-ci.

Pour exécuter toutes les soumissions sur cette page, utilisez java -jar SplixKoTH-all.jar -q 126815.

Formater votre message

Pour vous assurer que le contrôleur peut télécharger tous les robots, vous devez suivre ce format.

[BotName], Java                     // this is a header
                                    // any explanation you want
[BotName].java                      // filename, in the codeblock
[code]

De même, n'utilisez pas de déclaration de package.


Tableau de bord

+------+--------------+-----------+
| Rank | Name         |     Score |
+------+--------------+-----------+
|    1 | ImNotACoward | 8940444.0 |
|    2 | TrapBot      |  257328.0 |
|    3 | HunterBot    |  218382.0 |
+------+--------------+-----------+

S'il vous plaît laissez-moi savoir si une partie des règles ne sont pas claires, ou si vous trouvez des erreurs dans le contrôleur dans la salle de discussion .

S'amuser!


Hé, ça a finalement été posté! Je me demandais: D
MD XF

Depuis combien de temps attends-tu? ;) Avez-vous l'intention de soumettre?
J Atkin

Je ne sais pas si je serai capable de résoudre un tel problème, car j'écris principalement des programmes en esolangs. Mais je l'ai vu dans le bac à sable et cela ressemblait à un grand défi!
MD XF

@hyperneutrino J'ai vu l'édition, ça vous dérange vraiment? La rectitude politique n’est nulle part dans le propos de cet article, et elle est parfaitement correcte dans la grammaire anglaise ...
J Atkin

2
0.o petit monde? Je connais le développeur de splix.io. (Tweeté @ lui)
CAD97

Réponses:


2

ImNotACoward, Java

Ce bot est un expert en survie lâche . S'il n'y a pas d'ennemi à proximité, il réclame une partie de la terre. Si la boucle d'un autre joueur peut être atteinte en toute sécurité, il poignarde l'autre joueur dans le dos et engage l'autre joueur dans un duel. Si l’autre joueur ne peut pas être attaqué en toute sécurité, il prend la fuite et effectue une retraite stratégique sur son propre terrain.

ImNotACoward.java
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.impl.factory.Lists;
import org.eclipse.collections.impl.factory.Maps;
import org.eclipse.collections.impl.factory.Sets;

import com.jatkin.splixkoth.ppcg.game.Direction;
import com.jatkin.splixkoth.ppcg.game.SplixPlayer;
import com.jatkin.splixkoth.ppcg.game.readonly.HiddenPlayer;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyBoard;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyGame;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlySplixPoint;
import com.nmerrill.kothcomm.game.maps.Point2D;
import com.nmerrill.kothcomm.game.maps.graphmaps.bounds.point2D.SquareRegion;

public class ImNotACoward extends SplixPlayer {
    private static final MutableSet<Direction> DIRECTIONS = Sets.mutable.of(Direction.values());

    private static class Board {
        public MutableSet<Point2D> allPoints = null;
        private SquareRegion globalBounds = null;
        private SquareRegion viewBounds = null;
        private MutableMap<Point2D, ReadOnlySplixPoint> global = null;
        private MutableMap<Point2D, ReadOnlySplixPoint> view = null;

        public void update(ReadOnlyBoard readOnlyBoard) {
            if (this.allPoints == null) {
                this.allPoints = readOnlyBoard.getGlobal().keysView().toSet();
                this.globalBounds = readOnlyBoard.getBounds();
            }
            this.viewBounds = readOnlyBoard.viewingArea;
            this.global = readOnlyBoard.getGlobal();
            this.view = readOnlyBoard.getView();
        }

        public boolean inBounds(Point2D point) {
            return globalBounds.inBounds(point);
        }

        public boolean inView(Point2D point) {
            return viewBounds.inBounds(point);
        }

        public ReadOnlySplixPoint getSplixPoint(Point2D point) {
            return inView(point) ? view.get(point) : global.get(point);
        }

        public MutableSet<Point2D> getNeighbors(Point2D point) {
            return DIRECTIONS.collect(d -> point.move(d.vector.getX(), d.vector.getY())).select(this::inBounds);
        }

        public MutableSet<Point2D> getNeighbors(MutableSet<Point2D> points) {
            return points.flatCollect(this::getNeighbors);
        }

        public MutableSet<Point2D> getBorders(SquareRegion region) {
            return allPoints.select(p -> region.inBounds(p) &&
                    (p.getX() == region.getLeft() || p.getX() == region.getRight() ||
                    p.getY() == region.getTop() || p.getY() == region.getBottom() ||
                    p.getX() == globalBounds.getLeft() || p.getX() == globalBounds.getRight() ||
                    p.getY() == globalBounds.getTop() || p.getY() == globalBounds.getBottom()));
        }
    }

    private class Player {
        public final HiddenPlayer hiddenPlayer;
        public MutableSet<Point2D> owned = Sets.mutable.empty();
        private MutableSet<Point2D> unowned = null;
        private MutableSet<Point2D> oldClaimed = Sets.mutable.empty();
        public MutableSet<Point2D> claimed = Sets.mutable.empty();
        private MutableSet<Point2D> oldPos = Sets.mutable.empty();
        public MutableSet<Point2D> pos = Sets.mutable.empty();

        public Player(HiddenPlayer hiddenPlayer) {
            super();
            this.hiddenPlayer = hiddenPlayer;
        }

        public void nextMove() {
            owned.clear();
            unowned = null;
            oldClaimed = claimed;
            claimed = Sets.mutable.empty();
            oldPos = pos;
            pos = Sets.mutable.empty();
        }

        public MutableSet<Point2D> getUnowned() {
            if (unowned == null) {
                unowned = board.allPoints.difference(owned);
            }
            return unowned;
        }

        public void addOwned(Point2D point) {
            owned.add(point);
        }

        public void addClaimed(Point2D point) {
            claimed.add(point);
        }

        public void setPos(Point2D point) {
            pos.clear();
            pos.add(point);
        }

        public void calcPos() {
            if (pos.isEmpty()) {
                MutableSet<Point2D> claimedDiff = claimed.difference(oldClaimed);
                if (claimedDiff.size() == 1) {
                    pos = board.getNeighbors(claimedDiff).select(p -> !claimed.contains(p) && !board.inView(p));
                } else if (!oldPos.isEmpty()) {
                    pos = board.getNeighbors(oldPos).select(p -> owned.contains(p) && !board.inView(p));
                } else {
                    pos = owned.select(p -> !board.inView(p));
                }
            }
        }
    }

    private Board board = new Board();
    private Point2D myPos = null;
    private final Player nobody = new Player(new HiddenPlayer(null));
    private final Player me = new Player(new HiddenPlayer(this));
    private MutableMap<HiddenPlayer, Player> enemies = Maps.mutable.empty();
    private MutableMap<HiddenPlayer, Player> players = Maps.mutable.of(nobody.hiddenPlayer, nobody, me.hiddenPlayer, me);
    private MutableSet<Point2D> path = Sets.mutable.empty();

    private Player getPlayer(HiddenPlayer hiddenPlayer) {
        Player player = players.get(hiddenPlayer);
        if (player == null) {
            player = new Player(hiddenPlayer);
            players.put(player.hiddenPlayer, player);
            enemies.put(player.hiddenPlayer, player);
        }
        return player;
    }

    private Direction moveToOwned() {
        MutableSet<Point2D> targets = me.owned.difference(me.pos);
        if (targets.isEmpty()) {
            return moveTo(myPos);
        } else {
            return moveTo(targets.minBy(myPos::cartesianDistance));
        }
    }

    private Direction moveTo(Point2D target) {
        return DIRECTIONS.minBy(d -> {
            Point2D p = myPos.move(d.vector.getX(), d.vector.getY());
            return !board.inBounds(p) || me.claimed.contains(p) ? Integer.MAX_VALUE : target.cartesianDistance(p);
        });
    }

    @Override
    protected Direction makeMove(ReadOnlyGame readOnlyGame, ReadOnlyBoard readOnlyBoard) {
        board.update(readOnlyBoard);
        myPos = readOnlyBoard.getPosition(this);
        path.remove(myPos);

        for (Player e : players.valuesView()) {
            e.nextMove();
        }
        for (Point2D point : board.allPoints) {
            ReadOnlySplixPoint splixPoint = board.getSplixPoint(point);
            getPlayer(splixPoint.getOwner()).addOwned(point);
            getPlayer(splixPoint.getClaimer()).addClaimed(point);
            getPlayer(splixPoint.getWhosOnSpot()).setPos(point);
        }
        for (Player e : players.valuesView()) {
            e.calcPos();
        }

        if (me.owned.contains(myPos) && path.allSatisfy(p -> me.owned.contains(p))) {
            path.clear();
        }

        if (path.isEmpty()) {
            MutableSet<Point2D> enemyPositions = enemies.valuesView().flatCollect(e -> e.pos).toSet();
            int enemyDistance = enemyPositions.isEmpty() ? Integer.MAX_VALUE :
                    enemyPositions.minBy(myPos::cartesianDistance).cartesianDistance(myPos);

            if (enemyDistance < 20) {
                MutableSet<Point2D> enemyClaimed = enemies.valuesView().flatCollect(e -> e.claimed).toSet();
                if (!enemyClaimed.isEmpty()) {
                    Point2D closestClaimed = enemyClaimed.minBy(myPos::cartesianDistance);
                    if (closestClaimed.cartesianDistance(myPos) < enemyDistance) {
                        return moveTo(closestClaimed);
                    } else if (enemyDistance < 10) {
                        return moveToOwned();
                    }
                }
            }

            if (me.owned.contains(myPos)) {
                if (!me.getUnowned().isEmpty()) {
                    Point2D target = me.getUnowned().minBy(myPos::cartesianDistance);
                    if (target.cartesianDistance(myPos) > 2) {
                        return moveTo(target);
                    }
                }

                int safeSize = Math.max(1, Math.min(enemyDistance / 6, readOnlyGame.getRemainingIterations() / 4));
                SquareRegion region = Lists.mutable
                        .of(new SquareRegion(myPos, myPos.move(safeSize, safeSize)),
                                new SquareRegion(myPos, myPos.move(safeSize, -safeSize)),
                                new SquareRegion(myPos, myPos.move(-safeSize, safeSize)),
                                new SquareRegion(myPos, myPos.move(-safeSize, -safeSize)))
                        .maxBy(r -> me.getUnowned().count(p -> r.inBounds(p)));
                path = board.getBorders(region);
            } else {
                return moveToOwned();
            }
        }

        if (!path.isEmpty()) {
            return moveTo(path.minBy(myPos::cartesianDistance));
        }

        return moveToOwned();
    }
}

1

TrapBot, Java

TrapBot.java

import com.jatkin.splixkoth.ppcg.game.Direction;
import com.jatkin.splixkoth.ppcg.game.SplixPlayer;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyBoard;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyGame;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlySplixPoint;
import com.nmerrill.kothcomm.game.maps.Point2D;
import com.nmerrill.kothcomm.game.maps.graphmaps.bounds.point2D.SquareRegion;
import javafx.util.Pair;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Lists;

import java.util.Comparator;

/**
 * Trap bot goes to the wall and traces the entirety around. Hopes that
 * the players in the middle die and that nobody challenges him. Nearly 
 * all turns are left turns.
 */
public class TrapBot extends SplixPlayer {

    /**
     * Mode when the bot is attempting to reach the wall from it's original spawn
     * location.
     */
    public static final int MODE_GOING_TO_WALL = 1;

    /**
     * Mode when we have reached the wall and are now going around the board.
     */
    public static final int MODE_FOLLOWING_WALL = 2;

    private int mode = MODE_GOING_TO_WALL;

    public static int WALL_EAST = 1;
    public static int WALL_NORTH = 2;
    public static int WALL_WEST = 3;
    public static int WALL_SOUTH = 4;


    /**
     * How long the bot would like to go before he turns around to go back home.
     */
    private static final int PREFERRED_LINE_DIST = 5;

    private int distToTravel = 0;

    private Direction lastMove = Direction.East;// could be anything that's not null
    private int lastTrailLength = 0;

    @Override
    protected Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board) {
        Direction ret = null;
        MutableMap<Point2D, ReadOnlySplixPoint> view = board.getView();
        int trailLength = getTrailLength(board, view);

        if (trailLength == 0) {

            int closestWall = getClosestWall(board);
            Direction directionToWall = getDirectionToWall(closestWall);

            if (lastTrailLength != 0) {
                ret = lastMove.leftTurn();
                // move to the other half of 2 width line so we can start without shifting to the left
            }

            if (mode == MODE_GOING_TO_WALL && ret == null) {
                int distCanTravel = getDistCanTravel(
                        getSelfPosition(board), board.getBounds(), directionToWall);
                if (distCanTravel == 0) mode = MODE_FOLLOWING_WALL;
                else ret = directionToWall;
                distToTravel = distCanTravel;

            }

            if (mode == MODE_FOLLOWING_WALL && ret == null) {
                int distCanTravel = 0;
                ret = directionToWall;
                while (distCanTravel == 0) {// keep turning left until we can get somewhere
                    ret = ret.leftTurn();
                    distCanTravel = getDistCanTravel(
                            getSelfPosition(board), board.getBounds(), ret);
                }

                distToTravel = distCanTravel;
            }
        }

        // once we have started we are on auto pilot (can't run after the before block)
        else if (trailLength == distToTravel || trailLength == (distToTravel + 1))
            ret = lastMove.leftTurn();

        if (ret == null)// if we don't have a move otherwise, we must be on our trail. ret same as last time
            ret = lastMove;

        lastTrailLength = trailLength;
        lastMove = ret;
        return ret;
    }

    int getClosestWall(ReadOnlyBoard board) {
        Point2D thisPos = getSelfPosition(board);
        return Lists.mutable.of(
                new Pair<>(WALL_NORTH, board.getBounds().getTop() - thisPos.getY()),
                new Pair<>(WALL_SOUTH, thisPos.getY()), 
                new Pair<>(WALL_EAST, board.getBounds().getRight() - thisPos.getX()),
                new Pair<>(WALL_WEST, thisPos.getX())
        ).min(Comparator.comparingInt(Pair::getValue)).getKey();
    }

    /**
     * This goes around some intended behavior in the controller to get the correct result. When a player goes outside
     * his territory the land under him is converted to a trail -- on the next step of the game. So a trail length may
     * be the count of the trail locations plus one. That is what this function calculates. Depends on the whole trail
     * being contained inside the view passed to it.
     * @return
     */
    int getTrailLength(ReadOnlyBoard board, MutableMap<Point2D, ReadOnlySplixPoint> view) {
        boolean isPlayerOutsideHome = !view.get(getSelfPosition(board)).getOwner().equals(getThisHidden());
        int trailLength = view.count(rop -> rop.getClaimer().equals(getThisHidden()));
        return trailLength + (isPlayerOutsideHome? 1 : 0);
    }

    /**
     * Calculate how far we can travel in the direction before we hit the wall.
     * @return
     */
    int getDistCanTravel(Point2D currPos, SquareRegion bounds, Direction direction) {
        for (int i = 1; i <= PREFERRED_LINE_DIST; i++) {
            if (!bounds.inBounds(currPos.move(direction.vector.getX()*i, direction.vector.getY()*i)))
                return i-1;
        }
        return PREFERRED_LINE_DIST;
    }

    /**
     * Get which direction needs to be traveled to reach the specified wall.
     * Requires that neither Direction nor the values of `WALL_...` change.
     * @param targetWall
     * @return
     */
    Direction getDirectionToWall(int targetWall) {
        return Direction.values()[targetWall-1];
    }
}

C'est peut-être le bot le plus simple. Tout ce qu’il fait, c’est tracer le bord du tableau, se doubler pour réduire le risque de se faire tuer.


Cool de voir que vous avez utilisé les collections Eclipse. Il existe une interface Pair dans EC. Vous pouvez utiliser Tuples.pair () pour obtenir une instance Pair. Il existe également une classe PrimitiveTuples si l'une ou les deux valeurs de la paire sont des primitives.
Donald Raab

1

random_bot, Clojure

C'est RandomBot , mais je devais m'en tenir aux conventions de nommage, et certains problèmes m'empêchent d'utiliser le trait d'union dans le nom, donc les soulignements règnent! Le make-movefn renvoie une vec avec le premier élément que Directionvous souhaitez déplacer et le second étant l'état que vous souhaitez vous transmettre lors du prochain tour. N'utilisez pas d'atomes externes, car ce code peut exécuter plusieurs jeux en parallèle.

 random_bot.clj
 (ns random-bot
     (:import
      [com.jatkin.splixkoth.ppcg.game Direction]))

 (defn make-move [game board state]
       [(rand-nth [Direction/East
                   Direction/West
                   Direction/North
                   Direction/South])
        nil])

0

HunterBot, Java

HunterBot.java

import com.jatkin.splixkoth.ppcg.game.Direction;
import com.jatkin.splixkoth.ppcg.game.SplixPlayer;
import com.jatkin.splixkoth.ppcg.game.readonly.HiddenPlayer;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyBoard;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlyGame;
import com.jatkin.splixkoth.ppcg.game.readonly.ReadOnlySplixPoint;
import com.nmerrill.kothcomm.game.maps.Point2D;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.api.set.ImmutableSet;
import org.eclipse.collections.impl.factory.Sets;

import java.util.Comparator;

/**
 * This bot looks for any trail points left behind by another player and sets that as his target. If the target ever
 * disappears, it will continue on in hopes that the player will return soon, or if another target appears, it will
 * go towards that one. Works best when the other player repeatedly goes in the same general direction.
 */
public class HunterBot extends SplixPlayer {

    private Point2D lastTarget;

    private Direction lastMove = Direction.East;

    @Override
    protected Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board) {
        Point2D thisPos = getSelfPosition(board);
        MutableMap<Point2D, ReadOnlySplixPoint> global = board.getGlobal();
        MutableMap<Point2D, ReadOnlySplixPoint> targets = global.select((pt, rosp) ->
                !rosp.getClaimer().equals(getThisHidden()) 
                        && !rosp.getClaimer().equals(new HiddenPlayer(null)));

        if (targets.size() == 0 && lastTarget == null) {
            lastMove = lastMove.leftTurn();
            return lastMove;
        }

        Point2D target = null;
        if (targets.size() == 0) target = lastTarget;
        else target = targets.keysView().min(Comparator.comparingInt(thisPos::cartesianDistance));
        if (target.equals(thisPos)) {
            lastTarget = null;
            if (global.get(thisPos).getOwner().equals(getThisHidden())) {
                lastMove = lastMove.leftTurn();
                return lastMove;
            } else 
            // time to go home
            target = global.select((z_, x) -> getThisHidden().equals(x.getOwner())).keySet().iterator().next();

        }

        lastTarget = target;
        lastMove = makeSafeMove(target, global, board, thisPos);
        return lastMove;
    }

    private Direction makeSafeMove(Point2D targetLocation, MutableMap<Point2D, ReadOnlySplixPoint> map, ReadOnlyBoard board, Point2D currLoc) {
        Point2D dist = targetLocation.move(-currLoc.getX(), -currLoc.getY());
        ImmutableSet<Direction> possibleMoves = Sets.immutable.of(Direction.values())
                .select(x -> {
                    Point2D pos = currLoc.move(x.vector.getX(), x.vector.getY());
                    return !board.getBounds().outOfBounds(pos) && !getThisHidden().equals(map.get(pos).getClaimer());
                });
        Direction prefMove;
        if (Math.abs(dist.getX()) > Math.abs(dist.getY()))
            prefMove = getDirectionFroPoint(new Point2D(normalizeNum(dist.getX()), 0));
        else
            prefMove = getDirectionFroPoint(new Point2D(0, normalizeNum(dist.getY())));

        if (possibleMoves.contains(prefMove)) return prefMove;
        if (possibleMoves.contains(prefMove.leftTurn())) return prefMove.leftTurn();
        if (possibleMoves.contains(prefMove.rightTurn())) return prefMove.rightTurn();
        return prefMove.leftTurn().leftTurn();
    }

    private Direction getDirectionFroPoint(Point2D dir) {
        return Sets.immutable.of(Direction.values()).select(d -> d.vector.equals(dir)).getOnly();
    }

    private int normalizeNum(int n) { if (n < -1) return -1; if (n > 1) return 1; else return n;}

}

L'un des robots les plus élémentaires. Il cherche des endroits pour tuer les autres sur le tableau et suivra le chemin le plus court possible pour atteindre une position de mise à mort. S'il se trouve en dehors de son territoire, il effectuera des mouvements aléatoires jusqu'à ce qu'il dispose d'une autre ouverture pour tuer un autre joueur. Il a une certaine logique pour l'empêcher de courir sur lui-même, et lorsque tous les autres joueurs sont morts, il retourne à son domicile. Une fois à la maison, ça se passe sur une petite place.

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.