Mastermind in Prolog - backtracking - prolog

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.

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.

Related

Prolog go through all lists of a list

I would like to make the following piece of code work without using maplist.
only_two([Person|Choice]) :- subset([red, red], Choice), not(subset([red, red, red], Choice).
only_two([[Person|Choice]|Others]) :- only_two([Person|Choice]), only_two(Others).
Then I have
?-only_two([John, red, blue, blue, green, red]). -> True
?-only_two([[John, red, blue, blue, green, red],
[Alice, green, red, red, blue, green],
[Fred, red, red, blue, yellow, green]]). -> False
What do I do wrong?

PROLOG: process of inference, why returns false

I have a definition of conc:
conc([], L2, L2).
conc([X1|R1], L2, [X1|RN]) :-
conc(R1, L2, RN).
I don't understand why conc([X | green], Y, [red, green, blue]). returns false rather than
X = [red],
Y = [blue]
What is the process of inference here?
Disclaimer: I don't know Prolog. The rest of this answer is an edumacated guess.
Your proposed solution of X = [red] doesn't make sense because that would make X a one-element list. Let's assume
X = red
instead.
That would give us
conc([red | green], [blue], [red, green, blue]).
With the second equation of conc that turns into
conc(R1, L2, RN).
% with:
% X1 = red
% R1 = green
% L2 = [blue]
% [X1|RN] = [red, green, blue]
% i.e. X1 = red
% RN = [green, blue]
I.e.
conc(green, [blue], [green, blue]).
And now we're stuck because none of your conc rules applies to green.
The problem is [X | green] because green is not the tail of a list.
Did you mean [X, green] instead?
In Prolog list notation, the | separates the elements enumerated at its left from a list of the remaining elements at its right. The issue is in your query. Instead of [X | green] you need to write either [X | [green]] or [X,green]. With one of these fixes, you get correct answer. E.g.
?- conc([X | [green]], Y, [red, green, blue]).
X = red,
Y = [blue].

Prolog: Finding all possible permutations of a list of elements with only two states

I am trying to instantiate multiple lists in Prolog of elements with only two states, the states being red and blue. Initially, I instantiate a list of elements that are only blue by creating a list of size n:
generate_list(0, []) :- !.
generate_list(N, [H | T]) :-
N2 is N-1,
H = blue,
generate_list(N2, T).
I have also defined a predicate to change the state of colors
flip(blue, red).
flip(red, blue).
I would like to use this predicate to change the color during the instantiation of a new list, however I am stuck on how to approach this problem. The default permutation and combination predicate requires you use separate predefined elements to instantiate the new list, however I have a list of elements already generated.
It's not clear from your question what you mean by "changing" the color "during the instantiation". It would be great if you could update it with a concrete example of what you want.
However, here is something that may or may not go into the direction of what you want:
color(red).
color(blue).
colorlist([]).
colorlist([C|Cs]) :-
color(C),
colorlist(Cs).
The definition of colorlist/2 says that its argument is a list, with elements satisfying color/1. Either color is fine, so any list of any permutation of elements from red and blue is a solution. We can use this already to check color lists:
?- colorlist([red, blue, blue]).
true.
And also to try to enumerate them, although the enumeration is not fair, i.e., some things that are solutions (in this case, any list containing blue) will never be generated:
?- colorlist(Cs).
Cs = [] ;
Cs = [red] ;
Cs = [red, red] ;
Cs = [red, red, red] ;
Cs = [red, red, red, red] ;
Cs = [red, red, red, red, red] . % etc.
To solve the fairness problem, we can enumerate by length: First all the length-0 lists, then all the length-1 lists, all the length-2 ones, etc. If we expose the length as a parameter, we get something that at least has the same interface as the predicate you are trying to write:
length_colorlist(N, Cs) :-
length(Cs, N),
colorlist(Cs).
This can enumerate solutions fairly and generally:
?- length_colorlist(N, Cs).
N = 0,
Cs = [] ;
N = 1,
Cs = [red] ;
N = 1,
Cs = [blue] ;
N = 2,
Cs = [red, red] ;
N = 2,
Cs = [red, blue] ;
N = 2,
Cs = [blue, red] .
And also answer more specific queries restricted by length:
?- length_colorlist(8, Cs).
Cs = [red, red, red, red, red, red, red, red] ;
Cs = [red, red, red, red, red, red, red, blue] ;
Cs = [red, red, red, red, red, red, blue, red] ;
Cs = [red, red, red, red, red, red, blue, blue] ;
Cs = [red, red, red, red, red, blue, red, red] ;
Cs = [red, red, red, red, red, blue, red, blue] ;
Cs = [red, red, red, red, red, blue, blue, red] ;
Cs = [red, red, red, red, red, blue, blue, blue] ;
Cs = [red, red, red, red, blue, red, red, red] ;
Cs = [red, red, red, red, blue, red, red, blue] .
Note: No cuts needed, and the final definition is built up as a simple composition of more generic, individually useful parts. When stuck on a problem, especially in Prolog, always try to solve individual subparts first. In this case, "how do I define lists (of any length) containing colors?" and "how do I generate lists of specific lengths?" are two distinct subproblems that are best solved separately.

How to check the repeatable variables in a list in prolog

I'm working on this Prolog question where I have to design a program that creates a grid of wizard hats of 4 different colours (blue, red, green, and yellow) where each hat has one of 4 different letters (w, x, y, and z). The hats have to be arranged in such a way that no row or column has two hats with the same colour or hats with the same letter in them.
I have to write a predicate validRow that is true if a row is valid, i.e., if no two hats have the same color or the same letter.
ex:
?- validRow([(1, 1, red, w), (1, 2, green, x), (1, 3, yellow, y), (1, 4, blue, z)]).
true.
This is my code so far
validRow([(R,C1,Colour1,Letter1), (R,C2,Colour2,Letter2),(R,C3,Colour3,Letter3), (R,C4,Colour4,Letter4)]) :-
isValid([Colour1,Colour2,Colour3,Colour4], [Letter1,Letter2,Letter3,Letter4]).
isValid([HC|TC],[HL|TL]) :-
not(member(HC,TC)),
not(member(HL,TL)),
isValid(TC,TL).
This doesn't give me the correct answer. How can i fix this?
Recursion requires a base case; you have not specified one for isValid.

Simple Prolog setof

this is simple yet cannot seem to grasp it
I have these "colors"
color(blue).
color(red).
color(white).
using setof I need to get all possible combinations of these colors in a list
It would be great if you can provide a brief explanation. I tried this query
setof(X,color(X),Colors). which failed obviously
Thanks
I suppose you meant this with combinations:
?- setof((X,Y), (color(X), color(Y)), ColorsCombined).
ColorsCombined = [ (blue, blue), (blue, green), (blue, red), (green, blue), (green, green), (green, red), (red, blue), (red, green), (..., ...)].
Or did you mean the superset?
subset([Element|Set], [Element|Subset]):- subset(Set, Subset).
subset([_|Set], Subset):- subset(Set, Subset).
subset([], []).
superset(Set, Superset) :- setof(Subset, subset(Set, Subset), Superset).
This is the output:
?- superset([1,2,3], Superset).
Superset = [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]].
You mean like this ?
all_permutations(Permutations) :-
% get all colors into a list
setof(Color, color(Color), One_Color_List),
% find all combinations using permutation/2 on One_Color_List
setof(Permutation,
permutation(One_Color_List, Permutation),
Permutations).
Results:
?- all_permutations(X).
X = [[blue, red, white], [blue, white, red], [red, blue, white], [red, white, blue], [white, blue, red], [white, red, blue]].
The trick is to get the facts into a list - as you did, then use permutation/2 to generate all permutations of that list.
If that's what you wanted.. wasn't clear...

Resources