Implement counter prolog

2019-08-18 14:46发布

问题:

I'm developing a board game in PROLOG and in order to make the interface more enjoyable for the user, I decided to add a grid with the coordinates (0->4) as shown below:

    0 1 2 3 4
    ---------
0 | x x x x x
1 | x o x o o
2 | o x o x x
3 | x x o o o
4 | o x x x o

After developing some code, I came across with an issue regarding the counter for the vertical coordinates. The predicate stops right after I implement the counter Index is Index + 1, as shown below:

printGrid :- %Only prints the horizontal grid
        write('\t'), write(0), write('   '), write(1), write('   '), write(2), write('   '), write(3), write('   '), write(4), nl,
        write('\t'), write('------------------'), nl.     

printBoard([Head|Tail]) :-
        Index = 0,
        Index is Index + 1,
        % STOPS HERE ------------
        write('    '), write(Index), write('  |'), write(' '),
        printRow(Head),
        printBoard(Tail).
printBoard([]).

printRow([Head|Tail]) :-
        write(Head),
        write('  '),
        printRow(Tail).
printRow([]) :- nl.

I'm aware the counter will reset to 0 every time recursion is called, thus I don't really know how to set the Index to 0 just about once and go from there. Any tips on how to solve both of the issues?

回答1:

You cannot change the value of a variable that has been already bound. You need to use a new variable, for example, I1 is I + 1, or maybe succ(I, I1).

Another thing you can do if you want to anyway use the side effect (printing in your case), is to put between in a forall loop:

?- forall(between(0, 4, X), format('~d~n', [X])).
0
1
2
3
4
true.

You can of course have nested foralls:

?- forall(between(0, 5, X),
       (   forall(between(0, 4, Y),
               format('~d-~d ', [X,Y])),
           format('~n')
       )).
0-0 0-1 0-2 0-3 0-4 
1-0 1-1 1-2 1-3 1-4 
2-0 2-1 2-2 2-3 2-4 
3-0 3-1 3-2 3-3 3-4 
4-0 4-1 4-2 4-3 4-4 
5-0 5-1 5-2 5-3 5-4 
true.

The way to enumerate the members of a list, then, would be to use nth0, for example,

?- forall(nth0(N, [a,b,c,d], E), format('~d-~a~n', [N,E])).
0-a
1-b
2-c
3-d
true.

Or, if you don't need the element (when you are just marking the columns:

?- length([a,b,c,d], Len),
   Last is Len - 1,
   forall(between(0, Last, X), format('~d~n', [X])).
0
1
2
3
Len = 4,
Last = 3.

Or ignoring the element when you are using nth0:

?- forall(nth0(N, [a,b,c,d], _), format('~d~n', [N])).
0
1
2
3
true.

There are other predicates that can offer similar functionality, depending on what exactly your goal is. See findall and maplist, for example.

But of course you can do the recursion yourself, if you remember to do the I1 is I + 1.



回答2:

I examined the link which @Otrebor provided and I came up with a fine solution. I forgot the "little" detail that when bound, a variable can't be changed, thus I added an extra one. Here's how it looks:

printBoard([], _).
printBoard([Head|Tail], Counter) :-
        Index is Counter + 1,
        write('    '), write(Index), write('  |'), write(' '),
        printRow(Head),
        printBoard(Tail, Index).

main :- printBoard(Board, 0).


标签: prolog