% Filter & generate to solve moo game
% 4 different digit code selected

:-dynamic response/2.
:- dynamic code/1.
:-use_module(library(lists)).
:-use_module(library(ordsets)).

% guess is a list of length 4 (different digits)

% pick next digit leaving remainder for next choice

next_dig(D,[D|Rem],Rem).
next_dig(D,[D1|Ds],[D1|Rem]) :-
			next_dig(D,Ds,Rem).

% now for generator for guess

generate([D1,D2,D3,D4]) :-
				next_dig(D1,[1,2,3,4,5,6,7,8,9],R1),
				next_dig(D2,R1,R2),
				next_dig(D3,R2,R3),
				next_dig(D4,R3,_).

% store the responses in db using response/2 first arg is guess, 2nd is response L-R
% where L number to left of correct answer & R is number to right


% Alternative for evaluation of the guess relative to code val(Guess,Code,Bulls,Cows)
/******
val([G|Gs],[C|Cs],Bulls,Cows) :-
    val(Gs,Cs,B1,C1),
    (G=:=C -> Bulls is B1+1;
            Bulls =B1),
    (member(G,Cs) -> 
            C2 is C1+1; C2 = C1),
    (member(C,Gs) ->  Cows is C2+1; Cows = C2).

val([],[],0,0).

******/
% evaluate the guess relative to code val(Guess,Code,Bulls,Cows)

val(G,C,Bulls,Cows) :-
     bulls(G,C,Bulls),
     list_to_ord_set(G,OG),
     list_to_ord_set(C,OC),
     ord_intersection(OG,OC,GC),
     length(GC,L),
     Cows is L - Bulls.

bulls([G|Gs],[C|Cs],Bulls) :-
     bulls(Gs,Cs,B1),
     (G=:=C -> Bulls is B1 +1; Bulls = B1).

bulls([],[],0).

% suppose code is asserted as code e.g.

% predicate to play:

play :-
   retractall(response(_,_)),
   retractall(code(_)),
   write('enter code '),
   read(C),assert(code(C)),!,
    generate(G),
    filter(G),
    write(G),
    get_response(G,R),write('  '),write(R),nl,
    (R==(4-0) -> write('code found'),nl;
                   fail).


% get response is system providing info on guess relative to asserted code

get_response(G,Corr-I) :-
     code(C),
     val(G,C,Corr,I),
     assert(response(G,Corr-I)).


% forall implemented using \+

forall(G,H) :-
      \+ (G, \+ H).

% filter checks that guess would give same responses as stored in db if it were correct code

filter(G) :-

    forall(response(Cod,C-I),val(Cod,G,C,I)).



