Reputation: 35
I want to write a prolog code to resolve the following game : Crack the 3 digit code based on these statements
Here is my code for the first statement: "One number is correct and well placed", but I get the answer false instead of [six,,], [,eight,], [,,two] :
first(X, [X|_]).
second(X, [_,X,_]).
third(X, [_,_,X]).
one_correct_well([A,B,C], [X,Y,Z]):-first(A, [X,Y,Z]), B\=Y, C\=Z.
one_correct_well([A,B,C], [X,Y,Z]):-second(B, [X,Y,Z]), A\=X, C\=Z.
one_correct_well([A,B,C], [X,Y,Z]):-third(C, [X,Y,Z]), B\=Y, A\=X.
solution(CODE):-
CODE = [_,_,_],
one_correct_well([six,eight,two], CODE).
Upvotes: 2
Views: 126
Reputation: 4515
The following gives me [zero,four,two]
as the result:
One digit correct and well placed:
For [A,B,C], the authorized patterns are :
[A,_,_]
[_,B,_]
[_,_,C]
therefore the following code:
one_correct_well([A,B,C],[A,X,Y]):-
delete([zero,one,two,three,four,five,six,seven,eight,nine],B,ListB),
member(X,ListB), % X can take any value different from B
delete([zero,one,two,three,four,five,six,seven,eight,nine],C,ListC),
member(Y,ListC). % Y can take any value different from C
one_correct_well([A,B,C],[X,B,Y]):-
delete([zero,one,two,three,four,five,six,seven,eight,nine],A,ListA),
member(X,ListA),
delete([zero,one,two,three,four,five,six,seven,eight,nine],C,ListC),
member(Y,ListC).
one_correct_well([A,B,C],[X,Y,C]):-
delete([zero,one,two,three,four,five,six,seven,eight,nine],A,ListA),
member(X,ListA),
delete([zero,one,two,three,four,five,six,seven,eight,nine],B,ListB),
member(Y,ListB).
One digit correct but wrongly placed:
For [A,B,C], the authorized patterns are :
[_,A,_]
[_,_,A]
[B,_,_]
[_,_,B]
[C,_,_]
[_,C,_]
therefore the following code:
one_correct_wrong([A,B,C],[X,A,Y]):-
not_in2([X,Y],[A,B,C]).
one_correct_wrong([A,B,C],[X,Y,A]):-
not_in2([X,Y],[A,B,C]).
one_correct_wrong([A,B,C],[B,X,Y]):-
not_in2([X,Y],[A,B,C]).
one_correct_wrong([A,B,C],[X,Y,B]):-
not_in2([X,Y],[A,B,C]).
one_correct_wrong([A,B,C],[C,X,Y]):-
not_in2([X,Y],[A,B,C]).
one_correct_wrong([A,B,C],[X,C,Y]):-
not_in2([X,Y],[A,B,C]).
not_in2([X,Y],[A,B,C]):- % X and Y are different from A, B and C
delete([zero,one,two,three,four,five,six,seven,eight,nine],A,List1),
delete(List1,B,List2),
delete(List2,C,List3),
member(X,List3),
member(Y,List3).
Edit:
Maybe a more elegant way of writing this :
one_correct_wrong([A,B,C],L):-
(L=[X,A,Y]; % this, OR ..
L=[X,Y,A]; % .. this, OR ..
L=[B,X,Y]; % .. this, OR ..
L=[X,Y,B]; % .. this, OR ..
L=[C,X,Y]; % .. this, OR ..
L=[X,C,Y]),
not_in2([X,Y],[A,B,C]).
Two digits correct but wrongly placed:
two_correct_wrong([A,B,C],[B,A,X]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[B,X,A]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[X,A,B]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[X,C,B]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[C,X,B]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[B,C,X]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[C,X,A]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[C,A,X]):-
not_in(X,[A,B,C]).
two_correct_wrong([A,B,C],[X,C,A]):-
not_in(X,[A,B,C]).
not_in(X,[A,B,C]):- % X is different from A, B and C
delete([zero,one,two,three,four,five,six,seven,eight,nine],A,List1),
% List1 contains zero-nine without A
delete(List1,B,List2),
% List2 contains zero-nine without A and B
delete(List2,C,List3),
% List3 contains zero-nine without A, B and C
member(X,List3).
Nothing correct:
nothing_correct([A,B,C],[X,Y,Z]):-
delete([zero,one,two,three,four,five,six,seven,eight,nine],A,ListA),
delete(ListA,B,ListB),
delete(ListB,C,ListC),
member(X,ListC),
member(Y,ListC),
member(Z,ListC).
Solution:
solution(Result):-
one_correct_well([six,eight,two],Result),
one_correct_wrong([six,one,four],Result),
one_correct_wrong([seven,eight,zero],Result),
two_correct_wrong([two,zero,six],Result),
nothing_correct([seven,three,eight],Result).
Please note that this is a fast try and therefore there are a lot of duplicate pieces of code, so it obviously can be improved
Second note : consider the reuse of A
in one_correct_well([A,B,C],[A,X,Y])
instead of using first(A, [X,Y,Z])
The predicate delete/3
allows me to use a list from zero
to nine
excluding some values such as the following :
delete([one,two,three],two,S).
-> S = [one,three].
I'm not an expert in prolog, so there might be a better way of achieving this, but that's what I found with a quick search.
Last but not least : here is a SWISH link to a working example
Upvotes: 2