You would not use a loop, because you would be awaiting user input.
Your button's action listener would wait for the user to click a button. There would be no loops inside the hander function, unless you are iterating over the buttons.
All you need to do is subtract the guessed letter from the target letter. If the delta (difference) is 0, and the player has not exhausted all their guesses, then they win. Else, if they run out, let them know they lost and reveal the letter. If they still have guesses let them now if they guessed too low/high.
In the Swing app below, if the player guesses too high, all buttons after the button (including the guessed button) will be disabled. This is a simple UX design to make guessing easier for the user.
Note: I created an interface called InputAcceptor
that has an acceptInput(input:String):void
signature. I then gave this interface to the ButtonListener
's constructor for handling buttons input and passing its text around.
GuessApp.java
import java.util.List;
import java.util.OptionalInt;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GuessApp implements InputAcceptor, Runnable {
private static final char[] alphabet;
private List<JButton> buttons;
private ButtonListener buttonListener;
private char letterToGuess;
private int guessesLeft;
private int maxGuesses;
static {
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
}
public GuessApp(int maxGuesses) {
this.maxGuesses = maxGuesses;
this.buttonListener = new ButtonListener(this);
setup();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new GuessApp(3));
}
@Override
public void run() {
JFrame frame = new JFrame("Guess a Letter");
frame.setContentPane(initializeContent());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
@Override
public void acceptInput(String input) {
int buttonIndex = indexOf(buttons, input, JButton::getText).orElse(-1);
char guessed = input.toUpperCase().charAt(0);
int diff = guessed - letterToGuess;
guessesLeft--;
if (diff == 0) {
int response = JOptionPane.showConfirmDialog(null,
String.format("You won with %d guess(es) left! Restart?", this.guessesLeft),
"Congratulations!",
JOptionPane.INFORMATION_MESSAGE);
if (response == JOptionPane.OK_OPTION) {
setup();
} else if (response == JOptionPane.NO_OPTION || response == JOptionPane.CANCEL_OPTION) {
System.exit(0);
}
} else {
if (guessesLeft < 1) {
int response = JOptionPane.showConfirmDialog(null,
String.format("You ran out of guesses! The answer was %c. Restart?", this.letterToGuess),
"You Lose!",
JOptionPane.ERROR_MESSAGE);
if (response == JOptionPane.OK_OPTION) {
setup();
} else if (response == JOptionPane.NO_OPTION) {
System.exit(0);
}
} else {
if (diff > 0) {
JOptionPane.showMessageDialog(null,
String.format("You need to guess lower than %c", guessed),
"Too High",
JOptionPane.WARNING_MESSAGE);
disableButtons(buttonIndex, buttons.size());
} else {
JOptionPane.showMessageDialog(null,
String.format("You need to guess higher than %c", guessed),
"Too Low",
JOptionPane.WARNING_MESSAGE);
disableButtons(0, buttonIndex + 1);
}
}
}
}
protected void setup() {
this.guessesLeft = maxGuesses;
this.letterToGuess = randomValue(alphabet);
if (buttons != null && !buttons.isEmpty()) {
buttons.forEach(button -> {
if (!button.isEnabled()) {
button.setEnabled(true);
}
});
}
System.out.printf("Answer: %c%n", this.letterToGuess);
}
protected JPanel initializeContent() {
JPanel container = new JPanel(new GridLayout(4, 8));
buttons = generateButtons();
buttons.forEach(button -> {
button.addActionListener(buttonListener);
container.add(button);
});
return container;
}
private List<JButton> generateButtons() {
return IntStream
.range(0, alphabet.length)
.mapToObj(i -> alphabet[i])
.map(letter -> new JButton(Character.toString(letter)))
.collect(Collectors.toList());
}
private void disableButtons(int from, int to) {
for (int i = from; i < to; i++) {
if (buttons.get(i).isEnabled()) {
buttons.get(i).setEnabled(false);
}
}
}
public static char randomValue(char[] arr) {
int index = (int) (Math.random() * arr.length);
return arr[index];
}
private static <E> OptionalInt indexOf(List<E> list, String text, Function<E, String> predicate) {
return IntStream.range(0, list.size())
.filter(i -> text.equals(predicate.apply(list.get(i))))
.findFirst();
}
}
InputAcceptor.java
public interface InputAcceptor {
void acceptInput(String input);
}
ButtonListener.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class ButtonListener implements ActionListener {
private InputAcceptor inputAcceptor;
public ButtonListener(InputAcceptor inputAcceptor) {
this.inputAcceptor = inputAcceptor;
}
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JButton)) {
throw new IllegalArgumentException("Event source must be a JButton");
}
this.inputAcceptor.acceptInput(((JButton) e.getSource()).getText());
}
}