2016-11-02 7 views
-4

私は、JavaでさまざまなAIやMLテクニックを使用するTic Tac Toeバージョンを開発していますが、シミュレーションを遅くすることにはいくつか問題があります。 基本的には、通常の2人のプレイヤーと同じようにゲームを見たいと思いますが、今すぐ実行するとすぐに最終的なゲーム状態になります。ここでAI vs. AIシミュレーションが速すぎる

が私のコードです:

Board.java

package com.nicolagheza.tictactoe; 

public class Board { 

    // package access 
    Cell[][] cells; // 2D array of ROWS-by-COLS Cell instances 

    /** Constructor to initialize the game board */ 
    public Board() { 
     cells = new Cell[GameMain.ROWS][GameMain.COLS]; // allocate the array 
     for (int row = 0; row < GameMain.ROWS; row++) { 
      for (int col = 0; col < GameMain.COLS; col++) { 
       cells[row][col] = new Cell(row, col); // allocate element of array 
      } 
     } 
    } 

    /** Initialize (or re-initialize) the game board */ 
    public void init() { 
     for (int row = 0; row < GameMain.ROWS; row++) { 
      for (int col = 0; col < GameMain.COLS; col++) { 
       cells[row][col].clear(); // clear the cell content 
      } 
     } 
    } 

    /** Return true if it is a draw (i.e., no more EMPTY cell) */ 
    public boolean isDraw() { 
     for (int row = 0; row < GameMain.ROWS; row++) { 
      for (int col = 0; col < GameMain.COLS; col++) { 
       if (cells[row][col].content == Seed.EMPTY) { 
        return false; // an empty seed found, not a draw, exit 
       } 
      } 
     } 
     return true; // no empty cell, it's a draw 
    } 

    /** Return true if the player with "seed" has won after placing at (seedRow, seedCol) */ 
    public boolean hasWon(Seed seed, int seedRow, int seedCol) { 
     return (cells[seedRow][0].content == seed // 3-in-the-row 
        && cells[seedRow][1].content == seed 
        && cells[seedRow][2].content == seed 
       || cells[0][seedCol].content == seed // 3-in-the-column 
        && cells[1][seedCol].content == seed 
        && cells[2][seedCol].content == seed 
       || seedRow == seedCol    // 3-in-the-diagonal 
        && cells[0][0].content == seed 
        && cells[1][1].content == seed 
        && cells[2][2].content == seed 
       || seedRow + seedCol == 2 // 3-in-the-opposite-diagonal 
        && cells[0][2].content == seed 
        && cells[1][1].content == seed 
        && cells[2][0].content == seed); 
    } 

} 

GameState.java

package com.nicolagheza.tictactoe; 

public enum GameState { 
    PLAYING, DRAW, CROSS_WON, NOUGHT_WON 
} 

GameMain.java

package com.nicolagheza.tictactoe; 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

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 BoardView boardView; 
    private AIPlayer aiPlayer1; 
    private AIPlayer aiPlayer2; 
    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) { 
       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 

        } 
       } else { // game over 
        initGame(); 
       } 
       // Refresh the drawing canvas 
       repaint(); 
       currentPlayer = (currentPlayer == Seed.CROSS) ? Seed.NOUGHT : Seed.CROSS; 
      } 
     }); 

     // 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.SOUTH); 
     setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30)); 
     board = new Board(); // allocate the game-board 
     boardView = new BoardView(board.cells); 
     initGame(); 
     initAI(); 
    } 

    private void initAI() { 
     aiPlayer1 = new AIPlayerRuleBased(board); 
     aiPlayer1.setSeed(Seed.CROSS); 
     aiPlayer2 = new AIPlayerTableLookup(board); 
     aiPlayer2.setSeed(Seed.NOUGHT); 
    } 

    /** 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 
    } 

    public void makeAIMove(AIPlayer player) { 

     int[] move = player.move(); 
     if (move != null) { 
      System.out.println("Player " + player.mySeed + " row: " + move[0] + " col: " + move[1]); 
      board.cells[move[0]][move[1]].content = player.mySeed; 
      updateGame(currentPlayer, move[0], move[1]); 
      repaint(); 
      currentPlayer = (currentPlayer == Seed.CROSS) ? Seed.NOUGHT : Seed.CROSS; 
     } 

    } 

    /** 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) { 
     super.paintComponent(g); // fill background 
     setBackground(Color.WHITE); // set its background color 

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

     // Print status-ba 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."); 
     } 
    } 

    public void getNextState() { 

      if (currentPlayer == aiPlayer1.mySeed) { 
       makeAIMove(aiPlayer1); 
      } 
      if (currentPlayer == aiPlayer2.mySeed) { 
       makeAIMove(aiPlayer2); 
      } 

    } 

    /** 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() { 
      @Override 
      public void run() { 
       JFrame frame = new JFrame(TITLE); 
       // Set the content-pane of the JFrame to an instance of main JPanel 
       GameMain game = new GameMain(); 
       frame.setContentPane(game); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
       while (game.currentState == GameState.PLAYING) { 
        game.getNextState(); 
        try { 
         Thread.sleep(500); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }); 
    } 

} 

AIPlayer.java

package com.nicolagheza.tictactoe; 

public abstract class AIPlayer { 
    protected int ROWS = GameMain.ROWS; // number of rows 
    protected int COLS = GameMain.COLS; // number of cols 

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

    public abstract int[] move(); 
} 

AIPlayerRuleBased.java

package com.nicolagheza.tictactoe; 

import java.util.ArrayList; 
import java.util.List; 

public class AIPlayerRuleBased extends AIPlayer { 
    /** 
    * Constructor with reference to game board 
    * 
    * @param board 
    */ 
    public AIPlayerRuleBased(Board board) { 
     super(board); 
    } 


    private List<int[]> generatePossibleMoves() { 
     List<int[]> nextMoves = new ArrayList<int[]>(); 
     for (int row = 0; row < ROWS; row++) { 
      for (int col = 0; col < COLS; col++) { 
       if (cells[row][col].content == Seed.EMPTY) 
        nextMoves.add(new int[] {row, col}); 
      } 
     } 
     return nextMoves; 
    } 

    @Override 
    public int[] move() { 
     List<int[]> nextPossibleMoves = generatePossibleMoves(); 
     // Rule 1: If I have a winning move, take it. 
     for (int[] nextMove : nextPossibleMoves) { 
      // Try this move 
      cells[nextMove[0]][nextMove[1]].content = mySeed; 
      if (hasWon(mySeed)) { 
       cells[nextMove[0]][nextMove[1]].content = Seed.EMPTY; // Undo move 
       return nextMove; 
      } 
      cells[nextMove[0]][nextMove[1]].content = Seed.EMPTY; // Undo move 
     } 

     // Rule 2: If the opponent has a winning move, block it 
     for (int[] nextMove: nextPossibleMoves) { 
      // Try this move 
      cells[nextMove[0]][nextMove[1]].content = oppSeed; 
      if (hasWon(oppSeed)) { 
       cells[nextMove[0]][nextMove[1]].content = Seed.EMPTY; // Undo move 
       return nextMove; 
      } 
      cells[nextMove[0]][nextMove[1]].content = Seed.EMPTY; // Undo move 
     } 

     // Moves {row, col} in order of preferences. {0,0} at top-left corner 
     int[][] preferredMoves = { 
       {1,1}, {0,0}, {0,2}, {2,0}, {2,2}, 
       {0,1}, {1,0}, {1,2}, {2,1}}; 


     for (int[] move : preferredMoves) { 
      if (cells[move[0]][move[1]].content == Seed.EMPTY) { 
       return move; 
      } 
     } 
     assert false : "No empty cell?!"; 
     return null; 
    } 

    private int[] winningPatterns = { 
      0b111000000, 0b000111000, 0b000000111, // rows 
      0b100100100, 0b010010010, 0b001001001, // cols 
      0b100010001, 0b001010100    // diagonals 
    }; 

    /** Returns true if thePlayer wins */ 
    private boolean hasWon(Seed thePlayer) { 
     int pattern = 0b000000000; // 9-bit pattern for the 9 cells 
     for (int row = 0; row < ROWS; ++row) { 
      for (int col = 0; col < COLS; ++col) { 
       if (cells[row][col].content == thePlayer) { 
        pattern |= (1 << (row * COLS + col)); 
       } 
      } 
     } 
     for (int winningPattern : winningPatterns) { 
      if ((pattern & winningPattern) == winningPattern) return true; 
     } 
     return false; 
    } 
} 

私はのThread.sleepを試みたが、それは仕事を文句を言いません。

+2

私はこのコードにアクセスできません。ここにコードを投稿し、リンクしないでください。 – nhouser9

+0

1.ここにコードを直接追加します。 2.一般的なエンジンを使用している場合は、スリープ用の独自のバージョンがあります。 – Carcigenicate

+3

各アクションにタスクを与え、タスク間でGUIに画面を更新させる必要があります。 Thread.sleepの場合は、GUIスレッドも停止しています。 –

答えて

0

(OPの代わりに掲示)

私はJavax.swing.Timerを使用して問題を解決しました。他の誰かが興味を持っている場合にどうしたのですか。

new javax.swing.Timer(TIMER_DELAY, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (game.currentState != GameState.PLAYING) 
          return; 
        game.getNextState(); 
       } 
      }).start();