कनेक्ट-एन समय!


20

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

किसी को भी 2 खिलाड़ी खेल 4 कनेक्ट याद है? जो लोग ऐसा नहीं करते उनके लिए एक 6x7 बोर्ड था जो एक सतह पर लंबवत था। कनेक्ट 4 का लक्ष्य है, अच्छी तरह से कनेक्ट 4! कनेक्शन को गिना जाता है यदि यह क्षैतिज, विकर्ण या ऊर्ध्वाधर है। आप अपने टुकड़ों को एक स्तंभ के शीर्ष पर एक टुकड़ा डालकर बोर्ड पर रख देते हैं, जहाँ यह उस स्तंभ के नीचे आता है। हमारे नियम कनेक्ट 4 में 3 चीजें बदलते हैं।

  • परिवर्तन # 1 जीतना सबसे अधिक अंकों के साथ खिलाड़ी के रूप में परिभाषित किया गया है। आप नियमों की तरह 4 को जोड़कर अंक प्राप्त करते हैं - उस पर बाद में।
  • # 2 बदलें आप प्रत्येक दौर में 3 खिलाड़ी हैं।
  • # 3 बदलें बोर्ड का आकार 9x9 है।

स्कोरिंग:

स्कोर इस बात पर आधारित है कि आप कितने पंक्ति में हैं। यदि आपके पास पंक्ति समूह में 4 है तो आपको 1 अंक मिलता है। यदि आपके पास पंक्ति समूह में 5 है तो आपको 2 अंक मिलेंगे, एक पंक्ति 3 में 6 और इसी तरह।

उदाहरण:

नोट oऔर xबदल दिए जाते हैं #और ~बेहतर विपरीत के लिए क्रमश:

खाली बोर्ड का उदाहरण: (सभी उदाहरण 2 खिलाड़ी मानक आकार बोर्ड हैं)

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

यदि हम टकराव में एक टुकड़ा गिराते हैं d, तो यह स्थान में उतर जाएगा 1d

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

यदि हम अब एक टुकड़े को dफिर से टकराते हैं , तो वह स्थान पर आ जाएगा 2d। यहाँ पंक्ति पदों में 4 के उदाहरण दिए गए हैं:

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

इस मामले में x1 अंक तिरछे ( 1a 2b 3c 4d) मिलता है।

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

इस स्थिति में, o1 बिंदु लंबवत ( 1d 2d 3d 4d) मिलता है।

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

