(Updated August 26, 2024)
At one point, you may have played Mastermind®. Your opponent picks 4 pegs of various colors (red, orange, yellow, white, blue, green) and places them behind a secret. You then have a predetermined number of guesses to figure it out. You may have 8 or 10 or some other number of guesses.
Following each guess, you are told how many are correct but in the wrong place (white peg) and how many are exact matches (red or black peg). However, you are not told which ones fall into their respective category!
As we move through the chapters of Java Programming by Design, we will have interludes, like this one, where we will pause and build more of this game as we discover the new facility we have developed from the reading and exercises. The game will be called CodeBreaker.
While the graphical representation below looks exciting, we are not prepared to build this yet and will not be for some time.
However, we can begin with a text-based solution with a limit of 10 guesses and feedback to the player as to how successful they are. (Later, we will build both Swing and JavaFX graphical solutions.)
The process will involve:
- Identifying data types.
- Performing string analysis.
- Converting between different data types.
- Employing loops for selecting the secret and guess matching.
- Designing the logic flow of game play.
- Employing user-defined methods for breaking down the problem into smaller, digestible pieces.
- Developing a fully functional text-based game.
- Designing a Swing and JavaFX GUI layout.
- Designing the logic for gameplay within Swing and JavaFX.
- Developing a fully functional Swing and JavaFX game.
The following code has a link allowing you to play the current prototype for the text-based version in Replit. The code is provided as a summary of where we are headed.
import java.util.Scanner;
public class Main {
private static Scanner kb = new Scanner(System.in);
private static void displayInstructions() {
System.out.println("\n"+
"The game of CodeBreaker:\n\n"+
"The computer will choose 4 colors from the list RED, ORANGE, YELLOW,\n"+
"BLUE, GREEN and WHITE. You will have 10 chances to guess the colors\n"+
"from left to right. You will use the first letter of each color. Your\n"+
"guess could be \"RWYY\" or \"R W Y Y\". Spaces are not an issue. If\n"+
"you make a mistake with color selection, you will be prompted to\n"+
"reenter your guess.\n\n"+
"Each guess is graded. You will be told how many colors are correct\n"+
"and how many are in the correct place.\n");
}
private static String selectSecret(String colors) {
int x;
String secret = "";
for ( x = 0 ; x < 4; x++ ) {
secret += colors.charAt((int)(Math.random() * colors.length()));
}
return secret;
}
private static boolean validGuess(String g) {
return g.matches("^[ROYGBW]{4}$");
}
private static int checkGuess(String secret, String guess) {
int x, correct=0, exact=0;
// Convert String to StringBuffer so we can modify it.
StringBuffer b = new StringBuffer(secret);
StringBuffer g = new StringBuffer(guess);
// System.out.println("b is " + b + " g is " + g);
/*
Working from the far end, remove all exact matches.
Working from the far end handles position changes at the beginning
of the array.
*/
for ( x = 3; x >= 0; x-- ) {
if ( b.charAt(x) == g.charAt(x) ) {
exact++;
b.deleteCharAt(x);
g.deleteCharAt(x);
}
}
//System.out.println("b is " + b + " g is " + g);
/*
Using the remaining guess, check for presence of each char.
Remove the char from the secret, if we find it, to handle repeats.
*/
for ( x = 0; x < g.length(); x++ ) {
String t = "" + g.charAt(x);
int pos = b.indexOf(t);
if ( pos != -1 ) {
correct++;
b.deleteCharAt(pos);
}
//System.out.println("b is " + b + " g is " + g);
}
/*
We return the analysis as a two digit number. The tens position
represents the number of exact matches and the ones position
indicates the number of correct colors that are not exact matches.
*/
return exact*10+correct;
}
private static void displayGameProgress(String secret, String[] guesses, int guess) {
int x, check;
if ( guess == 0 )
return;
System.out.println();
for ( x = 0; x < guess ; x++ ) {
check = checkGuess(secret, guesses[x]);
System.out.printf("Guess %2d: %4s exact:%d correct:%d\n", x+1, guesses[x], check/10, check%10);
}
}
public static void main(String[] args) {
final int maxGuesses = 10;
String secret, input="", guessed[] = new String[maxGuesses];
int guess=0;
displayInstructions();
secret = selectSecret("ROYBGW");
//System.out.println(secret);
do {
displayGameProgress(secret, guessed, guess);
System.out.println("Enter your guess:");
input = kb.nextLine().toUpperCase().replace(" ", "");
if ( !validGuess(input) ) {
System.out.println(input + " is an invalid guess. Please retry!\n");
continue;
}
if ( checkGuess(secret, input) == 40 ) {
System.out.println("You did it!");
return;
} else {
guessed[guess] = input;
guess++;
}
} while (guess < maxGuesses);
System.out.println("You ran out of guesses.");
System.out.println("The secret was " + secret);
}
}
[NOTE: Donald Knuth (q.v.) wrote a paper in 1976 whereby he proposed a programmatic solution, or algorithm, to the "codemaker" game.]
A sample run of the game might look like the following (guesses are in bold):
The game of CodeBreaker: The computer will choose 4 colors from the list RED, ORANGE, YELLOW, BLUE, GREEN and WHITE. You will have 10 chances to guess the colors from left to right. You will use the first letter of each color. Your guess could be "RWYY" or "R W Y Y". Spaces are not an issue. If you make a mistake with color selection, you will be prompted to reenter your guess. Each guess is graded. You will be told which colors are correct and how many are in the correct place. Enter your guess: rrrr Guess 1: RRRR exact:0 correct:0 Enter your guess: bbbb Guess 2: BBBB exact:2 correct:0 Enter your guess: rrbb Guess 3: RRBB exact:1 correct:1 Enter your guess: rbbr Guess 4: RBBR exact:2 correct:0 Enter your guess: obbo Guess 5: OBBO exact:2 correct:0 Enter your guess: gbbg Guess 6: GBBG exact:3 correct:0 Enter your guess: wbbg You did it!
In this example, Knuth's solution is applied to eliminate colors rapidly. You can see that the final guess was afforded a bit of luck.