Last active
August 29, 2015 14:19
-
-
Save handcraftsman/71feb1ce3e3b4e5b0261 to your computer and use it in GitHub Desktop.
Determining Cheryl's birthday logically with LINQ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// for the problem description see: http://www.cnn.com/2015/04/15/living/feat-cheryl-birthday-math-problem-goes-viral/ | |
public class Birthday | |
{ | |
public Birthday(string monthName, int dayOfMonth) | |
{ | |
MonthName = monthName; | |
DayOfMonth = dayOfMonth; | |
} | |
public override string ToString() | |
{ | |
return MonthName + " " + DayOfMonth; | |
} | |
public int DayOfMonth { get; private set; } | |
public string MonthName { get; private set; } | |
} | |
[TestFixture] | |
public class CherylsBirthdayProblem | |
{ | |
[Test] | |
public void Should_be_able_to_determine_Cheryls_birthday_logically() | |
{ | |
var potentialDates = new[] | |
{ | |
new Birthday("May", 15), | |
new Birthday("May", 16), | |
new Birthday("May", 19), | |
new Birthday("June", 17), | |
new Birthday("June", 18), | |
new Birthday("July", 14), | |
new Birthday("July", 16), | |
new Birthday("August", 14), | |
new Birthday("August", 15), | |
new Birthday("August", 17), | |
}; | |
var afterStatement1 = AlbertDoesNotKnowAndKnowsThatBernardDoesNotKnowEither(potentialDates); | |
var afterStatement2 = BernardNowKnows(afterStatement1); | |
var afterStatement3 = AlbertAlsoKnows(afterStatement2); | |
var result = afterStatement3.Single(); | |
if (result.ToString() != "July 16") | |
{ | |
Assert.Fail("Incorrect result: " + result); | |
} | |
Console.WriteLine("Cheryl's birthday is " + result); | |
} | |
public IEnumerable<Birthday> AlbertDoesNotKnowAndKnowsThatBernardDoesNotKnowEither(IEnumerable<Birthday> birthdays) | |
{ | |
// Albert doesn't know the date | |
// => the month he knows has multiple dates | |
// Albert knows that Bernard does not know | |
// => the month he knows doesn't have any unique day-of-month values | |
// otherwise there would be the potential that Bernard could know. | |
// so eliminate all months where ANY day-of-month is unique across the set | |
var matches = birthdays | |
.GroupBy(x => x.DayOfMonth) | |
.SelectMany(x => | |
{ | |
var isUnique = !x.Skip(1).Any(); | |
return x.Select(y => new | |
{ | |
IsUniqueDayOfMonth = isUnique, | |
Birthday = y | |
}); | |
}) | |
.GroupBy(x => x.Birthday.MonthName) | |
.Where(x => x.All(y => !y.IsUniqueDayOfMonth)) | |
.SelectMany(x => x) | |
.Select(x => x.Birthday); | |
return matches; | |
} | |
public IEnumerable<Birthday> BernardNowKnows(IEnumerable<Birthday> birthdays) | |
{ | |
// Bernard didn't know originally but, because of Albert's statement, now he does | |
// => the day-of-month Bernard knows is now unique | |
// so, eliminate all birthdays where the day-of-month is not unique | |
return birthdays | |
.GroupBy(x => x.DayOfMonth) | |
.Where(x => !x.Skip(1).Any()) | |
.SelectMany(x => x); | |
} | |
public IEnumerable<Birthday> AlbertAlsoKnows(IEnumerable<Birthday> birthdays) | |
{ | |
// Albert didn't know originally but, because of Bernard's statement, now he does | |
// => the month Bernard knows is now unique | |
// so, eliminate all birthdays where the month is not unique | |
return birthdays | |
.GroupBy(x => x.MonthName) | |
.Where(x => !x.Skip(1).Any()) | |
.SelectMany(x => x); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment