简体   繁体   中英

Infinite while loop and counting for loop errors in java

I trying to create the game nim. I made it so the computer can randomly take 1-3 cards from a random row. Right not the computer will do it, but when there is only one or three cards left it will go in an infinite loop.

Main file. Does not need touched

package nimgame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
 *
 * @author Angela
 */
public class NimApp extends JFrame implements ActionListener {

    private static final int ROWS = 3;
    private JTextField[] gameFields; // Where sticks for each row shown
    private JTextField rowField;     // Where player enters row to select
    private JTextField sticksField;  // Where player enters sticks to take
    private JButton playButton;      // Pressed to take sticks
    private JButton AIButton;        // Pressed to make AI's move

    private NimGame nim;

    public NimApp() {

        // Build the fields for the game play 
        rowField = new JTextField(5);
        sticksField = new JTextField(5);
        playButton = new JButton("PLAYER");
        AIButton = new JButton("COMPUTER");
        playButton.addActionListener(this);
        AIButton.addActionListener(this);
        AIButton.setEnabled(false);

        // Create the layout
        JPanel mainPanel = new JPanel(new BorderLayout());
        getContentPane().add(mainPanel);

        JPanel sticksPanel = new JPanel(new GridLayout(3, 1));
        mainPanel.add(sticksPanel, BorderLayout.EAST);

        JPanel playPanel = new JPanel(new GridLayout(3, 2));
        mainPanel.add(playPanel, BorderLayout.CENTER);

        // Add the fields to the play panel
        playPanel.add(new JLabel("Row: ", JLabel.RIGHT));
        playPanel.add(rowField);
        playPanel.add(new JLabel("Sticks: ", JLabel.RIGHT));
        playPanel.add(sticksField);
        playPanel.add(playButton);
        playPanel.add(AIButton);

        // Build the array of textfields to display the sticks
        gameFields = new JTextField[ROWS];
        for (int i = 0; i < ROWS; i++) {
            gameFields[i] = new JTextField(10);
            gameFields[i].setEditable(false);
            sticksPanel.add(gameFields[i]);
        }
        setSize(350, 150);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        nim = new NimGame(new int[]{3, 5, 7});
        draw();
    }

    // Utility function to redraw game
    private void draw() {
        for (int row = 0; row < ROWS; row++) {
            String sticks = "";
            for (int j = 0; j < nim.getRow(row); j++) {
                sticks += "|   ";
            }
            gameFields[row].setText(sticks);
        }
        rowField.setText("");
        sticksField.setText("");
    }

    public void actionPerformed(ActionEvent e) {

        // Player move
        if (e.getSource() == playButton) {

            // Get the row and number of sticks to take
            int row = Integer.parseInt(rowField.getText())-1;
            int sticks = Integer.parseInt(sticksField.getText());

            // Play that move
            nim.play(row, sticks);

            // Redisplay the board and enable the AI button
            draw();
            playButton.setEnabled(false);
            AIButton.setEnabled(true);

            // Determine whether the game is over
            if (nim.isOver()) {
                JOptionPane.showMessageDialog(null, "You win!");
                playButton.setEnabled(false);
            }
        }

        // Computer move
        if (e.getSource() == AIButton) {

            // Determine computer move
            nim.AIMove();

            // Redraw board
            draw();
            AIButton.setEnabled(false);
            playButton.setEnabled(true);

            // Is the game over?
            if (nim.isOver()) {
                JOptionPane.showMessageDialog(null, "You win!");
                playButton.setEnabled(false);
            }
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        NimApp a = new NimApp();
    }
}

This is the support class for the main file

package nimgame;
import java.util.Random;
/**
 *
 * @author Angela
 */
public class NimGame { 
     int[] Sticks; //creating an array of sticks
     int totalSticks=0;

    public NimGame(int[] initialSticks){
    Sticks = initialSticks;}

    public int getRow(int r){
        return Sticks[r];}

    public void play(int r, int s){
    Sticks[r]=Sticks[r]-s;}

This is supposed to count up all the sticks left on the board. It should return true if 1 stick is left and false if there is more than one stick on the board. I am having trouble with the for loop and making it correctly count the sticks.

public boolean isOver(){
    int theTotal = 0;
    for (int i =1; i<Sticks.length; i++){
         theTotal = totalSticks + Sticks[i];
            System.out.println(totalSticks);}
       totalSticks = theTotal;
       System.out.println(totalSticks);
        if (totalSticks<=1){
            return true;
        }
        return false;

This method is supposed to randomly generate a row and an amount of sticks to discard for the computer. This is where i am getting my infinite loop.

public void AIMove(){
    Random randomInt = new Random ();
    int RandomRow = randomInt.nextInt(3);
    int RandomDiscard = randomInt.nextInt(3-0)+1;
    int randomize=0;



    while (RandomDiscard >Sticks[RandomRow] && totalSticks>1){
        RandomRow = randomInt.nextInt(3);
        RandomDiscard = randomInt.nextInt(3-0)+1;
        Sticks[RandomRow]=Sticks[RandomRow]-RandomDiscard;
        randomize = 1;}

    if (randomize==0)
    Sticks[RandomRow]=Sticks[RandomRow]-RandomDiscard;

    if (totalSticks <= 1){
    Sticks[RandomRow]=Sticks[RandomRow]-1;}
    isOver();
    }

            }

The condition to terminate the while loop is when you have RandomDiscard > Sticks[RandomRow] or totalSticks>1 on the body of the loop the value of Sticks[RandomRow] gets smaller at least by one, maintaining the condition.

To break the loop either on the body you need to increment Sticks[RandomRow] or decrease the totalSticks or change the condition to RandomDiscard < Sticks[RandomRow] || totalSticks>1 RandomDiscard < Sticks[RandomRow] || totalSticks>1

Edit(10:18PM): Looking at the problem and the solution, I got a better way to solve the problem here is what I have done:

public void AIMove(){
    Random randomInt = new Random ();

    boolean tryRemove =  true;

    while(tryRemove && totalSticks > 1){
        int RandomRow = randomInt.nextInt(3);
        if(Sticks[RandomRow] <= 0)//the computer can't remove from this row
            continue;

        //the max number to remove from row
        int size = 3;
        if( Sticks[RandomRow] < 3)//this row have lest that 3 cards
            size = Sticks[RandomROw];//make the max number to remove from the row be the number of cards on the row 
        int RandomDiscard = randomInt.nextInt(size) + 1;
        Sticks[RandomRow] = Sticks[RandomRow] - RandomDiscard;
        //I don't know if this is needed, but since we remove a RandomDiscard amount lest decrease the totalSticks
        totalSticks = totalSticks - RandomDiscard;
        //exit loop
        tryRemove = false;
    }

    if(totalSticks <= 1){
        Sticks[RandomRow]=Sticks[RandomRow]-1;
        isOver();
    }


}

What I have done was combine the random loop and the if statements in one loop.

theTotal = totalSticks + Sticks[i];

should be

theTotal = theTotal + Sticks[i];

Also, the for loop probably should start with the index 0 instead of 1:

for (int i =1; i<Sticks.length; i++){

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM