Connect-n zamanı!


20

https://en.wikipedia.org/wiki/Connect_Four

2 oyuncu oyunu 4 bağlamak bağ hatırlayan var mı? Yapmayanlar için, bir yüzeyde dikey duran 6x7 bir tahta vardı. 4 bağlantı hedefi, iyi 4 bağlantı! Bağlantı yatay, çapraz veya dikey ise sayılır. Bir sütunun üst kısmına o sütunun altına düşecek bir parça takarak parçalarınızı tahtaya yerleştirirsiniz. Kurallarımız bağlantı 4'te 3 şeyi değiştirir.

  • Değişim # 1 Kazanma en çok puanı alan oyuncu olarak tanımlanır. Kurallarda olduğu gibi 4'ü bağlayarak puan alırsınız - daha sonra daha fazla.
  • Değişim # 2 Her turda 3 oyuncunuz var.
  • Değişiklik # 3 Pano boyutu 9x9'dur.

puanlama:

Puan, arka arkaya kaç tane aldığınıza bağlıdır. Bir satır grubunda 4'ünüz varsa 1 puan alırsınız. Eğer bir satır grubunda 5 varsa, 2 puan alırsınız, 6 satır 3'te vb.

Örnekler:

Daha iyi kontrast için not edin ve sırasıyla ove xile değiştirilir#~

Boş tahta örneği: (tüm örnekler 2 oyuncu standart boyutlu tahtadır)

   a b c d e f g
6 | | | | | | | |
5 | | | | | | | |
4 | | | | | | | |
3 | | | | | | | |
2 | | | | | | | |
1 |_|_|_|_|_|_|_|

Bir parçayı kol halinde bırakırsak d, yere inecektir 1d.

   a b c d e f g
6 | | | | | | | |
5 | | | | | | | |
4 | | | | | | | |
3 | | | | | | | |
2 | | | | | | | |
1 |_|_|_|#|_|_|_|

Şimdi dtekrar bir parçaya kol halinde bırakırsak , yere inecektir 2d. Aşağıda sıra konumlarında 4 örnek verilmiştir:

   a b c d e f g
6 | | | | | | | |
5 | | | | | | | |
4 | | | |~| | | |
3 | | |~|#| | | |
2 | |~|#|~| |#| |
1 |~|#|~|#|_|#|_|

Bu durumda xçapraz olarak 1 puan alır ( 1a 2b 3c 4d).

  a b c d e f g
6 | | | | | | | |
5 | | | | | | | |
4 | | | |#| | | |
3 | | | |#| | | |
2 | | | |#| | | |
1 |_|~|_|#|~|_|~|

Bu durumda, odikey olarak 1 puan alır ( 1d 2d 3d 4d).

   a b c d e f g
6 | | | | | | | |
5 | | | | | | | |
4 | | | | | | | |
3 | | | | | | | |
2 | | |#|#|#|#| |
1 |_|_|~|~|~|~|~|

Bu durumda oyatay olarak 2 puan alır ( 1c 1d 1e 1f 1g) ve xyatay olarak 1 puan alır ( 2c 2d 2e 2f).

   a b c d e f g
6 | | |#| | | | |
5 | | |#| | | | |
4 | | |#| | | | |
3 | | |#| | |~| |
2 |~| |#| | |#|~|
1 |~|_|#|~| |~|~|

Bu kez xarka arkaya 6 için 3 puan kazanılır ( 1c 2c 3c 4c 5c 6c).

Giriş çıkış

2d dizisi üzerinden panoya erişebileceksiniz. Her konum intbir oyuncu kimliğini temsil edecek şekilde temsil edilecektir . Ayrıca oyuncu kimliğinizin işlevinize geçmesini sağlayabilirsiniz. Taşınızı hangi parçayı bırakmak istediğinizi döndürerek yaparsınız. Her turda 3 oyuncu seçilecek. Oyunun sonunda, tüm oyuncular eşit miktarda oyun oynamış olacaklar.

Şu an 100 bin mermi gerçekleştirilecek (bunun uzun sürdüğünü unutmayın , hızlı geri dönüş testi için azaltmak isteyebilirsiniz). Genel olarak kazanan en çok kazanan oyuncu.

Denetleyiciyi burada bulabilirsiniz: https://github.com/JJ-Atkinson/Connect-n/tree/master .

Bot yazmak:

