문제

I am a beginner java student writing a gui tic-tac-toe program for my class. (No players, just computer generated).

Everything in my program works as expected, except for one thing; it seems that the placement of my method call for checkWinner is not place correctly, because the assignment for the X's and O's always finish. Why won't the loop end as soon as there is a winner?

It will return the correct winner based on the method call, but the for-loop will continue to iterate and fill in the rest (so sometimes it looks like both the x and o win or one wins twice). I've been going crazy, thinking it might be the placement of my checkWinner method call and if statement. When I set the winner = true; shouldn't that cancel the loop? I have tried putting it between, inside and outside each for-loop with no luck :(

I have marked the area I think is the problem //What is wrong here?// off to the right of that part the code. Thank you for any input!! :)

  public void actionPerformed(ActionEvent e)
  {
    int total = 0, i = 0;
    boolean winner = false;


    //stop current game if a winner is found
    do{

      // Generate random # 0-1 for the labels and assign 
      // X for a 0 value and O for a 1 value

      for (int row = 0; row < gameboard.length; row++) //rows
      {
        for (int col = 0; col < gameboard[row].length; col++) //columns
        { 

          //Generate random number
          gameboard[row][col] = (int)(Math.random() * 2);  

          //Assign proper values
          if(gameboard[row][col] == 0)
          {
            labels[i].setText("X");
            gameboard[row][col] = 10; //this will help check for the winner
          }

          else if(gameboard[row][col] == 1)
          {
            labels[i].setText("O");   
            gameboard[row][col] = 100; //this will help check for winner
          }             


          /**Send the array a the method to find a winner
            The x's are counted as 10s
            The 0s are counted as 100s
            if any row, column or diag = 30, X wins
            if any row, column or diag = 300, Y wins
            else it will be a tie
            */

          total = checkWinner(gameboard);      **//Is this okay here??//**
          if(total == 30 || total == 300)        //
            winner = true;                //Shouldn't this cancel the do-while?


          i++; //next label

        }
      }//end for
    }while(!winner);//end while



    //DISPLAY WINNER
    if(total == 30)
      JOptionPane.showMessageDialog(null, "X is the Winner!");
    else if(total == 300)
      JOptionPane.showMessageDialog(null, "0 is the Winner!");
    else
      JOptionPane.showMessageDialog(null, "It was a tie!");
  }
도움이 되었습니까?

해결책 2

First of all, your code iterates through a board and generates random marks of X and O. This leads to some very odd board states, being always filled row-by-row, and possibly with unbalanced number of X and O marks.

IMHO you should organize your code in opposite manner to fill a board similary to a true game. I mean a series of 9 marks 'XOXOXOXOX' spreaded over the board.

Let Labels labels be a nine-character array, initialized to 9 spaces.

public int doGame( Labels labels)
{
    labels = "         ";
    int itisXmove = true;              // player X or O turn
    for( int movesLeft = 9; movesLeft > 0; movesLeft --)
    {
        int position =          // 0 .. movesLeft-1
                (int) Math.floor(Math.random() * movesLeft);

        for( int pos = 0; pos < 9; pos ++)        // find position
            if( labels[ pos] == " ")              // unused pos?
                if( position-- == 0)              // countdown
                {
                    if( itisXmove)                // use the pos
                        labels[ pos] = "X";       // for current player
                    else
                        labels[ pos] = "O";
                    break;
                }

        int result = checkWinner( labels);        // who wins (non-zero)?
        if( result != 0)
            return result;

        itisXmove = ! itisXmove;                  // next turn
    }
    return 0;                                     // a tie
}

then

public void actionPerformed(ActionEvent e)
{
    Labels labels;

    int result = doGame( labels);

    if( result == valueForX)
        JOptionPane.showMessageDialog(null, "X is the Winner!");
    else if( result == valueForO)
        JOptionPane.showMessageDialog(null, "O is the Winner!");
    else
        JOptionPane.showMessageDialog(null, "It's a tie!");

    for( int rowpos = 0; rowpos < 9; rowpos += 3)
    {
        for( int colpos = 0; colpos < 3; colpos ++)
            /* output (char)label[ rowpos + colpos] */;

        /* output (char)newline */;
    }
}

다른 팁

The easiest way would be to break all loops at once. (Even if some people dont like this)

outerwhile: while(true){

  // Generate random # 0-1 for the labels and assign 
  // X for a 0 value and O for a 1 value

  for (int row = 0; row < gameboard.length; row++) //rows
  {
    for (int col = 0; col < gameboard[row].length; col++) //columns
    { 

      total = checkWinner(gameboard);     
      if(total == 30 || total == 300)        
        break outerwhile;  //leave outer while, implicit canceling all inner fors.


      i++; //next label
    }
  }//end for
}//end while

This However would not allow for the "tie" option, because the while will basically restart a game, if no winner has been found. To allow tie, you dont need the outer while at all, and can leave both fors at once, when a winner is found:

  Boolean winner = false;
  outerfor: for (int row = 0; row < gameboard.length; row++) //rows
  {
    for (int col = 0; col < gameboard[row].length; col++) //columns
    { 

      total = checkWinner(gameboard);     
      if(total == 30 || total == 300){        
        winner = true;     
        break outerfor;  //leave outer for, implicit canceling inner for.

      }

      i++; //next label
    }
  }//end for

  if (winner){
    //winner
  }else{
     //tie.
  }

I think you should change your loop condition and add one more bool.

You have a "tie" condition but currently you only check for winner. The only explanation without the checkWinner code is that you are encountering a tie every time.

So...

boolean tie;
boolean winner;

do {
//your stuff
}
while(!(tie || winner))

Edit: I didn't realize you put the while loop outside your for loop, you will need to break out of your for loops in order for the while condition to be checked.

//stop current game if a winner is found
    do{

      for (int row = 0; row < gameboard.length; row++) //rows
      {
        for (int col = 0; col < gameboard[row].length; col++) //columns
        { 
            if(winner || tie)
                break;
        }//end for

        if(winner || tie)
            break;
      }//end for
    }while(!(winner || tie));//end while
//the rest of your stuff here

You're not checking the value of winner until both for loops complete. Add a break right after you set winner = true, and add an

if (winner)
{
    break;
}

to the beginning or end of your outer for loop.

Your issue is that your do/while statement is wrapped around the for statements. So the for statements end up running their entire cycle before it ever reaches the while statement. A solution to get around this is checking for a winner in the for statements and breaking:

//stop current game if a winner is found
do {

    for (int row = 0; row < gameboard.length; row++) //rows
    {
        for (int col = 0; col < gameboard[row].length; col++) //columns
        { 

            // ... your other code ...

            total = checkWinner(gameboard);
            if(total == 30 || total == 300) {
                winner = true;
                break; // end current for-loop
            }

            i++; //next label
        }

        if (winner) break; // we have a winner so we want to kill the for-loop
    } //end for

} while(!winner); //end while

So you should be able to just loop through the two for-statements and break upon a winner. Your code also does not seem to handle a tied case, but I am guessing you already know that.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top