使用LINQ在C#中使用MasterMind评分算法

我正在寻找一种优雅的方法来计算C#中MasterMind游戏的猜测得分,最好是使用LINQ。

在MasterMind中,代码生成器使用数字1到6生成4位数的密码。可以多次使用数字。 例如,密码是:

int[] secret = { 1, 2, 3, 1 }; 

代码破解者试图通过猜测来破解密码。 在这个例子中,猜测是:

 int[] guess = { 1, 1, 2, 2 }; 

(代码和猜测现在都存储在一个数组中,但其他集合类型也可以)。

然后,代码制作者通过宣布“黑人”和“白人”的数量来“评分”这个猜测。 从猜测的每个数字中获得黑色,其在值和位置都是正确的。 对于放置在错误位置的每个正确数字,将获得白色。 在该示例中,得分为1黑色(对于位置1中的“1”)和2个白色(对于位置2和3中的“1”和“2”)。

回到问题:我正在寻找一种优雅的方法来计算C#中的猜测分数,最好使用LINQ。 到目前为止,我已经提出了一个计算黑人数量的声明:

 int blacks = new int[] { 0, 1, 2, 3 }.Count(i => (guess[i] == secret[i])); 

我打算继续说明白人数是总匹配数(3)减去黑人数。 所以我尝试过:

 int whites = guess.Intersect(secret).Count() - blacks; 

但是,唉,IEnumerable.Intersect()产生{1,2}而不是{1,1,2},因为它只查看不同的数字。 所以它计算白色= 1而不是2。

除了使用“C”样式的嵌套循环之外,我无法想出另一种计算“白人”的方法。 你能? 最好使用LINQ – 我喜欢使用LINQ在代码中表示算法的方式。 执行速度不是真正的问题。

 var black = guess .Zip(secret, (g, s) => g == s) .Count(z => z); var white = guess .Intersect(secret) .Sum(c => System.Math.Min( secret.Count(x => x == c), guess.Count(x => x == c))) - black; 

鉴于:

 int[] secret = { 1, 2, 3, 1 }; int[] guess = { 1, 1, 2, 2 }; 

然后:

 black == 1 && white == 2 

这是一种方式(假设我已正确理解问题):

  1. 找到黑色分数 – 这很容易; 它只是压缩序列并计算匹配的相应元素的数量。

  2. 找出两个序列之间“共同元素”的数量 – 这必须是白色和黑色分数的总和。

  3. 找到白色分数 – 只需2.和1之间的差异。


 // There must be a nicer way of doing this bit int blackPlusWhite = secret.GroupBy(sNum => sNum) .Join(guess.GroupBy(gNum => gNum), g => g.Key, g => g.Key, (g1, g2) => Math.Min(g1.Count(), g2.Count())) .Sum(); int black = guess.Zip(secret, (gNum, sNum) => gNum == sNum) .Count(correct => correct); int white = blackPlusWhite - black; 

编辑:混合黑色和白色。

编辑:( OP不在.NET 4上)在.NET 3.5中,您可以使用以下方法计算黑色:

 int black = Enumerable.Range(0, secret.Count) .Count(i => secret[i] == guess[i]); 

Ani的答案很好。 这是一种更好(更清晰)的方式来进行分组和加入。

 ILookup guessLookup = guess.ToLookup(i => i); int blackPlusWhite ( from secretNumber in secret.GroupBy(i => i) let secretCount = secretNumber.Count() let guessCount = guessLookup[secretNumber.Key].Count() select Math.Min(secretCount, guessCount) ).Sum() int black = Enumerable.Range(0, secret.Count).Count(i => guess[i] == secret[i]); int white = blackPlusWhite - black;