我是 clingo(答案集编程)的新手,我遇到了一个非常简单的问题。
我想模拟一个非常简单的行为: 一个两行三列的游戏板,三个令牌放置在第一行。 就像棋子一样,三个棋子只能走一种棋:领先一步。
每次只能移动一个令牌,并且必须移动。为了简单起见,我想代表仅一步棋后的游戏。 所以,最初的时刻会是这样的:
下一刻应该看起来像这三种情况之一:
我的目标是准确获得这三个答案集。
所以我的代码是这样的:
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).
随后它会根据当前代码生成游戏在第二时刻可能呈现的八种可能的方式:
答案:1→令牌(零,零,零)令牌(零,一,零)令牌(零,二,零)
答案:2 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,一,一)
答案:3 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,零,一)
答案:4 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,一,一) 令牌(一,零,一)
答案:5 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,二,一)
答案:6 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,二,一) 令牌(一,零,一)
答案:7 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,二,一) 令牌(一,一,一)
答案:8 -> 令牌(零,零,零) 令牌(零,一,零) 令牌(零,二,零) 令牌(一,二,一) 令牌(一,一,一) 令牌(一,零) ,一个)
剩下要做的唯一任务是消除一次移动多于或少于一个标记而生成的所有答案集。对于游戏来说,每回合只能移动一个令牌......因此必须仅包含上面公开的三个所需的集合。
所以我在代码中添加了这个否定规则:
% 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).
它否定了 8 个答案集中的第一个和最后一个,仍然留下 6 个答案。
那么,“如果其中一个且只有一个移动”到底该怎么用 clingo 表达呢?
注意: 我还尝试为令牌创建一个 Id,但由于 clingo 将否定规则模糊地应用于集合的所有事实,因此我认为这不适用于解决方案。 我尝试了代码:
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).
但也是错误的...
这是一个可能的解决方案,但可能存在更有效的解决方案
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(_,_,_).