I'm pretty proud of the following, but would welcome any comments from experts:
%% Provide with a Goal and it will iterate towards it.
guess(Goal, Res) :-
guessIterate(Goal, [], Res).
guessIterate(Goal, Guesses, Res) :-
makeGuess(Guess),
check_against_guesses(Guess, Guesses),
score(Guess, Goal, ThisScore),
(
%% if completely correct,...
ThisScore == [4, 0]
->
Res = Guess
;
write(Guess), write(' '), write(ThisScore),nl,
NewGuesses = [guess(Guess, ThisScore) | Guesses],
guessIterate(Goal, NewGuesses, Res)
).
/*
If this Guess is correct, it will pedict the right results for previous guesses
*/
check_against_guesses(_, []).
check_against_guesses(Guess, [guess(Code, Score) | TGuesses]) :-
score(Code, Guess, Score),
check_against_guesses(Guess, TGuesses).
makeGuess(Guess) :-
Colours = [red, blue, green, yellow, orange, purple, pink],
member(G1, Colours),
member(G2, Colours),
member(G3, Colours),
member(G4, Colours),
Guess = [G1, G2, G3, G4].
/*
Score a guess, [#Black, #White], by first looking for exact matches - black - and then
look for inexaxct matches - white.
It is not possible for a guess of [...red, red...] to match twice with a
single 'red' in the Goal
*/
score(Guess, Goal, Res) :-
pass1(Guess, Goal, [], Pass1Res),
pass2(Guess, Pass1Res, Pass2Res),
countUp(Pass2Res, [0,0], Res).
pass1(_, [], Acc, AccRev) :-
reverse(Acc, AccRev).
pass1([HGuess | TGuess], [HGoal | TGoal], Acc, Res) :-
(
HGuess == HGoal
->
AccNew = [black | Acc]
;
AccNew = [HGoal | Acc]
),
pass1(TGuess, TGoal, AccNew, Res).
%% check each Guess element with Goal and change Goal element to 'white' if there is a match
pass2([], Goal, GoalRev) :-
reverse(Goal, GoalRev).
pass2([HGuess | TGuess], Goal, Res) :-
pass2Helper(HGuess, Goal, [], ModifiedGoal),
pass2(TGuess, ModifiedGoal, Res).
pass2Helper(_, [], Acc, AccRev) :-
reverse(Acc, AccRev).
pass2Helper(Guess, [HGoal | TGoal], Acc, Res) :-
(
Guess == HGoal
->
reverse(TGoal, TGoalRev),
%% Res = [white | TGoalRev]
append(TGoalRev, [white | Acc], Res)
;
AccNew = [HGoal | Acc],
pass2Helper(Guess, TGoal, AccNew, Res)
).
countUp([], Acc, Acc).
countUp([HRes|TRes], [AccB, AccW|_], Res) :-
(
HRes == black
->
AccBNew is AccB + 1,
countUp(TRes, [AccBNew, AccW], Res)
;
(
HRes == white
->
AccWNew is AccW + 1,
countUp(TRes, [AccB, AccWNew], Res)
;
countUp(TRes, [AccB, AccW], Res)
)
).