Tempo di connessione!


20

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

Qualcuno ricorda il gioco a 2 giocatori connect 4? Per quelli che non lo facevano era una tavola 6x7 che stava in verticale su una superficie. L'obiettivo di connect 4 è quello di ben 4! La connessione viene conteggiata se è orizzontale, diagonale o verticale. Metti i tuoi pezzi sul tabellone inserendo un pezzo nella parte superiore di una colonna dove cade nella parte inferiore di quella colonna. Le nostre regole cambiano 3 cose in connect 4.

  • Modifica n. 1 La vincita è definita come il giocatore con il maggior numero di punti. Ottieni punti collegando 4 come nelle regole - ne parleremo più avanti.
  • Modifica n. 2 Hai 3 giocatori per round.
  • Modifica n. 3 La dimensione della scheda è 9x9.

punteggio:

Il punteggio si basa su quanti ne ottieni di fila. Se hai un gruppo di 4 in una riga ottieni 1 punto. Se hai un gruppo 5 in una riga ottieni 2 punti, 6 in una riga 3 e così via.

Esempi:

Nota oe xvengono sostituiti con #e ~rispettivamente, per un migliore contrasto

Esempio di tabellone vuoto: (tutti gli esempi sono tabelloni di dimensioni standard per 2 giocatori)

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

Se lasciamo cadere un pezzo nel coll d, atterrerà sul posto 1d.

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

Se ora lasciamo cadere di nuovo un pezzo nel coll d, questo atterrerà sul posto 2d. Ecco alcuni esempi di 4 posizioni di fila:

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

In questo caso xottiene 1 punto in diagonale ( 1a 2b 3c 4d).

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

In questo caso, oottiene 1 punto in verticale ( 1d 2d 3d 4d).

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

In questo caso oottiene 2 punti in orizzontale ( 1c 1d 1e 1f 1g) e xottiene 1 punto in orizzontale ( 2c 2d 2e 2f).

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

Questa volta xottiene 3 punti per un 6 di fila ( 1c 2c 3c 4c 5c 6c).

Input Output

Avrai accesso alla scheda tramite un array 2d. Ogni posizione verrà rappresentata con un intID giocatore rappresentativo. Avrai anche il tuo ID giocatore passato alla tua funzione. Fai la tua mossa restituendo in quale coll che vuoi far cadere il tuo pezzo. Ogni round 3 giocatori saranno scelti per giocare. Alla fine del gioco, tutti i giocatori avranno giocato un numero pari di partite.

Per il momento verranno eseguiti 100.000 round (nota che questo richiede molto tempo, potresti voler ridurlo per test di inversione rapida). Complessivamente il vincitore è il giocatore con il maggior numero di vittorie.

Il controller si trova qui: https://github.com/JJ-Atkinson/Connect-n/tree/master .

Scrivere un bot:

Per scrivere un bot è necessario estendere la Playerclasse. Playerè estratto e ha un metodo per implementare, int makeMove(void). In makeMovedeciderai in quale coll che vuoi far cadere il tuo pezzo. Se hai scelto un coll non valido (es. Coll non esiste, coll è già pieno), il tuo turno verrà saltato . Nella Playerclasse hai molti utili metodi di supporto. Segue un elenco di quelli più importanti:

  • boolean ensureValidMove(int coll): Restituisce vero se il coll è sul tabellone e il coll non è ancora pieno.
  • int[] getBoardSize(): Restituisce un array int in cui [0]è il numero di colonne ed [1]è il numero di righe.
  • int[][] getBoard(): Restituisce una copia della scheda. Si dovrebbe accedere in questo modo: [coll number][row number from bottom].
  • Per trovare il resto, guarda la Playerlezione.
  • EMPTY_CELL: Il valore di una cella vuota

Dal momento che questo sarà multi-thread, ho anche incluso una randomfunzione se ne hai bisogno.

Debug del tuo bot:

Ho incluso alcune cose nel controller per rendere più semplice il debug di un bot. Il primo è Runner#SHOW_STATISTICS. Se questo è abilitato, vedrai una stampa dei gruppi di giocatori giocati, incluso un conteggio delle vincite del bot. Esempio:

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

Puoi anche fare un gioco personalizzato con la connectn.game.CustomGameclasse, puoi vedere i punteggi e il vincitore di ogni round. Puoi anche aggiungerti al mix con UserBot.

Aggiungi il tuo bot:

Per aggiungere il tuo bot all'allineamento, vai al PlayerFactoryblocco statico e aggiungi la seguente riga:

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

Altre cose da notare:

  • Le simulazioni sono multi-thread. Se vuoi disattivarlo, vai a Runner#runGames()e commenta questa riga ( .parallel()).
  • Per modificare il numero di giochi, impostare Runner#MINIMUM_NUMBER_OF_GAMESa proprio piacimento.

Aggiunto in seguito:

  • La comunicazione tra i robot non è consentita.

Correlati: Gioca a Connect 4!

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

Quadro di valutazione: (100000 partite)

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

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


Puoi aggiungere funzionalità per determinare su quale svolta è attivo il gioco?
Conor O'Brien,

Già fatto, controlla la Playerclasse per vedere tutti i metodi disponibili.
J Atkin,

7
"un quadrato 6x7" che non è un quadrato
ev3commander l'

1
Dare ai giocatori la possibilità di "passare" facendo una mossa illegale cambia un po 'la dinamica. Il gioco finisce se tutti passano?
istocratico l'

1
Sì, è per questo che è molto importante usare ensureValidMove(a meno che la tua strategia non passi naturalmente in questo turno).
J Atkin,

Risposte:


