-1

作为自学经验,我构建了一个 3x3 TicTacToe 游戏。现在我想将该游戏扩展到 N x N 大小的棋盘。在确定获胜条件时,这给我带来了一个问题。

原始游戏使用数组来寻找获胜条件:

private final int[][] win = new int[][] {
        {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, //horizontal
        {0, 3, 6}, {1, 4, 7}, {2, 5, 8}, //vertical
        {0, 4, 8}, {2, 4, 6}             //diagonal
};

在 ActionListener 中:

// Check the win array for 3-in-a-line condition.
        for(int i = 0; i<=7; i++){
            if( b[win[i][0]].getText().equals( b[win[i][1]].getText() ) && // A == B
                b[win[i][1]].getText().equals( b[win[i][2]].getText() ) && // B == C
                !b[win[i][0]].getText().equals("")){                       // Not empty 

                b[win[i][0]].setBackground(Color.GREEN);
                b[win[i][1]].setBackground(Color.GREEN);
                b[win[i][2]].setBackground(Color.GREEN);
                gameOver = true;
                System.out.println("WIN WIN WIN");

随着游戏扩展到 N x N 大小,我不能有一个固定的数组来确定获胜条件。

我需要一些程序来确定一行中是否有 3 个(或更多)。那么你将如何处理这个问题?有没有更聪明的方法来做到这一点,而不是检查所有最接近放置的方块?(北+南、东+西、N+N、E+E、S+S、W+W、NE+SW、NW+SE、NE+NE、NW+NW、SE+SE、SW+SW)和尝试过滤掉所有的PointerExceptions?

每次检查整个板子,控制for循环的索引不越界?

这两种解决方案都像是编码的噩梦。有人对这个问题有更聪明的方法吗?

添加整个程序以供参考:

package heniv181;


import javax.swing.JFrame;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JOptionPane;


/**
 *  @author Henrik
 *  Also code by John (john@codecall.net) http://forum.codecall.net/topic/36472-javatutorial-tic-tac-toe/
 *  
 */
public class TicTacToeBig extends JFrame
                       implements ActionListener {

    private int size = 5;
    private JButton[] b = new JButton[size*size];
    private int turn = 0;


    private final int[][] win = new int[][] {
            {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, //horizontal
            {0, 3, 6}, {1, 4, 7}, {2, 5, 8}, //virticle
            {0, 4, 8}, {2, 4, 6}             //diagonal
    };                               


    //  Constructor
    public TicTacToeBig(){   

        setTitle("Tic-Tac-Toe");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 300);
        setLocation(200, 200);
        setVisible(true);  

        setLayout(new GridLayout(size,size));

        for(int i=0; i < size*size; i++){
            b[i] = new JButton();
            b[i].setText("");
            b[i].addActionListener(this);
            b[i].setActionCommand( Integer.toString(i));       
            add(b[i]);

        }

    }

    public static void main(String args[]){      


        TicTacToeBig t = new TicTacToeBig();

    }


    @Override
    public void actionPerformed(ActionEvent ae) {

        String sign;
        boolean gameOver = false;

        //  Whos turn is it? X's or O's? 
        turn++;
        if(turn % 2 == 0)
            sign="X";
        else
            sign="O";

        // Set X or O on the button pressed.
        JButton press = (JButton)ae.getSource();
        press.setText(sign);
        press.setEnabled(false);
        gameOver = checkWin(press);



        /* Check the win array for 3-in-a-line condition.
        for(int i = 0; i<=7; i++){
            if( b[win[i][0]].getText().equals( b[win[i][1]].getText() ) && // A == B
                b[win[i][1]].getText().equals( b[win[i][2]].getText() ) && // B == C
                !b[win[i][0]].getText().equals("")){                       // Not empty 

                b[win[i][0]].setBackground(Color.GREEN);
                b[win[i][1]].setBackground(Color.GREEN);
                b[win[i][2]].setBackground(Color.GREEN);
                gameOver = true;
                System.out.println("WIN WIN WIN");

            }   

        }*/

        //End game if winning conditon is true or no more turns.
        if(gameOver){
            JOptionPane.showMessageDialog(null, "Congratulation!\n" + sign + " have won!");
            System.exit(0);
        }
        else if(turn>=(size*size) ){
            JOptionPane.showMessageDialog(null, "To bad!\n No winners. ");
            System.exit(0);
        }

    }

    public boolean checkWin(JButton j){

        //HHmmmm..........

        int index = Integer.valueOf( j.getActionCommand() );

        System.out.println(index);   



        if((index+1) % size == 0 || (index+1) % size == 1)
            System.out.println("R or L Edge.");

        if(index-size < 0 || index+size > b.length-1)
            System.out.println("U or D Edge");

        //check right and left
            //check if point is on right or left edge
            //compare index-1   L
            //compare index+1   R

        //check up and down
            //check if point is on top or bottom edge
            //compare index - size  D   
            //compare index + size  U

        //check diagonals
            //check if point is on edge
            //compare index - size -1   UL
            //compare index - size +1   UR
            //compare index + size -1   DL  
            //compare index + size +1   DR



        return false;
    }

}
4

3 回答 3

1

解决此问题的最佳方法是在您将新标记添加到游戏板时。

然后,您只需要测试包含当前单元格的行、列和对角线,而不是测试整个电路板。

于 2013-05-23T12:44:56.457 回答
0

好的,亨利克,

您在击中边缘时遇到的问题并不是从上次播放位置进行测试所固有的。如果您小心并反复编程,则可以做到这一点。

这是您游戏的部分解决方案。它不是最优的,并且不测试从左到右向上倾斜的对角线。但是,它似乎有效 - 清理和理解取决于您。

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
* @author JayDM
*         Loosely based on code provide by Henrik
* 
*/
public class TicTacToeBig extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;

private int size = 5;
private JButton[][] b;
private int turn = 0;

// Constructor
public TicTacToeBig() {
    setTitle("Tic-Tac-Toe");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300, 300);
    setLocation(200, 200);
    setVisible(true);

    b = new JButton[size][size];

    setLayout(new GridLayout(size, size));

    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            System.out.println("Adding button for position: " + row + ", " + col);

            b[row][col] = new JButton();
            b[row][col].setText("_");
            b[row][col].addActionListener(this);
            b[row][col].setActionCommand(row + "," + col);
            add(b[row][col]);
        }
    }

    invalidate();
    validate();
}