Bir bot yazmak için Playersınıfı genişletmelisiniz . Playersoyuttur ve uygulamak için bir yöntemi vardır int makeMove(void). İçinde makeMovehangi kolunu parçanıza bırakmak istediğinize karar vereceksiniz. Geçersiz bir koleksiyon seçtiyseniz (ör. Coll mevcut değil, coll zaten doldurulmuş), sıralamanız atlanacaktır . In Playersınıfında birçok kullanışlı yardımcı yöntemler var. En önemlilerinin listesi aşağıdaki gibidir:

  • boolean ensureValidMove(int coll): Coll tahtada ise ve coll henüz doldurulmamışsa true değerini döndürün .
  • int[] getBoardSize(): [0]Sütun [1]sayısı ve satır sayısı olan bir int dizisi döndürür .
  • int[][] getBoard(): Kartın bir kopyasını iade edin. Böyle erişmek olmalıdır: [coll number][row number from bottom].
  • Gerisini bulmak için Playersınıfa bakın.
  • EMPTY_CELL: Boş bir hücrenin değeri

Bu çok iş parçacıklı olacağından, randomihtiyacınız varsa bir işlev de ekledim .

Botunuzda hata ayıklama:

Bir botta hata ayıklamayı kolaylaştırmak için denetleyiciye bazı şeyler ekledim. İlki Runner#SHOW_STATISTICS. Bu etkinleştirilirse, bir dizi kazanma da dahil olmak üzere, oynatılan oyuncu gruplarının bir çıktısını göreceksiniz. Misal:

OnePlayBot, PackingBot, BuggyBot, 
OnePlayBot -> 6
PackingBot -> 5
BuggyBot -> 3
Draw -> 1

Ayrıca connectn.game.CustomGamesınıf ile özel bir oyun yapabilir, her turun puanlarını ve kazananını görebilirsiniz. Kendinizi ile karışıma bile ekleyebilirsiniz UserBot.

Botunuzu ekleme:

Botunuzu dizilişe eklemek için PlayerFactorystatik bloğa gidin ve aşağıdaki satırı ekleyin:

playerCreator.put(MyBot.class, MyBot::new);

Dikkat edilmesi gereken diğer şeyler:

  • Simülasyonlar çok iş parçacıklı. Bunu kapatmak istiyorsanız, Runner#runGames()bu satıra ( .parallel()) gidin ve yorum yapın .
  • Oyun sayısını değiştirmek Runner#MINIMUM_NUMBER_OF_GAMESiçin isteğinize göre ayarlayın .

Daha sonra eklendi:

  • Botlar arasındaki iletişime izin verilmez.

İlgili: Play Connect 4!

================================

Skorbord: (100 000 oyun)

MaxGayne -> 22662
RowBot -> 17884
OnePlayBot -> 10354
JealousBot -> 10140
Progressive -> 7965
Draw -> 7553
StraightForwardBot -> 7542
RandomBot -> 6700
PackingBot -> 5317
BasicBlockBot -> 1282
BuggyBot -> 1114
FairDiceRoll -> 853
Steve -> 634

================================


Oyunun hangi açıkta olduğunu belirlemek için işlevsellik ekleyebilir misiniz?
Conor O'Brien

Zaten yapıldı, Playermevcut tüm yöntemleri görmek için sınıfı kontrol et .
J Atkin

7
"kare 6x7" kare değil
ev3commander

1
Oyunculara yasadışı bir hamle yaparak "geçme" yeteneği, dinamikleri biraz değiştirir. Herkes geçerse oyun biter mi?
histokrat

1
Evet, bu yüzden kullanımı çok önemlidir ensureValidMove(stratejiniz bu dönüşü geçmek değilse).
J Atkin

Yanıtlar:


11

MaxGayne

Bu bot, esas olarak bağlı parçaların uzunluğuna bağlı olarak her pozisyona bir puan atar. Her aşamada en iyi görünen 3 hamleyi inceleyerek 3 hamle derinlemesine görünüyor ve beklenen maksimum puana sahip olanı seçiyor.

