Java: Tic-Tac-Toe - 如何避免用户输入重复的单元格?

Java: Tic-Tac-Toe - How To AVOID Repeated Cell From Being Input By User?

如何防止用户输入相同的井字坐标?

用户输入是在游戏的 main 方法中获取的 Class。

[x,y]坐标范围为(0-2)的井字棋格可以是:

0(_)、1 (X) 或 2 (O)

具有 alpha beta 搜索树修剪算法的网格 Class

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

class Grid {

  List<Cell> availableCells;
  int[][] board = new int[3][3];
  Scanner scan = new Scanner(System.in);
  // Set limit to search tree depth
  int treeDepth = 9;

  List<CellsAndScores> rootsChildrenScore = new ArrayList<>();

  public int score() {
    int score = 0;

    // Check all columns
    for (int j = 0; j < 3; ++j) {
      int X = 0;
      int O = 0;
      for (int i = 0; i < 3; ++i) {
        if (board[i][j] == 0) {
        } else if (board[i][j] == 1) {
          X++;
        } else {
          O++;
        }
      }
      score += changeInScore(X, O);
    }

    // Check all rows
    for (int i = 0; i < 3; ++i) {
      int X = 0;
      int O = 0;
      for (int j = 0; j < 3; ++j) {
        if (board[i][j] == 0) {
        } else if (board[i][j] == 1) {
          X++;
        } else {
          O++;
        }
      }
      score += changeInScore(X, O);
    }

    int X = 0;
    int O = 0;

    // Check diagonal (first)
    for (int i = 0, j = 0; i < 3; ++i, ++j) {
      if (board[i][j] == 1) {
        X++;
      } else if (board[i][j] == 2) {
        O++;
      } else {
      }
    }

    score += changeInScore(X, O);

    X = 0;
    O = 0;

    // Check Diagonal (Second)
    for (int i = 2, j = 0; i > -1; --i, ++j) {
      if (board[i][j] == 1) {
        X++;
      } else if (board[i][j] == 2) {
        O++;
      } else {
      }
    }

    score += changeInScore(X, O);

    return score;
  }

  private int changeInScore(int X, int O) {
    int change;
    if (X == 3) {
      change = 100;
    } else if (X == 2 && O == 0) {
      change = 10;
    } else if (X == 1 && O == 0) {
      change = 1;
    } else if (O == 3) {
      change = -100;
    } else if (O == 2 && X == 0) {
      change = -10;
    } else if (O == 1 && X == 0) {
      change = -1;
    } else {
      change = 0;
    }
    return change;
  }

  public int alphaBetaMinimax(int alpha, int beta, int depth, int turn) {

    if (beta <= alpha) {
      System.out.println("Pruning at tree depth = " + depth + " alpha: " + alpha + " beta: " + beta);
      if (turn == 1)
        return Integer.MAX_VALUE;
      else
        return Integer.MIN_VALUE;
    }

    if (depth == treeDepth || gameOver()) {
      return score();
    }

    List<Cell> cellsAvailable = getAvailableStates();

    if (cellsAvailable.isEmpty()) {
      return 0;
    }

    if (depth == 0) {
      rootsChildrenScore.clear();
    }

    int maxValue = Integer.MIN_VALUE, minValue = Integer.MAX_VALUE;

    for (int i = 0; i < cellsAvailable.size(); ++i) {
      Cell cell = cellsAvailable.get(i);

      int currentScore = 0;

      if (turn == 1) {
        placeAMove(cell, 1);
        currentScore = alphaBetaMinimax(alpha, beta, depth + 1, 2);
        maxValue = Math.max(maxValue, currentScore);

        // Set alpha
        alpha = Math.max(currentScore, alpha);

        if (depth == 0) {
          rootsChildrenScore.add(new CellsAndScores(currentScore, cell));
        }
      } else if (turn == 2) {
        placeAMove(cell, 2);
        currentScore = alphaBetaMinimax(alpha, beta, depth + 1, 1);
        minValue = Math.min(minValue, currentScore);

        // Set beta
        beta = Math.min(currentScore, beta);
      }
      // reset board
      board[cell.x][cell.y] = 0;

      // Do not evaluate the rest of the branches after search tree is pruned
      if (currentScore == Integer.MAX_VALUE || currentScore == Integer.MIN_VALUE)
        break;
    }
    return turn == 1 ? maxValue : minValue;
  }

  public boolean gameOver() {
    // Game is over is someone has won, or board is full (draw)
    return (hasXWon() || hasOWon() || getAvailableStates().isEmpty());
  }

