Splix.io-땅의 왕


37

당신은 통제하에 토지를 늘리고 자 하는 진취적인 점 입니다. 이것은 매우 간단합니다. 현재 땅 밖으로 여행하고 다시 땅으로 돌아 가면 해당 루프의 모든 것이 소유됩니다. 그러나 캐치가 있습니다. 다른 점이 어떻게 든 루프를 찾아서 건너면 죽습니다.

아직 시도하지 않은 경우 Splix.io 로 이동하여 게임을 시도하십시오. 화살표 키를 사용하여 움직임을 제어하십시오.

GIF

여기에 이미지 설명을 입력하십시오

크레딧 : http://splix.io/

사양

모든 플레이어는 200x200 보드에서 임의의 위치에서 시작합니다. (나는 이것을 변경할 권리가있다 :). 가능한 많은 포인트를 모으기 위해 일정량의 움직임이있을 것입니다. 포인트는 다음과 같이 계산됩니다.

  • 죽인 플레이어 수 300 회
  • 라운드가 끝날 때 소유 한 토지의 양

이것은 다른 사람들이 당신의 땅을 훔칠 수있는 지점을 제시합니다. 그들이 당신의 땅의 일부와 교차하는 고리를 시작하면, 그것을 주장 할 수 있습니다. 라운드 중에 죽으면 해당 라운드의 모든 포인트가 사라집니다.

각 라운드에는 무작위로 선택된 플레이어 그룹 (최대 5 명의 고유 플레이어)이 있습니다 (변경 될 수 있음). 모든 플레이어는 같은 라운드 수에 참여합니다. 봇의 최종 점수는 게임당 평균 점수에 의해 결정됩니다. 각 게임은 2000 턴으로 구성됩니다 (변경 될 수도 있음). 모든 봇은 동시에 움직입니다.

사망 사례

머리 엉덩이

머리 엉덩이

두 선수가 서로 맞대면 죽습니다. 두 플레이어가 모두 공간의 가장자리에있을 때에도 마찬가지입니다.

머리 엉덩이

그러나 한 명의 플레이어 만 자신의 땅에 있으면 다른 플레이어는 죽습니다.

여기에 이미지 설명을 입력하십시오

라인 크로스

여기에 이미지 설명을 입력하십시오

이 경우 보라색 플레이어 만 죽습니다.

당신은 자신의 선을 넘을 수 없습니다.

여기에 이미지 설명을 입력하십시오

보드 나가기

플레이어는 보드에서가

플레이어가 보드에서 나 가려고하면 죽고 모든 포인트를 잃게됩니다.

캡처 영역

플레이어는 트레일이있을 때 지역을 점령하고 다시 자신의 땅에 들어갑니다.

여기에 이미지 설명을 입력하십시오

빨간색은 두 개의 빨간색 선 사이를 채 웁니다. 플레이어가 채우지 않는 유일한 경우는 다른 플레이어가 루프 안에있을 때입니다. 분명히, 이것은 다른 플레이어 자신이 자신이 소유 한 토지가 아니라 루프에있을 때만 적용됩니다. 플레이어는 다른 사람으로부터 토지를 점령 할 수 있습니다. 플레이어가 자신의 트레일로 둘러싸인 영역을 채울 수없는 경우 트레일은 일반 토지로 직접 변환됩니다. 다른 플레이어 랜드 루프 내의 플레이어가 죽으면 해당 루프의 영역이 채워집니다. 플레이어가 죽을 때마다 채워질 수있는 영역에 대해 보드가 재검토됩니다.

컨트롤러 세부 사항

컨트롤러가 여기 있습니다 . 원래 게임과 매우 유사하지만 기술적 인 이유로 KotH에 더 적합하도록 약간 변경되었습니다. @NathanMerrillKotHComm 라이브러리@NathanMerrill 의 실질적인 도움으로 구축되었습니다. 대화방 의 컨트롤러에서 발견 된 모든 버그를 알려주십시오 . KotHComm과 일관성을 유지하기 위해 컨트롤러 전체에서 Eclipse 컬렉션을 사용했지만 Java 컬렉션 라이브러리 만 사용하여 봇을 작성할 수 있습니다.

모든 것은 github releases 페이지 의 uberjar에 패키지되어 있습니다. 사용하려면 자동 완성에 사용할 수 있도록 다운로드하여 프로젝트에 첨부하십시오 ( IntelliJ , Eclipse 지침 ). 제출물을 테스트하려면을 사용하여 jar을 실행하십시오 java -jar SplixKoTH-all.jar -d path\to\submissions\folder. path\to\submissions\folder이라는 이름의 하위 폴더가 있는지 확인하고 java모든 파일을 거기에 배치하십시오. 봇에서 패키지 이름을 사용하지 마십시오 (KotHComm에서는 가능하지만 조금 더 문제가 될 수 있습니다). 모든 옵션을 보려면를 사용하십시오 --help. 모든 봇을로드하려면을 사용하십시오 --question-id 126815.

봇 작성

봇 작성을 시작하려면을 확장해야합니다 SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • 여기에서 봇이 원하는 움직임을 결정합니다. null을 반환해서는 안됩니다.
  • HiddenPlayer getThisHidden()
    • HiddenPlayer버전을 구하십시오 this. 봇과 보드를 비교하는 데 유용합니다.

enum Direction

  • 가치
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Direction좌회전하면 얻을 수 있는 것을 얻으십시오 .
  • Direction RightTurn()
    • Direction올바른 방향으로 돌면 얻을 수 있는 것을 얻으십시오 .

ReadOnlyBoard

이것은 보드에 액세스하는 클래스입니다. 플레이어 위치가 표시된 보드의 로컬 뷰 (20x20) 또는 보드의 위치를 ​​소유하고 주장하는 사람의 정보 만있는 전체 뷰 (전체 보드)를 얻을 수 있습니다. 이것은 또한 당신이 당신의 입장을 얻는 곳이기도합니다.

  • SquareRegion getBounds()
    • 보드의 크기를 검색하십시오.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • 보드의 세계지도를 얻으십시오.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • getGlobal()플레이어 주변의 20x20 영역으로 제한되고 플레이어 위치를 표시한다는 점을 제외하고 와 동일 합니다.
  • Point2D getPosition(SplixPlayer me)
    • 플레이어의 위치를 ​​확인하십시오. 로 사용하십시오 board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • 칠판에 당신의 입장을 알려주세요. 용법:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGame를 통해 게임에서 남은 턴 수에만 액세스 할 수 int getRemainingIterations()있습니다.

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • HiddenPlayer요점을 주장하는 사람 의 버전 (클레임 = 트레일)을 가져 옵니다 .
  • HiddenPlayer getOwner()
    • 포인트를 소유 한 사람을 확보하십시오.
  • HiddenPlayer getWhosOnSpot()
    • 플레이어가이 지점에 있으면 숨겨진 버전을 반환하십시오. 에서 작동합니다 getLocal().

Point2D

여기의 다른 클래스와 달리 Point2DKotHComm 라이브러리에 포함되어 있습니다.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)
    • x의 범위 내로 값을 maxX.
  • Point2D wrapY(int maxY)
    • y의 범위 내로 값을 maxY.
  • int cartesianDistance(Point2D other)
    • 이것은 플레이어가 지점 a에서 지점 b로 이동하는 데 걸리는 턴 수를 의미합니다.

클로저 지원

Clojure 컴파일러는와 번들로 제공 SplixKoTH-all.jar되므로 봇에 Clojure를 사용할 수 있습니다! random_bot사용 방법을 보려면 my 를 참조하십시오.

봇 디버깅

컨트롤러에는 테스트 전략을 돕기위한 디버거가 제공됩니다. 시작하려면 --gui옵션으로 jar을 실행하십시오 .

디버거를 jar에 첨부하려면 IntelliJ에 대한 다음 지시 사항 또는 Eclipse에 대한 지시 사항 을 따르십시오 (Eclipse 버전은 테스트되지 않음).

여기에 이미지 설명을 입력하십시오

코드와 함께 디버거를 사용하는 경우이 코드를 사용하여 봇이보고있는 것을 시각화 할 수 있습니다. makeMove봇 의 시작 부분에 중단 점을 설정 하고 현재 스레드 만 일시 중지하는지 확인하십시오. 그런 다음 UI에서 시작 버튼을 클릭하고 코드를 단계별로 실행하십시오.

여기에 이미지 설명을 입력하십시오

이제 모든 것을 하나로 합치십시오.

봇 실행

다른 사람과 함께 봇을 실행하려면 릴리스 페이지에서 jar을 실행해야합니다. 다음은 플래그 목록입니다.

  • --iterations( -i) <= int(기본 500)
    • 실행할 게임 수를 지정하십시오.
  • --test-bot( -t) <=String
    • 봇이 포함 된 게임 만 실행하십시오.
  • --directory( -d) <= 경로
    • 제출을 실행할 디렉토리입니다. 이것을 사용하여 봇을 실행하십시오. 봇이라는 경로의 하위 폴더에 있는지 확인하십시오 java.
  • --question-id( -q) <= int(만 사용 126815)
    • 사이트에서 다른 제출물을 다운로드하여 컴파일하십시오.
  • --random-seed( -r) <= int(기본값은 임의의 숫자)
    • 무작위를 사용하는 봇이 결과를 재현 할 수 있도록 러너에게 시드를 제공하십시오.
  • --gui( -g)
    • 토너먼트를 실행하는 대신 디버거 UI를 실행하십시오. 와 함께 사용하는 것이 가장 --test-bot좋습니다.
  • --multi-thread( -m) <= boolean(기본 true)
    • 멀티 스레드 모드에서 토너먼트를 실행하십시오. 컴퓨터에 여러 코어가있는 경우 더 빠른 결과를 얻을 수 있습니다.
  • --thread-count( -c) <= int(기본 4)
    • 다중 스레드가 허용되는 경우 실행할 스레드 수
  • --help( -h)
    • 이와 유사한 도움말 메시지를 인쇄하십시오.

이 페이지에서 모든 제출물을 실행하려면을 사용하십시오 java -jar SplixKoTH-all.jar -q 126815.

게시물 서식

컨트롤러가 모든 봇을 다운로드 할 수 있도록하려면이 형식을 따라야합니다.

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

또한 패키지 선언을 사용하지 마십시오.


스코어 보드

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

규칙의 일부가 불분명하거나 대화방 의 컨트롤러에서 오류를 발견하면 알려주십시오 .

즐기세요!


이봐, 마침내 게시되었습니다! 궁금 해서요 : D
MD XF

얼마나 기다렸어? ;) 제출할 계획입니까?
J Atkin

나는 주로 esolang으로 프로그램을 작성하기 때문에 이와 같은 도전을 해결할 수 있을지 모르겠다. 그러나 나는 샌드 박스에서 그것을 보았고 큰 도전처럼 보였습니다!
MD XF

@hyperneutrino 편집 내용을 보았습니다. 정말 귀찮습니까? 정치적인 정확성은이 글에서 다루지 않으며 완벽하게 정확한 영어 문법입니다.
J Atkin

2
작은 세상? splix.io의 개발자를 알고 있습니다. (이것을 @ 그
트위터

답변:


2

ImNotACoward, 자바

이 봇은 겁쟁이 생존 전문가입니다. 근처에 적이 없으면 땅의 일부를 차지합니다. 다른 플레이어의 루프에 안전하게 도달 할 수 있는 경우, 뒷면에있는 다른 플레이어를 찔러 다른 플레이어와 결투를합니다. 다른 플레이어가 안전하게 공격 할 수없는 경우, 그는 도망 수행을 자신의 땅으로 전략적 후퇴를.

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

흥미 롭군 아주 좋아요! 이것이 얼마나 더 나아질 지 궁금합니다.
J Atkin

1

트랩 봇, 자바

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

아마도 가장 간단한 봇일 것입니다. 보드 가장자리를 찾아 내면 죽을 위험을 줄이기 위해 스스로 배가됩니다.


Eclipse Collections를 사용한 것을 보았습니다. EC에는 페어 인터페이스가 있습니다. Tuples.pair ()를 사용하여 Pair 인스턴스를 얻을 수 있습니다. 쌍의 값 중 하나 또는 둘 다가 프리미티브 인 경우 PrimitiveTuples 클래스도 있습니다.
Donald Raab

1

random_bot, 클로저

이것은 RandomBot 이지만 명명 규칙을 고수해야하며 일부 문제로 인해 이름에 하이픈을 사용할 수 없으므로 밑줄이 지배됩니다! make-moveFN은 첫 번째 항목은 존재와 VEC를 반환 Direction당신이 이동하려는, 그리고 두 번째는 당신이 원하는 상태가 다음 턴에 다시 여러분에게 전달 될 것. 이 코드는 여러 게임을 병렬로 실행할 수 있으므로 외부 원자를 사용하지 마십시오.

 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

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

}

가장 기본적인 봇 중 하나입니다. 보드를 검색하여 다른 사람을 죽일 지점을 찾고, 가장 짧은 길을 따라 죽일 수 있습니다. 그것이 영토 밖에 있다면, 다른 플레이어를 죽일 다른 구멍이 생길 때까지 무작위로 움직입니다. 그것은 그 자체로 실행되는 것을 막는 논리가 있으며, 다른 모든 플레이어가 죽으면 집으로 돌아갑니다. 집에 도착하면 작은 광장에 들어갑니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.