@Override
public void actionPerformed(ActionEvent ae) {
    String sign;

    // Whos turn is it? X's or O's?
    turn++;

    if (turn % 2 == 0) {
        sign = "O";
    } else {
        sign = "X";
    }

    // Set X or O on the button pressed.
    JButton press = (JButton) ae.getSource();

    press.setText(sign);
    press.setEnabled(false);

    // End game if winning conditon is true or no more turns.
    if (checkWin(press)) {
        JOptionPane.showMessageDialog(null, "Congratulations!\n" + sign + " has won!");

        System.exit(0);
    } else if (turn >= (size * size)) {
        JOptionPane.showMessageDialog(null, "To bad!\n No winners. ");

        System.exit(0);
    }
}

public boolean checkWin(JButton j) {
    String position[] = j.getActionCommand().split(",");

    int row = Integer.parseInt(position[0]);
    int col = Integer.parseInt(position[1]);

    System.out.println(b[row][col].getText() + " played @ " + row + ", " + col);

    String winner = b[row][col].getText() + b[row][col].getText() + b[row][col].getText();
    String field;

    // row
    field = "";

    for (int testCol = Math.max(0, col - 2); testCol < Math.min(size, col + 3); testCol++) {
        field += b[row][testCol].getText();
    }

    System.out.println("Testing row field: " + field);

    if (field.contains(winner)) {
        System.out.println("Row winner!");

        return true;
    }

    // col
    field = "";

    for (int testRow = Math.max(0, row - 2); testRow < Math.min(size, row + 3); testRow++) {
        field += b[testRow][col].getText();
    }

    System.out.println("Testing column field: " + field);

    if (field.contains(winner)) {
        System.out.println("Column winner!");

        return true;
    }

    // diagonals
    int lowerBound = 0;
    int upperBound = 0;

    // diagonal down
    field = "";

    // top left
    lowerBound = - Math.min(2, Math.min(col, row));

    // bottom right
    upperBound = Math.min(3, size - Math.max(row, col));

    System.out.println("Bounds: " + lowerBound + ", " + upperBound);

    for (int offset = lowerBound; offset < upperBound; offset++) {
        field += b[row + offset][col + offset].getText();
    }

    System.out.println("Testing diagonal down field: " + field);

    if (field.contains(winner)) {
        System.out.println("Diagonal down winner!");

        return true;
    }

    // diagonal up
    field = "";

    // bottom left
    // lowerBound = ?????????????;
    lowerBound = 0;

    // top right
    // upperBound = ?????????????;
    upperBound = 0;

    System.out.println("Bounds: " + lowerBound + ", " + upperBound);

    for (int offset = lowerBound; offset < upperBound; offset++) {
        // field += b[row +/- offset][col +/- offset].getText();
    }

    System.out.println("Testing diagonal up field: " + field);

    if (field.contains(winner)) {
        System.out.println("Diagonal up winner!");

        return true;
    }

    return false;
}

public static void main(String args[]) {
    TicTacToeBig t = new TicTacToeBig();
}
}
于 2013-05-24T17:53:35.967 回答
0

您必须自己进行维度计算。这是一个开始。它为棋盘创建一维数组,但提供从 n 维坐标中选择该数组中的单元格的访问权限。

