Question

I am currently working on a project which is a Mastermind Game created in Windows Forms.

After each time the player makes a guess where he put up what he thinks might be the correct colour order, he will get to know how many of his pins which were right colour on the right place, and right colour but on the wrong place.

I asked a mate who is far more experienced with programming for some help, and he gave me this:

/* RightCRightP is the variable for how many pins which are right colour and on right
                place. 
   RightCWrongP is the variable for how many pins which are right colour but on wrong
                place.
   guessList    is a list including the players guesses.
   answerList   is a list including the right answer ( right order ).
*/
//His code
var RightCRightP = guessList
        .Zip(answerList, (g, s) => g == s)
        .Count(z => z);

var RightCWrongP = guessList
        .Intersect(answerList)
        .Sum(c =>
            System.Math.Min(
                answerList.Count(x => x == c),
                guessList.Count(x => x == c))) - RightCRightP;

The thing is, I want to learn what each thing in this code does. Sadly I can't ask him personally because he is currently on vacation.

Was it helpful?

Solution

The data we will use will be

guesses = [1,2,0,3]
answers = [1,2,3,4]

First Expression

guessList.Zip(answerList, (g, s) => g == s)

The Zip extension 'zips' two list by performing the supplied lambda operation on each corresponding element between guessList and answerList, and returns a collection of the results.

Zip essentialy yields

 [f(guesses[0], answers[0]), f(guesses[1],
 answers[1]), f(guesses[2], answers[2]), f(guesses[3],answers[3])] 

where function f is the lambda function supplied:

f(g,s) => g == s

The result is [true,true, false, false]

We then take

.Count(z => z) 

of the result of the Zip method, which counts the number of elements in the zipresult that are true.

(read this as .Count(z => z != false) if it helps)

Thus, the Count is 2 because we have two elements that are true. So our RightCRightP is 2. Checking our input this is what we expected, because our first two guesses are the right color and placement, but the last two are not.

Second Expression

guessList.Intersect(answerList) 

Quoting http://www.dotnetperls.com/intersect Intersect applies set theory. In set theory, an intersection is the subset of each collection that is found in both collections. In a nutshell it yields a set of items that exist in both lists. Remember that set elements are distinct.

So from our above guesses and answers, intersection of [1,2,0,3] and [1,2,3,4] will yield [1,2,3] ( notice how 3 is included here but its not in the right place! )

We then apply the Sum operation of the result of the intersect. Sum will iterate through each element and find the sum of the results yielded by the supplied lambda expression. The purpose of this intersect operation is to gives us a list of correctly guessed colors irregardless of correct placement.

Our lambda is

c => Min(answerList.Count(x => x == c), guessList.Count(x => x == c))

We count the number of values in answerList and guessList that are equal to color c, and take the smaller of the two. This sum operation gives us the number of items correctly guessed colors irregardless of correct placement. So iterating through the Intersection result of [1,2,3], the lambda will return the value 1 for all iterations, so the Sum will be 1 + 1 + 1 = 3. This is our count of correctly guessed colors.

Since we now have the Number of correct colors, we can deduce the number of correct colors with wrong placement by subtracting the number of right colors with right placements.

RightCWrongP = 3 - 2 => 1.

Checking our inputs guesses = [ 1, 2, 0, 3 ] and answers = [ 1, 2, 3, 4]

RightColorWrongP is 1 like we expected because our guess of colorvalue 3 is a correct color but not in the right place.

P.S. If anything I said is wrong, please let me know in the comments and don't just downvote, I am not a LINQ or C# wizard.

OTHER TIPS

What you see is Linq code. I will explain the first line for now to allow you to try and understand the second one on your own.

var RightCRightP = guessList
        .Zip(answerList, (g, s) => g == s)
        .Count(z => z);

This line basically takes both lists (guesslist and answerlist) and compares each answer (g == s) and counts the identical ones.

For example, if guessList is {1, 2, 3, 4, 5} and answerlist is {1, 2, 4, 5, 3} then "RightCRightP" would be 2. (1 == 1, 2 == 2 but 3 != 4, 4 != 5, 3 != 5)

Adding to my answer for completeness:

The following code:

    List<int> guessList = new List<int>() { 1, 2, 3, 4, 5 };
    List<int> answerList = new List<int>() { 1, 2, 4, 5, 3 };

    List<bool> zipList = guessList.Zip(answerList, (g, s) => g == s).ToList<bool>();

    Console.WriteLine("Content of 'zipList': ");
    foreach (bool b in zipList) { Console.WriteLine(b); }

    int RightCRightP = zipList.Count(z => z);

    Console.WriteLine("Number of matches in 'RightCRightP': " + RightCRightP);

Outputs:

Content of 'zipList':
True
True
False
False
False
Number of matches in 'RightCRightP': 2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top