Splix.io - König des Landes

37

Sie sind ein unternehmerischer Punkt, der das Land unter seiner Kontrolle vergrößern möchte. Dies ist ganz einfach: Reisen Sie außerhalb Ihres aktuellen Landes und kehren Sie in Ihr Land zurück. Alles, was sich in diesem Loop befindet, gehört Ihnen. Aber es gibt einen Haken. Wenn ein anderer Punkt irgendwie Ihre Schleife findet und sie kreuzt, sterben Sie.

Wenn Sie es noch nicht ausprobiert haben, gehen Sie zu Splix.io und probieren Sie ein Spiel aus. Verwenden Sie die Pfeiltasten, um Ihre Bewegung zu steuern.

GIF

Bildbeschreibung hier eingeben

Bildnachweis: http://splix.io/

Besonderheiten

Alle Spieler beginnen an zufälligen Positionen auf einem 200x200-Brett. (Ich behalte mir das Recht vor, dies zu ändern :). Sie müssen eine bestimmte Anzahl von Zügen ausführen, um die größtmögliche Anzahl von Punkten zu erreichen. Punkte werden gezählt von:

  • Die Anzahl der getöteten Spieler beträgt 300
  • Die Menge an Land, die Sie am Ende der Runde besitzen

Dies bringt den Punkt auf den Punkt, dass andere Ihr Land stehlen können. Wenn sie eine Schleife starten, die einen Teil Ihres Landes schneidet, können sie diese beanspruchen. Wenn Sie während der Runde sterben, verlieren Sie alle Punkte für diese Runde.

Jede Runde hat eine zufällig ausgewählte Gruppe von Spielern (maximal 5 einzigartige Spieler) (Änderungen vorbehalten). Jeder Spieler nimmt an einer gleichen Anzahl von Runden teil. Die endgültige Punktzahl Ihres Bots wird durch die durchschnittliche Punktzahl pro Spiel bestimmt. Jedes Spiel besteht aus 2000 Runden (Änderungen vorbehalten). Alle Bots machen ihre Züge zur gleichen Zeit.

Todesfälle

Kopfstoß

Kopfstoß

Beide Spieler sterben, wenn sie sich gegenseitig stoßen. Dies gilt auch dann, wenn sich beide Spieler am Rand ihres Feldes befinden.

Kopfstoß

Wenn sich jedoch nur einer der Spieler in seinem Land befindet, stirbt der andere Spieler.

Bildbeschreibung hier eingeben

Linienkreuz

Bildbeschreibung hier eingeben

In diesem Fall stirbt nur der lila Spieler.

Sie können Ihre eigene Linie nicht überschreiten.

Bildbeschreibung hier eingeben

Board verlassen

Spieler geht vom Brett

Wenn ein Spieler versucht, das Spielfeld zu verlassen, stirbt er und verliert alle Punkte.

Erfassungsbereich

Ein Spieler erobert ein Gebiet, wenn er eine Spur hat und er betritt wieder sein eigenes Land.

Bildbeschreibung hier eingeben

Rot füllt die beiden roten Linien aus. Der einzige Fall, in dem ein Spieler nicht ausfüllt, ist, wenn sich ein anderer Spieler in der Runde befindet. Dies gilt natürlich nur, wenn der andere Spieler selbst auf dem Laufenden ist und nicht nur Land, das ihm gehört. Ein Spieler kann Land von einer anderen Person erobern. Wenn ein Spieler das von seiner Spur umgebene Gebiet nicht ausfüllen kann, wird die Spur direkt in normales Land umgewandelt. Wenn der Spieler in der Landschleife eines anderen Spielers stirbt, wird der Bereich in dieser Schleife gefüllt. Jedes Mal, wenn ein Spieler stirbt, wird das Spielfeld auf einen Bereich überprüft, der ausgefüllt werden kann.

Steuerungsdetails

Der Controller ist hier . Es ist dem Originalspiel sehr ähnlich, aber es wurden kleine Änderungen vorgenommen, um es besser für KotH und aus technischen Gründen zu machen. Es wurde mit der KotHComm - Bibliothek von @ NathanMerrill und mit der erheblichen Hilfe von @ NathanMerrill erstellt. Bitte teilen Sie mir alle Fehler mit, die Sie auf dem Controller im Chat-Raum finden . Um mit KotHComm konsistent zu sein, habe ich Eclipse-Auflistungen im gesamten Controller verwendet, aber Bots können nur mit der Java-Auflistungsbibliothek geschrieben werden.

Alles ist in einem Uberjar auf der Github-Veröffentlichungsseite verpackt . Laden Sie es herunter und hängen Sie es an Ihr Projekt an, damit Sie es für die automatische Vervollständigung verwenden können (Anweisungen für IntelliJ , Eclipse ). Um Ihre Einsendungen zu testen, führen Sie das Glas mit java -jar SplixKoTH-all.jar -d path\to\submissions\folder. Stellen Sie sicher, dass path\to\submissions\folderein Unterordner mit dem Namen vorhanden ist java, und platzieren Sie alle Ihre Dateien dort. Verwenden Sie keine Paketnamen in Ihren Bots (obwohl dies mit KotHComm möglich ist, ist es nur ein bisschen schwieriger). Verwenden Sie, um alle Optionen anzuzeigen --help. Verwenden Sie, um alle Bots zu laden --question-id 126815.

