0

I’m new to clingo (answer set programming) and I’m stuck with a very simple problem.

I want to simulate a very simple behaviour: A game board with two rows and three columns, and three tokens, placed on the first row. As if they were chess pawns, the three tokens can only make one kind of move: one step ahead.

Only one token can move each time, and has to. To simplify, I want to represent the game after just one move. So, the initial moment will look like this:

enter image description here

And the next moment should look like one of this three situations:

enter image description hereenter image description hereenter image description here

My goal is to get exactly that three answer sets.

So I made my code like this:

next(zero, one).

% The three tokens at initial positions. Parameters are (Row, Column, Moment).
token(zero, zero, zero).
token(zero, one, zero).
token(zero, two, zero).

% The position of the tokens in time, that may result from moving one step ahead
{ token(Row, Column, Moment) } :-
    token(InitialRow, Column, InitialMoment),
    next(InitialRow, Row),
    next(InitialMoment, Moment).

And it subsequently generates the eight possible ways the game may look like at second moment, attending to the current code:

enter image description here enter image description here

Answer: 1 → token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero)
Answer: 2 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,one,one)
Answer: 3 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,zero,one)
Answer: 4 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,one,one) token(one,zero,one)
Answer: 5 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,two,one)
Answer: 6 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,two,one) token(one,zero,one)
Answer: 7 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,two,one) token(one,one,one)
Answer: 8 -> token(zero,zero,zero) token(zero,one,zero) token(zero,two,zero) token(one,two,one) token(one,one,one) token(one,zero,one)


The only task left to do is eliminate all the answer sets that have been generated moving more or less than one token at a time. It’s mandatory for the game that only one token moves each turn… so must contain only the three desired sets exposed above.

So I add to the code this negation rules:

% Eliminate if
:- token(Row, Column, Moment), % all of its tokens didn't move
    next(Moment, NextMoment),
    token(Row, Column, NextMoment).

% Eliminate if
:- token(Row, Column, Moment), % all of its tokens moved
    next(Moment, NextMoment),
    not token(Row, Column, NextMoment).

And it negates the first and the last of the 8 answer sets, still leaving 6 sets.

Then, how on earth should I express “if one and only one of them moved” in clingo?

Note: I also tried creating an Id for tokens, but since clingo applies negation rules to all facts of a set indistinctly, I dont think works for a solution. I tried the code:

next(zero, one).

% The three tokens at initial positions. Parameters are (Row, Column, Moment, Id).
token(zero, zero, zero, zero).
token(zero, one, zero, one).
token(zero, two, zero, two).

% The position of the tokens in time, that may result from moving one step ahead
{ token(Row, Column, Moment, _) } :-
    token(InitialRow, Column, InitialMoment, _),
    next(InitialRow, Row),
    next(InitialMoment, Moment).

% Eliminate if
:- token(Row, Column, Moment, Id), % all of it's tokens moved while the rest of tokens stay still (nonesense)
    next(Moment, NextMoment),
    not token(Row, Column, NextMoment, Id),
    token(Row2, Column2, Moment2, Id2),
    not Id = Id2, % (intended to get only the rest of the tokens. Does this make sense?)
    next(Moment2, NextMoment2),
    token(Row2, Column2, NextMoment2).

But is wrong, as well...

false
  • 10,264
  • 13
  • 101
  • 209
Marc
  • 101
  • 2
  • 4

1 Answers1

0

Here a possible solution, but there may exist more efficient ones

next(0, 1).
col(0..2).
row(0..1).

% The three tokens at initial positions. Parameters are (Row, Column, Moment).
token(0, 0, 0).
token(0, 1, 0).
token(0, 2, 0).

{next_token(R1,C,T1)}:- token(R,C,T), R1 = R + 1, row(R1), next(T,T1).

% no more than one next move
:- next_token(_,C0,T), next_token(_,C1,T), C0 != C1. 

% at least one next move
:- not next_token(_,_,_). 
damianodamiano
  • 2,528
  • 2
  • 13
  • 21
  • Thank you very much. But your answer is only applicable to this very reduced (as I said in the question, for simplicity) version of the problem. If I extend the game to have 3 rows, with 2 rounds of movement, the "next_token/3" statement would no more be indicative of the quantity of tokens that moved on each round. So it's adjusted for this simplified version, but inapplicable. – Marc Aug 11 '23 at 07:37