  public boolean hasXWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 1)
        || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 1)) {
      // System.out.println("X Diagonal Win");
      return true;
    }
    for (int i = 0; i < 3; ++i) {
      if (((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 1)
          || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 1))) {
        // System.out.println("X Row or Column win");
        return true;
      }
    }
    return false;
  }

  public boolean hasOWon() {
    if ((board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] == 2)
        || (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] == 2)) {
      // System.out.println("O Diagonal Win");
      return true;
    }
    for (int i = 0; i < 3; ++i) {
      if ((board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] == 2)
          || (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] == 2)) {
        // System.out.println("O Row or Column win");
        return true;
      }
    }

    return false;
  }

  public List<Cell> getAvailableStates() {
    availableCells = new ArrayList<>();
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        if (board[i][j] == 0) {
          availableCells.add(new Cell(i, j));
        }
      }
    }
    return availableCells;
  }

  public void placeAMove(Cell Cell, int player) {
    board[Cell.x][Cell.y] = player; // player = 1 for X, 2 for O
  }

  public Cell returnBestMove() {
    int MAX = -100000;
    int best = -1;

    for (int i = 0; i < rootsChildrenScore.size(); ++i) {
      if (MAX < rootsChildrenScore.get(i).score) {
        MAX = rootsChildrenScore.get(i).score;
        best = i;
      }
    }

    return rootsChildrenScore.get(best).cell;
  }

  public void displayBoard() {
    System.out.println();
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        if (board[i][j] == 0)
          System.out.print("_" + " ");
        if (board[i][j] == 1)
          System.out.print("X" + " ");
        if (board[i][j] == 2)
          System.out.print("O" + " ");
      }
      System.out.println("");
    }
    System.out.println();
  }

  public void resetGrid() {
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        board[i][j] = 0;
      }
    }
  }
}

单元格class

class Cell {

  int x, y;

  public Cell(int x, int y) {
    this.x = x;
    this.y = y;
  }

  public String toString() {
    return "[" + x + ", " + y + "]";
  }
}

class CellsAndScores {

  int score;
  Cell cell;

  CellsAndScores(int score, Cell cell) {
    this.score = score;
    this.cell = cell;
  }
}

游戏 Class 使用主要方法 - 获取用户输入

import java.util.Random;

public class Game {

  public static void main(String[] args) {
    Grid grid = new Grid();
    Random random = new Random();

    grid.displayBoard();

    System.out.print("Who moves first? [1]Computer(X) [2]User(O): ");
    int turn = grid.scan.nextInt();
    if (turn == 1) {
      Cell p = new Cell(random.nextInt(3), random.nextInt(3));
      grid.placeAMove(p, 1);
      grid.displayBoard();
    }

    while (!grid.gameOver()) {
      int x = 0, y = 0;

      System.out.print("Please enter an x coordinate [0-2]: ");
      x = grid.scan.nextInt();
      System.out.print("Please enter an y coordinate [0-2]: ");
      y = grid.scan.nextInt();

      Cell userMove = new Cell(y, x);

      grid.placeAMove(userMove, 2); // 2 for O and O is the user
      grid.displayBoard();
      if (grid.gameOver())
        break;

      grid.alphaBetaMinimax(Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 1);
      for (CellsAndScores pas : grid.rootsChildrenScore)
        System.out.println("Cell: " + pas.cell + " Score: " + pas.score);

      grid.placeAMove(grid.returnBestMove(), 1);
      grid.displayBoard();
    }
    if (grid.hasXWon()) {
      System.out.println("Unfortunately, you lost!");
      grid.resetGrid();
    } else if (grid.hasOWon()) {
      System.out.println("You win!");
      grid.resetGrid();
    } else {
      System.out.println("It's a draw!");
      grid.resetGrid();
    }
  }
}

我的答案是在您的 Grid.java class 中添加一个布尔检查方法,然后在您的主要方法中 - 在 placeAMove() 方法之前调用此布尔检查方法。

比如在你的Grid.javaclass中添加如下方法:

/*
 * Return true if space is ok to use.
 */
public boolean isMoveOK(Cell cell) {
    return board[cell.x][cell.y] == 0;
}

这样,使用您预先存在的跟踪 empty/X/O space 值的 0/1/2 值,您可以检查 space 值是否是否为零。

这是在您的主要方法中使用它的一种方式,可以回答您的问题,'How do I prevent the same tic tac toe coordinate from being inputted by the user?'

Cell userMove = new Cell(y, x);

if (grid.isMoveOK(userMove)) {
    grid.placeAMove(userMove, 2); // 2 for O and O is the user
} else {
    System.out.println("Please try a different space/cell");
    continue;
}

grid.displayBoard();
if (grid.gameOver())
    break;

这样,我将跳过您的主方法循环中剩余的循环代码,直到有一个有效的打开 space。 (如果有,则程序应继续检查中奖值或是否继续播放)

希望这能回答您的问题! :)

干杯