ERROR: Out of global stack

359 views
Skip to first unread message

Kelly

unread,
Jan 24, 2017, 11:10:51 AM1/24/17
to swi-p...@googlegroups.com
Hello all,

I'm trying to implement a mastermind game, the rules can be found on https://en.wikipedia.org/wiki/Mastermind_(board_game).
My program generates a sequence of four distinct colors.
The player has 10 turns to guess the code.
I know that the code can be improved, but for now I'm trying to solve an out of global stack error.
It occurs when I count the number of white, but not always.  Probably the problem is in the common or distinct predicate (or both).
I'm a beginner in Prolog and I appreciate any help.

Here follows the code

start:-
write('Start a new game? y/n'),
nl,
read(Start),
(Start==y -> write('\e[2J'),newgame,nl; halt(0)).

newgame:-
random_member(A1,[yellow,blue,pink,green,purple,orange]),
random_member(B1,[yellow,blue,pink,green,purple,orange]),
random_member(C1,[yellow,blue,pink,green,purple,orange]),
        random_member(D1,[yellow,blue,pink,green,purple,orange]),
S=[A1,B1,C1,D1],
        %It checks if all the colors generated are different
(all_diff(S)->true;newgame),
        %loop for the attempts
dec(10,A1,B1,C1,D1),
        %out of loop means you have lost
write('You have lost.'),nl,
write('Code: '),
printlist([A1,B1,C1,D1]),
nl,nl,
start.

all_diff(L) :- \+ (select(X,L,R), member(X,R)).

dec(0,A1,B1,C1,D1).
dec(X,A1,B1,C1,D1) :-
%printlist([A1,B1,C1,D1]),
write('Attempt # '),
Y is abs(X-11),
write(Y),nl,
        write('Color 1'),
        read(A2),
write('Color 2'),
        read(B2),
write('Color 3'),
        read(C2),
write('Color 4'),
        read(D2),
nl,
I is 0,
        %It checks the number of black
        % if there is a match increases the count for black
        %else: put the different values in two lists, one for the code and one for the guess
(A1==A2 -> J is I + 1; J is I + 0, LA1=[A1],LA2=[A2]),
(B1==B2 -> K is J + 1; K is J + 0, LB1=[B1],LB2=[B2]),
(C1==C2 -> L is K + 1; L is K + 0, LC1=[C1],LC2=[C2]),
(D1==D2 -> Black is L + 1; Black is L + 0, LD1=[D1],LD2=[D2]),
        %append the values in the code that didn't match with the guess
append(LA1,LB1,AB1),
append(LC1,LD1,CD1),
append(AB1,CD1,L1),
        %append the values in the guess that didn't match with the code
append(LA2,LB2,AB2),
append(LC2,LD2,CD2),
append(AB2,CD2,L2),
%If number of black is 4 means you have won
(Black==4 -> write('You have won.'),nl,
write('Code: '),
printlist([A1,B1,C1,D1]),
nl,nl,
start;
write('Black: '),
write(Black),
        %remove duplicate values from the guess list
distinct(L2,R2),
        %count the number of common elements in both lists(number of white)
common(L1,R2,White),
write(' White: '),
write(White),
nl,nl,
        NewX is X - 1,
        dec(NewX,A1,B1,C1,D1)).


member1(X,[H|_]) :- X==H,!.
member1(X,[_|T]) :- member1(X,T).

distinct([],[]).
distinct([H|T],C) :- member1(H,T),!, distinct(T,C).
distinct([H|T],[H|C]) :- distinct(T,C).

common([],Ys,0).
common([X|Xs],Ys,N):- member(X,Ys), common(Xs,Ys,M), N is M+1.
common([X|Xs],Ys,N):- nonmember(X,Ys), common(Xs,Ys,N).


nonmember(Arg,[Arg|_]):-
        !,
        fail.
nonmember(Arg,[_|Tail]):-
!,
        nonmember(Arg,Tail).
nonmember(_,[]).

printlist([]).
printlist([X|Y]) :- write(X),write(' '),printlist(Y).


Thank you in advance.

Jan Wielemaker

unread,
Jan 24, 2017, 3:46:10 PM1/24/17
to Kelly, SWI-Prolog
You run out of global stack if you create really large terms that remain
accessible. In small domains like this, running out of the (default) 256
Mb stack typically means something is wrong with your program.

In theory, the (all_diff(S)->true;newgame) can run out of stack, but
you must be really unfortunately. Better though would be

newgame :-
repeat,
Colors = [yellow,blue,pink,green,purple,orange],
S = [A1,B1,C1,D1],
maplist(random_color(Colors), S),
all_diff(S), !,
...

random_color(Colors, C) :-
random_member(C, Colors).

That may -in theory- backtrack for a long time. It uses no significant
amount of resources though.

Next is

(A1==A2 -> J is I + 1; J is I + 0, LA1=[A1],LA2=[A2]),

This means LA1 and LA2 remain variable if A1 == A2. You can append
variables to variables, but be aware that this is non deterministic
and if you backtrack into it will create infinitely large terms:

?- append(A, B, C).
A = [],
B = C ;
A = [_7412],
C = [_7412|B] ;
A = [_7412, _7424],
C = [_7412, _7424|B] ;
A = [_7412, _7424, _7436],
C = [_7412, _7424, _7436|B] ;
A = [_7412, _7424, _7436, _7448],
C = [_7412, _7424, _7436, _7448|B]

etc.

Not sure what is really causing your code to run out of control, but
this is definitely worrying.

If you want to compute blacks, what about abstracting a little:

%! blacks(+Set, -Guess, -Blacks, -SetRemain, -GuessRemain)

blacks([], [], 0, [], []).
blacks([H|T0], [H|T1], Blacks, SetRemain, GuessRemain) :-
!,
blacks(T0, T1, Blacks0, SetRemain, GuessRemain),
Blacks is Blacks0 + 1.
blacks([H0|T0], [H1|T1], Blacks, [H0|SetRemain], [H1|GuessRemain]) :-
blacks(T0, T1, Blacks, SetRemain, GuessRemain).

Now you have the blacks and the non-matched sets and have to
compute the whites :)

Cheers --- Jan

On 01/24/2017 05:10 PM, Kelly wrote:
> Hello all,
>
> I'm trying to implement a mastermind game, the rules can be found on
> https://en.wikipedia.org/wiki/Mastermind_(board_game).
> In my program duplicates are not allowed and the player has 10 turns to
> guess the code.
> I know that the code can be improved, but for now I'm trying to resolve
> --
> You received this message because you are subscribed to the Google
> Groups "SWI-Prolog" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to swi-prolog+...@googlegroups.com
> <mailto:swi-prolog+...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/swi-prolog.
> For more options, visit https://groups.google.com/d/optout.

Kelly

unread,
Mar 4, 2017, 6:04:13 PM3/4/17
to SWI-Prolog, kellym.ol...@gmail.com
Thanks a lot, that was really helpful!
Reply all
Reply to author
Forward
0 new messages