mastermind project report
-
Upload
jacob-rodeheffer -
Category
Documents
-
view
48 -
download
2
Transcript of mastermind project report
Mastermind Solver
EE201 project by Jacob Rodeheffer and Ethan Chan
2
Table of Contents
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
The game of Mastermind . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Playing Mastermind on the FPGA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Mastermind Solver’s state machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Mastermind Solver’s custom algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Measures of success . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Appendix: algorithm details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Appendix: hardware usage report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Appendix: waveforms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Appendix: Verilog code, and code of C++ simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Abstract
For this project we made a Verilog program, Mastermind Solver, that lets you play the puzzle
game Mastermind against an AI player via an FPGA board. The innovative part of the program
is its AI algorithm. We came up with a new Mastermind-solving algorithm with the goal of
needing to use fewer hardware components than the Mastermind-solving algorithms already in
existence. We have established that Mastermind Solver works (it always wins the game) and
there are indications that it may require fewer hardware components.
The Game of Mastermind
Mastermind is a two-player game where one player comes up with a sequence of colors and the
other tries to guess this sequence within ten tries. The sequence is made up of four slots that can
be fill a permutation of six different colors with repetitions allowed. Order matters. The other
player then places his guesses and the player that knows the sequence will give the other player
clues for the guessed sequence with red and white pegs. A red peg is placed for each color in the
guessed sequence that is found in the correct sequence and is located in the correct slot. A white
peg is placed for each color in the guessed sequence that is found in the correct sequence but is
not located in the correct slot. The user has a total of ten guesses to correct the correct sequence.
Playing Mastermind on the FPGA
In our project we will be implementing and Artificial Intelligence onto the FPGA called
Mastermind Solver, which will be able to guess any user’s sequence within ten tries. The four
slots are represented by the four SSDs (SSD0, SSD1, SSD2, SSD3), the six colors are
3
represented by digits 0-5, switches Sw4-Sw7 each represent a red peg, switches Sw0-Sw3 each
represent a white peg, and the number of LEDs L0-L7 lit correspond with the number of guessed
sequences. Because we only have eight LEDs to work with and we can have a possible of nine
guessed sequences when we are on the 10th
guess we encoded a special pattern of LEDs, which
represents that nine sequences have been guessed.
The Reset button (BtnC) initializes the game and the SSDs display “PLAY” and waits for a user
to press the start/respond button (BtnD) to begin the game. Once the game begins the AI
produces its first guess. The user then inputs the correct amount of red and white pegs by
switching on or off the corresponding switches. When the correct number of red and white pegs
is in place the user hits the respond button (BtnD) to enter the information, which the AI uses to
produce its next guess until the correct sequence is guessed.
The AI checks for three cases when red and white pegs are placed. If only four red pegs are
placed the user is indicating that the AI has guessed his/her sequence and the SSDs display
“YAY” indicating that it has won. If the AI detects that the total number of red and white pegs
exceeds the number of slots, four in this case, the SSDs display “nono” which tells that user that
he/she has entered invalid information. Also if the AI detects, with its own logic, that it should
have guessed the user’s sequence by that guess but the user enters a combination of red and
white pegs that is not four reds, the AI tells the user that it has entered an false current or
previous combination of red and white pegs by displaying “FErr” (Fatal Error) on the SSDs.
In the top file we implemented SSD scanning and set the value of the corresponding SSDs
depending on the state the program was in.
Fig. 1
4
Mastermind Solver’s State Machine
Fig. 2 Displays the Mastermind Solver’s state machine. Reset initializes the program to begin at
state “Initial”. The arrow transitioning from “Initial” to “Guess and wait for user response” is
triggered by an active high Respond button pressed by the user. The arrow transitioning from the
“Guess and wait for user response” state to the “Check for problems” state is triggered by an
active high Response button pressed by the user. Here we can see a problem. Because our
Response button is used to begin the game and enter a guess, the Response button must be
debounced to active for only one cycle else we would transition straight to the “Check for
problems” state without processing data in the “Guess and wait for user response” state. Even if
we did not use the Respond button to begin the game and enter a guess we would still need to
debounce the signal to prevent it from being high for multiple clock cycles and looping among
the “Guess and wait for user response”, “Check for problems”, and “Algorithm” state. Therefore
we must make sure the Response button has only a single-clock pulse with the SCEN signal the
debouncer module offers.
The “Check for problems” state checks for three cases when pegs are placed. This was
mentioned earlier. If the AI guesses correctly or if there is a Fatal Error, we transition to the
“Initial” state. If there is a non fatal error where the user enters a total of more than four pegs we
return to the “Guess and wait for user response” state and the user is given another try to give
correct information. Else we transition to the Algorithm state.
In the “Algorithm” state the AI uses the information given to it to formulate the next guess. This
algorithm will be discussed in depth later on. The “Algorithm” state always transitions to the
Guess and wait for response” state.
5
Fig. 2
As noted there is a lot of logic in the Algorithm state which is the bulk of the code. This created a
bug in our implementation on the FPGA board where our debouncer didn’t work half the time
and state machine skipped states half the time. Both these problems were related to tremendous
amount of logic implemented into these two modules. With help from the TA, we realized that
our clock was too fast and the logic it took to carry out operations was not fast enough to keep up
to finish before transitioning to the next state. This was simply fixed by slowing down to clock to
give the computer more time to “think” in each state.
Mastermind Solver’s Custom Algorithm
Deciding on an algorithm
At first we researched online for an algorithm we could use for this project. We discovered
several candidates. The most promising one, the Five-Guess Algorithm, can always solve the
code in five guesses or less. To do this, the algorithm requires maintaining a list of all 1296 (64)
possible solution codes, so that as each clue is received the codes that are incompatible with the
clue’s information can be struck off the list, leaving a reduced number of possible codes.
However, we wanted to make a new contribution instead of simply implementing someone else’s
algorithm. We did not attempt to design an algorithm that takes less guesses than the Five-Guess
6
Algorithm, since much professional research has already been done on that problem. Instead, we
chose to optimize a variable other than the number of guesses taken: the number of hardware
components needed to implement the solver on an FPGA. This idea came to us because the Five-
Guess Algorithm would need 1296 flip-flops right off the bat to record its possible-solutions list,
and that seemed like a large number that we had some chance of beating.
So the algorithm we came up with does not try to minimize the number of guesses taken to solve
the code. The only constraint we put on the algorithm regarding number of guesses was that it
must always win (use ten guesses or less). In fact, taking more guesses lets the algorithm’s logic
be “lazier”, using less hardware; decreased guess-efficiency can allow for increased hardware-
efficiency.
Structure of the algorithm
The first five guesses always made by Mastermind Solver are the following: 0000, 1111, 2222,
3333, 4444. The purpose of these guesses is to determine which numbers the solution code
contain, without yet finding their ordering. For example, if the user were to declare two matches
for the guess 0000, then the program knows that the solutions code contains two 0s. Mastermind
Solver always makes these first five guesses, even if all numbers contained in the code are found
before the fifth guess. We chose to have this guess-inefficiency for the purpose of greater
hardware-efficiency: checking after each guess for whether all numbers have been found would
require more hardware, probably muxes for if-statements.
At first we also had a sixth guess of 5555. This guess would have been “lazy”, because the
program can figure out the number of 5s in the code by process of elimination, without having to
use an additional guess. Having this lazy guess would have saved hardware. However, we had to
go with the logic-intensive method (process of elimination) instead, because at the time our
algorithm was requiring eleven guesses for some code sequences; we needed the algorithm to be
more efficient by one guess in order to always win.
At this point, the algorithm has greatly reduced the number of possible solutions. In the worst
case, when none of the code’s numbers are repeats, there are 24 (4!) remaining possibilities,
down from the original 1296 (64). Here is a table listing out all remaining possible forms of the
solution, depending on the form of repetition exhibited by the numbers found to be in the code.
(A, B, C, and D are variables containing distinct numbers.)
Repetition (form of the sixth guess)
AAAB AABB AABC ABCD
Remaining possible solution forms
AABA BBAA ABAB BCAA ACAB AACB BADC ADBC ABDC
ABAA BABA CBAA ABCA ACBA BCDA ACDB ADCB
BAAA ABBA CAAB ABAC BDAC DBAC ACBD
BAAB BACA CABA CADB CBDA DBCA
BAAC CDAB DACB CBAD
7
CDBA BDCA BACD
DABC CABD
DCAB BCAD
DCBA
The sixth guess is an arbitrary ordering of all the numbers that the program found to be contained
in the code during the previous guesses. For example, if one 0, one 3, one 4, and one 5 were
found to be in the code, then the sixth guess would be 5430. The clue provided by the user in
response to this sixth guess, specifically, the number of strong matches (i.e., how many numbers
in the guess are correct and in the correct location), is then used to narrow down the possible
solutions even more. In the worst case, 9 possible solutions remain.
Repetition (form of the sixth guess)
AAAB AABB AABC ABCD
Strong matches for sixth guess
2 0 2 0 1 2 0 1 2
Remaining possible solution forms
AABA BBAA ABAB BCAA ACAB AACB BADC ADBC ABDC
ABAA BABA CBAA ABCA ACBA BCDA ACDB ADCB
BAAA ABBA CAAB ABAC BDAC DBAC ACBD
BAAB BACA CABA CADB CBDA DBCA
BAAC CDAB DACB CBAD
CDBA BDCA BACD
DABC CABD
DCAB BCAD
DCBA
The logic to use from the seventh guess onwards depends on which column of the above table
the solution code belongs to. If the solution is somewhere in the five left-most columns, then the
algorithm simply iterates through the remaining solutions. This works because there are four
remaining guesses, and these columns have four or less remaining possibilities. Also, it is the
desirable method, even though it is not the most guess-efficient procedure: it is hardware-
efficient, because the program does not need to spend hardware on checking the user’s clues
after each guess.
Solving codes that fall into the four right-most columns requires logic that is smarter than dumb
iteration, since these columns have more possible solutions (five or more) than the number of
8
remaining guesses (four). Each of these four columns has its own sub-algorithm. Please refer to
the appendix if you are interested in the details.
Implementing the algorithm in Verilog
There were two challenges to implementing the algorithm in Verilog. The first was that Verilog
apparently does not support nested for-loops (there was always an error unless the nested for-
loops were removed). Fortunately we were only planning on using two sets of nested loops, and
these did not have large iteration intervals, so it was not too hard to explicitly write out each
iteration of the inner loops.
The second challenge was the question of how to fit the algorithm into the state machine – put it
all into one state, or spread it out over multiple states? We are still not sure which design would
result in less hardware used. We opted for the one-state design because that one was easier to
implement, but the other design might use less hardware because it might be able to do loops
more efficiently. If we had more time, we could have tried both designs and compared their
synthesis hardware usage reports.
Measures of Success
We have two primary goals for Mastermind Solver: that it always wins Mastermind, and that it
minimizes hardware usage. The first goal, at least, has been met. We made sure by simulating the
algorithm’s performance in all 1296 possible games, using a C++ program. (The C++ simulator
code can be found in the appendix.) It was a good thing we used the simulator, because it
revealed an error in our algorithm: the algorithm could not solve certain codes of the form
AABC, contrary to our expectations. We fixed that bug, and subsequent C++ simulations
indicated a flawless algorithm. We have also done several dozen tests on the FPGA to verify that
the algorithm was correctly translated into Verilog. In the appendix is a waveform depicting
several successful tests of the program.
As for the second goal, minimizing hardware usage, we cannot claim to have definitely
accomplished it, although there are reasons to believe we have. We did observe the Xilinx
hardware usage report for our custom-algorithm implementation, and it is encouraging. Only 265
flip-flops were needed, as compared to the 1296 expected to be the minimum number needed for
the Five-Guess Algorithm implementation. However, all of 524 muxes were needed for our
implementation, and that sounds large. (For the complete hardware report, see the appendix.)
Ideally we would have done a duplicate project in parallel that used the Five-Guess Algorithm,
and then compared the Xilinx hardware usage reports of the two.
9
Appendix: Algorithm Details
Sub-algorithm for AABC, with 2 strong matches
guess AEEE // where E is distinct from A, B, and C
if (0 strong matches for AEEE) {
guess BAAC
guess CABA
}
else {
// 1 strong match for AEEE
guess ABAC
guess ACBA
guess AACB
}
Sub-algorithm for ABCD, with 0 strong matches
guess BACD
if (0 strong matches for BACD) {
guess CDAB
if (0 strong matches for CDAB) {
guess DCBA
}
else {
guess DCAB
guess CDBA
}
}
else if (1 strong match for BACD) {
guess AACD
if (0 strong matches for AACD) {
guess BCCD
if (1 strong match for BCCD) {
guess BDAC
}
else {
// 2 strong matches for BCCD
guess BCDA
}
}
else {
// 1 strong match for AACD
guess CACD
if (1 strong match for CACD) {
guess DABC
}
10
else {
// 2 strong matches for CACD
guess CADB
}
}
}
else {
// 2 strong matches for BACD
guess BADC
}
Sub-algorithm for ABCD, with 1 strong match
guess ABEE // where E is distinct from A, B, C, and D
if (0 strong matches for ABEE) {
guess EECE
if (0 strong matches for EECE) {
guess CABD
guess BCAD
}
else {
// 1 strong match for EECE
guess DACB
guess BDCA
}
}
else {
// 1 strong match for ABEE
guess AEEE
if (0 strong matches for AEEE) {
guess DBAC
guess CBDA
}
else {
// 1 strong match for AEEE
guess ADBC
guess ACDB
}
}
Sub-algorithm for ABCD, with 2 strong matches
guess AEEE // where E is distinct from A, B, C, and D
if (0 strong matches for AEEE) {
guess BACD
guess CBAD
guess DBCA
11
}
else {
// 1 strong match for AEEE
guess ABDC
guess ACBD
guess ADCB
}
Appendix: Hardware Usage Report
Advanced HDL Synthesis Report
Macro Statistics
# Adders/Subtractors 14
2-bit adder 1
21-bit adder 1
3-bit adder 1
3-bit adder carry in 2
32-bit adder 4
4-bit adder 4
5-bit adder 1
# Counters 1
27-bit up counter 1
# Registers 265
Flip-Flops 265
# Comparators 44
3-bit comparator equal 10
32-bit comparator lessequal 20
4-bit comparator greater 6
4-bit comparator lessequal 8
# Multiplexers 524
1-bit 2-to-1 multiplexer 136
1-bit 4-to-1 multiplexer 6
12-bit 2-to-1 multiplexer 39
12-bit 4-to-1 multiplexer 2
2-bit 2-to-1 multiplexer 12
21-bit 2-to-1 multiplexer 1
3-bit 2-to-1 multiplexer 160
3-bit 4-to-1 multiplexer 4
32-bit 2-to-1 multiplexer 164
# FSMs 3
12
Appendix: Waveforms
Note: in the following three test games, the delay in transitioning between certain message-
displaying states (such as the Fatal Error state) has been abbreviated to make the waveform
layout friendlier.
13
14
15