GRoutar
GRoutar

Reputation: 1425

Counter resets after predicate call

I am developing a board game and to finalize I'm just missing my win condition.

The winner is supposed to be the 1st player to complete 4 stacks and those stacks are represented by the following board symbols:

Player 1 - 's1' , 'S1'
Player 2 - 's2' , 'S2'

Therefore, in order to determinate the winner,I have to run through the board (list of lists) and count the number of times the symbols are in the same one. When one of the players reaches 4 stacks completed, then he shall be the winner of the game:

checkWin([],_,_).
checkWin([Head|Tail], Counter1, Counter2) :-

        checkStacks(Head, Counter1, Counter2), nl,
        (Counter1 = 4 -> write('Player 1 is the winner!'); true),
        (Counter2 = 4 -> write('Player 2 is the winner!'); true),
        checkWin(Tail,Counter1,Counter2).

checkStacks([],_,_).
checkStacks([Head|Tail], Counter1, Counter2) :-

        Symbol = Head,
        ((Symbol = 's1'; Symbol = 'S1') -> StackCounter1 is Counter1 + 1; StackCounter1 is Counter1),
        ((Symbol = 's2'; Symbol = 'S2') -> StackCounter2 is Counter2 + 1; StackCounter2 is Counter2),

        write('SC1 = '), write(StackCounter1), write('   SC2 = '), write(StackCounter2), nl,

        checkStacks(Tail, StackCounter1, StackCounter2).

Although, the code developed does not work as expected. Counter1 and Counter2 from checkWin/3 are meant to be initialized at 0 ?-checkWin([...],0,0). and increment as matches are found but, instead, it resets to 0 everytime the predicate calls recursion.

Current Output:

?- checkWin( [['b0','b0','b0','S1','s1'],
              ['b0','b0','b0','b0','B0'],
              ['b0','b0','b0','s1','S2'],
              ['b0','b0','b0','b0','s2'],
              ['b2','b0','b0','b0','b0']], 0, 0).

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 1   SC2 = 0
SC1 = 2   SC2 = 0 % SC1 = 2, 2 matches were found for Player1 in the first row

SC1 = 0   SC2 = 0 % SC1 resets to 0 instead of having the previous value(2)
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 1   SC2 = 0
SC1 = 1   SC2 = 1

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 1

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
yes
% source_info

Expected Output:

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 1   SC2 = 0
SC1 = 2   SC2 = 0 

SC1 = 2   SC2 = 0 
SC1 = 2   SC2 = 0
SC1 = 2   SC2 = 0
SC1 = 2   SC2 = 0
SC1 = 2   SC2 = 0

SC1 = 2   SC2 = 0
SC1 = 2   SC2 = 0
SC1 = 2   SC2 = 0
SC1 = 3   SC2 = 0
SC1 = 3   SC2 = 1

SC1 = 3   SC2 = 1
SC1 = 3   SC2 = 1
SC1 = 3   SC2 = 1
SC1 = 3   SC2 = 1
SC1 = 3   SC2 = 2 % - number of matches for each player 

SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
SC1 = 0   SC2 = 0
yes
% source_info

Upvotes: 0

Views: 57

Answers (2)

GRoutar
GRoutar

Reputation: 1425

Thanks to CapelliC, and after adjusting the predicates provided, I finally got to a solution to my problem. Here's how it looks:

occurrences(Symbol, L, N) :-
        aggregate_all(count, member(Symbol, L), N).

checkWin([], C1, C2) :- write('Player 1 Counter = '), write(C1), nl, 
                        write('Player 2 Counter = '), write(C2), nl.
checkWin([Head|Tail], C1, C2) :-

        occurrences('s1', Head, N),
        occurrences('S1', Head, N1),
        occurrences('s2', Head, N2),
        occurrences('S2', Head, N3),

        D1 is N + N1 + C1, D2 is N2 + N3 + C2,
        checkWin(Tail, D1, D2).

Upvotes: 0

CapelliC
CapelliC

Reputation: 60024

You are 'reversing' the computation flow. Try

checkStacks([],0,0).
checkStacks([Head|Tail], Counter1, Counter2) :-

        checkStacks(Tail, StackCounter1, StackCounter2),

        Symbol = Head,
        ((Symbol = 's1'; Symbol = 'S1') -> Counter1 is StackCounter1 + 1; Counter1 is StackCounter1),
        ((Symbol = 's2'; Symbol = 'S2') -> Counter2 is StackCounter2 + 1; Counter2 is StackCounter2).

If you want to give Prolog' builtins a try, here is an alternative:

checkStacks(L,N1,N2) :-
    findall(t, (member(s1, L) ; member('S1', L)), L1), length(L1,N1)
    findall(t, (member(s2, L) ; member('S2', L)), L2), length(L2,N2).

which can be shortened using library(aggregate)

checkStacks(L,N1,N2) :-
    aggregate_all(count, (member(s1, L) ; member('S1', L)), N1), 
    aggregate_all(count, (member(s2, L) ; member('S2', L)), N2).

and a bit generalized, like

occurrences(Symbols, L, N) :-
    aggregate_all(count, (member(S, Symbols), member(S, L)), N).

checkStacks(L,N1,N2) :-
    occurrences([s1,'S1'], L, N1),
    occurrences([s2,'S2'], L, N2).

I think checkWin/3 definition doesn't match your description, I would write instead

checkWin(Stacks, P) :-
    member(S, Stacks),
    ( occurrences([s1,'S1'], S, 4) -> P = player1
    ; occurrences([s2,'S2'], S, 4) -> P = player2
    ).

Upvotes: 1

Related Questions