BlackstarMC97
BlackstarMC97

Reputation: 35

need help to write a prolog statement

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

Answers (1)

Rafalon
Rafalon

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

Related Questions