Инициализировать крестики-нолики ИИ-плеера

Так что я пытаюсь выяснить учебник по Tic Tac Toe. Но мне интересно, где я инициализирую компьютерный проигрыватель.

Итак, у меня есть абстрактный класс AIPlayer

public abstract class AIPlayer {
protected int ROWS = 3;  // number of rows
protected int COLS = 3;  // number of columns

protected Cell[][] cells; // the board's ROWS-by-COLS array of Cells
protected Seed mySeed;    // computer's seed
protected Seed oppSeed;   // opponent's seed

/** Constructor with reference to game board */
public AIPlayer(Board board) {
  cells = board.cells;
}

/** Set/change the seed used by computer and opponent */
public void setSeed(Seed seed) {
   this.mySeed = seed;
   oppSeed = (mySeed == Seed.CROSS) ? Seed.NOUGHT : Seed.CROSS;
}

/** Abstract method to get next move. Return int[2] of {row, col} */
abstract int[] move();  // to be implemented by subclasses
}

Это мой алгоритм, чтобы найти лучший ход для компьютера.

import AIPlayer;
import Board;
import Seed;

import java.util.*;
/** AIPlayer using Minimax algorithm */
public class AIPlayerMinimax extends AIPlayer {

/** Constructor with the given game board */
public AIPlayerMinimax(Board board) {
  super(board);
}


int[] move() {
  int[] result = minimax(2, mySeed); // depth, max turn
  return new int[] {result[1], result[2]};   // row, col
}


private int[] minimax(int depth, Seed player) {
   //minmax code
}

private List<int[]> generateMoves() {
   //generate moves
}


private int evaluate() {

   //Evaluating
 }

private int evaluateLine(int row1, int col1, int row2, int col2, int row3, int col3) {
   // .. 

 }

private int[] winningPatterns = {

       //

};


private boolean hasWon(Seed thePlayer) {
   //

   }
}

А это мой GameMain с графикой и другими полезными вещами.

public class GameMain extends JPanel {
// Named-constants for the game board
public static final int ROWS = 3;  // ROWS by COLS cells
public static final int COLS = 3;
public static final String TITLE = "Tic Tac Toe";

// Name-constants for the various dimensions used for graphics drawing
public static final int CELL_SIZE = 100; // cell width and height (square)
public static final int CANVAS_WIDTH = CELL_SIZE * COLS;  // the drawing canvas
public static final int CANVAS_HEIGHT = CELL_SIZE * ROWS;
public static final int GRID_WIDTH = 8;  // Grid-line's width
public static final int GRID_WIDHT_HALF = GRID_WIDTH / 2; // Grid-line's half-width
// Symbols (cross/nought) are displayed inside a cell, with padding from border
public static final int CELL_PADDING = CELL_SIZE / 6;
public static final int SYMBOL_SIZE = CELL_SIZE - CELL_PADDING * 2;
public static final int SYMBOL_STROKE_WIDTH = 8; // pen's stroke width

private Board board;            // the game board
private GameState currentState; // the current state of the game
private Seed currentPlayer;     // the current player
private JLabel statusBar;       // for displaying status message

/** Constructor to setup the UI and game components */
public GameMain() {

    // This JPanel fires MouseEvent
    this.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {  // mouse-clicked handler
            int mouseX = e.getX();
            int mouseY = e.getY();
            // Get the row and column clicked
            int rowSelected = mouseY / CELL_SIZE;
            int colSelected = mouseX / CELL_SIZE;

            if (currentState == GameState.PLAYING) {
                if (rowSelected >= 0 && rowSelected < ROWS
                    && colSelected >= 0 && colSelected < COLS
                && board.cells[rowSelected][colSelected].content == Seed.EMPTY) {
                    board.cells[rowSelected][colSelected].content = currentPlayer; // move
                    updateGame(currentPlayer, rowSelected, colSelected); // update currentState
                    // Switch player
                    currentPlayer = (currentPlayer == Seed.CROSS) ? Seed.NOUGHT : Seed.CROSS;
                }
            } else {        // game over
                initGame();  // restart the game
            }
            // Refresh the drawing canvas
            repaint();  // Call-back paintComponent().
        }
    });

    // Setup the status bar (JLabel) to display status message
    statusBar = new JLabel("         ");
    statusBar.setFont(new Font(Font.DIALOG_INPUT, Font.BOLD, 14));
    statusBar.setBorder(BorderFactory.createEmptyBorder(2, 5, 4, 5));
    statusBar.setOpaque(true);
    statusBar.setBackground(Color.LIGHT_GRAY);

    setLayout(new BorderLayout());
    add(statusBar, BorderLayout.PAGE_END); // same as SOUTH
    setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30));
    // account for statusBar in height

    board = new Board();   // allocate the game-board
    initGame();  // Initialize the game variables
}

/** Initialize the game-board contents and the current-state */
public void initGame() {
    for (int row = 0; row < ROWS; ++row) {
        for (int col = 0; col < COLS; ++col) {
            board.cells[row][col].content = Seed.EMPTY; // all cells empty
        }
    }
    currentState = GameState.PLAYING;  // ready to play
    currentPlayer = Seed.CROSS;        // cross plays first
}

/** Update the currentState after the player with "theSeed" has placed on (row, col) */
public void updateGame(Seed theSeed, int row, int col) {
    if (board.hasWon(theSeed, row, col)) {  // check for win
        currentState = (theSeed == Seed.CROSS) ? GameState.CROSS_WON : GameState.NOUGHT_WON;
    } else if (board.isDraw()) {  // check for draw
        currentState = GameState.DRAW;
    }
    // Otherwise, no change to current state (PLAYING).
}

/** Custom painting codes on this JPanel */
@Override
public void paintComponent(Graphics g) {  // invoke via repaint()
    super.paintComponent(g);    // fill background
    setBackground(Color.WHITE); // set its background color

    board.paint(g);  // ask the game board to paint itself

    // Print status-bar message
    if (currentState == GameState.PLAYING) {
        statusBar.setForeground(Color.BLACK);
        if (currentPlayer == Seed.CROSS) {
            statusBar.setText("X's Turn");
        } else {
            statusBar.setText("O's Turn");
        }
    } else if (currentState == GameState.DRAW) {
        statusBar.setForeground(Color.RED);
        statusBar.setText("It's a Draw! Click to play again.");
    } else if (currentState == GameState.CROSS_WON) {
        statusBar.setForeground(Color.RED);
        statusBar.setText("'X' Won! Click to play again.");
    } else if (currentState == GameState.NOUGHT_WON) {
        statusBar.setForeground(Color.RED);
        statusBar.setText("'O' Won! Click to play again.");
    }
}

/** The entry "main" method */
public static void main(String[] args) {
    // Run GUI construction codes in Event-Dispatching thread for thread safety
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame(TITLE);
            // Set the content-pane of the JFrame to an instance of main JPanel
            frame.setContentPane(new GameMain());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo(null); // center the application window
            frame.setVisible(true);            // show it
        }
    });
}
}

Итак, мой вопрос: как мне инициализировать AIPlayer, чтобы конкурировать со мной? На данный момент это работает как многопользовательская игра Human vs Human.


person theOGloc    schedule 26.10.2015    source источник


Ответы (1)


Что ж, возможно, вы захотите добавить свойство go GameMain:

private AIPlayer aiPlayer; 

Создайте свой AIPlayer в initGame():

aiPlayer = new AIPlayer(board)
aiPlayer.setSeed(Seed.NOUGHT);

Затем это зависит от того, когда вы хотите, чтобы AI Player сделал свой ход. Вам нужно будет вызвать что-то вроде этого:

public void AIMove() {
    int[] generatedMove = aiPlayer.move();
    board.cells[generatedMove[0]][generatedMove[1]].content = currentPlayer;
    updateGame(currentPlayer, generatedMove[0], generatexMove[1]);
    repaint();
}

Это должно работать, но это не лучший дизайн кода. Как видите, много дублирования, нет разделения задач и других недостатков дизайна. Но это был бы лучший вопрос для CodeReview.SE.

person Sven    schedule 27.10.2015
comment
Спасибо, я понял это почти сразу, как задал вопрос. - person theOGloc; 27.10.2015