Алгоритм оценки MasterMind в C # с использованием LINQ - PullRequest
18 голосов
/ 16 декабря 2010

Я ищу элегантный способ для вычисления оценки догадки в игре MasterMind на C #, предпочтительно с использованием LINQ.

В MasterMind создатель кода генерирует секретный код из 4 цифр, используя цифрыОт 1 до 6. Цифра может использоваться более одного раза.Например, секретный код:

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

Взломщик кода пытается взломать секретный код, выдвинув предположение.В этом примере предположение:

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

(и код, и предположение теперь хранятся в массиве, но с другими типами коллекций тоже все в порядке).

Затем создатель кода "забивает"это предположение, объявляя количество «черных» и «белых».За каждую цифру от догадки присваивается черный, который является правильным как по значению, так и по положениюБелый присуждается за каждую правильную цифру, помещенную в неправильную позицию.В этом примере оценка составляет 1 черный (для «1» в позиции 1) и 2 белых (для «1» и «2» в позициях 2 и 3).

Вернуться к вопросу:Я ищу элегантный способ вычислить оценку предположения в 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.Скорость выполнения на самом деле не проблема.

Ответы [ 3 ]

11 голосов
/ 16 декабря 2010
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
3 голосов
/ 16 декабря 2010

Вот один из способов (при условии, что я правильно понял проблему):

  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]); 
0 голосов
/ 16 декабря 2010

Ани ответ хороший. Вот более хороший (более ясный) способ сделать это группированием и объединением.

ILookup<int, int> 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...