102 lines
3.4 KiB
Prolog
102 lines
3.4 KiB
Prolog
mastermind :- mastermind(7, 4, 8, no_duplicates).
|
|
|
|
mastermind(Colours, Length, Guesses, Duplicates) :-
|
|
between(2, 20, Colours),
|
|
between(4, 10, Length),
|
|
between(7, 20, Guesses),
|
|
member(Duplicates, [allow_duplicates, no_duplicates]),
|
|
|
|
create_board(Colours, Length, Duplicates, Board),
|
|
intro(Colours, Length, Duplicates),
|
|
play(board(Board, Length, Colours, Guesses), [], 0), !.
|
|
|
|
intro(Colours, Length, Duplicates) :-
|
|
format('Guess the code!~n'),
|
|
format('There are ~p character types, and ~p letters to guess~n',
|
|
[Colours, Length]),
|
|
Duplicates = allow_duplicates
|
|
-> format('Duplicates are allowed~n~n')
|
|
; format('Duplicates are not allowed~n~n').
|
|
|
|
/* Create the combination to be guessed */
|
|
create_board(Colours, Length, Duplicates, Board) :-
|
|
length(Board, Length),
|
|
valid_char_list(Colours, CharSet),
|
|
repeat,
|
|
maplist(random_alpha(CharSet), Board),
|
|
check_for_duplicates(Board, Duplicates).
|
|
|
|
check_for_duplicates(_, allow_dupicates).
|
|
check_for_duplicates(Board, no_duplicates) :- is_set(Board).
|
|
|
|
/* Main loop - get the player guess and print out status */
|
|
play(board(Board,_,_,MaxGuesses), _, MaxGuesses) :-
|
|
write('Sorry, You failed to guess in time...!\nThe code was : '),
|
|
maplist(write, Board),
|
|
nl.
|
|
play(BoardData, PrevGuesses, GuessNum) :-
|
|
BoardData = board(_, Length, Colours, MaxGuesses),
|
|
GuessNum < MaxGuesses,
|
|
ReportedGuess is GuessNum + 1,
|
|
format('Guess #~p of #~p: ', [ReportedGuess, MaxGuesses]),
|
|
get_player_guess(Length, Colours, Guess),
|
|
evaluate_and_print_result(BoardData, PrevGuesses, ReportedGuess, Guess).
|
|
|
|
evaluate_and_print_result(board(Board,_,_,_), _, _,Board) :-
|
|
format('Well done! You Guessed Correctly.~n').
|
|
evaluate_and_print_result(BoardData, PrevGuesses, NextGuessNum, Guess) :-
|
|
BoardData = board(Board, _, _, _),
|
|
dif(Board, Guess),
|
|
match_guess_to_board(Board, Guess, Diffs),
|
|
append(PrevGuesses, [guess(NextGuessNum, Guess, Diffs)], Guesses),
|
|
maplist(print_guess, Guesses),
|
|
play(BoardData, Guesses, NextGuessNum).
|
|
|
|
/* Get the player guess and validate that it matches the rules */
|
|
get_player_guess(Length, Colours, Guess) :-
|
|
repeat,
|
|
read_line_to_string(user_input, Line),
|
|
string_chars(Line, Guess),
|
|
|
|
% validate the correct number of items have been entered
|
|
length(Guess, Length),
|
|
|
|
% validate that all the characters are valid for the number of colours
|
|
valid_char_list(Colours, ValidCharSet),
|
|
subset(Guess, ValidCharSet).
|
|
|
|
/* Predicates to figure out how many places are correct */
|
|
match_guess_to_board(Board, Guess, Matches) :-
|
|
maplist(guess_differences(Board), Board, Guess, Differences),
|
|
sort(0, @>=, Differences, Matches).
|
|
|
|
% Same position, same type
|
|
guess_differences(_Board, B, B, 'X').
|
|
% Same type, different position
|
|
guess_differences(Board, B, G, 'O') :- dif(B, G), member(G, Board).
|
|
% Type not on board
|
|
guess_differences(Board, B, G, '-') :- dif(B, G), \+ member(G, Board).
|
|
|
|
/* Print out the current progress */
|
|
print_guess(guess(NextGuessNumber, Guess, Differences)) :-
|
|
format('~w: ', NextGuessNumber),
|
|
maplist(format('~w '), Guess),
|
|
format(' : '),
|
|
maplist(format('~w '), Differences),
|
|
nl.
|
|
|
|
/* Utils */
|
|
alpha_chars([a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]).
|
|
|
|
valid_char_list(Colours, CharSet) :-
|
|
alpha_chars(AllChars),
|
|
truncate_list(AllChars, Colours, CharSet).
|
|
|
|
random_alpha(AllChars, RandomMember) :- random_member(RandomMember, AllChars).
|
|
|
|
truncate_list(_, 0, []).
|
|
truncate_list([A|T], N, [A|R]) :-
|
|
N > 0,
|
|
N1 is N - 1,
|
|
truncate_list(T, N1, R).
|