

%----------------
% Project 1
% Mindmaster Game
%
% Josh Cogliati
% Mike Emery
% 2/12/2004
%----------------

% Mindmaster is a basic mastermind game capable of both
%  being played, and solving itself
% To play, run 'play_mindmaster.'
% To play with solution visible, run 'play_debug'

% -----Mindmaster Player Functions-----

% play_mindmaster
%   player side of mindmaster, call this to begin
play_mindmaster :-
	write_instructions,
	gen_solution(Solution),
	play_helper(Solution).

% play_debug 
%   runs like normal play, except the solution is shown at the beginning
play_debug :-
	write_instructions,
	gen_solution(Solution),
	show_solution(Solution),
	play_helper(Solution).

% write_instructions
%   displays the rules of mindmaster
write_instructions :-
	write('Welcome to MindMaster!\n\n'),
	write('Guesses follow the form [r,b,g,y].\n'),
	write('Valid colors are (b)lue, (r)ed, (g)reen, (y)ellow, (p)urple,'),
	write('and (o)range\n'),
	write('A guess will be replied to with either a notification for\n'),
	write('  a correct guess, or two numbers. The first represents\n'),
	write('  the number of correct colors in the correct slot,\n'),
	write('  the second represents the number of correct colors not in\n'),
	write('  correct slot. After finding the solution, a computer player'),
	write(' will\n  also attempt to find the solution.\nGood luck!\n\n').

% show_solution
%   displays the correct solution
show_solution(Solution) :-
	write('\n\nSolution: '),
	write(Solution),
	write('\n\n').

% play_helper
%   contains the guess & check player cycle
play_helper(Solution) :-
	get_guess(Guess),
	calc_score(Guess,Solution,X,Y),
	judge_score(Solution,X,Y).

% get_guess
%   prompts for, and reads a player guess
get_guess(Guess) :-
	write('Guess: '),
	read(Guess).

% judge_score 
%   determines the correctness of a solution

%   correct solution
judge_score(Solution,4,_) :-
	write('Correct solution! You are a Mindmaster!'),
	run(Solution).

%   incorrect solution
judge_score(Solution,X,Y) :-
	write('Correct colors in correct slots: '),
	write(X),
	write('\nCorrect colors in wrong slots: '),
	write(Y),
	write('\n'),
	play_helper(Solution).

% -----Mindmaster Engine Functions-----

% Colors allowed
color(b). %Blue
color(r). %Red
color(g). %Green
color(y). %Yellow
color(p). %Purple
color(o). %Orange

% gen_solution
%   randomly selects colors for the solution
gen_solution(Solution) :-
	pick_color(A),
	pick_color(B),
	pick_color(C),
	pick_color(D),
	Solution = [A,B,C,D].

% pick_color
%   randomly chooses one color
pick_color(X) :-
	%random(Raw),6
	%Y is Raw*100,
	%Z is round(Y),
	%Rand is mod(Z,6),
	Rand is random(6),
	det_color(Rand,X).

% det_color
%   associates a number to the corresponding color
det_color(0,X):- X = 'b'.
det_color(1,X):- X = 'r'.
det_color(2,X):- X = 'g'.
det_color(3,X):- X = 'y'.
det_color(4,X):- X = 'p'.
det_color(5,X):- X = 'o'.


% ordered_count
%   returns the number of slots containing the correct color
%   in the correct position
ordered_count([],[],0).

%   Correct color, correct position
ordered_count([Same|GuessRest],[Same|SolRest],Correct) :- 
	ordered_count(GuessRest,SolRest,RestCount),Correct is RestCount + 1.

%   Not correct color | correct position
ordered_count([Guess1|GuessRest],[Sol1|SolRest],Correct) :- 
	Guess1 \= Sol1,
	ordered_count(GuessRest,SolRest,RestCount),Correct is RestCount.

% remove_first_match
%   deletes the first item in the list matching the parameter
remove_first_match(Match, [Match|Rest], Rest).

remove_first_match(Match, [First|Rest], [First|RecursiveRest]) :-
	remove_first_match(Match, Rest, RecursiveRest).

% count 
%   calculates the number of slots containing a color found in the solution
count([],_,0).

count([Same],[Same],1).

count([First|Rest], BottomList, X) :- 
	member(First,BottomList),
	remove_first_match(First, BottomList, Y),
	count(Rest,Y,RecursiveCount),
	X is RecursiveCount + 1.

count([_|Rest], BottomList, X) :- 
	count(Rest,BottomList,RecursiveCount),
	X is RecursiveCount.

% calc_score
%   returns the overall score for the guess
calc_score(Guess,Solution,X,Y) :-
	ordered_count(Guess,Solution,X),
	count(Guess,Solution,Z),
	Y is Z - X.

% same
%   returns true if the two lists are identical
same([A,B,C,D],[A,B,C,D]).


% -----Mindmaster Computer Player Functions-----

% run
%   computer player entry point
run(Solution) :-
	calc_score([r,b,g,y],Solution,X,Y),
	possibility([[r,b,g,y,X,Y]],[E,F,G,H]),
	calc_score([E,F,G,H],Solution,X1,Y1),
	run_helper([[E,F,G,H,X1,Y1],[r,b,g,y,X,Y]],Solution).

% run_helper
%   recursive helper for run
run_helper([[E,F,G,H,4,0]|Possibility],_) :-
	write('\nComputer player found the solution, too!'),
	write('\nComputer player path to solution follows (reverse order):\n'),
	write([[E,F,G,H,4,0]|Possibility]).

run_helper(Possibility,Solution) :-	
	possibility(Possibility,[E,F,G,H]),
	calc_score([E,F,G,H],Solution,X,Y),
	run_helper([[E,F,G,H,X,Y]|Possibility],Solution).

%possibility 
%   allows the computer player to determine a resonable guess based on 
%   previous results
possibility([],_).

possibility([[A,B,C,D,X,Y]|Rest],[E,F,G,H]) :-
	color(E),
	color(F),
	color(G),
	color(H),
	not(same([A,B,C,D],[E,F,G,H])),
	calc_score([A,B,C,D],[E,F,G,H],X,Y),
	possibility(Rest,[E,F,G,H]).