package connectn.players;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MaxGayne extends Player {
    private static final int PLAYERS = 3;

    private static class Result {
        protected final int[] score;
        protected int lastCol;

        public Result(int[] score, int lastCol) {
            super();
            this.score = score;
            this.lastCol = lastCol;
        }

        public Result() {
            this(new int[PLAYERS], -1);
        }

        public Result(Result other) {
            this(new int[PLAYERS], other.lastCol);
            System.arraycopy(other.score, 0, this.score, 0, PLAYERS);
        }

        public int getRelativeScore(int player) {
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < PLAYERS; ++ i) {
                if (i != player && score[i] > max) {
                    max = score[i];
                }
            }
            return score[player] - max;
        }
    }

    private static class Board extends Result {
        private final int cols;
        private final int rows;
        private final int[] data;
        private final int[] used;

        public Board(int cols, int rows) {
            super();
            this.cols = cols;
            this.rows = rows;
            this.data = new int[cols * rows];
            Arrays.fill(this.data, -1);
            this.used = new int[cols];
        }

        public Board(Board other) {
            super(other);
            this.cols = other.cols;
            this.rows = other.rows;
            this.data = new int[cols * rows];
            System.arraycopy(other.data, 0, this.data, 0, this.data.length);
            this.used = new int[cols];
            System.arraycopy(other.used, 0, this.used, 0, this.used.length);
        }

        private void updatePartScore(int player, int length, int open, int factor) {
            switch (length) {
                case 1:
                    score[player] += factor * open;
                    break;
                case 2:
                    score[player] += factor * (100 + open * 10);
                    break;
                case 3:
                    score[player] += factor * (10_000 + open * 1_000);
                    break;
                default:
                    score[player] += factor * ((length - 3) * 1_000_000 + open * 100_000);
                    break;
            }
        }

        private void updateLineScore(int col, int row, int colOff, int rowOff, int length, int factor) {
            int open = 0;
            int player = -1;
            int partLength = 0;
            for (int i = 0; i < length; ++ i) {
                int newPlayer = data[(col + i * colOff) * rows + row + i * rowOff];
                if (newPlayer < 0) {
                    if (player < 0) {
                        if (i == 0) {
                            open = 1;
                        }
                    } else {
                        updatePartScore(player, partLength, open + 1, factor);
                        open = 1;
                        player = newPlayer;
                        partLength = 0;
                    }
                } else {
                    if (newPlayer == player) {
                        ++ partLength;
                    } else {
                        if (player >= 0) {
                            updatePartScore(player, partLength, open, factor);
                            open = 0;
                        }
                        player = newPlayer;
                        partLength = 1;
                    }
                }
            }
            if (player >= 0) {
                updatePartScore(player, partLength, open, factor);
            }
        }

        private void updateIntersectionScore(int col, int row, int factor) {
            updateLineScore(col, 0, 0, 1, rows, factor);
            updateLineScore(0, row, 1, 0, cols, factor);
            if (row > col) {
                updateLineScore(0, row - col, 1, 1, Math.min(rows - row, cols), factor);
            } else {
                updateLineScore(col - row, 0, 1, 1, Math.min(cols - col, rows), factor);
            }
            if (row > cols - col - 1) {
                updateLineScore(cols - 1, row - (cols - col - 1), -1, 1, Math.min(rows - row, cols), factor);
            } else {
                updateLineScore(col + row, 0, -1, 1, Math.min(col + 1, rows), factor);
            }
        }

        private void updatePiece(int player, int col, int row) {
            updateIntersectionScore(col, row, -1);
            data[col * rows + row] = player;
            ++ used[col];
            lastCol = col;
            updateIntersectionScore(col, row, 1);
        }

        public Board updatePiece(int player, int col) {
            int row = used[col];
            if (row >= rows) {
                return null;
            } else {
                Board result = new Board(this);
                result.updatePiece(player, col, row);
                return result;
            }
        }

        private void updateBoard(int[][] board) {
            for (int col = 0; col < cols; ++ col) {
                for (int row = 0; row < rows; ++ row) {
                    int oldPlayer = data[col * rows + row];
                    int newPlayer = board[col][row] - 1;
                    if (newPlayer < 0) {
                        if (oldPlayer < 0) {
                            break;
                        } else {
                            throw new RuntimeException("[" + col + ", " + row + "] == "  + oldPlayer + " >= 0");
                        }
                    } else {
                        if (oldPlayer < 0) {
                            updatePiece(newPlayer, col, row);
                        } else if (newPlayer != oldPlayer) {
                            throw new RuntimeException("[" + col + ", " + row + "] == "  + oldPlayer + " >= " + newPlayer);
                        }
                    }
                }
            }
        }

        private Result bestMove(int depth, int player) {
            List<Board> boards = new ArrayList<>();
            for (int col = 0; col < cols; ++ col) {
                Board board = updatePiece(player, col);
                if (board != null) {
                    boards.add(board);
                }
            }
            if (boards.isEmpty()) {
                return null;
            }
            Collections.sort(boards, (o1, o2) -> Integer.compare(o2.getRelativeScore(player), o1.getRelativeScore(player)));
            if (depth <= 1) {
                return new Result(boards.get(0).score, boards.get(0).lastCol);
            }
            List<Result> results = new ArrayList<>();
            for (int i = 0; i < 3 && i < boards.size(); ++ i) {
                Board board = boards.get(i);
                Result result = board.bestMove(depth - 1, (player + 1) % PLAYERS);
                if (result == null) {
                    results.add(new Result(board.score, board.lastCol));
                } else {
                    results.add(new Result(result.score, board.lastCol));
                }
            }
            Collections.sort(results, (o1, o2) -> Integer.compare(o2.getRelativeScore(player), o1.getRelativeScore(player)));
            return results.get(0);
        }
    }

    private Board board = null;

    @Override
    public int makeMove() {
        if (board == null) {
            int[][] data = getBoard();
            board = new Board(data.length, data[0].length);
            board.updateBoard(data);
        } else {
            board.updateBoard(getBoard());
        }

        Result result = board.bestMove(3, getID() - 1);
        return result == null ? -1 : result.lastCol;
    }
}