Einen Bot schreiben

Um einen Bot zu schreiben, müssen Sie erweitern SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • Hier entscheidest du, welchen Zug dein Bot machen soll. Darf nicht null zurückgeben.
  • HiddenPlayer getThisHidden()
    • Holen Sie sich die HiddenPlayerVersion von this. Nützlich, um Ihren Bot mit dem Board zu vergleichen.

enum Direction

  • Werte
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Holen Sie sich das Direction, was Sie bekommen würden, wenn Sie links abbiegen würden.
  • Direction RightTurn()
    • Holen Sie sich das Direction, was Sie bekommen würden, wenn Sie rechts abbiegen würden.

ReadOnlyBoard

Dies ist die Klasse, in der Sie auf das Board zugreifen. Sie können entweder eine lokale Ansicht (20x20) des Bretts mit den angezeigten Spielerpositionen oder eine globale Ansicht (das gesamte Brett) erhalten, in der nur angegeben ist, wer Positionen auf dem Brett besitzt und beansprucht. Hier bekommen Sie auch Ihre Position.

  • SquareRegion getBounds()
    • Ermitteln Sie die Größe der Platine.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • Holen Sie sich eine globale Karte des Boards.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • Das Gleiche wie getGlobal(), außer dass es auf einen Bereich von 20 x 20 um Ihren Spieler beschränkt ist und die Spielerpositionen anzeigt.
  • Point2D getPosition(SplixPlayer me)
    • Holen Sie sich die Position Ihres Spielers. Verwenden Sie als board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • Holen Sie sich Ihre Position auf dem Brett. Verwendung:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGameErmöglicht nur den Zugriff auf die Anzahl der verbleibenden Runden im Spiel int getRemainingIterations().

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • Holen Sie sich die HiddenPlayerVersion, die einen Punkt beansprucht - Claiming = eine Spur.
  • HiddenPlayer getOwner()
    • Holen Sie sich, wem ein Punkt gehört.
  • HiddenPlayer getWhosOnSpot()
    • Wenn sich der Player an diesem Punkt befindet, geben Sie die verborgene Version davon zurück. Funktioniert nur in getLocal().

Point2D

Im Gegensatz zu den anderen Klassen ist hier Point2Din der KotHComm-Bibliothek enthalten.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)
    • Wickeln Sie den xWert so ein, dass er im Bereich von liegt maxX.
  • Point2D wrapY(int maxY)
    • Wickeln Sie den yWert so ein, dass er im Bereich von liegt maxY.
  • int cartesianDistance(Point2D other)
    • Dies bedeutet, wie viele Runden ein Spieler brauchen würde, um von Punkt a zu Punkt b zu gelangen.

Clojure-Unterstützung

Der Clojure-Compiler ist im Lieferumfang von enthalten SplixKoTH-all.jar, sodass Sie Clojure für Ihren Bot verwenden können! Informationen random_botzur Verwendung finden Sie unter my .

Einen Bot debuggen

Der Controller wird mit einem Debugger geliefert, der beim Testen von Strategien hilft. Um es zu starten, starte das Glas mit der --guiOption.

Befolgen Sie diese Anweisungen für IntelliJ oder diese Anweisungen für Eclipse (ungetestete Eclipse-Version), um den Debugger an Ihr JAR anzuhängen .

Bildbeschreibung hier eingeben

Wenn Sie einen Debugger mit Ihrem Code verwenden, können Sie diesen verwenden, um zu visualisieren, was Ihr Bot sieht. Setzen Sie makeMoveauf Ihrem Bot einen Haltepunkt am Anfang von und stellen Sie sicher, dass nur der aktuelle Thread angehalten wird. Klicken Sie anschließend auf der Benutzeroberfläche auf die Schaltfläche "Start" und gehen Sie den Code durch.

Bildbeschreibung hier eingeben

Nun, um alles zusammen zu fassen:

Laufende Bots

