เชื่อมต่อเวลา!


20

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

ไม่มีใครจำเกมผู้เล่น 2 คนเชื่อมต่อ 4 ได้หรือไม่? สำหรับผู้ที่ไม่ได้เป็นบอร์ดขนาด 6x7 ที่ยืนอยู่บนพื้นผิว เป้าหมายของการเชื่อมต่อ 4 คือเพื่อเชื่อมต่อ 4 กัน! การเชื่อมต่อจะถูกนับหากเป็นแนวนอนแนวทแยงหรือแนวตั้ง คุณวางชิ้นส่วนของคุณบนกระดานโดยการแทรกชิ้นส่วนที่ด้านบนของคอลัมน์ที่มันอยู่ด้านล่างของคอลัมน์นั้น กฎของเราเปลี่ยน 3 สิ่งในการเชื่อมต่อ 4

  • เปลี่ยนอันดับที่ 1 การชนะหมายถึงผู้เล่นที่มีคะแนนมากที่สุด คุณจะได้รับคะแนนจากการเชื่อมต่อ 4 เหมือนในกฎ - เพิ่มเติมในภายหลัง
  • เปลี่ยน # 2คุณมีผู้เล่น 3 คนในแต่ละรอบ
  • เปลี่ยน # 3ขนาดบอร์ดคือ 9x9

เกณฑ์การให้คะแนน:

คะแนนขึ้นอยู่กับจำนวนที่คุณได้รับในแถว หากคุณมี 4 ในกลุ่มแถวคุณจะได้รับ 1 คะแนน หากคุณมี 5 ในกลุ่มแถวคุณจะได้รับ 2 คะแนน, 6 ในแถวที่ 3 และอื่น ๆ

ตัวอย่าง:

หมายเหตุoและxจะถูกแทนที่ด้วย#และ~ตามลำดับเพื่อความคมชัดที่ดีขึ้น

ตัวอย่างกระดานเปล่า: (ตัวอย่างทั้งหมดเป็นกระดานขนาดมาตรฐานผู้เล่น 2 คน)

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

ถ้าเราวางชิ้นใน Coll จะที่ดินในสถานที่d1d

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

ถ้าตอนนี้เราวางชิ้นใน Coll อีกครั้งก็จะได้ที่ดินในสถานที่d 2dนี่คือตัวอย่างของ 4 ในตำแหน่งแถว:

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

ในกรณีนี้xรับ 1 จุดแนวทแยงมุม ( 1a 2b 3c 4d)

  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ได้รับ 3 คะแนนสำหรับ 6 ในแถว ( 1c 2c 3c 4c 5c 6c)

อินพุต / เอาต์พุต

คุณจะสามารถเข้าถึงบอร์ดผ่านอาร์เรย์ 2d แต่ละสถานที่จะถูกแสดงด้วยintรหัสผู้เล่นที่เป็นตัวแทน คุณจะต้องส่งรหัสผู้เล่นของคุณไปยังฟังก์ชั่นของคุณ คุณทำการย้ายโดยการคืน coll ที่คุณต้องการปล่อยชิ้นส่วนของคุณ ผู้เล่น 3 คนในแต่ละรอบจะได้รับเลือกให้เล่น ในตอนท้ายของเกมผู้เล่นทุกคนจะได้เล่นเกมเป็นจำนวนเท่ากัน

สำหรับช่วงเวลา 100k รอบที่จะทำงาน (โปรดทราบว่าใช้เวลานานคุณอาจต้องการลดความเร็วในการทดสอบการหมุนรอบอย่างรวดเร็ว) โดยรวมผู้ชนะคือผู้เล่นที่ชนะมากที่สุด

ควบคุมสามารถพบได้ที่นี่: https://github.com/JJ-Atkinson/Connect-n/tree/master

เขียนบอท:

ในการเขียนบอทคุณต้องขยายPlayerชั้นเรียน เป็นนามธรรมและมีวิธีการหนึ่งในการดำเนินการPlayer int makeMove(void)ในตัวmakeMoveคุณคุณจะต้องตัดสินใจว่าคอลไหนที่คุณอยากจะปล่อยให้เป็นชิ้น ๆ หากคุณเลือก Coll ไม่ถูกต้อง (เช่น Coll ไม่ได้อยู่ Coll เต็มไปแล้ว), การเปิดของคุณจะถูกข้ามไป ในPlayerชั้นเรียนคุณมีวิธีการช่วยเหลือที่มีประโยชน์มากมาย รายชื่อของคนที่สำคัญที่สุดดังนี้:

  • boolean ensureValidMove(int coll): กลับจริงถ้า coll อยู่บนกระดานและ coll ยังไม่เต็ม
  • int[] getBoardSize(): ส่งคืนอาร์เรย์ int โดยที่[0]จำนวนคอลัมน์[1]คือและจำนวนแถว
  • int[][] getBoard(): คืนสำเนาของคณะกรรมการ [coll number][row number from bottom]คุณควรจะเข้าถึงได้เช่นนี้
  • ในการค้นหาส่วนที่เหลือให้ดูที่Playerชั้นเรียน
  • EMPTY_CELL: ค่าของเซลล์ว่าง

ตั้งแต่นี้จะเป็นแบบมัลติเธรดฉันได้รวมrandomฟังก์ชั่นถ้าคุณต้องการ

การดีบัก ธ ปทของคุณ:

ฉันรวมบางอย่างไว้ในคอนโทรลเลอร์เพื่อให้ง่ายต่อการดีบักบอท Runner#SHOW_STATISTICSคนแรกคือ หากเปิดใช้งานสิ่งนี้คุณจะเห็นผลงานพิมพ์ของกลุ่มผู้เล่นที่เล่นรวมถึงจำนวน bot ที่ชนะ ตัวอย่าง:

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

ทำเสร็จแล้วให้ตรวจสอบPlayerชั้นเรียนเพื่อดูวิธีการทั้งหมดที่มี
J Atkin

7
"a square 6x7" นั่นไม่ใช่รูปสี่เหลี่ยม
ev3commander

1
ให้ผู้เล่นมีความสามารถในการ "ส่ง" โดยการย้ายที่ผิดกฎหมายเปลี่ยนแปลงพลวัตเล็กน้อย เกมนี้จบลงหรือไม่ถ้าทุกคนผ่านไป
ฮิสโทแคต

1
ใช่นั่นเป็นเหตุผลว่าทำไมจึงมีความสำคัญมากที่จะใช้ensureValidMove(ยกเว้นว่ากลยุทธ์ของคุณคือผ่านการเปลี่ยนของหลักสูตรนี้)
J Atkin

คำตอบ:


11

MaxGayne

บอทนี้กำหนดคะแนนให้กับแต่ละตำแหน่งโดยยึดตามความยาวของชิ้นส่วนที่เชื่อมต่อ ดูเหมือนว่ามีการเคลื่อนไหว 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 คนแทนที่จะเป็นแบบ 1 หลักเช่นเกมหลัก เพียงแค่แบ่งบอทของฉัน มีอีก 2 ปัญหา javafx.util.Pairไม่ทำงานใน Eclipse เพราะไม่ถือว่าเป็นส่วนหนึ่งของ API สาธารณะ และฉันไม่รู้ว่าจะไปหาsun.plugin.dom.exception.InvalidStateExceptionที่ไหน java.lang.IllegalStateExceptionคุณอาจหมายถึง
Sleafar

ดูเหมือนว่าจะแปลกนิดหน่อย ... อย่างไรก็ตามPairมันก็ใกล้เคียงกับประเภทข้อมูลที่ฉันต้องการโดยไม่ต้องหมุนเองดังนั้นถ้าคราสไม่ได้รวบรวมฉันคิดว่ามันโอเค สำหรับ # 3 คุณพูดถูกการเติมข้อความอัตโนมัติของฉันใน IntelliJ ไม่ถูกต้องเสมอไป (ส่วนใหญ่มันเป็นเหตุผลที่ฉันไม่ได้ตรวจสอบ)
J Atkin