Çok çok güzel! +1
J Atkin

Ben ve oyun oynarken etrafında fark ettim bir şey UserBotbot bir noktadan sonra MaxGayneatmak olacaktı (örneğin 15 hamle sonra oyun bitene kadar her tur atlar).
J Atkin

Bunun nedeni büyük olasılıkla CustomGame içinde bir hata. Ana oyun gibi 1 tabanlı yerine 0 tabanlı oyuncu kimlikleri kullanıyor. Bu sadece botumu kırar. 2 sorun daha var. javafx.util.Pairgenel API'nin bir parçası olarak değerlendirilmediğinden Eclipse'de çalışmaz. Nereye bakacağım hakkında hiçbir fikrim yok sun.plugin.dom.exception.InvalidStateException. Muhtemelen demek istedin java.lang.IllegalStateException.
Sleafar

Bu biraz tuhaf görünüyor ... Her neyse Pair, olduğu gibi, kendi yuvarlanmadan istediğim veri türüne ulaşabildiğim kadar yakın, bu yüzden tutulma derlenmezse, bence sorun yok. # 3'e gelince, haklısın, IntelliJ'deki otomatik tamamlamam her zaman doğru değil. (çoğu zaman, bu yüzden kontrol etmedim)
J Atkin

@JAtkin Aslında, geçici çözümüPair bilmiyorsanız sorun Eclipse'de derlemeyi gerçekten engelliyor .
Sleafar

6

RowBot

Her yöne bakar ve en uygun sütunu belirler. Rakiplerinin de aynısını yapmasına izin vermezken parçalarını birleştirmeye çalışır.

package connectn.players;

import connectn.game.Game;
import java.util.ArrayList;
import java.util.List;

public class RowBot extends Player {

    @Override
    public int makeMove() {
        int[][] board = getBoard();
        int best = -1;
        int bestScore = -10;
        for (int col = 0; col < board.length; col++) {
            if (ensureValidMove(col)) {
                int score = score(board, col, false);
                score -= score(board, col, true);
                if (score > bestScore) {
                    bestScore = score;
                    best = col;
                }
            }
        }
        return best;
    }

    private int score(int[][] board, int col, boolean simulateMode) {
        int me = getID();
        int row = getLowestEmptyRow(board, col);
        List<Score> scores = new ArrayList<>();
        if (!simulateMode) {
            scores.add(getScoreVertical(board, col, row));
        } else {
            row += 1;
        }
        scores.addAll(getScoreHorizontal(board, col, row));
        scores.addAll(getScoreDiagonal(board, col, row));
        int score = 0;
        for (Score s : scores) {
            if (s.player == me) {
                score += s.points > 2 ? 100 : s.points * 5;
            } else if (s.player != Game.EMPTY_CELL) {
                score += s.points > 2 ? 50 : 0;
            } else {
                score += 1;
            }
        }
        return score;
    }

    private Score getScoreVertical(int[][] board, int col, int row) {
        return getScore(board, col, row, 0, -1);
    }

    private List<Score> getScoreHorizontal(int[][] board, int col, int row) {
        List<Score> scores = new ArrayList<>();

        Score left = getScore(board, col, row, -1, 0);
        Score right = getScore(board, col, row, 1, 0);
        if (left.player == right.player) {
            left.points += right.points;
            scores.add(left);
        } else {
            scores.add(left);
            scores.add(right);
        }
        return scores;
    }

    private List<Score> getScoreDiagonal(int[][] board, int col, int row) {
        List<Score> scores = new ArrayList<>();

        Score leftB = getScore(board, col, row, -1, -1);
        Score rightU = getScore(board, col, row, 1, 1);
        Score leftBottomToRightUp = leftB;
        if (leftB.player == rightU.player) {
            leftBottomToRightUp.points += rightU.points;
        } else if (leftB.points < rightU.points || leftB.player == Game.EMPTY_CELL) {
            leftBottomToRightUp = rightU;
        }

        Score leftU = getScore(board, col, row, -1, 1);
        Score rightB = getScore(board, col, row, 1, -1);
        Score rightBottomToLeftUp = leftU;
        if (leftU.player == rightB.player) {
            rightBottomToLeftUp.points += rightB.points;
        } else if (leftU.points < rightB.points || leftU.player == Game.EMPTY_CELL) {
            rightBottomToLeftUp = rightB;
        }

        if (leftBottomToRightUp.player == rightBottomToLeftUp.player) {
            leftBottomToRightUp.points += rightBottomToLeftUp.points;
            scores.add(leftBottomToRightUp);
        } else {
            scores.add(leftBottomToRightUp);
            scores.add(rightBottomToLeftUp);
        }
        return scores;
    }

    private Score getScore(int[][] board, int initCol, int initRow, int colOffset, int rowOffset) {
        Score score = new Score();
        outerLoop: for (int c = initCol + colOffset;; c += colOffset) {
            for (int r = initRow + rowOffset;; r += rowOffset) {
                if (outside(c, r) || board[c][r] == Game.EMPTY_CELL) {
                    break outerLoop;
                }
                if (score.player == Game.EMPTY_CELL) {
                    score.player = board[c][r];
                }

                if (score.player == board[c][r]) {
                    score.points++;
                } else {
                    break outerLoop;
                }

                if (rowOffset == 0) {
                    break;
                }
            }
            if (colOffset == 0) {
                break;
            }
        }
        return score;
    }

    private boolean outside(int col, int row) {
        return !boardContains(col, row);
    }

    private int getLowestEmptyRow(int[][] board, int col) {
        int[] rows = board[col];
        for (int row = 0; row < rows.length; row++) {
            if (rows[row] == Game.EMPTY_CELL){
                return row;
            }
        }
        return -1;
    }

    private class Score {
        private int player = Game.EMPTY_CELL;
        private int points = 0;
    }
}

5

OnePlayBot

Bu botun sadece bir oyunu var - parçasını geçerli olan en soldaki hücreye yerleştirin. İşin garibi yeterince iyi;)

static class OnePlayBot extends Player {
    @Override
    int makeMove() {
        int attemptedMove = 0;

        for (int i = 0; i < getBoardSize()[0]; i++)
            if (ensureValidMove(i)) {
                attemptedMove = i;
                break;
            }

        return attemptedMove;
    }
}

3

RandomBot

Geçerli olan herhangi bir yere bir parça koyun.

static class RandomBot extends Player {
    @Override
    int makeMove() {
        int attemptedMove = (int)Math.round(random() * getBoardSize()[0]);
        while (!ensureValidMove(attemptedMove))
            attemptedMove = (int)Math.round(random() * getBoardSize()[0]);

        return attemptedMove;
    }
}

3

StraightForwardBot

OnePlayBot'a benzer, ancak son hamleyi dikkate alır ve bir sonraki sütunu geçerli olarak oynatır.

static class StraightForwardBot extends Player {
    private int lastMove = 0;

    @Override
    int makeMove() { 
        for (int i = lastMove + 1; i < getBoardSize()[0]; i++) {
            if (ensureValidMove(i)) {
                lastMove = i;
                return i;
            }
        }
        for (int i = 0; i < lastMove; i++) {
            if (ensureValidMove(i)) {
                lastMove = i;
                return i;
            }
        }
        return 0;
    }
}

