Hi there! I'm glad you're interested in my coding project. The Mastermind game is quite simple but entertaining code, to present my skills in pure Python 3, e.g.:
- OOP principles - encapsulation, polymorphism
- class inheritance, overriding methods, abstract methods, meta classes
- method properties, decorators, class and static methods
- Python closures
- iterators, generators, map and lambda functions
- list comprehensions
- exceptions raises and catches, assertions
- context managers
- tuple, dict and function arguments (*args, **kwargs) unpacking
- colored output in terminal
- PEP 8, DRY, KISS, YAGNI, code comments
Mastermind is a code-breaking game for two players. In my program one of the players is the computer. One player becomes the codemaker, the other the codebreaker. The codemaker chooses a pattern of 4 pegs (by default) using 6 different color pegs (by default). The solution pattern is visible to the codemaker, but not to the codebreaker.
The codebreaker tries to guess the pattern, in both order and color, within 12 turns (by default). Each guess is made by entering a row (pattern) of colored pegs into terminal. Once placed, the codemaker provides a response by placing from 0 to 4 response pegs nearby the row with the guess. A black peg is placed for each code peg from the guess which is correct in both color and position. A white peg indicates the existence of a correct color peg placed in the wrong position. Once response is provided, another guess is made. Guesses and responses continue to alternate until either the codebreaker guesses correctly, or reaches the turns limit. In computer solving modes the game also could end after being convinced that there is no possible solution based on user provided responses.
-
game
: In this mode the codemaker is the computer - prepares the solution pattern and returns you the responses. The codebreaker is you - you enter the patterns and try to guess the solution. Since you are the one who guesses, choosing a Solver and defining his settings is unnecessary. -
solver
: In this mode the codemaker is you - you have prepared the solution pattern and you give the computer responses for every guess. The codebreaker is the computer and he guesses the pattern using one of the two different Solvers #1 or #2 (described below). Sometimes the computer is sure that his guess is the proper solution and tells you about it. -
helper
: In this mode the computer helps you to guess the solution pattern when you are playing with someone else. Very similar tosolver
mode. You enter every guess you made and his response, and then the computer gives you one of the possible solutions using the same Solvers as insolver
mode. You can enter any pattern and response, or just a response based on the previously proposed pattern.
-
Solver #1
= patterns checking generator Solver. This Solver generates patterns one by one and checks if they satisfy every previous guess and his response. After the pattern is passed to codemaker and the response is received Solver continue scanning for the next possible solutions. Therefore, at the beginning of the game this Solver can quickly make guesses, as the solving time raises when the game reaches the end. This Solver doesn't need patterns to be generated before starting a game, so he doesn't consume so much memory asSolver #2
. Also, this Solver can search for second possible solution (seesolver1_calc_2nd_solution
setting) to be sure that the first found is the only one possible. -
Solver #2
= patterns list filtering Solver. This Solver prepares list of all possible solutions (which can take a lot of memory) and reduces it after each guess. So, first turns can take some time, but the closer the solution this Solver is, the faster he can give possible solutions. This Solver can be more efficient from the Mastermind's point of view thanSolver #1
, because he can take random pattern from the list (seesolver2_take_random_pattern
setting) and get the response that rejects more patterns. Additionally, this Solver can print the remaining possible solutions list (seesolver2_print_possible_solutions_threshold
setting) if there are only few of them. -
Solver #3
= logic thinking Solver using constraint module. Not implemented yet!
In my game you can specify various settings that affects a game. They are grouped into 5 categories.
-
(bool)
styled_prints
(default valueFalse
- for compatibility). When enabled the most of terminal prints will be formatted using colors, bolds, underlines, frames etc. Use only when your terminal supports this function, otherwise the output would be unreadable. -
(bool)
use_digits_for_colors
(default valueTrue
). Describes the way how to input/output colors for pegs. When enabled the program uses digits from1
-10
(digit0
means10
value) and then letters (almost like in hexadecimal number system). The minimum pattern is then1111
. When disabled the program uses only letters (starting froma
), so the minimum patterns isaaaa
. -
(bool)
progress_timing
(default valueTrue
). Enables the time measurements for long taking operations and prints the result after finish. -
(bool)
print_settings_list
(default valueFalse
). Enables printing the list of all settings before starting a game. Additional information for advanced users. -
(bool)
print_guesses_list
(default valueTrue
). Enables printing the list of all guesses so far after each game turn.
-
(int)
peg_colors
(default value6
). Main Mastermind setting. The number of different peg colors to be used in patterns (from2
to24
). The more color pegs there are, the harder the game is. -
(int)
pegs_in_pattern
(default value4
). Main Mastermind setting. The number of ordered pegs in one pattern (from2
to16
). The more pegs there are in the pattern, the harder the game is. -
(bool)
allow_blanks
(default valueFalse
). Not implemented yet! In future you will be able to enable blank pegs for guesses, the ones that cannot occur in solution pattern for sure. -
(bool)
allow_duplicates
(default valueTrue
). Not implemented yet! In future you will be able to disable duplicating color pegs in pattern. Both for guesses and for solution pattern. -
(int)
guesses_limit
(default value12
). The number of guesses the codebreaker has to reveal the solution. Set to0
if you want to have an unlimited play.
-
(int)
chosen_solver
(default value1
). Choose index of the implemented Solvers. #1 = patterns checking generator Solver, #2 = patterns list filtering Solver. They are described above. Ingame
mode this and related settings are unnecessary. -
(bool)
pre_build_patterns
(default valueFalse
). Enables building possible patterns list for several games at once. Useful when you play several games one by one using the same settings. This setting can take a lot of RAM to keep all the patterns in memory. When disabled the patterns will be generated real-time during computer solving, but it can be slower and not efficient from the Mastermind's point of view (list of the patterns cannot be shuffled). -
(bool)
use_itertools_for_build
(default valueTrue
). Enables Python built-in itertools module to generate patterns. It is a bit faster than my generating function, but it doesn't handle all shuffling settings below. -
(bool)
shuffle_colors_before_build
(default valueFalse
). Enables one-time color pegs order shuffling before pattern generation is started. It doesn't change the efficiency of guessing, but allows not to start always with the first minimum (the same one color) pattern. -
(bool)
shuffle_colors_during_build
(default valueFalse
). Enables color pegs order shuffling for every peg in pattern. It can improve the efficiency of guessing, when the codebreaker starts from mixed color pattern. This setting is unused when itertools module is used. -
(bool)
shuffle_patterns_after_build
(default valueFalse
). Enables one-time patterns order shuffling after the pattern list is built. You can achieve the best guessing efficiency, but first you must pre build patterns and keep them in memory. Patterns shuffling is impossible for pattern real-time generators. In Solver #2 you can use insteadsolver2_take_random_pattern
setting which is faster.
- (bool)
solver1_calc_2nd_solution
(default valueTrue
). Enables searching for second possible solution after finding the first one. Using this setting Solver #1 can sometimes be sure that current guess is the only one possible solution (and it's not a guess in fact).
-
(bool)
solver2_take_random_pattern
(default valueFalse
). Enables taking random pattern from the possible solutions list, which is more efficient from the Mastermind's point of view. It is similar toshuffle_patterns_after_build
setting, but it can be used only for Solver #2, which has the whole list. When disabled Solver #2 takes the first possible solution from the list. -
(int)
solver2_print_possible_solutions_threshold
(default value10
). Sets the maximum number of patterns in the possible solutions list, which will be printed after filtering the list. You can see patterns which still can be a solution after each turn. Set to0
if you want to disable this printing. If there is only one possible solution in the list, the computer knows that it must be a solution.
Please keep in mind that not every settings combinations are possible. You won't get an error, however some less significant settings will be omitted.
Just launch ./main.py
. Most of the settings are set, for some important you will be asked.
If you don't want to be asked you can give some settings as a parameter launching a program in any order, e.g.:
./main.py mode=solver peg_colors=8 pegs_in_pattern=6 chosen_solver=2 pre_build_patterns=1 use_itertools_for_build=0 solver2_take_random_pattern=1 styled_prints=1
Running main.py
you will be asked if you want to play again after the current game is ended. The settings will be the same. If there were patterns generated they will not be generated again.
You can also manually call once the proper Mastermind class
- MastermindGame()
- MastermindSolver()
- MastermindHelper()
giving some keywords arguments. For example:
MastermindSolver(
peg_colors=8,
pegs_in_pattern=6,
chosen_solver=2,
pre_build_patterns=True,
use_itertools_for_build=False,
solver2_take_random_pattern=True,
styled_prints=True,
)
Piotr Loos (c) 2023