Splix.io - Re della terra


37

Sei un punto intraprendente che vuole aumentare la terra sotto il suo controllo. Questo è abbastanza semplice: viaggia fuori dalla tua attuale terra e ritorna nella tua terra e tutto in quel giro è ora di tua proprietà. Ma c'è un problema. Se qualche altro punto trova in qualche modo il tuo anello e lo attraversa, muori.

Se non l'hai ancora provato, vai su Splix.io e prova un gioco. Usa i tasti freccia per controllare i tuoi movimenti.

GIF

inserisci qui la descrizione dell'immagine

Attestazione: http://splix.io/

specifiche

Tutti i giocatori iniziano in posizioni casuali su una tavola 200x200. (Mi riservo il diritto di modificare questo :). Avrai un certo numero di mosse per accumulare il maggior numero di punti possibile. I punti vengono conteggiati da:

  • Il numero di giocatori che hai ucciso è 300 volte
  • La quantità di terra che possiedi alla fine del round

Questo porta al punto che gli altri possono rubare la tua terra. Se iniziano un circuito che interseca parte della tua terra, possono reclamarla. Se muori durante il round, perdi tutti i punti per quel round.

Ogni round ha un gruppo di giocatori selezionato casualmente (max 5 giocatori unici) (soggetto a modifiche). Ogni giocatore partecipa a un numero uguale di round. Il punteggio finale del tuo bot è determinato dal suo punteggio medio per partita. Ogni partita è composta da 2000 turni (anche soggetti a modifiche). Tutti i robot fanno le loro mosse contemporaneamente.

Casi di morte

Testa a testa

testa a testa

Entrambi i giocatori muoiono quando si scontrano a vicenda. Questo è ancora vero anche quando entrambi i giocatori sono al limite del loro spazio.

testa a testa

Tuttavia, quando solo uno dei giocatori è nella sua terra, l'altro giocatore muore.

inserisci qui la descrizione dell'immagine

Linea Croce

inserisci qui la descrizione dell'immagine

In questo caso, muore solo il giocatore viola.

Non puoi attraversare la tua linea.

inserisci qui la descrizione dell'immagine

Uscire dal consiglio di amministrazione

giocatore che esce dal tabellone

Se un giocatore tenta di uscire dal tabellone, morirà e perderà tutti i punti.

Catturare l'area

Un giocatore catturerà l'area quando ha una pista ed entra di nuovo nella sua terra.

inserisci qui la descrizione dell'immagine

Il rosso si riempie tra le due linee rosse. L'unico caso in cui un giocatore non si riempie è quando un altro giocatore è all'interno del loop. Per essere chiari, questo si applica solo quando l'altro giocatore è nel loop, non solo terra posseduta da lui. Un giocatore può catturare terre da un'altra persona. Se un giocatore non può riempire l'area circondata dalla sua traccia, la traccia viene convertita direttamente in terra normale. Se il giocatore all'interno del loop di terra di un altro giocatore muore, l'area in quel loop viene riempita. Ogni volta che un giocatore muore, il tabellone viene riesaminato per un'area che può essere riempita.

Dettagli del controller

Il controller è qui . È molto simile al gioco originale, ma sono state apportate piccole modifiche per renderlo più adatto a KotH e per motivi tecnici. E 'costruito con @NathanMerrill 's biblioteca KotHComm , e con l'aiuto sostanziale da @NathanMerrill pure. Per favore fatemi sapere di eventuali bug che trovate nel controller nella chat room . Per essere coerente con KotHComm, ho usato le raccolte Eclipse in tutto il controller, ma i robot possono essere scritti usando solo la libreria Collezioni Java.

Tutto è impacchettato in un uberjar nella pagina delle versioni di github . Per usarlo, scaricalo e allegalo al tuo progetto in modo da poterlo utilizzare per il completamento automatico (istruzioni per IntelliJ , Eclipse ). Per testare i tuoi invii, esegui il jar con java -jar SplixKoTH-all.jar -d path\to\submissions\folder. Assicurati che path\to\submissions\folderabbia un subfoler chiamato javae posiziona lì tutti i tuoi file. Non usare i nomi dei pacchetti nei tuoi robot (anche se potrebbe essere possibile con KotHComm, è solo un po 'più problematico). Per vedere tutte le opzioni, utilizzare --help. Per caricare tutti i robot, utilizzare --question-id 126815.

Scrivere un bot

Per iniziare a scrivere un bot, è necessario estendere SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • Qui è dove decidi quale mossa vuoi che il tuo bot faccia. Non deve restituire null.
  • HiddenPlayer getThisHidden()
    • Ottieni la HiddenPlayerversione di this. Utile per confrontare il tuo bot con la scheda.

enum Direction

  • Valori
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Ottieni Directionciò che otterrai se avessi girato a sinistra.
  • Direction RightTurn()
    • Ottieni Directionciò che otterrai se avessi fatto una svolta a destra.

ReadOnlyBoard

Questa è la classe in cui accedi alla scheda. Puoi ottenere una vista locale (20x20) del tabellone con le posizioni dei giocatori mostrate, oppure una vista globale (l'intero tabellone) con solo le informazioni di chi possiede e rivendica le posizioni sul tabellone. Questo è anche il luogo in cui ottieni la tua posizione.

  • SquareRegion getBounds()
    • Recupera le dimensioni della scheda.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • Ottieni una mappa globale della scheda.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • Lo stesso getGlobal(), tranne per il fatto che è limitato a un'area 20x20 attorno al tuo giocatore e che mostra le posizioni del giocatore.
  • Point2D getPosition(SplixPlayer me)
    • Ottieni la posizione del tuo giocatore. Usa come board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • Ottieni la tua posizione sul tabellone. Uso:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGamefornisce solo l'accesso al numero di turni rimasti nel gioco int getRemainingIterations().

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • Ottieni la HiddenPlayerversione di chi sta rivendicando un punto - claiming = a trail.
  • HiddenPlayer getOwner()
    • Ottieni chi possiede un punto.
  • HiddenPlayer getWhosOnSpot()
    • Se il giocatore è posizionato su questo punto, restituiscene la versione nascosta. Funziona solo in getLocal().

Point2D

A differenza delle altre classi qui, Point2Dè contenuta nella libreria 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)
    • Avvolgere il xvalore per essere compreso nell'intervallo di maxX.
  • Point2D wrapY(int maxY)
    • Avvolgere il yvalore per essere compreso nell'intervallo di maxY.
  • int cartesianDistance(Point2D other)
    • Questo si traduce in quanti turni ci vorrebbe per un giocatore per passare dal punto a al punto b.

Supporto per clojure

Il compilatore Clojure è in bundle con il SplixKoTH-all.jar, quindi puoi usare Clojure per il tuo bot! Fare riferimento a my random_botper vedere come usarlo.

Debug di un bot

Il controller viene fornito con un debugger per aiutare a testare le strategie. Per avviarlo, esegui il vaso con il--gui opzione.

Per collegare il debugger al tuo jar, segui queste istruzioni per IntelliJ o queste istruzioni per Eclipse (versione di Eclipse non testata).

inserisci qui la descrizione dell'immagine

Se stai usando un debugger con il tuo codice, puoi usarlo per aiutare a visualizzare ciò che sta vedendo il tuo bot. Imposta un punto di interruzione all'inizio del makeMovetuo bot e assicurati che sospenda solo il thread corrente. Quindi, fai clic sul pulsante Start sull'interfaccia utente e passa attraverso il codice.

inserisci qui la descrizione dell'immagine

Ora, per mettere tutto insieme:

Esecuzione di robot

Per eseguire i tuoi robot con altri, devi eseguire il jar nella pagina dei rilasci. Ecco un elenco di flag:

  • --iterations( -i) <= int(impostazione predefinita 500)
    • Specifica il numero di giochi da eseguire.
  • --test-bot( -t) <=String
    • Esegui solo i giochi in cui è incluso il bot.
  • --directory( -d) <= Percorso
    • La directory da cui eseguire gli invii. Usa questo per eseguire i tuoi robot. Assicurati che i tuoi robot si trovino in una sottocartella del percorso indicato java.
  • --question-id( -q) <= int(usare solo126815 )
    • Scarica e compila gli altri invii dal sito.
  • --random-seed( -r) <=int (il valore predefinito è un numero casuale)
    • Dai un seme al corridore in modo che i robot che usano casualmente possano ottenere risultati riprodotti.
  • --gui (-g )
    • Esegui l'interfaccia utente del debugger invece di eseguire un torneo. Meglio usato con --test-bot.
  • --multi-thread( -m) <= boolean(impostazione predefinitatrue)
    • Esegui un torneo in modalità multi-thread. Ciò consente un risultato più veloce se il tuo computer ha più core.
  • --thread-count( -c) <= int(impostazione predefinita4)
    • Numero di thread da eseguire se è consentito il multi-thread.
  • --help( -h)
    • Stampa un messaggio di aiuto simile a questo.

Per eseguire tutti gli invii in questa pagina, utilizzare java -jar SplixKoTH-all.jar -q 126815.

Formattazione del tuo post

Per garantire che il controller possa scaricare tutti i bot, è necessario seguire questo formato.

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

Inoltre, non utilizzare una dichiarazione del pacchetto.


tabellone segnapunti

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

Per favore fatemi sapere se una parte delle regole non è chiara o se trovate errori nel controller nella chat room .

Divertiti!


Ehi, questo finalmente è stato pubblicato! Mi chiedevo: D
MD XF,

Da quanto tempo stai aspettando? ;) Prevedi di inviarlo?
J Atkin,

Non so se sarò in grado di risolvere una sfida come questa, dato che scrivo principalmente programmi in esolangs. Ma l'ho visto nella sandbox e sembrava una grande sfida!
MD XF,

@hyperneutrino Ho visto la modifica, ti dà davvero fastidio? La correttezza politica non è da nessuna parte nell'ambito di questo post, ed è perfettamente corretta la grammatica inglese ...
J Atkin

2
0.o piccolo mondo? Conosco (di) lo sviluppatore di splix.io. (Lo ha twittato @ lui)
CAD97

Risposte:


2

ImNotACoward, Java

Questo bot è un esperto di sopravvivenza codarda . Se non c'è nemico nelle vicinanze, rivendica una parte della terra. Se il loop di un altro giocatore può essere raggiunto in modo sicuro, accoltella l'altro giocatore nella parte posteriore coinvolge l'altro giocatore in un duello. Se l'altro giocatore non può essere attaccato in modo sicuro, fugge eseguendo un ritiro strategico nella propria terra.

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

Questo è forse il bot più semplice. Tutto ciò che fa è tracciare il bordo del tabellone, raddoppiando su se stesso per ridurre il rischio di essere ucciso.


Fantastico vedere che hai usato le collezioni Eclipse. C'è un'interfaccia Pair in EC. Puoi usare Tuples.pair () per ottenere un'istanza di Pair. Esiste anche una classe PrimitiveTuples se uno o entrambi i valori nella coppia sono primitivi.
Donald Raab,

1

random_bot, Clojure

Questo è RandomBot , ma ho dovuto attenermi alle convenzioni di denominazione e alcuni problemi mi impediscono di utilizzare il trattino nel nome, quindi regnano i caratteri di sottolineatura! Il make-movefn restituisce un vec con il primo oggetto in Directioncui vuoi spostarti, e il secondo è lo stato in cui vuoi tornare al turno successivo. Non utilizzare alcun atomo esterno, poiché questo codice potrebbe eseguire più giochi in parallelo.

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

}

Uno dei robot più elementari. Cerca sulla scacchiera i punti per uccidere gli altri e seguirà il percorso più breve possibile per raggiungere una posizione di uccisione. Se è fuori dal suo territorio, farà mosse casuali fino a quando non avrà un'altra apertura per uccidere un altro giocatore. Ha una logica per impedirgli di correre su se stesso, e quando tutti gli altri giocatori sono morti torna a casa. Una volta a casa va solo in una piccola piazza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.