The The Hardest Logic Puzzle Ever recently came to my attention:
Three gods A, B, and C are called, in no particular order, True, False, and Random. True always speaks truly, False always speaks falsely, but whether Random speaks truly or falsely is a completely random matter. Your task is to determine the identities of A, B, and C by asking three yes-no questions; each question must be put to exactly one god. The gods understand English, but will answer all questions in their own language, in which the words for yes and no are da and ja, in some order. You do not know which word means which.
Furthermore, a single god may be asked more than one question, questions are permitted to depend on the answers to earlier questions, and the nature of Random's response should be thought of as depending on the flip of a fair coin hidden in his brain: if the coin comes down heads, he speaks truly; if tails, falsely.
I quickly wrote a Python solution. The code is meant to be mostly PEP8 compliant but was not intended to be very formal — just a straight port from word problem to program. If there is a problem, the program should immediately crash to prevent undiscovered bugs.
Given that the code shown below was meant to simply test the ideas provided in the solution for the puzzle, would it be best to rewrite the program and clean it up if code quality is to be improved without having regards for how the problem and its solution reads?
#! /usr/bin/env python3
# Reference: https://en.wikipedia.org/wiki/The_Hardest_Logic_Puzzle_Ever
from random import choice, sample
def question_1(god):
if god == 'Random':
return choice((yes, no))
truth = a == 'Random' # part 1
if god == 'True':
answer = yes if truth else no
elif god == 'False':
answer = no if truth else yes
truth = answer == 'ja' # part 2
if god == 'True':
return yes if truth else no
elif god == 'False':
return no if truth else yes
def question_2(god):
if god == 'Random':
return choice((yes, no))
truth = god == 'False' # part 1
if god == 'True':
answer = yes if truth else no
elif god == 'False':
answer = no if truth else yes
truth = answer == 'ja' # part 2
if god == 'True':
return yes if truth else no
elif god == 'False':
return no if truth else yes
def question_3(god):
if god == 'Random':
return choice((yes, no))
truth = b == 'Random' # part 1
if god == 'True':
answer = yes if truth else no
elif god == 'False':
answer = no if truth else yes
truth = answer == 'ja' # part 2
if god == 'True':
return yes if truth else no
elif god == 'False':
return no if truth else yes
for _ in range(10000):
# setup
a, b, c = sample(('True', 'False', 'Random'), 3)
da, ja = sample(('yes', 'no'), 2)
temp = {y: x for x, y in globals().items() if isinstance(y, str)}
yes, no = temp['yes'], temp['no']
del temp
# question
answer = question_1(b)
if answer == 'ja':
not_random = 'c'
elif answer == 'da':
not_random = 'a'
answer = question_2(globals()[not_random])
if answer == 'da':
not_random_id = 'True'
elif answer == 'ja':
not_random_id = 'False'
answer = question_3(globals()[not_random])
if answer == 'ja':
b_id = 'Random'
elif answer == 'da':
if not_random != 'a':
a_id = 'Random'
elif not_random != 'c':
c_id = 'Random'
# decide
if not_random == 'a':
a_id = not_random_id
elif not_random == 'c':
c_id = not_random_id
try:
a_id
except NameError:
a_id = ({'True', 'False', 'Random'} - {b_id, c_id}).pop()
else:
try:
b_id
except NameError:
b_id = ({'True', 'False', 'Random'} - {a_id, c_id}).pop()
else:
try:
c_id
except NameError:
c_id = ({'True', 'False', 'Random'} - {a_id, b_id}).pop()
# verify
try:
assert (a, b, c) == (a_id, b_id, c_id)
except AssertionError:
print(f'a, b, c = {a!r}, {b!r}, {c!r}')
print(f'a_id, b_id, c_id = {a_id!r}, {b_id!r}, {c_id!r}')
raise
else:
del a, b, c, da, ja, yes, no, \
answer, not_random, not_random_id, \
a_id, b_id, c_id
yes
andno
are used to make the code readable while leaving the meaning of "da" and "ja" as ambiguous. \$\endgroup\$not_random
on lines 61 and 63: the purpose of not assigningc
ora
directly is to avoid gaining any knowledge that has not been earned yet. By using an indirect reference and then having to pull the value out ofglobals()
, the true identity of god A or god C is not stolen and cannot be used accidently without merit. \$\endgroup\$question_1
,question_2
, andquestion_3
? \$\endgroup\$# part 1
of the question is always different. Each question function is meant to evaluate the related question as defined in the riddle. \$\endgroup\$# part 1
into a function. \$\endgroup\$