3

JealousBot

Bu bot diğer oyuncudan nefret ediyor. Ve tahtaya taş düşürmekten hoşlanmıyor. Bu yüzden bir sütuna bir parça düşüren son kişi olmaya çalışır.

public class JealousBot extends Player {

    @Override
    public int makeMove() {
        int move = 0;
        boolean madeMove = false;
        int[] boardSize = getBoardSize();
        int id = getID();
        int[][] board = getBoard();

        if(getTurn()!=0) {
            for(int col = 0; col<boardSize[0]; col++) {
                for(int row = 0; row<boardSize[1]; row++) {
                    if(ensureValidMove(col)) {
                        if(board[col][row]!=EMPTY_CELL && board[col][row]!=id) {
                            move = col;
                            madeMove = true;
                            break;
                        }
                    }
                }
                if(madeMove) break;
            }

            if(!madeMove) {
                int temp = (int)Math.round(random()*boardSize[0]);
                while(madeMove!=true) {
                    temp = (int)Math.round(random()*boardSize[0]);
                    if(ensureValidMove(temp)) {
                        madeMove = true;
                    }
                }
                move = temp;
            }
        } else {
            move = (int)Math.round(random()*boardSize[0]);
        }

        return move;
    }
}

İlk kez CodeGolf'a geldim, umarım bu cevap yeterince iyi olacaktır. Henüz test edemedim, bu yüzden herhangi bir hata varsa lütfen affedersiniz.

EDIT : İkincisini kırmak için bir satır eklendi for.

DÜZENLEME 2 : Neden whilesonsuz olduğunu anladım. Şimdi tamamlandı ve kullanılabilir!


PPCG'ye hoş geldiniz, bu cevapla beni güldürdünüz, bu harika! Sadece koşullarınıza dikkat edin. Bence yönetim kurulu varsayılan olarak -1 değerlerle dolu, bu yüzden if(board[col][row]!=null && board[col][row]!=id)değiştirilmelidir if(board[col][row]!=-1..... Emin olmak istiyorsanız OP'nin github'ında game.Game.genBoard () 'u kontrol edin. Ya random()senin istediğini yapacak mı bilmiyorum, belki kullanın (int)Math.random()*col?
Katenkyo

@Katenkyo Çok teşekkür ederim, sizi güldürürse mutlu olurum! random()Yöntem olduğu Playersınıfın! Bu yüzden işe yarayacağını düşünüyorum =) Ama evet, koşullarıma güvenmiyordum. OP kodunda nasıl tanımlandığını bulamadım, ama tekrar kontrol edeceğim. Çok teşekkür ederim!
Keker

Player sınıfı random () öğesini tanımlar public double random() {return ThreadLocalRandom.current().nextDouble();}. Nasıl çalıştığını tam olarak bilmiyorum, ancak 0 ile 1 arasında bir değer döndürdüğünü varsayıyorum, bu yüzden yapmanız gerekebilir (int)random()*col:)
Katenkyo

@Katenkyo Oh, bunu zaten yaptığını sanıyordum ... Kötüüm. Tahtada boş bir hücre için doğru değeri bulduğumda düzenleyeceğim, tekrar teşekkür ederim!
Keker

@Katenkyo Doğru, ve nextDoublearasında bir sayı döndürür . Ben dahil ettim çünkü simülasyonlar paralel çalıştırılıyor ve iplik güvenli değil. 01Math.random()
J Atkin

3

BasicBlockBot

Basit (ve naif) bir blok bot. Yatay veya çapraz olarak arka arkaya 4 yapabileceğinizi bilmiyor !

static class BasicBlockBot extends Player {
    @Override
    int makeMove() {
        List<Integer> inARows = detectInARows();
        double chanceOfBlock = 0.5;

        if (inARows.isEmpty())
            chanceOfBlock = 0;

        if (random() < chanceOfBlock) {
            return inARows.get((int)Math.round(random() * (inARows.size() - 1)));
        } else {
            return (int)Math.round(random() * getBoardSize()[0]);
        }
    }


