Hello again! In this video, we are going to have a practical based on the "Mastermind(TM)" game.
This is a board game from the 1970s.
As you can probably guess from the rather dated photo.
This was really popular - or, well, so my parents tell me :) It is a board game for two players.
There are lots of coloured pegs which go in these holes, and some small, black and white pegs which
go in these holes.
The idea is that one of the players takes some pegs and makes a secret code, which is hidden behind
this block.
And then the second player tries to guess the code by putting coloured pegs in these holes.
The first player will put black and white pegs in these holes at the sides, which will tell them how
close they were.
So this is what it looks like from the first player's point of view. Here is the secret code.
The second player wins if he guesses the secret code. So all the correct coloured pegs in the correct holes.
So this is where the second player won the game.
If they get all the way to here and they have not guessed it, then they lose and the first player wins.
The pegs at the side depend on how close the guess is. If there is the right colour in the right hole,
then you get a black peg at the side.
If there is the right colour in the wrong hole, then you get a white peg.
And if you have the wrong colour, then you get nothing at all.
So, for example, there is no yellow in the solution, so there is an empty peg on the right. In this
one, all the coloured pegs are in the right holes.
So there are four black pegs and the first player wins.
In the previous attempts, they had all the colours right.
But only one peg was in the write hole, so they had one black peg and three right pegs.
We are going to make a simple command-line game based on this. The actual game is rather complicated and
there are lots of colours.
So we are just going to use three colours: red, green and blue. So the computer is going to generate
a secret code from those characters.
The user will enter their guess at the code, and the computer will tell them how many exact matches
they got.
So the right character in the right position. And the number of near misses or loose matches, so they
have the right character but in the wrong position. And this will continue until the user guesses right.
Or they run out of turns.
So it will look like this. We get prompted, telling us what to do. So enter four characters which can be red
green or blue.
So let's try 4 reds. One exact match and zero near misses.
So we have one peg in the right colour.
So we have one red.
Let's try 4 greens.
So we have zero exact matches and zero near matches, so there are no greens in the solution at
all.
So the others must be three blues.
Yep, three exact matches.
So we know there is one red and three blues, but we need to work out what order they are in.
So let's try red at the front. And we get 2 exact matches and 2 near matches.
So the four colours are correct, but two of them are in the wrong place.
So let's try swapping them round. And there we are. So, four exact matches and we have won!
So the program logic is going to be like this. We are going to generate the secret code, then we are
going to read the user's input. Then we are going to convert it to a normal form to make the processing
a bit simpler.
So we convert it to alphabetical only, and uppercase.
We find the number of exact matches - the right character in the right place - and the number of loose matches.
The right character in the wrong place.
And then we display that to the user and we ask them for their next guess.
And we carry on doing this until there four exact matches, or the user runs out of turns.
So here is our main function.
So this is going to generate the secret code.
Or, if you are testing, you can
hard-code it.
We have a flag to keep track of whether the user has won
yet. Or should that be lost
yet? We loop over the allowed number of turns.
We process the input from the player.
We get the number of exact and loose matches.
And the way that I have calculated the loose matches will also include the number of exact matches.
So we need to subtract that, to avoid double counting.
Then we display that.
And if the users got it right, then we congratulate them.
And if they run out of turns, we commiserate.
When I am writing a game, I like to have a file which contains all the parameters for the game, in their
own namespace.
You could also use a namespace for the rest of the program, if you like.
I have not bothered here, but perhaps I should. So we have four pegs in the code.
The user is allowed a maximum of 10 guesses, and there are three colours in the combination.
Then we create a couple of types which are going to be useful.
So these are library arrays with the right number of elements, so we can never have an out-of-bounds
error.
We have one for the peg arrays.
So that is going to be the secret code and the user's guesses. And another one for the potential colours,
the allowed colours.
And then, in our constants namespace, we created an array
of these allowed colours.
To generate the code, we have one of these peg arrays, which we are going to populate.
We use the generate() algorithm, so this will populate each element in the array with the return value
from this callable object.
This lambda expression is going to pick a colour at random from the allowed colours.
So we need to have a random number engine and a uniform distribution. And we need to make the distribution
produce a number which can be a valid index.
So it is between zero and the number of colours, minus one.
We need to capture by reference, because we are going to modify the engine and the distribution. I have
used the capture-all, but you can use separate capture statements if you like.
For validating the input, we use get_line(). We print some prompts to the user, to tell them
what to do. And then we call our normalize() function.
So you have seen this before.
This uses copy_if(), so it only keeps characters, which are letters of the alphabet. Then
it does a transform() to convert everything to uppercase, and then it returns the normalized string.
If the user enters the wrong number of characters, then we prompt them to do it again.
Obviously, you could make this a bit more robust! And then we have to copy the result into the peg array.
And we have to use a loop here, because there is a string on the right hand side and a library array on the
left hand side, and they do not convert.
Unfortunately.
Then we need to work out how to do these matches.
To find the number of exact matches. So this is where the colour of the peg in the user's guess matches the
colour of the same peg in the solution.
We are going to write to a temporary object. If they do match, then we write the colour.
Otherwise we write 0. And then we return the number of non-zero elements in this temporary object.
So this exact_matches() function, it takes two arguments: the user's guess and the actual solution.
We have this temporary object we are going to populate. And then we use transform() to compare the elements
from these two arguments, and write the results to a third array.
If the corresponding elements are the same, then we write that elements to this array, otherwise
we write 0. And then we use count_if() to find how many elements in this array are non-zero. And then
for the loose matches, we make a back-up of the user's
guess. Then we iterate over each peg in the solution, and we look for a peg in the user's guess which
has the same colour.
And if we find one, we increment a counter, and then we erase that element from the user's guess.
So that is why we are working with a backup, because we need to erase elements.
And then, at the end, we return the value of this counter.
So this will give us all the elements for which the user has guessed the colour which is somewhere
in the solution.
This will also include pegs which are in the correct place, which are the exact matches, so we need
to subtract the number of exact matches to get the correct answer.
So here is our loose_matches() function again, with the same arguments.
We have this backup string and our counter.
We make a copy of the user's guess into our backup string, and then we iterate over all the elements
of the solution.
We look for an element in the user's guess which has the same colour as the colour we are looking at at the
moment.
If we find one, we increment our counter and then we remove the element from the array.
Now, when you see iterators being erased inside a loop, you should get a bit suspicious.
In this case, it's safe because we are erasing elements from this copy guess array, and the loop is
looping over the colour array, which is a different array.
So there is no possibility that
any of the operators in this container could become invalidated.
And then finally, we return our counter.
Okay, so that is it.
So as I said, one thing you can do is to improve the error checking for the input processing.
Another thing you could do is to look up the complete rules of Mastermind, because they are quite a bit
more complex.
There is eight colours, I think, and not just three.
And if you really fancy getting busy, you could write a graphical version which will look much nicer!
But this is enough to get started.
Okay, so that is it for this video.
I will see you next time.
But until then, keep coding!