Skip to content
This repository has been archived by the owner on Jan 18, 2025. It is now read-only.

Commit

Permalink
Extract code input panel
Browse files Browse the repository at this point in the history
  • Loading branch information
powersagitar committed Jan 11, 2025
1 parent e4d0c5d commit 67a1837
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package mastermind.gui.panels;

import mastermind.Mastermind;
import mastermind.core.Code;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class CodeInput {
private final List<JButton> submitButtons = new ArrayList<>(Mastermind.CODE_LENGTH);
private final JButton clearButton = new JButton("Clear");
private final List<Integer> code = new ArrayList<>(Mastermind.CODE_LENGTH);

public JPanel drawButtonsToPanel() {
final JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

final JLabel title = new JLabel("Controls");
title.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(title);

drawSubmitButtons(panel);
drawClearButton(panel);

return panel;
}

private void drawSubmitButtons(final JPanel panel) {
if (!submitButtons.isEmpty()) {
throw new IllegalStateException("Buttons already drawn");
}

final int rowWidth = Mastermind.TOTAL_COLORS / 2;

for (int rowIndex = 0; rowIndex < Mastermind.TOTAL_COLORS / rowWidth; ++rowIndex) {
final JPanel colorPanel = new JPanel(new FlowLayout());
panel.add(colorPanel);

for (int colorIndex = rowWidth * rowIndex; colorIndex < rowWidth * (rowIndex + 1); ++colorIndex) {
JButton colorButton = new JButton(" ");
colorButton.setBackground(GameBoard.codeColorToAwtColor.get(Code.Color.values()[colorIndex]));
colorButton.setForeground(Color.BLACK);
colorButton.setOpaque(true);
colorButton.setContentAreaFilled(true);
colorPanel.add(colorButton);
submitButtons.add(colorButton);
}
}
}

private void drawClearButton(final JPanel panel) {
clearButton.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(clearButton);
}

public void addActionListener(final Consumer<List<Integer>> onCodeModified) {
addSubmitListener(onCodeModified);
addClearListener(onCodeModified);
}

private void addSubmitListener(final Consumer<List<Integer>> onCodeEntered) {
if (submitButtons.isEmpty()) {
throw new IllegalStateException("No buttons to add action listeners to");
}

for (int i = 0; i < submitButtons.size(); ++i) {
final JButton button = submitButtons.get(i);
final int colorIndex = i;
button.addActionListener(event -> {
if (code.size() < Mastermind.CODE_LENGTH) {
code.add(colorIndex);
onCodeEntered.accept(code);
}
});
}
}

private void addClearListener(final Consumer<List<Integer>> onCodeCleared) {
clearButton.addActionListener(event -> {
code.clear();
onCodeCleared.accept(code);
});
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,23 @@
import mastermind.core.Response;
import mastermind.core.solvers.HumanSolver;
import mastermind.core.solvers.MastermindSolver;
import mastermind.gui.panels.CodeInput;
import mastermind.gui.panels.GameBoard;
import mastermind.gui.panels.HomeButton;
import mastermind.utils.Tuple2;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class CodeMaker extends Scene {
private final ArrayList<Integer> nextGuess = new ArrayList<>(Mastermind.CODE_LENGTH);
private List<Integer> nextGuess = null;
private final Code secretCode = Code.generateRandomCode(List.of());
private final HumanSolver solver = new HumanSolver(secretCode);

private final ArrayList<JButton> colorSelectionButtons = new ArrayList<>(Mastermind.TOTAL_COLORS);
private final GameBoard gameBoard = new GameBoard();
private final JButton proceedButton = new JButton("Proceed");
private final JButton deleteButton = new JButton("Delete");
private final JPanel flowPanel = new JPanel(new FlowLayout());
private final JPanel controlPanel = new JPanel();

/**
* Constructs a new CodeMaker instance, initializing the game environment,
Expand All @@ -51,14 +48,8 @@ public CodeMaker(final JFrame frame) {

drawControlPanel();

drawProceedButton();

HomeButton.drawHomeButton(frame);

registerColorSelectionHandlers();

registerDeleteHandlers();

HomeButton.registerHomeHandlers(frame);

registerProceedHandlers();
Expand All @@ -81,120 +72,19 @@ private void drawGameBoard() {
flowPanel.add(gameBoard.getBoardPanel());
}

/**
* Constructs and populates the control panel for the Mastermind game interface.
*
* <p>
* This method sets up a vertically aligned control panel within the user interface.
* It includes the following components:
* - A title label ("Controls") displayed at the top of the panel.
* - Color selection buttons grouped into rows. Each button corresponds to a color
* and allows the player to make selections for their guesses.
* </p>
*
* <p>
* The control panel is added to the primary layout (`flowPanel`) of the game.
* Buttons for color selection are dynamically created and stored in the
* `colorSelectionButtons` list for event handling and future access. The rows
* are organized based on the total number of colors defined in the game (`Mastermind.TOTAL_COLORS`).
* </p>
*/
private void drawControlPanel() {
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
flowPanel.add(controlPanel);

final JLabel title = new JLabel("Controls");
title.setAlignmentX(Component.CENTER_ALIGNMENT);
controlPanel.add(title);

final int rowWidth = Mastermind.TOTAL_COLORS / 2;

for (int rowIndex = 0; rowIndex < Mastermind.TOTAL_COLORS / rowWidth; ++rowIndex) {
final JPanel colorPanel = new JPanel(new FlowLayout());
controlPanel.add(colorPanel);

for (int colorIndex = rowWidth * rowIndex; colorIndex < rowWidth * (rowIndex + 1); ++colorIndex) {
JButton colorButton = new JButton(" ");
colorButton.setBackground(GameBoard.codeColorToAwtColor.get(Code.Color.values()[colorIndex]));
colorButton.setForeground(Color.BLACK);
colorButton.setOpaque(true);
colorButton.setContentAreaFilled(true);
colorPanel.add(colorButton);
colorSelectionButtons.add(colorButton);
}
}

drawDeleteButton();
}

/**
* Registers action handlers for the color selection buttons to manage user guesses.
*
* <p>
* This method iterates over the list of color selection buttons (`colorSelectionButtons`)
* and attaches an `ActionListener` to each button. When a button is pressed, the associated
* color index is added to the current guess (`nextGuess`), provided that the guess has
* not yet reached the maximum length (`Mastermind.CODE_LENGTH`).
* </p>
*
* <p>
* The handler also updates the game board visually to reflect the selected colors
* by modifying the guess displayed on the corresponding row of the game board, based
* on the number of attempts made by the solver (`solver.getAttempts()`).
* </p>
*
* <p>
* It ensures that:
* - The user's guess does not exceed the expected number of colors.
* - The game board is updated in real-time to indicate the progress of the guess.
* </p>
*/
private void registerColorSelectionHandlers() {
for (int i = 0; i < colorSelectionButtons.size(); ++i) {
final JButton button = colorSelectionButtons.get(i);
final int colorIndex = i;
button.addActionListener(event -> {
if (nextGuess.size() < Mastermind.CODE_LENGTH) {
final int gameBoardRowNumber = solver.getAttempts();
nextGuess.add(colorIndex);
gameBoard.updateGuessFromColorIndices(gameBoardRowNumber, nextGuess);
}
});
}
}

private void drawDeleteButton() {
deleteButton.setAlignmentX(Component.CENTER_ALIGNMENT);
controlPanel.add(deleteButton);
}
final CodeInput codeInput = new CodeInput();
final JPanel controlPanel = codeInput.drawButtonsToPanel();

private void registerDeleteHandlers() {
deleteButton.addActionListener(event -> {
if (!nextGuess.isEmpty()) {
final int gameBoardRowNumber = solver.getAttempts();
nextGuess.removeLast();
gameBoard.updateGuessFromColorIndices(gameBoardRowNumber, nextGuess);
}
codeInput.addActionListener(guess -> {
gameBoard.updateGuessFromColorIndices(solver.getAttempts(), guess);
nextGuess = guess;
});
}

/**
* Draws and configures the "Proceed" button within the control panel of the game interface.
*
* <p>
* This method aligns the "Proceed" button to the center horizontally within the control panel
* and adds it to the panel. The button is integral to the gameplay, allowing the player to
* submit their guess during each turn after selecting the desired colors.
* </p>
*
* <p>
* The control panel is a vertically aligned part of the user interface, and the "Proceed"
* button is added at the appropriate position to enable ease of interaction for the player.
* </p>
*/
private void drawProceedButton() {
proceedButton.setAlignmentX(Component.CENTER_ALIGNMENT);
controlPanel.add(proceedButton);
proceedButton.setAlignmentX(Component.CENTER_ALIGNMENT);

flowPanel.add(controlPanel);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class CodeMakerResult extends Scene {
public CodeMakerResult(final JFrame frame, MastermindSolver.Status status, final Code correctCode) {
super(frame);

Mastermind.log.info("Creating CodeMakerResult scene.");

this.correctCode = correctCode;

if (status == MastermindSolver.Status.Win) {
Expand Down

0 comments on commit 67a1837

Please sign in to comment.