    /**
     * Very limited - just detects vertical in a rows
     *
     * @return A list of colls that have 4 in a row vertical
     */
    private List<Integer> detectInARows() {
        List<Integer> ret = new ArrayList<>();
        int[][] board = getBoard();

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                int currId = board[i][j];
                if (currId != -1 && is4InARowVertical(i, j, board)) {
                    ret.add(i);
                }
            }
        }

        return ret;
    }

    private boolean is4InARowVertical(int coll, int row, int[][] board) {
        int id = board[coll][row];

        for (int i = 0; i < 4; i++) {
            int y = row + i;
            if (!boardContains(coll,y) || board[coll][y] != id)
                return false;
        }
        return true;
    }

}

3

ilerici

Progresif ... progresiftir. Her şeye bakmayı sever , ve bazıları! (Bunun yönteminden emin değilim. Bir zamanlar bir arkadaşınıza karşı çalıştı.) Ve bir nedenden dolayı, düzgün çalışıyor.

static class Progressive extends Player{
    @Override
    int makeMove(){
        int move = 0;
        boolean statusBroken = false;
        for(int n=getBoardSize()[0];n>2;n-=2){
            for(int i=0;i<getBoardSize()[0];i+=n){
                if(ensureValidMove(i)){
                    move = i;
                    statusBroken = true;
                    break;
                }
                if(statusBroken) break;
            }
        }
        return move;
    }
}

@JAtkin Üzgünüm, kodun eski bir sürümü vardı.
Conor O'Brien

3
@JAtkin Düzenlemenizi reddettim. Kodlarını gönderilerinde düzeltmelerine izin vermelisiniz. Denetleyiciniz için düzeltmek istiyorsanız, bu iyi (kişisel olarak hala bir not bırakıyorum), ancak SE'de birisinin kodunun açıkça değiştirilmesine izin verilmiyor.
Nathan Merrill


2

BuggyBot

Yenmek için örnek bir bot (FYI: zor değil;)

static class BuggyBot extends Player {
    @Override
    int makeMove() {
        return getBoardSize()[1] - 1;
    }
}

2

PackingBot

Bu bot doğrudan puan hedeflemiyor. Tahta dolana kadar maksimum jeton toplamaya çalışır. Sadece tekrar tekrar yukarı çıkmanın aptal olduğunu anladı, bu yüzden rastgele "etki alanı" na jeton koyacaktır.

Her yöne bazı puanlar alabilmeli, ancak en iyisi olmayacak!

(Test edilmedi)

package connectn.players;

static class PackingBot extends Player
{
    @Override
    int makeMove()
    {
        int move = 0;
        int[] sizes = getBoardSize();
        if(getTurn()==0)
            return sizes[0]/2+sizes[0]%2;

        int[][] board = getBoard();
        int[] flatBoard =new int[sizes[0]];
        //Creating a flat mapping of my tokens
        for(int i=0;i<sizes[0];i++)
            for (int j=0;j<sizes[1];j++)
                if(board[i][j]!=getID())
                    flatBoard[i]++;

        int max=0;
        int range=0;
        for(int i=0;i<flatBoard.length;i++)
        {
            if(flatBoard[i]!=0)
                range++;
            if(flatBoard[i]>flatBoard[max])
                max=i;
        }

        int sens = (Math.random()>0.5)?1:-1;
        move=((int)(Math.random()*(range+1)*sens))+max;

        while(!ensureValidMove(move))
        {
            move=(move+1*sens)%sizes[0];
            if(move<0)
                move=sizes[0]-1;
        }
        return move;
    }


}

@JAtkin Bunu işaret ettiğiniz için teşekkürler, düzeltildi :)
Katenkyo

2

Steve

package connectn.players;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import connectn.game.Game;

public class Steve extends Player {
    @Override
    public int makeMove() {
        Random r=ThreadLocalRandom.current();
        int attemptedMove = 0;
        int[][]board=getBoard();
        int ec=Game.EMPTY_CELL;
        for(int c=0;c<board.length;c++){
            int j=board[c].length-1;
            for(;j>=0;j--){
                if(board[c][j]!=ec)break;
            }

            if(j>2+r.nextInt(3)&&r.nextDouble()<0.8)return c;
        }
        int k=-2+board.length/2+r.nextInt(5);
        if(ensureValidMove(k))return k;
        for (int i = 0; i < getBoardSize()[0]; i++)
            if (ensureValidMove(i)) {
                attemptedMove = i;
                break;
            }

        return attemptedMove;
    }
}

2
Steve zor zamanlar geçiriyor, altını çiziyor BasicBlockBot.
J Atkin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.