Skip to content

Instantly share code, notes, and snippets.

@handcraftsman
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save handcraftsman/71feb1ce3e3b4e5b0261 to your computer and use it in GitHub Desktop.
Save handcraftsman/71feb1ce3e3b4e5b0261 to your computer and use it in GitHub Desktop.
Determining Cheryl's birthday logically with LINQ
// 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