I have been practicing using the python constraint library by solving logic puzzles with it. I've found it an absolute joy to work with, but I'm stuck on a relatively simple puzzle.
I can solve it programatically, but the goal is to solve it using this library.
It's a standard "each person hosted the others at a specific type of restaurant on a day of the week" type of puzzle, where you figure out who hosted on what day at what restaurant.
The other answers were easy, but I struggle with "Dave selected a steak house for the night before one of the follows hosted everyone at a pizza parlor." It's the combination of two different conditions that I can't figure out.
So, "Bill hates fish" is easy:
problem.addConstraint(NotInSetConstraint({"bill"}), ["fish"])
And even the idea that "Dave selected Steak" is easy:
problem.addConstraint(InSetConstraint({"dave"}), ["steak"])
It's the idea that Dave + Steak comes before Pizza that I'm struggling with.
Does anyone have a suggestion for this, that doesn't involve rewriting it to have the Days be the main numeric? Actually, if that is your suggestion, I'll definitely hear it, and if you have a reason. But these chained type of conditions are common in these puzzles, so I need to figure out how to do this sort of thing at some point.
Here's the code so far, it ends up with 8 solutions, and I want to get it down to the 1 solution without resorting to brute force (which would be easy enough, mind you.)
from constraint import *
problem = Problem()
hosts = ["andy", "bill", "carl", "dave", "eric"]
foods = ["fish", "pizza", "steak", "tacos", "thai"]
days = ["monday", "tuesday", "wednesday", "thursday", "friday"]
criteria = foods + days
problem.addVariables(criteria, hosts)
problem.addConstraint(AllDifferentConstraint(), foods)
problem.addConstraint(AllDifferentConstraint(), days)
# Eric was not Friday's host
problem.addConstraint(NotInSetConstraint({"eric"}), ["friday"])
# Carl hosted the group on Wednesday
problem.addConstraint(InSetConstraint({"carl"}), ["wednesday"])
# The fellows ate at a Thai place on Friday
problem.addConstraint(lambda f, d: f == d, ["thai", "friday"])
# Bill, who detests fish, volunteered to be the first host
problem.addConstraint(NotInSetConstraint({"bill"}), ["fish"])
problem.addConstraint(InSetConstraint({"bill"}), ["monday"])
# Dave selected a steak house for the night before one of the follows hosted everyone at a pizza parlor
problem.addConstraint(InSetConstraint({"dave"}), ["steak"])
problem.addConstraint(NotInSetConstraint({"dave"}), ["friday"])
problem.addConstraint()
i = 0
sols = problem.getSolutions()
for sol in sols:
i += 1
print(f"-----------{i}-----------")
for host in hosts:
print(f"{host}:")
for fact in sol:
if sol[fact] == host:
print(f" {fact}")
So I tried something like this:
# problem.addConstraint(lambda steak, pizza, today, yesterday: steak == yesterday and pizza == today and days.index(today) == 1 + days.index(yesterday), ["steak", "pizza"])
But that won't work since the lambda is looking for 4 items, and the constraint is only passing "steak" and "pizza" but I don't obviously know what days to pull for "yesterday" and "today"