连接n时间!


20

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

有人记得2人游戏连接4个吗?对于那些不喜欢的人来说,那是一块6x7的板,它垂直于表面。连接4的目标是连接4!如果连接是水平的,对角的或垂直的,则将其计算在内。您可以通过以下方式将棋子放置在板上:在棋子的顶部插入棋子,使其落在该棋子的底部。我们的规则更改了连接4中的3件事。

  • 变更#1获胜定义为得分最高的玩家。您可以通过像规则中那样连接4来获得积分-稍后再介绍。
  • 变更#2您每轮有3个玩家。
  • 变更#3电路板尺寸为9x9。

得分:

分数基于您连续获得的分数。如果您有一个连续的4组,您将获得1分。如果您在连续5组中获得5分,则在3行中获得6分,依此类推。

例子:

注意ox分别用#和代替~,以获得更好的对比

空棋盘示例:(所有示例均为2人标准尺寸棋盘)

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

如果我们在coll中放一块d,它会降落在适当的位置1d

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

如果现在d再次在coll中放入一块,它将落在location上2d。以下是连续4个位置的示例:

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

在这种情况下x,对角线(1a 2b 3c 4d)得到1点。

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

在这种情况下,o垂直获得1点(1d 2d 3d 4d)。

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

在这种情况下o,水平获得2点(1c 1d 1e 1f 1g),x水平获得1点(2c 2d 2e 2f)。

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

这次x获得了6分(1c 2c 3c 4c 5c 6c)的3分。

输入输出

您将可以通过二维阵列访问电路板。每个位置将以int代表玩家ID 的形式表示。您还将把您的玩家ID传递给函数。您可以通过返回要放入的列来采取行动。每回合将选出3名选手参加比赛。在游戏结束时,所有玩家都将玩均匀数量的游戏。

目前将进行10万发回合(请注意,这需要花费长时间,您可能希望减少它以进行快速周转测试)。总体而言,获胜者是获胜最多的玩家。

控制器可以在这里找到:https : //github.com/JJ-Atkinson/Connect-n/tree/master

编写机器人:

要编写机器人,您必须扩展Player该类。Player是抽象的,有一种实现方法int makeMove(void)。在其中,makeMove您将决定要放入哪个列。如果您选择了无效的列队(例如,列队不存在,列队已经被填满),您的回合将被跳过。在Player课堂上,您有许多有用的辅助方法。最重要的清单如下:

  • boolean ensureValidMove(int coll)如果 coll在板上并且尚未填充coll,则返回true 。
  • int[] getBoardSize():返回一个int数组,其中[0]是列[1]数和行数。
  • int[][] getBoard():退还电路板的副本。您应该这样访问它:[coll number][row number from bottom]
  • 要找到其余的内容,请看Player课。
  • EMPTY_CELL:空单元格的值

由于这将是多线程的,因此random如果需要,我还提供了一个函数。

调试您的机器人:

我在控制器中包含了一些东西,以使其更易于调试机器人。第一个是Runner#SHOW_STATISTICS。如果启用此功能,您将看到已打出的玩家组的打印输出,包括机器人获胜的次数。例:

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

您也可以与该connectn.game.CustomGame班级一起制作自定义游戏,您可以查看每个回合的得分和获胜者。您甚至可以使用添加自己UserBot

添加您的机器人:

要将您的机器人添加到阵容中,请转到PlayerFactory静态块并添加以下行:

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

其他注意事项:

  • 模拟是多线程的。如果您要关闭此功能,请转到Runner#runGames()并注释此行(.parallel())。
  • 要更改游戏数量,请Runner#MINIMUM_NUMBER_OF_GAMES根据自己的喜好进行设置。

稍后添加:

  • 禁止漫游器之间进行通信。

相关:玩Connect 4!

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

计分板:(100 000场比赛)

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

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


您可以添加功能来确定游戏打开了吗?
Conor O'Brien 2015年

已经完成,请检查Player该类以查看所有可用方法。
J Atkin

7
“不是正方形的6x7正方形”
ev3commander

1
通过采取非法动作来赋予球员“传球”的能力会稍微改变动力。如果每个人都通过游戏是否结束?
histocrat

1
是的,这就是为什么使用非常重要的原因ensureValidMove(除非您的策略是通过这一回合)。
J Atkin 2015年

Answers:


11

马克斯·盖恩

该机器人主要根据连接零件的长度为每个位置分配分数。看起来3个动作深入检查了每个阶段的3个最佳动作,并选择了预期得分最高的动作。

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

