2
votes

EDIT 2:

I solved it using list in list. Thanks for help.


I try to make Mastermind in Prolog. I have a function

guess(Colors, Size, Possibilities, Answer, Black, White)

which takes count of used colors, size of game field, list of colors and user evaluation of answer. It may looks like:

guess(4, 6, P, [red, red, blue, green, green, yellow], 2, 3)

which means there are 4 colors, 6 places for pegs and the guess

[red, red, blue, green, green, yellow] gets 2 black pegs and 3 white.


When I call this these functions directly like

guess(4, 6, O, [red, red, blue, green, green, yellow], 2, 3), 
guess(4, 6, O, [red, yellow, green, blue, red, blue], 0, 4), 
guess(4, 6, O, [green, blue, yellow, red, green, yellow], 4, 2), 
guess(4, 6, O, [yellow, blue, red, yellow, green, yellow], 5, 0).

it gives me correct answer O = [green, blue, red, yellow, green, yellow]


Now I try to make it more interactive, so I created functions

play:-
    write('Size: '), read(Size), nl,
    write('Colors: '), read(Colors), nl,
    createFirstGuess(Size, Colors, [], A), //initial guess
    run(Colors, Size, _, A).

run(Colors, Size, P, A) :- 
    tryGuess(Colors, Size, J, A),   //Possibilities in J
    copy(J, X),   //First possible result J -> X
    J = P,   //Unification of all results
    run(Colors, Size, J, X).   //loop

tryGuess(_, _, _, []) :- !. 
tryGuess(Colors, Size, P, A) :- 
    write('Evaluation of: '), write(A), nl,
    write('Black pegs: '), read(B), nl, 
    write('White pegs: '), read(W), nl,
    guess(Colors, Size, P, A, B, W).

copy([],[]) :- !.    //Copy list T1 to T2
copy([H|T1],[H|T2]) :- !, copy(T1,T2).

createFirstGuess(0, _, L, L) :- !.   //Initial guess (just field of the same colors)    
createFirstGuess(N, Colors, R, L) :-
    N > 0, N1 is N - 1, color(Colors, H), createFirstGuess(N1, Colors, [H|R], L).

I run 'play', set size and count of colors a start play.

Evaluation of: [red, red, red, red, red, red]   //Initial guess
Black pegs: 1.
White pegs: 0.

Evaluation of: [red, green, green, green, green, green]  //OK
Black pegs: 1.
White pegs: 2.

Evaluation of: [red, green, green, green, green, blue]  //Bad, it goes through the list one-by-one
Black pegs: 1.
White pegs: 2.

Evaluation of: [red, green, green, green, green, yellow]   //Bad
Black pegs: 2.
White pegs: 2.

Evaluation of: [red, green, green, green, blue, green]   //Bad
Black pegs: 0.
White pegs: 4.

It seems the first two answers are good (one is initial, second is computed), but the next one just goes through all possibilities one-by-one. I think there is a problem with backtracking, so there should be some cuts (!), but I am unable to find where to put them.

Thanks for any help.

EDIT:

Thank you for help.

I would like to get output like this:

Evaluation of: [red, red, red, red, red, red]   //Initial guess
Black pegs: 1.
White pegs: 0.

Evaluation of: [red, green, green, green, green, green]
Black pegs: 1.
White pegs: 2.

Evaluation of: [green, red, blue, yellow, green, blue]
Black pegs: 3.
White pegs: 2.

Evaluation of: [green, blue, yellow, yellow, green, red]
Black pegs: 4.
White pegs: 2.

Evaluation of: [green, blue, red, yellow, green, yellow]
Black pegs: 6.
White pegs: 0.

End of Game

But, in my case prolog goes through the list of all possibilities one-by-one but when I use guess (as shown above) it works great. There must be a problem with unification and backtracking. At first I use initial list and get correct possible results. Then I take first of results and let player to evaluate it. This first result with player evaluation I use for next guess, but there is a problem. As I see, because of backtracking is this result (answer) reunified, so player must go through the list one-by-one, no matter the evaluation.

I think, it should work, if the answer, evaluated by player, won't be reunified, but I cannot find a way to do so.

1
Prolog doesn't have functions, it has predicates that define relations. copy(J, X), just unifies J and X one element at a time. It does the same thing as J = X. And then you unify J with P (as J = P). So J, X, and P are all unified in that clause, and represent the same thing. That's what unification is. It doesn't assign a value to another variable position, as in other languages. If you did, X = [A,B], copy(X, Y), A = 1, B = 2. you'd get, X = [1,2] and Y = [1,2].lurker
You've shown output that you don't like. Can you describe what the output should be for you to like it?lurker

1 Answers

0
votes

OK, I finally solved it using lists in lists for saving Answers and evaluations. Then I just expand those lists and use it for building more precise solution.