इस स्थिति में o2 अंक क्षैतिज रूप से ( 1c 1d 1e 1f 1g) प्राप्त होते हैं और x1 अंक क्षैतिज रूप से प्राप्त होते हैं ( 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 अंक मिलते हैं ।

इनपुट आउटपुट

आपके पास 2d सरणी के माध्यम से बोर्ड तक पहुंच होगी। प्रत्येक स्थान का intप्रतिनिधित्व एक खिलाड़ी आईडी के साथ किया जाएगा । आप अपने खिलाड़ी आईडी को भी अपने कार्य के लिए पारित कर देंगे। आप अपने कदम को वापसी करके बनाते हैं, जिससे आप अपने टुकड़े को गिराना चाहते हैं। प्रत्येक राउंड 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): यदि बोर्ड पर टक्कर लगी है और लौटाया नहीं गया है, तो सच लौटें ।
  • int[] getBoardSize(): [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अपनी पसंद के अनुसार सेट करें।

बाद में जोड़ा गया:

  • बॉट्स के बीच संचार बाधित है।

संबंधित: Play कनेक्ट 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

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


क्या आप यह निर्धारित करने के लिए कार्यक्षमता जोड़ सकते हैं कि खेल किस मोड़ पर है?
कॉनर ओ'ब्रायन

पहले से ही किया हुआ, Playerउपलब्ध सभी विधियों को देखने के लिए कक्षा की जाँच करें ।
J Atkin

7
"एक वर्ग 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 में एक बग है। यह मुख्य गेम की तरह 1-आधारित के बजाय 0-आधारित प्लेयर आईडी का उपयोग कर रहा है। यह बस मेरे बॉट को तोड़ता है। 2 और समस्याएं हैं। javafx.util.Pairएक्लिप्स में काम नहीं करता है क्योंकि इसे सार्वजनिक एपीआई का हिस्सा नहीं माना जाता है। और मुझे पता नहीं है कि कहां देखना है sun.plugin.dom.exception.InvalidStateException। आपका शायद मतलब था java.lang.IllegalStateException
स्लिफ़र

यह थोड़ा अजीब लगता है ... वैसे भी Pair, मैं अपने खुद के रोल के बिना जिस प्रकार के डेटा को प्राप्त करना चाहता हूं, उसके करीब है, इसलिए जब तक ग्रहण संकलित नहीं होगा, मुझे लगता है कि यह ठीक है। # 3 के लिए, आप सही हैं, IntelliJ में मेरा स्वत: पूर्ण हमेशा सही नहीं है। (अधिकांश समय यह है, इसीलिए मैंने जांच नहीं की)
J Atkin

@Jtkin वास्तव में, Pairसमस्या वास्तव में ग्रहण में संकलित करने से रोकती है, जब तक कि आप वर्कअराउंड को नहीं जानते ।
स्लिफ़र

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

यह कोडगॉल्फ पर मेरा पहला समय है, इसलिए मुझे उम्मीद है कि यह उत्तर काफी अच्छा होगा। मैं अभी तक इसका परीक्षण नहीं कर सका, इसलिए यदि कोई गलती हो तो कृपया मुझे क्षमा करें।

संपादित करें : दूसरे को तोड़ने के लिए एक पंक्ति जोड़ी गई for

EDIT 2 : पता लगाया गया कि whileअनंत क्यों थे । यह अब पूरा हो गया है और इसका उपयोग किया जा सकता है!


PPCG में आपका स्वागत है, आपने मुझे इस जवाब के साथ हँसाया, यह बहुत अच्छा है! बस अपनी शर्तों का ध्यान रखें। मुझे लगता है कि बोर्ड डिफ़ॉल्ट रूप से -1 मानों से भरा है, इसलिए if(board[col][row]!=null && board[col][row]!=id)इसे बदल दिया जाना चाहिए if(board[col][row]!=-1....। यदि आप सुनिश्चित होना चाहते हैं, तो ओपी के गिथब में game.Game.genBoard () में चेक करें। मैं या तो नहीं जानता random()कि क्या आप चाहते हैं कि क्या करेंगे, शायद उपयोग करें (int)Math.random()*col?
काटेन्को

@Katenkyo बहुत बहुत धन्यवाद, मुझे खुशी है अगर यह आपको हंसाया है! random()विधि में है Playerवर्ग! इसलिए मुझे लगता है कि यह काम करेगा =) लेकिन हाँ, मुझे अपनी शर्तों पर भरोसा नहीं था। मुझे नहीं पता कि यह ओपी के कोड में कैसे परिभाषित किया गया है, लेकिन मैं फिर से जांच करूंगा। आपका बहुत बहुत धन्यवाद!
केकर

प्लेयर वर्ग यादृच्छिक () को परिभाषित करता है public double random() {return ThreadLocalRandom.current().nextDouble();}। मुझे ठीक से पता नहीं है कि यह कैसे काम करता है, लेकिन मुझे लगता है कि यह 0 और 1 के बीच एक मूल्य देता है, इसलिए इसे करने की आवश्यकता होगी (int)random()*col:)
Katenkyo

@Katenkyo ओह, मैंने सोचा कि यह पहले से ही किया है ... मेरा बुरा। जब मैंने बोर्ड में एक खाली सेल के लिए सही मान पाया है, तो मैं इसे संपादित करूँगा, फिर से धन्यवाद!
केकर

@Katenkyo आप सही हैं, और के nextDoubleबीच एक नंबर देता है । मैंने इसे शामिल किया क्योंकि सिमुलेशन समानांतर में चलाए जाते हैं, और थ्रेड सुरक्षित नहीं है। 01Math.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 क्षमा करें, मेरे पास कोड का एक पुराना संस्करण था।
कॉनर ओ'ब्रायन

3
@JAtkin मैंने आपका संपादन अस्वीकार कर दिया। आपको उन्हें अपने पोस्ट में अपना कोड ठीक करने की अनुमति देनी चाहिए। यदि आप इसे अपने नियंत्रक के लिए ठीक करना चाहते हैं, तो यह ठीक है (मैं व्यक्तिगत रूप से अभी भी एक नोट छोड़ दूंगा), लेकिन एसई पर किसी के कोड के एकमुश्त संशोधन की अनुमति नहीं है।
नाथन मेरिल


2

BuggyBot

हरा करने के लिए एक नमूना बॉट (FYI करें: यह कठिन नहीं है;)

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

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


}

@Jtkin ने इशारा करते हुए धन्यवाद दिया कि, तय :) :)
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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.