Thời gian kết nối!


20

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

Có ai nhớ game 2 người kết nối 4 không? Đối với những người không sử dụng nó là một bảng 6x7 đứng thẳng đứng trên một bề mặt. Mục tiêu của kết nối 4 là, kết nối tốt 4! Kết nối được tính nếu nó là ngang, chéo hoặc dọc. Bạn đặt các mảnh của bạn lên bảng bằng cách chèn một mảnh ở đầu cột nơi nó rơi xuống dưới cùng của cột đó. Quy tắc của chúng tôi thay đổi 3 điều trong kết nối 4.

  • Thay đổi số 1 Chiến thắng được xác định là người chơi có nhiều điểm nhất. Bạn nhận được điểm bằng cách kết nối 4 như trong quy tắc - nhiều hơn về điều đó sau.
  • Thay đổi # 2 Bạn có 3 người chơi mỗi vòng.
  • Thay đổi # 3 Kích thước bảng là 9x9.

Ghi điểm:

Điểm số dựa trên số lượng bạn nhận được liên tiếp. Nếu bạn có một nhóm 4 trong một hàng, bạn nhận được 1 điểm. Nếu bạn có một nhóm 5 trong một hàng, bạn nhận được 2 điểm, 6 trong một hàng 3 và cứ thế.

Ví dụ:

Lưu ý oxđược thay thế bằng #~tương ứng, để tương phản tốt hơn

Ví dụ về bảng trống: (tất cả các ví dụ là bảng kích thước tiêu chuẩn 2 người chơi)

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

Nếu chúng ta thả một mảnh trong coll d, nó sẽ hạ cánh tại vị trí 1d.

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

Nếu bây giờ chúng ta thả một mảnh trong coll dmột lần nữa, nó sẽ hạ cánh tại vị trí 2d. Dưới đây là ví dụ về 4 vị trí liên tiếp:

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

Trong trường hợp này xđược 1 điểm theo đường chéo ( 1a 2b 3c 4d).

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

Trong trường hợp này, ođược 1 điểm theo chiều dọc ( 1d 2d 3d 4d).

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

Trong trường hợp này ođược 2 điểm theo chiều ngang ( 1c 1d 1e 1f 1g) và xđược 1 điểm theo chiều ngang ( 2c 2d 2e 2f).

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

Lần này xđược 3 điểm cho 6 liên tiếp ( 1c 2c 3c 4c 5c 6c).

Đầu ra đầu vào

Bạn sẽ có quyền truy cập vào bảng thông qua một mảng 2d. Mỗi vị trí sẽ được đại diện với một intđại diện cho một id người chơi. Bạn cũng sẽ có id trình phát của bạn được chuyển đến chức năng của bạn. Bạn thực hiện di chuyển của bạn bằng cách trả lại coll mà bạn muốn thả mảnh của bạn vào. Mỗi người chơi vòng 3 sẽ được chọn để chơi. Vào cuối của trò chơi, tất cả người chơi sẽ chơi một số lượng trò chơi chẵn.

Đối với thời điểm 100k vòng sẽ được chạy (lưu ý điều này mất nhiều thời gian, bạn có thể muốn giảm nó để thử nghiệm quay vòng nhanh). Nhìn chung, người chiến thắng là người chơi có nhiều chiến thắng nhất.

Bộ điều khiển có thể được tìm thấy ở đây: https://github.com/JJ-Atkinson/Connect-n/tree/master .

Viết bot:

Để viết bot bạn phải mở rộng Playerlớp. Playerlà trừu tượng và có một phương pháp để thực hiện , int makeMove(void). Trong makeMovebạn sẽ quyết định coll nào bạn muốn thả tác phẩm của mình vào. Nếu bạn chọn một coll không hợp lệ (ví dụ coll không tồn tại, coll đã được điền), lượt của bạn sẽ bị bỏ qua . Trong Playerlớp bạn có nhiều phương thức trợ giúp hữu ích. Một danh sách những cái quan trọng nhất sau đây:

  • boolean ensureValidMove(int coll): Trả về true nếu coll nằm trên bảng coll chưa được điền.
  • int[] getBoardSize(): Trả về một mảng int trong đó [0]là số cột và [1]là số hàng.
  • int[][] getBoard(): Trả lại một bản sao của bảng. Bạn nên truy cập nó như thế này : [coll number][row number from bottom].
  • Để tìm phần còn lại, nhìn vào Playerlớp.
  • EMPTY_CELL: Giá trị của một ô trống

Vì đây sẽ là đa luồng, tôi cũng đã bao gồm một randomhàm nếu bạn cần nó.

Gỡ lỗi bot của bạn:

Tôi đã bao gồm một số thứ trong bộ điều khiển để đơn giản hơn để gỡ lỗi bot. Đầu tiên là Runner#SHOW_STATISTICS. Nếu điều này được kích hoạt, bạn sẽ thấy một bản in của các nhóm người chơi đã chơi, bao gồm cả số lần thắng bot. Thí dụ:

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

Bạn cũng có thể tạo một trò chơi tùy chỉnh với connectn.game.CustomGamelớp, bạn có thể xem điểm số và người chiến thắng của mỗi vòng. Bạn thậm chí có thể thêm mình vào hỗn hợp với UserBot.

Thêm bot của bạn:

Để thêm bot của bạn vào đội hình, hãy chuyển đến PlayerFactorykhối tĩnh và thêm dòng sau:

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

Những điều khác cần lưu ý:

  • Các mô phỏng là đa luồng. Nếu bạn muốn tắt nó đi, hãy đến Runner#runGames()và bình luận dòng này ( .parallel()).
  • Để thay đổi số lượng trò chơi, hãy đặt Runner#MINIMUM_NUMBER_OF_GAMEStheo ý thích của bạn.

Đã thêm sau:

  • Giao tiếp giữa các bot không được phép.

Liên quan: Chơi Kết nối 4!

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

Bảng điểm: (100 000 trò chơi)

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

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


Bạn có thể thêm chức năng để xác định bật trò chơi nào không?
Conor O'Brien

Đã xong, kiểm tra Playerlớp để xem tất cả các phương thức có sẵn.
J Atkin

7
"Hình vuông 6x7" không phải là hình vuông
ev3commander

1
Cung cấp cho người chơi khả năng "vượt qua" bằng cách di chuyển bất hợp pháp làm thay đổi động lực một chút. Trò chơi có kết thúc nếu mọi người vượt qua?
lịch sử

1
Vâng, đó là lý do tại sao rất quan trọng để sử dụng ensureValidMove(trừ khi chiến lược của bạn là vượt qua lượt này tất nhiên).
J Atkin

Câu trả lời:


11

MaxGayne

Bot này chỉ định một số điểm cho từng vị trí, chủ yếu dựa trên chiều dài của các phần được kết nối. Có vẻ như 3 bước di chuyển sâu kiểm tra 3 bước di chuyển tốt nhất ở mỗi giai đoạn và chọn một bước có số điểm dự kiến ​​tối đa.

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

Rất rất tốt! +1
J Atkin

Một cái gì đó tôi nhận thấy khi tôi đang chơi xung quanh UserBotvà bot của bạn là sau một thời điểm MaxGaynesẽ ném đi lượt (ví dụ: sau 15 lần di chuyển, nó bỏ qua mỗi lượt cho đến khi trò chơi kết thúc).
J Atkin

Nguyên nhân cho điều này có lẽ là một lỗi trong CustomGame. Đó là sử dụng ID người chơi dựa trên 0 thay vì dựa trên 1 như trò chơi chính. Điều này chỉ đơn giản là phá vỡ bot của tôi. Có 2 vấn đề nữa. javafx.util.Pairkhông hoạt động trong Eclipse vì nó không được coi là một phần của API công khai. Và tôi không biết phải tìm ở đâu sun.plugin.dom.exception.InvalidStateException. Bạn có thể có nghĩa java.lang.IllegalStateException.
Sleafar

Điều đó có vẻ hơi kỳ lạ ... Dù sao đi nữa Pair, nó gần đến mức tôi có thể có được kiểu dữ liệu tôi muốn mà không cần tự quay, vì vậy trừ khi nhật thực không được biên dịch, tôi nghĩ nó ổn. Đối với số 3, bạn đã đúng, tự động hoàn thành của tôi trong IntelliJ không phải lúc nào cũng đúng. (hầu hết thời gian, đó là lý do tại sao tôi không kiểm tra)
J Atkin

@JAtkin Trên thực tế, Pairvấn đề thực sự ngăn cản việc biên dịch trong Eclipse, trừ khi bạn biết cách giải quyết .
Sleafar

6

RowBot

Nhìn theo mọi hướng và xác định cột tối ưu. Cố gắng để kết nối các mảnh của mình, trong khi không để cho đối thủ của mình làm điều tương tự.

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

Bot này chỉ có một lần chơi - đặt phần của nó vào ô ngoài cùng bên trái là hợp lệ. Thật kỳ lạ, nó làm khá tốt;)

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

Chỉ cần đặt một mảnh bất cứ nơi nào là hợp lệ.

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

Tương tự như OnePlayBot nhưng có tính đến nước đi cuối cùng và đóng cột tiếp theo là hợp lệ.

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