我没有在范围检查或跟踪行和列上做任何工作。

我选择int数组的目的是使用0 = Empty,1 = O-1 = X. 然后,您可以将每行中的值相加,看看它是否出现 +/-s以查看是否有人赢了。

public class TicTacToe {
  // Each piece.
  static final int Empty = 0;
  static final int X = 1;
  static final int O = -1;
  // A Board is a number of cells.

  static class Board {
    // Dimensions.
    final int d;
    // Size.
    final int s;
    // The board is just an array of ints.
    final int[] board;

    // Create board of the specified size.
    public Board(int d, int s) {
      this.d = d;
      this.s = s;
      /* E.G.
       * 3 * 3 = 9 cells in a 2-D board.
       * 3 * 3 * 3 = 27 rows in a 3-D board.
       */
      board = new int[(int) Math.pow(d, s)];
    }

    void setPiece(int[] coords, int value) {
      board[getLoc(coords)] = value;
    }

    boolean won() {
      boolean won = false;
      // For each piece.
      for (int p = 0; p < board.length; p++) {
        // Where is this piece.
        int[] coords = getCoords(p);
        // No point in checking empty squares.
        int piece = getPiece(coords);
        if (piece != Empty) {
          // First check non-diagonals.
          int [] check;
          // Vary each dimension from 0 to 3.
          for (int i = 0; i < coords.length; i++) {
            // Back to there.
            check = Arrays.copyOf(coords, coords.length);
            // The sum across this dimension.
            int sum = 0;
            // By the size of the board.
            for (int j = 0; j < s; j++) {
              check[i] = j;
              sum += getPiece(check);
            }
            if (sum == piece * s) {
              // A line adds up!
              return true;
            }
          }
        }

      }
      return won;
    }

    int getPiece(int[] coords) {
      /*
       * Say [1,1] is the center of a 3x3 board so it is at 4 in the array.
       * 
       * i.e. the array is:
       * 
       * 0 - [0,0]
       * 1 - [0,1]
       * 2 - [0,2]
       * 3 - [1,0]
       * 4 - [1,1] - *
       * 5 - [1,2]
       * 6 - [2,0]
       * 7 - [2,1]
       * 8 - [2,2]
       * 
       * So (1 * 3) + 1 = 4
       * 
       * But [1,1,1], being the center of a 3x3x3 board must be at 13!
       * 
       * So ((1 * 3) + 1) * 3) + 1 = 13
       */
      return board[getLoc(coords)];
    }

    // Returns the location in the array where the cell at this coordinate is.
    private int getLoc(int[] coords) {
      // Where this piece is in the array.
      int loc = coords[0];
      for (int i = 1; i < coords.length; i++) {
        // Add in each dimension of coordinate.
        loc = loc * s + coords[i];
      }
      return loc;
    }

    // Reverse the getLoc by taking a loc and rolling it into a coordinates.
    private int[] getCoords(int loc) {
      // It must be that wide.
      int[] coords = new int[d];
      // Work backwards from the end.
      for (int i = coords.length - 1; i >= 0; i--) {
        // Take remainder.
        coords[i] = loc % s;
        // Divide.
        loc /= s;
      }
      return coords;
    }

  }

  private void test() {
    System.out.println("Board(2,3) - piece[1,1] @ " + new Board(2, 3).getLoc(new int[]{1, 1}));
    System.out.println("Board(3,3) - piece[1,1,1] @ " + new Board(3, 3).getLoc(new int[]{1, 1, 1}));
    System.out.println("Board(2,3) - loc[8] @ " + Arrays.toString(new Board(2, 3).getCoords(8)));
    System.out.println("Board(2,3) - loc[0] @ " + Arrays.toString(new Board(2, 3).getCoords(0)));
    System.out.println("Board(3,3) - loc[13] @ " + Arrays.toString(new Board(3, 3).getCoords(13)));
    Board board = new Board(3,3);
    boolean won = board.won();
    System.out.println("Won: " + won);
    // Set a row.
    board.setPiece(new int[]{0, 1, 1}, X);
    board.setPiece(new int[]{1, 1, 1}, X);
    board.setPiece(new int[]{2, 1, 1}, X);
    // Should have a win.
    won = board.won();
    System.out.println("Won: " + won);
  }

  public static void main(String args[]) {
    try {
      new TicTacToe().test();
    } catch (Throwable t) {
      t.printStackTrace(System.err);
    }
  }

}

正确打印:

Board(2,3) - piece[1,1] @ 4
Board(3,3) - piece[1,1,1] @ 13
Board(2,3) - loc[8] @ [2, 2]
Board(2,3) - loc[0] @ [0, 0]
Board(3,3) - loc[13] @ [1, 1, 1]
Won: false
Won: true

请注意,这还没有检查对角线 - 你必须自己做。

于 2013-05-23T13:26:45.037 回答