3 ms·
It can be more briefly solved without constraints than the linked code, brute-forcing through the possible correct-answer permutations: member_of(List, X)
by jodrellblank 2y ago
It can be more briefly solved without constraints than the linked code, brute-forcing through the possible correct-answer permutations:
member_of(List, X) :- % helper swaps args for use with maplist.
member(X, List).
score(Given, Correct, Adder, NewScore) :-
(Given = Correct % Prolog if/else
-> NewScore is Adder + 10
; NewScore = Adder).
puzzle(ColinScore) :-
length(CorrectAnswers, 10), % ten unknown correct answers,
maplist(member_of([a,b]), CorrectAnswers), % each 'a' or 'b'
% compare player answers to correct answers, add their scores.
foldl(score, [b,b,a,b,a,b,b,a,b,b], CorrectAnswers, 0, 70), % Mary
foldl(score, [b,a,a,a,b,a,b,a,a,a], CorrectAnswers, 0, 50), % Dan
foldl(score, [b,a,a,a,b,b,b,a,b,a], CorrectAnswers, 0, 30), % Lisa
foldl(score, [b,b,a,a,a,b,b,a,a,a], CorrectAnswers, 0, ColinScore).
Then:
?- puzzle(ColinScore).
ColinScore = 60
It's fine for a toy puzzle and it uses fewer resources than invoking the constraint solver, but it's a poor way to approach a puzzle or real world task with a larger search space.
- hwayne 2y agoThe `(if -> then; else)` syntax introduces a cut, which I found hides possible solutions.
- jodrellblank 2y agoI believe that is not a concern in my code; if "a=a" then commiting to that cannot hide any possible solutions where either side of the equals could be different because we've already tested and found them equal (they unify). One can avoid that worry by swapping in this version instead: score(X, X, Adder, NewScore) :- NewScore is Adder + 10. score(X, Y, Adder, Adder) :- dif(X, Y). Leaving choicepoints where I don't want them is an annoying part of Prolog when I know the answer is deterministic - that's where I used zcompare/3 in my other answer in this thread, but it's far too much effort to write that pattern for every test situation. For people who object to `is` then make it `succ(Adder, NewScore)` and adjust the player scores down by a factor of ten as per the blog post. For people who comment that succ/2 doesn't always work, note that the Adder is always initialised to 0 in the foldl goal so succ/2 always has one instantiated value. [It just wouldn't be a Prolog solution if it wasn't hard to write, hard to read, hard to verify that it's working properly, full of single letter variable names OrLongWordVariableNames and immediately making people talk about cut and constraint handlers and ISO compatibility and Prolog internals rather than the problem. On that note, PabloLife's code has "flip(correct, incorrect)" which is imperatively named but doesn't do anything imperative, uses nested lists instead of Number-Answer pairs which is more visually cluttered and uses more memory...].