% Cheryl's Birthday % ==================================================== % Albert and Bernard have just met Cheryl. 'When is your birthday?' % Albert asked Cheryl. Cheryl thought for a moment and said, 'I won't % tell you, but I'll give you some clues'. She wrote down a list of ten % dates: % May 15, May 16, May 19 % June 17, June 18 % July 14, July 16 % August 14, August 15, August 17 % 'One of these is my birthday,' she said. % Cheryl whispered in Albert's 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. % Albert: 'I don't know when your birthday is, but I know Bernard % doesn't know, either.' % Bernard: 'I didn't know originally, but now I do.' % Albert: 'Well, now I know, too!' % When is Cheryl's birthday? dates([may/15, may/16, may/19, june/17, june/18, july/14, july/16, aug/14, aug/15, aug/17]). months(Months) :- dates(Dates), setof(M, D^member(M/D, Dates), Months). days(Days) :- dates(Dates), setof(D, M^member(M/D, Dates), Days). daysIn(Month, Days) :- dates(Dates), findall(D, member(Month/D, Dates), Days). monthsWith(Day, Months) :- dates(Dates), findall(M, member(M/Day, Dates), Months). % Albert: I don't know s1a(Day, Month) :- % soluția este o dată zi-lună dates(Dates), member(Month/Day, Dates), % din mulțimea de date daysIn(Month, [_, _|_]). % în care luna are mai multe zile candidați % Albert: Bernard doesn't know s1b(Day, Month) :- % soluția este o dată zi-lună s1a(Day, Month), % care respectă prima afirmație daysIn(Month, Days), % și dintre zilele candidați din luna respectivă findall(D, % nu există nicio zi D ( member(D, Days), % dintre zilele din luna datei monthsWith(D, [_]) % care să indice unic o anumită luna ), []). % (nicio soluție) % Bernard: now I know s2(Day, Month) :- % soluția este o dată zi-lună s1b(Day, Month), % care respectă afirmațiile de mai sus monthsWith(Day, Ms), % și dintre lunile care conțin ziua respectivă findall(M, % există o singură lună ( member(M, Ms), % dintre lunile care conțin ziua s1b(Day, M)), % care respectă afirmațiile de mai sus [_]). % (o singură soluție) % Albert: now I know too s3(Day, Month) :- % soluția este o dată zi-lună s2(Day, Month), % care respectă afirmațiile de mai sus daysIn(Month, Days), % și dintre zilele din luna respectivă findall(D, % există o singură zi ( member(D, Days), % dintre zilele din lună s2(D, Month)), % care respectă afirmațiile de mai sus [_]). % (o singură soluție) sol(Month/Day) :- s3(Day, Month), !. % soluția este o dată care respectă toate afirmațiile % soluție care lucreză explicit pe lista de date disponibile % daysIn(+Dates, +Month, -Days) % zilele candidați din luna Month, considerând numai datele din Dates daysIn2(Dates, Month, Days) :- findall(Day, member(Month/Day, Dates), Days). % monthsWith(+Dates, +Day, -Months) % lunile conținând ziua Day, considerând numai datele din Dates monthsWith2(Dates, Day, Months) :- findall(Month, member(Month/Day, Dates), Months). % luna nu conține zile care sunt unice în problemă s1_non_unique_days_months(Dates, DatesOut) :- % găsim toate datele findall(Date, ( % în lista de date member(Date, Dates), Date = Month/_, % pentru care nu există soluție \+ ( % la a găsi o zi daysIn2(Dates, Month, Days), member(Day, Days), % care apare într-o singură lună printre datele date monthsWith2(Dates, Day, [_])) ), DatesOut). % în datele care au rămas, selectăm doar pe cele în care ziua este unică s2_unique_day(Dates, DatesOut) :- % găsim toate datele findall(Date, ( % în lista de date member(Date, Dates), Date = _/Day, % pentru care ziua indică unic data monthsWith2(Dates, Day, [_]) ), DatesOut). % în datele care au rămas, selectăm doar pe cele în care luna este unică s3_unique_month(Dates, DatesOut) :- % găsim toate datele findall(Date, ( % în lista de date member(Date, Dates), Date = Month/_, % pentru care luna indică unic data daysIn2(Dates, Month, [_]) ), DatesOut). % soluția este o dată din lista de date sol2(Date) :- dates(Dates), % pentru care cele 3 afirmații sunt adevărate s1_non_unique_days_months(Dates, Dates1), s2_unique_day(Dates1, Dates2), s3_unique_month(Dates2, Dates3), % știm că soluția este unică, și data căutată % este singurul membru rămas în lista de date Dates3 = [Date].