Um Ihre Bots mit anderen zu betreiben, müssen Sie das jar auf der Releaseseite ausführen. Hier ist eine Liste von Flags:

  • --iterations( -i) <= int(Standard 500)
    • Geben Sie die Anzahl der auszuführenden Spiele an.
  • --test-bot( -t) <=String
    • Führen Sie nur die Spiele aus, in denen der Bot enthalten ist.
  • --directory( -d) <= Pfad
    • Das Verzeichnis, aus dem die Übermittlungen ausgeführt werden sollen. Verwenden Sie dies, um Ihre Bots auszuführen. Stellen Sie sicher, dass sich Ihre Bots in einem Unterordner des genannten Pfads befinden java.
  • --question-id( -q) <= int(nur verwenden 126815)
    • Laden Sie die anderen Beiträge von der Website herunter und kompilieren Sie sie.
  • --random-seed( -r) <= int(Standard ist eine Zufallszahl)
    • Geben Sie dem Läufer einen Samen, damit bei Bots, die zufällige Werte verwenden, die Ergebnisse reproduziert werden können.
  • --gui( -g)
    • Führen Sie den Debugger ui aus, anstatt ein Turnier auszuführen. Am besten mit --test-bot.
  • --multi-thread( -m) <= boolean(Standard true)
    • Führe ein Turnier im Multithread-Modus aus. Dies ermöglicht ein schnelleres Ergebnis, wenn Ihr Computer über mehrere Kerne verfügt.
  • --thread-count( -c) <= int(Standard 4)
    • Anzahl der auszuführenden Threads, wenn mehrere Threads zulässig sind.
  • --help( -h)
    • Drucken Sie eine ähnliche Hilfemeldung.

Um alle Einsendungen auf dieser Seite auszuführen, verwenden Sie java -jar SplixKoTH-all.jar -q 126815.

Formatieren Sie Ihren Beitrag

Um sicherzustellen, dass der Controller alle Bots herunterladen kann, sollten Sie dieses Format befolgen.

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

Verwenden Sie auch keine Paketdeklaration.


Anzeigetafel

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

Bitte lassen Sie mich wissen, wenn ein Teil der Regeln unklar ist oder wenn Sie Fehler in der Steuerung im Chatraum finden .

Habe Spaß!

J Atkin
quelle
Hey, das wurde endlich gepostet! Ich habe mich gefragt: D
MD XF
Wie lange hast du gewartet? ;) Hast du vor einzureichen?
J Atkin
Ich weiß nicht, ob ich eine solche Herausforderung lösen kann oder nicht, da ich hauptsächlich Programme in Esolangs schreibe. Aber ich habe es im Sandkasten gesehen und es sah nach einer großen Herausforderung aus!
MD XF
@hyperneutrino Ich habe die Bearbeitung gesehen, stört es dich wirklich? Politische Korrektheit ist nirgends im Zuständigkeitsbereich dieses Beitrags, und es ist vollkommen korrekte englische Grammatik ...
J Atkin
2
0.o kleine Welt? Ich kenne den Entwickler von splix.io. (Hat dies bei ihm
getwittert

Antworten:

2

ImNotACoward, Java

Dieser Bot ist ein Überlebensexperte für Feiglinge . Wenn sich kein Feind in der Nähe befindet, beansprucht er einen Teil des Landes. Wenn die Schleife eines anderen Spielers sicher erreicht werden kann, sticht er den anderen Spieler in den Rücken und verwickelt den anderen Spieler in ein Duell. Wenn der andere Spieler nicht sicher angegriffen werden kann, führt die Flucht einen strategischen Rückzug in sein eigenes Land durch.

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();
    }
}
Sleafar
quelle
Interessant. Sehr schön! Ich frage mich, wie viel besser dies gemacht werden könnte ...
J Atkin
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];
    }
}

Dies ist vielleicht der einfachste Bot. Alles, was es tut, ist, die Kante des Bretts aufzuspüren und sich auf sich selbst zu verdoppeln, um das Risiko zu verringern, getötet zu werden.

J Atkin
quelle
Schön zu sehen, dass Sie Eclipse Collections verwendet haben. In EC gibt es eine Pair-Schnittstelle. Sie können Tuples.pair () verwenden, um eine Pair-Instanz abzurufen. Es gibt auch eine PrimitiveTuples-Klasse, wenn einer oder beide Werte im Paar Primitive sind.
Donald Raab
1

random_bot, Clojure

Dies ist RandomBot , aber ich musste mich an die Namenskonventionen halten, und einige Probleme hinderten mich daran, den Bindestrich im Namen zu verwenden. Der make-moveFn gibt einen VEC zurück, wobei der erste Gegenstand derjenige ist, in den DirectionSie einziehen möchten, und der zweite der Zustand ist, den Sie in der nächsten Runde zurückgeben möchten. Verwenden Sie keine externen Atome, da dieser Code möglicherweise mehrere Spiele gleichzeitig ausführt.

 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])
J Atkin
quelle
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;}

}

Einer der grundlegendsten Bots. Es durchsucht das Spielfeld nach Stellen, an denen andere getötet werden können, und folgt dem kürzesten Weg, um eine Tötungsposition zu erreichen. Wenn es sich außerhalb seines Territoriums befindet, führt es zufällige Züge aus, bis es eine weitere Öffnung hat, um einen anderen Spieler zu töten. Es hat eine Logik, um zu verhindern, dass es über sich selbst läuft, und wenn alle anderen Spieler tot sind, kehrt es zu seiner Heimat zurück. Zuhause angekommen geht es nur noch auf einem kleinen Platz.

J Atkin
quelle