11

MaxGayne

Questo bot assegna un punteggio a ciascuna posizione, basato principalmente sulla lunghezza delle parti collegate. Sembra 3 mosse in profondità ispezionando 3 mosse più belle in ogni fase e sceglie quella con il punteggio massimo previsto.

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

Molto molto carino! +1
J Atkin,

Qualcosa che ho notato mentre giocavo in giro UserBote il tuo robot era che dopo un certo punto MaxGaynegetterà via i turni (ad esempio, dopo 15 mosse, salta ogni turno fino alla fine del gioco).
J Atkin,

La causa di ciò è probabilmente un bug in CustomGame. Usa gli ID giocatore in base 0 anziché 1 in base al gioco principale. Questo semplicemente rompe il mio bot. Ci sono altri 2 problemi. javafx.util.Pairnon funziona in Eclipse perché non è considerato parte dell'API pubblica. E non ho idea di dove cercare sun.plugin.dom.exception.InvalidStateException. Probabilmente intendevi java.lang.IllegalStateException.
Sleafar,

Sembra un po 'strano ... Ad ogni modo Pair, è il più vicino possibile al tipo di dati che voglio senza scorrere il mio, quindi a meno che l'eclissi non si compili, penso che sia OK. Per quanto riguarda il n. 3, hai ragione, il mio completamento automatico in IntelliJ non è sempre giusto. (il più delle volte lo è, ecco perché non ho controllato)
J Atkin,

@JAtkin In realtà, il Pairproblema impedisce davvero la compilazione in Eclipse, a meno che non si conosca la soluzione alternativa .
Sleafar,

6

RowBot

Guarda in tutte le direzioni e determina la colonna ottimale. Cerca di collegare i suoi pezzi, senza lasciare che i suoi avversari facciano lo stesso.

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

Questo bot ha un solo gioco: posiziona il suo pezzo nella cella all'estrema sinistra che è valido. Stranamente, fa abbastanza bene;)

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

Metti un pezzo ovunque sia valido.

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

Simile a OnePlayBot, ma tiene conto dell'ultima mossa e riproduce la colonna successiva su quella valida.

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

Questo bot odia l'altro giocatore. E non gli piace che lascia cadere pezzi sul tabellone. Quindi cerca di essere l'ultimo che ha lasciato cadere un pezzo in una colonna.

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

È la mia prima volta su CodeGolf, quindi spero che questa risposta sia abbastanza buona. Non ho ancora potuto provarlo, quindi per favore scusami se ci sono errori.

EDIT : aggiunta una riga per interrompere la seconda for.

EDIT 2 : capito perché whileera infinito. Ora è completo e può essere utilizzato!


Benvenuto in PPCG, mi hai fatto ridere con questa risposta, è grandioso! Stai attento alle tue condizioni. Penso che la scheda sia riempita con valori -1 per impostazione predefinita, quindi if(board[col][row]!=null && board[col][row]!=id)dovrebbe essere cambiata in if(board[col][row]!=-1..... Controlla game.Game.genBoard () nel github di OP se vuoi esserne sicuro. Non so neanche se la tua random()volontà farà quello che vuoi, magari usare (int)Math.random()*col?
Katenkyo,

@Katenkyo Grazie mille, sono felice che ti abbia fatto ridere! Il random()metodo è in Playerclasse! Quindi penso che funzionerà =) Ma sì, non ero sicuro delle mie condizioni. Non ho trovato come è definito nel codice di OP, ma controllerò di nuovo. Grazie mille!
Keker,

La classe Player definisce random () come public double random() {return ThreadLocalRandom.current().nextDouble();}. Non so esattamente come funzioni, ma suppongo che restituisca un valore compreso tra 0 e 1, quindi potrebbe essere necessario farlo (int)random()*col:)
Katenkyo

@Katenkyo Oh, pensavo lo avesse già fatto ... Mio male. Lo modificherò quando ho trovato il valore giusto per una cella vuota nella scheda, grazie ancora!
Keker,

@Katenkyo Hai ragione, nextDoublerestituisce un numero compreso tra 0e 1. L'ho incluso perché le simulazioni vengono eseguite in parallelo e Math.random()non è thread-safe.
J Atkin,

3

BasicBlockBot

Un bot di blocco semplice (e ingenuo). Non sa che puoi fare un 4 di fila in orizzontale o in diagonale!

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

Progressivo

Il progressivo è ... progressivo. Gli piace guardare tutto e alcuni! (Non sono sicuro della metodologia di questo. Una volta ha funzionato contro un amico.) E, per qualche ragione, funziona in modo decente.

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 Spiacente, avevo una versione precedente del codice.
Conor O'Brien,

3
@JAtkin Ho rifiutato la tua modifica. Dovresti consentire loro di correggere il loro codice nel loro post. Se vuoi ripararlo per il tuo controller, va bene (personalmente lascerei comunque una nota), ma non è consentita la modifica del codice di qualcuno su SE.
Nathan Merrill,


2

BuggyBot

Un bot di esempio da battere (FYI: non è difficile;)

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

2

PackingBot

Questo bot non punta direttamente ai punti. Cerca di impacchettare un massimo di gettoni fino a quando la scheda non è piena. Capì che semplicemente risalire ancora e ancora è stupido, quindi casualmente metterà token attorno al suo "dominio".

Dovrebbe essere in grado di ottenere alcuni punti in tutte le direzioni, ma non sarà il migliore!

(Non testato)

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 Grazie per averlo indicato, risolto :)
Katenkyo l'

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 sta attraversando un momento difficile, segna sotto BasicBlockBot.
J Atkin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.