非常非常棒!+1
J Atkin

我在玩游戏时注意到的一件事情是UserBot,您的机器人在某个点之后MaxGayne会丢掉转弯(例如,经过15步移动后,它会每转一跳直到游戏结束)。
J Atkin

原因可能是CustomGame中的错误。它使用的是基于0的玩家ID,而不是像主要游戏那样基于1的玩家ID。这简直破坏了我的机器人。还有2个问题。javafx.util.Pair在Eclipse中不起作用,因为它不被视为公共API的一部分。而且我不知道在哪里寻找sun.plugin.dom.exception.InvalidStateException。你可能是说java.lang.IllegalStateException
Sleafar

这似乎有点奇怪……无论如何Pair,那与我想要的数据类型非常接近,而无需滚动自己的数据类型,因此,除非eclipse无法编译,否则我认为这是可以的。至于#3,您是对的,我在IntelliJ中的自动完成并不总是正确的。(大多数情况下,这就是为什么我没有检查的原因)
J Atkin

@JAtkin实际上,Pair除非您知道解决方法,否则问题实际上会阻止在Eclipse中进行编译。
Sleafar

6

RowBot

全方位查看并确定最佳列。尝试连接他的棋子,同时不要让他的对手做同样的事情。

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

该机器人只有一个玩法-将其片段放置在有效的最左侧单元格中。奇怪的是,它做的还不错;)

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

只要在有效的地方放一块。

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

直进

与OnePlayBot相似,但考虑到了最后一步,并在此有效的下一列播放。

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

嫉妒的宝

该机器人讨厌其他玩家。而且他不喜欢他把棋子丢在板上。因此,他努力成为最后一位在专栏中丢下一块的人。

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

这是我第一次使用CodeGolf,所以希望这个答案足够好。我还无法测试,所以如果有任何错误,请原谅。

编辑:添加一行以打破第二个for

编辑2:弄清楚了为什么while无限大的原因。现在已完成,可以使用!


欢迎使用PPCG,您的回答让我笑了,太好了!请注意您的情况。我认为默认情况下该板填充有-1值,因此if(board[col][row]!=null && board[col][row]!=id)应更改为if(board[col][row]!=-1....。如果您想确定的话,请在OP的github中签入game.Game.genBoard()。我也不知道您random()是否愿意做您想做的事,也许可以使用(int)Math.random()*col
Katenkyo,2015年

@Katenkyo非常感谢,如果让你笑了,我感到很高兴!该random()方法在Player课堂上!所以我认为这会起作用=)但是,是的,我对自己的状况不自信。我没有在OP的代码中找到它的定义方式,但我将再次检查。非常感谢你!
Keker

Player类将random()定义为public double random() {return ThreadLocalRandom.current().nextDouble();}。我不知道它是如何工作的,但我认为它返回的值介于0到1之间,所以可能需要这样做(int)random()*col:)
Katenkyo 2015年

@Katenkyo哦,我以为已经做到了……我的坏。当我在板上找到一个空单元格的正确值时,我将对其进行编辑,再次感谢您!
Keker

@Katenkyo您是正确的,nextDouble返回0和之间的数字1。我将其包括在内是因为模拟是并行运行的,并且Math.random()不是线程安全的。
J Atkin 2015年

3

基本块启动

一个简单(且天真)的块机器人。他不知道您可以水平对角连续制作4个!

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

进步

进步是……进步。他喜欢看一切,还有一些!(我不确定这种方法是否正确。它曾经一次与一个朋友对抗。)而且由于某种原因,它表现得很不错。

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抱歉,我有一个旧版本的代码。
Conor O'Brien 2015年

3
@JAtkin我拒绝了您的编辑。您应该允许他们在其帖子中修复其代码。如果您想为您的控制器修复它,那很好(我个人仍然会留意),但是不允许在SE上直接修改某人的代码。
弥敦道·美林


2

越野车

一个供您击败的示例机器人(仅供参考:这并不难;)

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

2

包装桶

该机器人并非直接针对积分。他尝试打包最多的令牌,直到棋盘被填满为止。他知道,一次又一次地爬上去是愚蠢的,所以他将随机地在其“域”周围放置令牌。

他应该能够在各个方向上获得一些要点,但不会是最好的!

(未测试)

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感谢您指出问题,已解决:)
Katenkyo 2015年

2

史蒂夫

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
史蒂夫过得很辛苦,他的成绩不及格BasicBlockBot
J Atkin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.