@JAtkin จริงแล้วPairปัญหาจริงๆป้องกันการรวบรวมในคราสจนกว่าคุณจะรู้วิธีแก้ปัญหา
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

StraightForwardBot

คล้ายกับ 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

JealousBot

บอทตัวนี้เกลียดผู้เล่นคนอื่น และเขาไม่ชอบที่จะวางหมากลงบนกระดาน ดังนั้นเขาจึงพยายามที่จะเป็นคนสุดท้ายที่ทิ้งชิ้นส่วนไว้ในคอลัมน์

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....เช็คอิน game.Game.genBoard () ใน gitub ของ OP หากคุณต้องการ ฉันไม่รู้เหมือนกันว่าคุณrandom()จะทำในสิ่งที่คุณต้องการหรืออาจจะใช้(int)Math.random()*col?
Katenkyo

@Katenkyo ขอบคุณมากฉันดีใจถ้ามันทำให้คุณหัวเราะ! random()วิธีการอยู่ในPlayerระดับ! ดังนั้นฉันคิดว่ามันจะทำงาน =) แต่ใช่ฉันไม่มั่นใจในเงื่อนไขของฉัน ฉันไม่พบวิธีการกำหนดไว้ในรหัสของ OP แต่ฉันจะตรวจสอบอีกครั้ง ขอบคุณมาก!
Keker

ชั้นผู้เล่นกำหนดแบบสุ่ม () public double random() {return ThreadLocalRandom.current().nextDouble();}ในฐานะ ผมไม่ทราบแน่ชัดว่ามันทำงานได้ แต่ผมถือว่ามันกลับค่าระหว่าง 0 และ 1 นั้นจะอาจจำเป็นต้องทำ(int)random()*col:)
Katenkyo

@ Katenkyo โอ้ฉันคิดว่ามันทำอย่างนั้นแล้ว ... ไม่ดีของฉัน ฉันจะแก้ไขเมื่อพบมูลค่าที่เหมาะสมสำหรับเซลล์ว่างในกระดานขอบคุณอีกครั้ง!
Keker

@Katenkyo คุณถูกต้องnextDoubleส่งกลับตัวเลขระหว่างและ0 1ฉันรวมไว้เนื่องจากการจำลองนั้นทำงานแบบขนานและMath.random()ไม่ปลอดภัยสำหรับเธรด
J Atkin

3

BasicBlockBot

บอทบล็อก (และไร้เดียงสา) ที่เรียบง่าย เขาไม่รู้ว่าคุณสามารถสร้าง 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

3
@JAtkin ฉันปฏิเสธการแก้ไขของคุณ คุณควรอนุญาตให้พวกเขาแก้ไขรหัสในโพสต์ของพวกเขา หากคุณต้องการแก้ไขสำหรับคอนโทรลเลอร์ของคุณมันก็ดี (ฉันยังคงทิ้งโน้ตไว้เป็นการส่วนตัว) แต่การแก้ไขโค้ดของใครบางคนใน SE ไม่ได้รับอนุญาต
Nathan Merrill



2

PackingBot

บอทนี้ไม่ได้เล็งไปที่คะแนนโดยตรง เขาพยายามที่จะบรรจุโทเค็นสูงสุดจนกว่าบอร์ดจะเต็ม เขาเข้าใจว่าการขึ้นอีกครั้งและอีกครั้งนั้นโง่ดังนั้นเขาจะสุ่มใส่โทเค็นรอบ ๆ "โดเมน" ของเขา

เขาควรจะได้รับคะแนนในทุกทิศทาง แต่จะไม่ดีที่สุด!

(ไม่ผ่านการทดสอบ)

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

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.