correl.github.io/_posts/2015-04-18-birthday-puzzle.html
Correl Roush f1dda5c521 Birthday Puzzle
Change-Id: Iffd1dc71347b5fdc1d66806e209960dc2aaa4071
2015-04-18 16:52:21 -04:00

473 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Birthday Puzzle
author: Correl Roush
---
<p>
This logic puzzle has been floating around the internet lately. When I
caught wind of it, I thought it would be a great exercise to tackle
using Prolog. I'm not especially good with the language yet, so it
added to the challenge a bit, but it was a pretty worthwhile
undertaking. When I got stumped, I discovered that mapping out the
birthdays into a grid helped me visualize the problem and ultimately
solve it, so I've included that with my prolog code so you can see how
I arrived at the answer.
</p>
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1">The Puzzle</h2>
<div class="outline-text-2" id="text-1">
<p>
Albert and Bernard have just met Cheryl. “When is your birthday?”
Albert asked Cheryl. Cheryl thought for a moment and said, “I wont
tell you, but Ill give you some clues”. She wrote down a list of
ten dates:
</p>
<ul class="org-ul">
<li>May 15, May 16, May 19
</li>
<li>June 17, June 18
</li>
<li>July 14, July 16
</li>
<li>August 14, August 15, August 17
</li>
</ul>
<p>
“One of these is my birthday,” she said.
</p>
<p>
Cheryl whispered in Alberts ear the month, and only the month, of
her birthday. To Bernard, she whispered the day, and only the
day. “Can you figure it out now?” she asked Albert.
</p>
<p>
Albert: “I dont know when your birthday is, but I know Bernard
doesnt know, either.”
</p>
<p>
Bernard: “I didnt know originally, but now I do.”
</p>
<p>
Albert: “Well, now I know, too!”
</p>
<p>
<i>When is Cheryls birthday?</i>
</p>
</div>
</div>
<div id="outline-container-sec-2" class="outline-2">
<h2 id="sec-2">The Solution</h2>
<div class="outline-text-2" id="text-2">
</div><div id="outline-container-sec-2-1" class="outline-3">
<h3 id="sec-2-1">The Dates</h3>
<div class="outline-text-3" id="text-2-1">
<p>
To start off, i entered each of the possible birthdays as facts:
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">possible_birthday</span>(may, 15).
<span style="color: #268bd2;">possible_birthday</span>(may, 16).
<span style="color: #268bd2;">possible_birthday</span>(may, 19).
<span style="color: #268bd2;">possible_birthday</span>(june, 17).
<span style="color: #268bd2;">possible_birthday</span>(june, 18).
<span style="color: #268bd2;">possible_birthday</span>(july, 14).
<span style="color: #268bd2;">possible_birthday</span>(july, 16).
<span style="color: #268bd2;">possible_birthday</span>(august, 14).
<span style="color: #268bd2;">possible_birthday</span>(august, 15).
<span style="color: #268bd2;">possible_birthday</span>(august, 17).
</pre>
</div>
<p>
And here they are, mapped out in a grid:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="right" />
<col class="left" />
<col class="left" />
<col class="left" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">&#xa0;</th>
<th scope="col" class="left">May</th>
<th scope="col" class="left">June</th>
<th scope="col" class="left">July</th>
<th scope="col" class="left">August</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">14</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">15</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">16</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
</tr>
<tr>
<td class="right">17</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">18</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
</tr>
<tr>
<td class="right">19</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
<td class="left">&#xa0;</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-sec-2-2" class="outline-3">
<h3 id="sec-2-2">Albert's Statement</h3>
<div class="outline-text-3" id="text-2-2">
<blockquote>
<p>
I dont know when your birthday is,&#x2026;
</p>
</blockquote>
<p>
Albert only knows the month, and the month isn't enough to uniquely
identify Cheryl's birthday.
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">month_is_not_unique</span>(<span style="color: #268bd2;">M</span>) :-
bagof(<span style="color: #268bd2;">D</span>, possible_birthday(<span style="color: #268bd2;">M</span>, <span style="color: #268bd2;">D</span>), <span style="color: #268bd2;">Days</span>),
length(<span style="color: #268bd2;">Days</span>, <span style="color: #268bd2;">Len</span>),
<span style="color: #268bd2;">Len</span> &gt; 1.
</pre>
</div>
<blockquote>
<p>
&#x2026; but I know Bernard doesnt know, either.
</p>
</blockquote>
<p>
Albert knows that Bernard doesn't know Cheryl's
birthday. Therefore, the day alone isn't enough to know Cheryl's
birthday, and we can infer that the month of Cheryl's birthday does
not include any of the unique dates.
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">day_is_not_unique</span>(<span style="color: #268bd2;">D</span>) :-
bagof(<span style="color: #268bd2;">M</span>, possible_birthday(<span style="color: #268bd2;">M</span>, <span style="color: #268bd2;">D</span>), <span style="color: #268bd2;">Months</span>),
length(<span style="color: #268bd2;">Months</span>, <span style="color: #268bd2;">Len</span>),
<span style="color: #268bd2;">Len</span> &gt; 1.
<span style="color: #268bd2;">month_has_no_unique_days</span>(<span style="color: #268bd2;">M</span>) :-
forall(possible_birthday(<span style="color: #268bd2;">M</span>,<span style="color: #268bd2;">D</span>),
day_is_not_unique(<span style="color: #268bd2;">D</span>)).
</pre>
</div>
<p>
Based on what Albert knows at this point, let's see how we've
reduced the possible dates:
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">part_one</span>(<span style="color: #268bd2;">M</span>,<span style="color: #268bd2;">D</span>) :-
possible_birthday(<span style="color: #268bd2;">M</span>,<span style="color: #268bd2;">D</span>),
month_is_not_unique(<span style="color: #268bd2;">M</span>),
month_has_no_unique_days(<span style="color: #268bd2;">M</span>),
day_is_not_unique(<span style="color: #268bd2;">D</span>).
</pre>
</div>
<pre class="example">
Results = [ (july, 14), (july, 16), (august, 14), (august, 15), (august, 17)].
</pre>
<p>
So the unique days (the 18th and 19th) are out, as are the months
that contained them (May and June).
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="right" />
<col class="left" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">&#xa0;</th>
<th scope="col" class="left">July</th>
<th scope="col" class="left">August</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">14</td>
<td class="left">X</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">15</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">16</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
</tr>
<tr>
<td class="right">17</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-sec-2-3" class="outline-3">
<h3 id="sec-2-3">Bernard's Statement</h3>
<div class="outline-text-3" id="text-2-3">
<blockquote>
<p>
I didnt know originally, but now I do.
</p>
</blockquote>
<p>
For Bernard to know Cheryl's birthday, the day he knows must be
unique within the constraints we have so far.
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">day_is_unique</span>(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>) :-
findall(<span style="color: #268bd2;">M</span>, part_one(<span style="color: #268bd2;">M</span>, <span style="color: #268bd2;">Day</span>), <span style="color: #859900; font-weight: bold;">[</span><span style="color: #268bd2;">Month</span><span style="color: #859900; font-weight: bold;">]</span>).
<span style="color: #268bd2;">part_two</span>(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>) :-
possible_birthday(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>),
day_is_unique(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>).
</pre>
</div>
<pre class="example">
Results = [ (july, 16), (august, 15), (august, 17)].
</pre>
<p>
Both July and August contain the 14th, so that row is out.
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="right" />
<col class="left" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">&#xa0;</th>
<th scope="col" class="left">July</th>
<th scope="col" class="left">August</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">15</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">16</td>
<td class="left">X</td>
<td class="left">&#xa0;</td>
</tr>
<tr>
<td class="right">17</td>
<td class="left">&#xa0;</td>
<td class="left">X</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-sec-2-4" class="outline-3">
<h3 id="sec-2-4">Albert's Second Statement</h3>
<div class="outline-text-3" id="text-2-4">
<blockquote>
<p>
Well, now I know, too!
</p>
</blockquote>
<p>
Albert's month must be the remaining unique month:
</p>
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">month_is_not_unique</span>(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>) :-
findall(<span style="color: #268bd2;">D</span>, part_two(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">D</span>), <span style="color: #859900; font-weight: bold;">[</span><span style="color: #268bd2;">Day</span><span style="color: #859900; font-weight: bold;">]</span>).
<span style="color: #268bd2;">part_three</span>(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>) :-
possible_birthday(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>),
month_is_not_unique(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>).
</pre>
</div>
<pre class="example">
Results = [ (july, 16)].
</pre>
<p>
August had two possible days, so it's now clear that the only
possible unique answer is July 16th.
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="right" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">&#xa0;</th>
<th scope="col" class="left">July</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">15</td>
<td class="left">&#xa0;</td>
</tr>
<tr>
<td class="right">16</td>
<td class="left">X</td>
</tr>
<tr>
<td class="right">17</td>
<td class="left">&#xa0;</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-sec-2-5" class="outline-3">
<h3 id="sec-2-5">Cheryl's Birthday</h3>
<div class="outline-text-3" id="text-2-5">
<div class="org-src-container">
<pre class="src src-prolog"><span style="color: #268bd2;">cheryls_birthday</span>(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>) :-
part_three(<span style="color: #268bd2;">Month</span>, <span style="color: #268bd2;">Day</span>).
</pre>
</div>
<pre class="example">
Month = july,
Day = 16.
</pre>
<p>
So, there we have it. Cheryl's birthday is July 16th!
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="right" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="right">&#xa0;</th>
<th scope="col" class="left">July</th>
</tr>
</thead>
<tbody>
<tr>
<td class="right">16</td>
<td class="left">X</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>