Splix.io - Raja tanah


37

Anda adalah titik giat yang ingin meningkatkan lahan di bawah kendalinya. Ini cukup sederhana - bepergian ke luar tanah Anda saat ini dan kembali ke tanah Anda dan semua yang ada di dalam lingkaran itu sekarang dimiliki oleh Anda. Tapi ada yang menangkap. Jika beberapa titik lain entah bagaimana menemukan lingkaran Anda dan melewatinya, Anda mati.

Jika Anda belum mencobanya, buka Splix.io dan coba permainan. Gunakan tombol panah untuk mengontrol gerakan Anda.

GIF

masukkan deskripsi gambar di sini

Kredit: http://splix.io/

Spesifik

Semua pemain mulai dari posisi acak di papan 200x200. (Saya berhak mengubah ini :). Anda akan memiliki sejumlah gerakan tertentu untuk mengumpulkan poin sebanyak mungkin. Poin dihitung dengan:

  • Jumlah pemain yang kamu bunuh 300 kali
  • Jumlah tanah yang Anda miliki di akhir putaran

Ini memunculkan poin bahwa orang lain dapat mencuri tanah Anda. Jika mereka memulai loop yang memotong sebagian tanah Anda, mereka dapat mengklaimnya. Jika Anda mati selama putaran, Anda kehilangan semua poin untuk putaran itu.

Setiap babak memiliki kelompok pemain yang dipilih secara acak (maks. 5 pemain unik) (dapat berubah). Setiap pemain berpartisipasi dalam jumlah putaran yang sama. Skor akhir bot Anda ditentukan oleh skor rata-rata per-pertandingannya. Setiap game terdiri dari 2000 putaran (juga dapat berubah). Semua bot melakukan gerakan pada saat bersamaan.

Kasus Kematian

Kepala Butt

kepala pantat

Kedua pemain mati ketika mereka saling berhadapan. Ini masih benar bahkan ketika kedua pemain berada di ujung ruang mereka.

kepala pantat

Namun, ketika hanya satu pemain di negaranya, pemain lainnya mati.

masukkan deskripsi gambar di sini

Garis Salib

masukkan deskripsi gambar di sini

Dalam hal ini, hanya pemain ungu yang mati.

Anda tidak dapat melewati batas Anda sendiri.

masukkan deskripsi gambar di sini

Keluar dari papan

pemain keluar papan

Jika seorang pemain mencoba untuk keluar dari papan, dia akan mati dan kehilangan semua poin.

Menangkap area

Seorang pemain akan menangkap area ketika dia memiliki jejak dan dia memasuki tanahnya sendiri lagi.

masukkan deskripsi gambar di sini

Merah mengisi di antara dua garis merah. Satu-satunya kasus di mana pemain tidak mengisi adalah ketika pemain lain berada di dalam loop. Untuk lebih jelasnya, ini hanya berlaku ketika pemain lain sendiri berada di loop, bukan hanya tanah yang dimiliki olehnya. Seorang pemain dapat merebut tanah dari orang lain. Jika seorang pemain tidak dapat mengisi area yang dikelilingi oleh jejaknya, jejak dikonversi langsung ke tanah normal. Jika pemain di dalam loop pemain lain mati, area dalam loop itu terisi. Setiap kali pemain meninggal, papan diperiksa ulang untuk area yang dapat diisi.

Detail pengontrol

Pengontrolnya ada di sini . Ini sangat mirip dengan game asli, tetapi perubahan kecil telah dibuat untuk membuat ini lebih cocok untuk KotH dan karena alasan teknis. Hal ini dibangun dengan @NathanMerrill 's KotHComm perpustakaan , dan dengan bantuan besar dari @NathanMerrill juga. Tolong beri tahu saya jika ada bug yang Anda temukan di controller di chat room . Agar konsisten dengan KotHComm, saya telah menggunakan koleksi Eclipse di seluruh pengontrol, tetapi bot dapat ditulis hanya dengan menggunakan perpustakaan Koleksi Java.

Semuanya dikemas dalam uberjar di halaman rilis github . Untuk menggunakannya, unduh dan lampirkan ke proyek Anda sehingga Anda dapat menggunakannya untuk auto-compleat (instruksi untuk IntelliJ , Eclipse ). Untuk menguji kiriman Anda, Anda menjalankan toples java -jar SplixKoTH-all.jar -d path\to\submissions\folder. Pastikan path\to\submissions\foldersubfoler diberi nama java, dan letakkan semua file Anda di sana. Jangan menggunakan nama paket di bot Anda (meskipun mungkin dengan KotHComm, itu hanya sedikit lebih banyak masalah). Untuk melihat semua opsi, gunakan --help. Untuk memuat semua bot, gunakan --question-id 126815.

