def solve_marple_logic(clues):
letters = "ABCDEFGHIJKLMNOPQRST"
poss = {letter: set(range(5)) for letter in letters}
rows = [
list("ABCDE"),
list("FGHIJ"),
list("KLMNO"),
list("PQRST")
]
def update_same_col(a, b):
common = poss[a] & poss[b]
if not common:
raise ValueError(f"Contradiction: {a} and {b} cannot be in the same column")
changed = False
if poss[a] != common:
poss[a] = common
changed = True
if poss[b] != common:
poss[b] = common
changed = True
return changed
def update_left_of(a, b):
max_b = max(poss[b])
new_a = {col for col in poss[a] if col < max_b}
if not new_a:
raise ValueError(f"Contradiction: {a} cannot be left of {b}")
changed = False
if new_a != poss[a]:
poss[a] = new_a
changed = True
min_a = min(poss[a])
new_b = {col for col in poss[b] if col > min_a}
if not new_b:
raise ValueError(f"Contradiction: {b} cannot be right of {a}")
if new_b != poss[b]:
poss[b] = new_b
changed = True
return changed
def update_next_to(a, b):
new_a = set()
for ca in poss[a]:
if any(abs(ca - cb) == 1 for cb in poss[b]):
new_a.add(ca)
if not new_a:
raise ValueError(f"Contradiction: {a} and {b} are not next to each other")
changed = False
if new_a != poss[a]:
poss[a] = new_a
changed = True
new_b = set()
for cb in poss[b]:
if any(abs(ca - cb) == 1 for ca in poss[a]):
new_b.add(cb)
if not new_b:
raise ValueError(f"Contradiction: {b} and {a} are not next to each other")
if new_b != poss[b]:
poss[b] = new_b
changed = True
return changed
def update_between(A, B, C):
new_B = set()
for b in poss[B]:
found = False
for a in poss[A]:
for c in poss[C]:
if (a < b < c) or (c < b < a):
found = True
break
if found:
break
if found:
new_B.add(b)
if not new_B:
raise ValueError(f"Contradiction: {B} is not between {A} and {C}")
print(new_B)
changed = False
if new_B != poss[B]:
print("bbb", poss[B])
poss[B] = new_B
changed = True
new_A = set()
for a in poss[A]:
found = False
for b in poss[B]:
for c in poss[C]:
if (a < b < c) or (c < b < a):
print(a)
found = True
break
if found:
break
if found:
new_A.add(a)
print(new_A)
if not new_A:
raise ValueError(f"Contradiction: {A} not valid for between with {B} and {C}")
if new_A != poss[A]:
poss[A] = new_A
print("aaa", poss[A])
changed = True
new_C = set()
for c in poss[C]:
found = False
for a in poss[A]:
for b in poss[B]:
if (a < b < c) or (c < b < a):
found = True
break
if found:
break
if found:
new_C.add(c)
print(new_C)
if not new_C:
raise ValueError(f"Contradiction: {C} not valid for between with {A} and {B}")
if new_C != poss[C]:
poss[C] = new_C
print("ccc", poss[C])
changed = True
return changed
def update_row(row_letters):
changed = False
for letter in row_letters:
if len(poss[letter]) == 1:
col = next(iter(poss[letter]))
for other in row_letters:
if other == letter:
continue
if col in poss[other]:
poss[other].remove(col)
changed = True
for col in range(5):
candidates = []
for letter in row_letters:
if col in poss[letter]:
candidates.append(letter)
if len(candidates) == 1:
letter = candidates[0]
print("letter :", letter)
if poss[letter] != {col}:
poss[letter] = {col}
changed = True
for other in row_letters:
if other == letter:
continue
if col in poss[other]:
poss[other].remove(col)
changed = True
print("update row :", changed)
return changed
changed = True
while changed:
changed = False
for clue in clues:
print('\n')
print(clue, changed)
try:
if '^' in clue:
s1, s3 = clue[0], clue[2]
if update_same_col(s1, s3):
print("1 true", clue)
changed = True
elif '<' in clue:
s1, s3 = clue[0], clue[2]
if update_left_of(s1, s3):
print("2 true", clue)
changed = True
else:
if clue[0] == clue[2] and clue[0] != clue[1]:
s1, s2 = clue[0], clue[1]
if update_next_to(s1, s2):
print("3 true", clue)
changed = True
else:
if len(set(clue)) == 3:
if update_between(clue[0], clue[1], clue[2]):
print("4 true", clue)
changed = True
print('\n'.join(f"{k}: {v}" for k, v in poss.items()) + "\n~~~~~~~~~~~~~~~~~~\n")
except ValueError as e:
print(f"Error processing clue {clue}: {e}")
return None
print("update before :", changed)
for row in rows:
try:
if update_row(row):
print( "After update row", '\n'.join(f"{k}: {v}" for k, v in poss.items()), "\n################")
changed = True
except ValueError as e:
print(f"Error in row {row}: {e}")
return None
grid = [['.' for _ in range(5)] for _ in range(4)]
for i, row_letters in enumerate(rows):
for letter in row_letters:
if len(poss[letter]) == 1:
col = next(iter(poss[letter]))
grid[i][col] = letter
else:
print(f"Warning: {letter} has multiple possibilities: {poss[letter]}")
return grid
# clues = ["MRT", "ABH", "LKO", "OKP", "JIM", "OPE", "GDO", "RAQ", "J^A", "M^P", "A<Q", "D<K", "OQO"]
clues = ["HJL","POA","DHJ","KMA","DRG","PHD","AMQ","H<F","M<K","F<E","M<I","T<E","CPC","SOS"]
result = solve_marple_logic(clues)
if result:
for row in result:
print(' '.join(row))
To embed this program on your website, copy the following code and paste it into your website's HTML: