Splix.io - Rei da terra


37

Você é um ponto empreendedor que deseja aumentar a terra sob seu controle. Isso é bastante simples - viaje para fora de sua terra atual e retorne à sua terra e tudo nesse loop agora é de sua propriedade. Mas há um porém. Se algum outro ponto encontrar seu laço e cruzá-lo, você morre.

Se você ainda não experimentou, acesse o Splix.io e experimente um jogo. Use as setas do teclado para controlar seu movimento.

GIF

insira a descrição da imagem aqui

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

Específicos

Todos os jogadores começam em posições aleatórias em um tabuleiro de 200x200. (Eu me reservo o direito de alterar isso :). Você terá uma certa quantidade de movimentos para acumular o maior número de pontos possível. Os pontos são computados por:

  • O número de jogadores que você matou vezes 300
  • A quantidade de terreno que você possui no final da rodada

Isso mostra que outras pessoas podem roubar sua terra. Se eles iniciarem um loop que cruza parte de sua terra, eles podem reivindicá-lo. Se você morrer durante a rodada, você perde todos os pontos dessa rodada.

Cada rodada tem um grupo de jogadores selecionados aleatoriamente (no máximo 5 jogadores únicos) (sujeito a alterações). Todo jogador participa de um número igual de rodadas. A pontuação final do seu bot é determinada pela pontuação média por jogo. Cada jogo consiste em 2000 turnos (também sujeitos a alterações). Todos os bots fazem seus movimentos ao mesmo tempo.

Casos de morte

Cabeça Butt

bunda cabeça

Ambos os jogadores morrem quando se enfrentam. Isso ainda é verdade mesmo quando os dois jogadores estão no limite de seu espaço.

bunda cabeça

No entanto, quando apenas um dos jogadores está em sua terra, o outro jogador morre.

insira a descrição da imagem aqui

Linha Cruzada

insira a descrição da imagem aqui

Nesse caso, apenas o jogador roxo morre.

Você não pode cruzar sua própria linha.

insira a descrição da imagem aqui

Saindo do quadro

jogador saindo do jogo

Se um jogador tentar sair do tabuleiro, ele morrerá e perderá todos os pontos.

Área de captura

Um jogador capturará a área quando tiver uma trilha e ele entra em sua própria terra novamente.

insira a descrição da imagem aqui

O vermelho preenche as duas linhas vermelhas. O único caso em que um jogador não preenche é quando outro jogador está dentro do loop. Para deixar claro, isso só se aplica quando o outro jogador está no circuito, e não apenas terras pertencentes a ele. Um jogador pode capturar terras de outra pessoa. Se um jogador não puder preencher a área cercada por sua trilha, a trilha será convertida diretamente em terreno normal. Se o jogador dentro de outro loop terrestre de jogadores morre, a área nesse loop é preenchida. Toda vez que um jogador morre, o tabuleiro é reexaminado para uma área que pode ser preenchida.

Detalhes do controlador

O controlador está aqui . É muito semelhante ao jogo original, mas foram feitas pequenas alterações para torná-lo um melhor ajuste para o KotH e por razões técnicas. Ele é construído com @NathanMerrill 's biblioteca KotHComm , e com ajuda substancial de @NathanMerrill também. Informe-me de todos os bugs encontrados no controlador na sala de bate-papo . Para ser consistente com o KotHComm, usei coleções Eclipse em todo o controlador, mas os bots podem ser gravados usando apenas a biblioteca Java Collections.

Tudo é empacotado em um uberjar na página de lançamentos do github . Para usá-lo, baixe-o e anexe-o ao seu projeto para que você possa usá-lo para o preenchimento automático (instruções para IntelliJ , Eclipse ). Para testar seus envios, execute o jar com java -jar SplixKoTH-all.jar -d path\to\submissions\folder. Verifique se path\to\submissions\folderpossui uma subpasta chamada javae coloque todos os seus arquivos lá. Não use nomes de pacotes em seus bots (embora isso seja possível com o KotHComm, é apenas um pouco mais problemático). Para ver todas as opções, use --help. Para carregar todos os bots, use --question-id 126815.

Escrevendo um bot

Para começar a escrever um bot, você deve estender SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • É aqui que você decide qual jogada deseja que seu bot faça. Não deve retornar nulo.
  • HiddenPlayer getThisHidden()
    • Obtenha a HiddenPlayerversão do this. Útil para comparar seu bot ao quadro.

enum Direction

  • Valores
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Consiga o Directionque conseguiria se fizesse uma curva à esquerda.
  • Direction RightTurn()
    • Consiga o Directionque conseguiria se fizesse uma curva à direita.

ReadOnlyBoard

Esta é a turma em que você acessa o quadro. Você pode obter uma visão local (20x20) do tabuleiro com as posições dos jogadores mostradas ou uma visão global (o tabuleiro inteiro) com apenas as informações de quem possui e reivindica posições no tabuleiro. É também aqui que você obtém sua posição.

  • SquareRegion getBounds()
    • Recupere o tamanho do quadro.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • Obtenha um mapa global do quadro.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • O mesmo que getGlobal(), exceto que ele é limitado a uma área de 20x20 em torno do seu jogador e mostra as posições do jogador.
  • Point2D getPosition(SplixPlayer me)
    • Obtenha a posição do seu jogador. Use como board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • Coloque sua posição no quadro. Uso:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGameapenas fornece acesso ao número de turnos restantes no jogo int getRemainingIterations().

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • Obtenha a HiddenPlayerversão de quem está reivindicando um ponto - reivindicando = uma trilha.
  • HiddenPlayer getOwner()
    • Veja quem possui um ponto.
  • HiddenPlayer getWhosOnSpot()
    • Se o player estiver posicionado nesse ponto, retorne a versão oculta. Só funciona em getLocal().

Point2D

Ao contrário das outras classes aqui, Point2Destá contido na biblioteca 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)
    • Quebra o xvalor para estar dentro do intervalo de maxX.
  • Point2D wrapY(int maxY)
    • Quebra o yvalor para estar dentro do intervalo de maxY.
  • int cartesianDistance(Point2D other)
    • Isso se traduz em quantas voltas levaria para um jogador passar do ponto a para o ponto b.

Suporte para Clojure

O compilador Clojure é fornecido com o SplixKoTH-all.jar, assim você pode usar o Clojure para o seu bot! Consulte o meu random_botpara ver como usá-lo.

Depurando um bot

O controlador vem com um depurador para ajudar a testar estratégias. Para iniciá-lo, execute o jar com a --guiopção

Para anexar o depurador ao seu jar, siga estas instruções para IntelliJ ou estas para Eclipse (versão do Eclipse não testada).

insira a descrição da imagem aqui

Se você estiver usando um depurador com seu código, poderá usar isso para ajudar a visualizar o que seu bot está vendo. Defina um ponto de interrupção no início do makeMoveseu bot e verifique se ele pausa apenas o segmento atual. Em seguida, clique no botão Iniciar na interface do usuário e passe pelo seu código.

insira a descrição da imagem aqui

Agora, para juntar tudo:

Executando bots

Para executar seus bots com outras pessoas, você precisa executar o jar na página de lançamentos. Aqui está uma lista de sinalizadores:

  • --iterations( -i) <= int(padrão 500)
    • Especifique o número de jogos a serem executados.
  • --test-bot( -t) <=String
    • Execute apenas os jogos nos quais o bot está incluído.
  • --directory( -d) <= Caminho
    • O diretório para executar envios. Use isso para executar seus bots. Verifique se seus bots estão em uma subpasta do caminho nomeado java.
  • --question-id( -q) <= int(apenas uso 126815)
    • Faça o download e compile os outros envios do site.
  • --random-seed( -r) <= int(o padrão é um número aleatório)
    • Dê uma semente ao corredor para que os bots que usam aleatoriamente possam ter resultados reproduzidos.
  • --gui( -g)
    • Execute a interface do usuário do depurador em vez de executar um torneio. Melhor usado com --test-bot.
  • --multi-thread( -m) <= boolean(padrão true)
    • Execute um tournoment no modo multithread. Isso permite um resultado mais rápido se o seu computador tiver vários núcleos.
  • --thread-count( -c) <= int(padrão 4)
    • Número de threads a serem executados se o multithread for permitido.
  • --help( -h)
    • Imprima uma mensagem de ajuda semelhante a esta.

Para executar todos os envios nesta página, use java -jar SplixKoTH-all.jar -q 126815.

Formatando sua postagem

Para garantir que o controlador possa baixar todos os bots, você deve seguir este formato.

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

Além disso, não use uma declaração de pacote.


Placar

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

Informe-me se alguma parte das regras não está clara ou se você encontrar algum erro no controlador na sala de bate - papo .

Diverta-se!


Ei, isso finalmente foi publicado! Eu estava pensando: D
MD XF

Há quanto tempo você está esperando? ;) Você planeja enviar?
J Atkins

Não sei se vou conseguir resolver um desafio como esse, pois escrevo principalmente programas em esolangs. Mas eu vi na caixa de areia e parecia um grande desafio!
MD XF

@hyperneutrino Eu vi a edição, isso realmente te incomoda? O politicamente correto é nenhum lugar no âmbito deste post, e é perfeitamente correta gramática Inglês ...
J Atkin

2
0.o mundo pequeno? Eu conheço (do) desenvolvedor do splix.io. (Tweeted this @ him)
CAD97

Respostas:


2

ImNotACoward, Java

Este bot é um especialista em sobrevivência covarde . Se não houver inimigo por perto, ele reivindica uma parte da terra. Se o loop de outro jogador puder ser alcançado com segurança, ele apunhala o outro jogador pelas costas e o envolve em um duelo. Se o outro jogador não puder ser atacado com segurança, ele foge realiza um retiro estratégico para sua própria 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];
    }
}

Este é talvez o bot mais simples. Tudo o que faz é traçar a borda do tabuleiro, dobrando-se para reduzir o risco de ser morto.


É legal ver que você usou o Eclipse Collections. Há uma interface de par no EC. Você pode usar Tuples.pair () para obter uma instância de Pair. Também há uma classe PrimitiveTuples se um ou ambos os valores no par forem primitivos.
Donald Raab

1

random_bot, Clojure

Isto é RandomBot , mas eu tive que me ater às convenções de nomenclatura e alguns problemas me impedem de usar o hífen no nome, para ressaltar o reinado! O make-movefn retorna um vec com o primeiro item sendo o que Directionvocê deseja mudar e o segundo sendo o estado que você deseja que seja devolvido no próximo turno. Não use átomos externos, pois esse código pode estar executando vários jogos em paralelo.

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

}

Um dos bots mais básicos. Ele procura pontos no tabuleiro para matar outras pessoas e seguirá o caminho mais curto possível para chegar a uma posição de matança. Se estiver fora do seu território, ele fará movimentos aleatórios até ter outra abertura para matar outro jogador. Ele tem alguma lógica para impedir que ele se atropele, e quando todos os outros jogadores estão mortos, ele volta para sua casa. Uma vez em casa, ele entra em uma pequena praça.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.