-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 つ (またはそれ以上) 並んでいるかどうかを判断するには、何らかの手順が必要です。では、これにどのようにアプローチしますか?配置された場所に最も近いすべての正方形をチェックするよりも、これを行うよりスマートな方法はありますか? (North+South、East+West、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

次元の計算は自分で行う必要があります。ここから始めます。ボードの 1 次元配列を作成しますが、n 次元座標からその配列内のセルを選択するためのアクセスを提供します。

範囲のチェックや行と列の追跡には何の作業もしていません。

、およびintを使用する目的で配列を選択しました。次に、各行の値を合計し、+/- になるかどうかを確認して、誰かが勝ったかどうかを確認できます。0 = Empty1 = O-1 = Xs

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 に答える