Menulis bot

Untuk mulai menulis bot, Anda harus memperluas SplixPlayer.

  • Direction makeMove(ReadOnlyGame game, ReadOnlyBoard board)
    • Di sinilah Anda memutuskan gerakan mana yang Anda inginkan bot Anda lakukan. Tidak boleh kembali nol.
  • HiddenPlayer getThisHidden()
    • Dapatkan HiddenPlayerversi this. Berguna untuk membandingkan bot Anda ke papan tulis.

enum Direction

  • Nilai-nilai
    • East (x = 1; y = 0)
    • West (x = -1; y = 0)
    • North (x = 0; y = 1)
    • South (x = 0; y = -1)
  • Direction leftTurn()
    • Dapatkan Directionyang akan Anda dapatkan jika Anda belok kiri.
  • Direction RightTurn()
    • Dapatkan Directionyang akan Anda dapatkan jika Anda belok ke kanan.

ReadOnlyBoard

Ini adalah kelas tempat Anda mengakses papan tulis. Anda bisa mendapatkan tampilan lokal (20x20) dari papan dengan posisi pemain ditampilkan, atau tampilan global (seluruh papan) dengan hanya informasi tentang siapa yang memiliki dan mengklaim posisi di papan tulis. Di sinilah Anda mendapatkan posisi Anda.

  • SquareRegion getBounds()
    • Ambil kembali ukuran papan.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getGlobal()
    • Dapatkan peta global dewan.
  • MutableMap<com.nmerrill.kothcomm.game.maps.Point2D,ReadOnlySplixPoint> getView()
    • Sama seperti getGlobal(), kecuali bahwa itu terbatas pada area 20x20 di sekitar pemain Anda, dan itu menunjukkan posisi pemain.
  • Point2D getPosition(SplixPlayer me)
    • Dapatkan posisi pemain Anda. Gunakan sebagai board.getPosition(this).
  • Point2D getSelfPosition(ReadOnlyBoard)
    • Dapatkan posisi Anda di papan tulis. Pemakaian:Point2D mypos = getSelfPosition(board)

ReadOnlyGame

ReadOnlyGamehanya menyediakan akses ke jumlah belokan yang tersisa dalam game melalui int getRemainingIterations().

ReadOnlySplixPoint

  • HiddenPlayer getClaimer()
    • Dapatkan HiddenPlayerversi siapa yang mengklaim poin - mengklaim = jejak.
  • HiddenPlayer getOwner()
    • Dapatkan siapa yang memiliki poin.
  • HiddenPlayer getWhosOnSpot()
    • Jika pemain diposisikan pada titik ini, kembalikan versi tersembunyi itu. Hanya bekerja di getLocal().

Point2D

Berbeda dengan kelas-kelas lain di sini, Point2Dterdapat di perpustakaan 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)
    • Bungkus xnilai agar berada dalam kisaran maxX.
  • Point2D wrapY(int maxY)
    • Bungkus ynilai agar berada dalam kisaran maxY.
  • int cartesianDistance(Point2D other)
    • Ini berarti berapa banyak putaran yang diperlukan bagi pemain untuk berpindah dari titik a ke titik b.

Dukungan Clojure

Compiler Clojure dibundel dengan SplixKoTH-all.jar, sehingga Anda dapat menggunakan Clojure untuk bot Anda! Rujuk ke saya random_botuntuk melihat cara menggunakannya.

Melakukan debug bot

Pengontrol dilengkapi dengan debugger untuk membantu menguji strategi. Untuk memulainya, jalankan toples dengan --guiopsi.

Untuk melampirkan debugger ke toples Anda, ikuti instruksi ini untuk IntelliJ, atau instruksi ini untuk Eclipse (versi Eclipse belum teruji).

masukkan deskripsi gambar di sini

Jika Anda menggunakan debugger dengan kode Anda, Anda dapat menggunakan ini untuk membantu memvisualisasikan apa yang dilihat oleh bot Anda. Tetapkan breakpoint di awal makeMovebot Anda, dan pastikan itu hanya menjeda utas saat ini. Selanjutnya, klik tombol mulai pada UI dan lewati kode Anda.

masukkan deskripsi gambar di sini

Sekarang, untuk menyatukan semuanya:

Menjalankan bot

Untuk menjalankan bot Anda dengan orang lain, Anda perlu menjalankan jar pada halaman rilis. Ini daftar bendera:

  • --iterations( -i) <= int(standar 500)
    • Tentukan jumlah game yang akan dijalankan.
  • --test-bot( -t) <=String
    • Jalankan hanya game yang termasuk dalam bot.
  • --directory( -d) <= Path
    • Direktori tempat menjalankan kiriman. Gunakan ini untuk menjalankan bot Anda. Pastikan bot Anda berada dalam subfolder dari path yang dinamai java.
  • --question-id( -q) <= int(hanya digunakan 126815)
    • Unduh dan kompilasi kiriman lainnya dari situs.
  • --random-seed( -r) <= int(standar ke nomor acak)
    • Berikan benih kepada pelari sehingga bot yang menggunakan acak dapat memiliki hasil yang direproduksi.
  • --gui( -g)
    • Jalankan debugger ui alih-alih menjalankan turnamen. Paling cocok digunakan dengan --test-bot.
  • --multi-thread( -m) <= boolean(standar true)
    • Jalankan turnamen dalam mode multi-utas. Ini memungkinkan hasil yang lebih cepat jika komputer Anda memiliki banyak inti.
  • --thread-count( -c) <= int(standar 4)
    • Jumlah utas untuk dijalankan jika multi-utas diizinkan.
  • --help( -h)
    • Cetak pesan bantuan yang mirip dengan ini.

Untuk menjalankan semua pengiriman di halaman ini, gunakan java -jar SplixKoTH-all.jar -q 126815.

Memformat pos Anda

Untuk memastikan bahwa pengontrol dapat mengunduh semua bot, Anda harus mengikuti format ini.

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

Juga, jangan gunakan deklarasi paket.


Papan angka

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

Harap beri tahu saya jika ada bagian dari aturan yang tidak jelas, atau jika Anda menemukan kesalahan di controller di chat room .

Selamat bersenang-senang!


Hei, ini akhirnya diposting! Saya bertanya-tanya: D
MD XF

Sudah berapa lama kamu menunggu? ;) Apakah Anda berencana mengirim?
J Atkin

Saya tidak tahu apakah saya akan dapat menyelesaikan tantangan seperti ini, karena saya terutama menulis program di esolang. Tapi saya melihatnya di kotak pasir dan itu tampak seperti tantangan besar!
MD XF

@hyperneutrino Saya melihat hasil edit, apakah itu benar-benar mengganggu Anda? Kebenaran politik tidak ada dalam bidang pos ini, dan itu adalah tata bahasa Inggris yang benar benar ...
J Atkin

2
0.o dunia kecil? Saya tahu pengembang splix.io. (Tweeted this @ him)
CAD97

Jawaban:


2

ImNotACoward, Java

Bot ini adalah ahli bertahan hidup pengecut . Jika tidak ada musuh di dekatnya, ia mengklaim bagian dari tanah itu. Jika loop dari pemain lain dapat dijangkau dengan aman, dia menusuk pemain lain di belakang melibatkan pemain lain dalam duel. Jika pemain lain tidak dapat diserang dengan aman, ia melarikan diri melakukan retret strategis ke negerinya sendiri.

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

Ini mungkin bot yang paling sederhana. Yang dilakukannya hanyalah menelusuri tepi papan, menggandakan diri untuk mengurangi risiko terbunuh.


Keren melihat Anda menggunakan Eclipse Collections. Ada antarmuka Pair di EC. Anda dapat menggunakan Tuples.pair () untuk mendapatkan instance Pair. Ada juga kelas PrimitiveTuples jika salah satu atau kedua nilai dalam pasangan adalah primitif.
Donald Raab

1

random_bot, Clojure

Ini adalah RandomBot , tapi saya harus tetap berpegang pada konvensi penamaan, dan beberapa masalah mencegah saya menggunakan tanda hubung dalam nama, jadi garis bawah berkuasa! The make-movefn kembali vec dengan item pertama adalah DirectionAnda ingin pindah, dan yang kedua menjadi negara yang ingin diteruskan kembali kepada Anda pada giliran berikutnya. Jangan gunakan atom eksternal apa pun, karena kode ini dapat menjalankan beberapa game secara paralel.

 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, Jawa

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

}

Salah satu bot paling dasar. Itu mencari papan untuk tempat untuk membunuh orang lain, dan itu akan mengikuti jalan sesingkat mungkin untuk sampai ke posisi membunuh. Jika berada di luar wilayahnya, ia akan membuat gerakan acak hingga memiliki celah lain untuk membunuh pemain lain. Ia memiliki beberapa logika untuk mencegahnya berlari sendiri, dan ketika semua pemain lain mati, ia akan kembali ke rumahnya. Setelah di rumah itu hanya berjalan di kotak kecil.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.