Ghen tị

Bot này ghét người chơi khác. Và anh ấy không thích điều đó, anh ấy làm rơi từng mảnh trên bảng. Vì vậy, anh cố gắng là người cuối cùng đã thả một mảnh trong một cột.

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

Đây là lần đầu tiên của tôi trên CodeGolf, vì vậy tôi hy vọng câu trả lời này sẽ đủ tốt. Tôi chưa thể kiểm tra nó, vì vậy xin vui lòng cho tôi biết nếu có bất kỳ sai lầm.

EDIT : Đã thêm một dòng để phá vỡ thứ hai for.

EDIT 2 : Tìm hiểu tại sao whilelà vô hạn. Bây giờ nó đã hoàn thành và có thể được sử dụng!


Chào mừng bạn đến với PPCG, bạn đã khiến tôi bật cười với câu trả lời này, thật tuyệt! Chỉ cần quan tâm với điều kiện của bạn. Tôi nghĩ rằng bảng được điền với -1 giá trị theo mặc định, vì vậy if(board[col][row]!=null && board[col][row]!=id)nên được thay đổi thành if(board[col][row]!=-1..... Kiểm tra trong trò chơi.Game.genBoard () trong github của OP nếu bạn muốn chắc chắn. Tôi không biết nếu bạn random()sẽ làm những gì bạn muốn, có thể sử dụng (int)Math.random()*col?
Katenkyo

@Katenkyo Cảm ơn bạn rất nhiều, tôi rất vui nếu điều đó làm bạn cười! Các random()phương pháp là trong Playerlớp học! Vì vậy, tôi nghĩ rằng nó sẽ hoạt động =) Nhưng vâng, tôi đã không tự tin vào điều kiện của mình. Tôi không tìm thấy nó được định nghĩa như thế nào trong mã của OP, nhưng tôi sẽ kiểm tra lại. Cảm ơn nhiều!
Keker

Lớp Player định nghĩa ngẫu nhiên () là public double random() {return ThreadLocalRandom.current().nextDouble();}. Tôi không biết chính xác nó hoạt động như thế nào, nhưng tôi cho rằng nó trả về giá trị từ 0 đến 1, vì vậy có thể cần phải làm (int)random()*col:)
Katenkyo

@Katenkyo Ồ, tôi nghĩ nó đã làm điều đó rồi ... Thật tệ. Tôi sẽ chỉnh sửa nó khi tôi tìm thấy giá trị phù hợp cho một ô trống trong bảng, cảm ơn bạn một lần nữa!
Keker

@Katenkyo Bạn đúng, nextDoubletrả về một số giữa 01. Tôi bao gồm nó bởi vì các mô phỏng được chạy song song và Math.random()không phải là luồng an toàn.
J Atkin

3

BasicBlockBot

Một bot khối đơn giản (và ngây thơ). Anh ta không biết bạn có thể thực hiện 4 liên tiếp theo chiều ngang hoặc đường chéo!

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

Cấp tiến

Tiến bộ là ... tiến bộ. Anh ấy thích nhìn vào mọi thứ , và một số! (Tôi không chắc chắn về phương pháp của việc này. Nó đã làm việc chống lại một người bạn, một lần.) Và, vì một số lý do, nó hoạt động tốt.

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 Xin lỗi, tôi đã có một phiên bản mã cũ hơn.
Conor O'Brien

3
@JAtkin Tôi đã từ chối chỉnh sửa của bạn. Bạn nên cho phép họ sửa mã của họ trong bài viết của họ. Nếu bạn muốn sửa nó cho bộ điều khiển của mình, điều đó tốt (cá nhân tôi vẫn để lại một ghi chú), nhưng việc sửa đổi hoàn toàn mã của ai đó trên SE không được phép.
Nathan Merrill


2

BuggyBot

Một bot mẫu để bạn đánh bại (FYI: nó không khó;)

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

2

Bao bì

Bot này không nhắm đến điểm trực tiếp. Anh ta cố gắng đóng gói tối đa các mã thông báo cho đến khi bảng được lấp đầy. Anh ta hiểu rằng chỉ đơn giản là đi đi lại lại là ngu ngốc, vì vậy anh ta sẽ ngẫu nhiên đặt mã thông báo xung quanh "miền" của mình.

Anh ta có thể có được một số điểm theo mọi hướng, nhưng sẽ không phải là người giỏi nhất!

(Không được kiểm tra)

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 Cảm ơn bạn đã chỉ ra rằng, đã sửa :)
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 đang có một thời gian khó khăn, anh ấy ghi bàn BasicBlockBot.
J Atkin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.