用序言解决 Str8ts,在设置约束(域)后标记

solve Str8ts with prolog, labeling after set the constraints(domain)

我想用prolog

解决str8ts

我为所有列表设置了 3 个约束:

  1. 约束 1: 每个列表 --> all_different(list)

  2. 约束 2: 每个列表 --> list ins 1..9

  3. 约束 3: 每个列表 --> 白色组之间(或一个黑色之前,或一个黑色之后)2 个黑色字段必须是 无缝

设置约束后,我调用 labeling([ff],PuzzleVariable)

问题是设置约束3 让我用我的代码解释一下。 我的代码:

首先我输入包含 81 个元素的列表的拼图(A1、B1、C1 是数字,IB11、IB12... 显示是否为黑色区域) :

puzzle([[A1,IB11],[A2,IB12],[A3,IB13], [A4,IB14],[A5,IB15],[A6,IB16],[A7,IB17],[A8,IB18],[A9,IB19],
  [B1,IB21],[B2,IB22],[B3,IB23], [B4,IB24],[B5,IB25],[B6,IB26],[B7,IB27],[B8,IB28],[B9,IB29],
   [C1,IB31],[C2,IB32],[C3,IB33], [C4,IB34],[C5,IB35],[C6,IB36],[C7,IB37],[C8,IB38],[C9,IB39],

   [D1,IB41],[D2,IB42],[D3,IB43], [D4,IB44],[D5,IB45],[D6,IB46],[D7,IB47],[D8,IB48],[D9,IB49],
   [E1,IB51],[E2,IB52],[E3,IB53], [E4,IB54],[E5,IB55],[E6,IB56],[E7,IB57],[E8,IB58],[E9,IB59],
   [F1,IB61],[F2,IB62],[F3,IB63], [F4,IB64],[F5,IB65],[F6,IB66],[F7,IB67],[F8,IB68],[F9,IB69],

   [G1,IB71],[G2,IB72],[G3,IB73], [G4,IB74],[G5,IB75],[G6,IB76],[G7,IB77],[G8,IB78],[G9,IB79],
   [H1,IB81],[H2,IB82],[H3,IB83], [H4,IB84],[H5,IB85],[H6,IB86],[H7,IB87],[H8,IB88],[H9,IB89],
   [I1,IB91],[I2,IB92],[I3,IB93], [I4,IB94],[I5,IB95],[I6,IB96],[I7,IB97],[I8,IB98],[I9,IB99]])

之后,我想为列表的每一行和每列设置 3 个约束,所以我为所有行和列调用 "pruefen":

 %CHECK ROWS
    pruefen([[A1,IB11],[A2,IB12],[A3,IB13], [A4,IB14],[A5,IB15],[A6,IB16],[A7,IB17],[A8,IB18],[A9,IB19]]),
    pruefen([[B1,IB21],[B2,IB22],[B3,IB23], [B4,IB24],[B5,IB25],[B6,IB26],[B7,IB27],[B8,IB28],[B9,IB29]]),
    pruefen([[C1,IB31],[C2,IB32],[C3,IB33], [C4,IB34],[C5,IB35],[C6,IB36],[C7,IB37],[C8,IB38],[C9,IB39]]),
    pruefen([[D1,IB41],[D2,IB42],[D3,IB43], [D4,IB44],[D5,IB45],[D6,IB46],[D7,IB47],[D8,IB48],[D9,IB49]]),
    pruefen([[E1,IB51],[E2,IB52],[E3,IB53], [E4,IB54],[E5,IB55],[E6,IB56],[E7,IB57],[E8,IB58],[E9,IB59]]),
    pruefen([[F1,IB61],[F2,IB62],[F3,IB63], [F4,IB64],[F5,IB65],[F6,IB66],[F7,IB67],[F8,IB68],[F9,IB69]]),
    pruefen([[G1,IB71],[G2,IB72],[G3,IB73], [G4,IB74],[G5,IB75],[G6,IB76],[G7,IB77],[G8,IB78],[G9,IB79]]),
    pruefen([[H1,IB81],[H2,IB82],[H3,IB83], [H4,IB84],[H5,IB85],[H6,IB86],[H7,IB87],[H8,IB88],[H9,IB89]]),
    pruefen([[I1,IB91],[I2,IB92],[I3,IB93], [I4,IB94],[I5,IB95],[I6,IB96],[I7,IB97],[I8,IB98],[I9,IB99]]),
    %CHECK COLUMNS
    pruefen([[A1,IB11],[B1,IB21],[C1,IB31], [D1,IB41],[E1,IB51],[F1,IB61],[G1,IB71],[H1,IB81],[I1,IB91]]),
    pruefen([[A2,IB12],[B2,IB22],[C2,IB32], [D2,IB42],[E2,IB52],[F2,IB62],[G2,IB72],[H2,IB82],[I2,IB92]]),
    pruefen([[A3,IB13],[B3,IB23],[C3,IB33], [D3,IB43],[E3,IB53],[F3,IB63],[G3,IB73],[H3,IB83],[I3,IB93]]),
    pruefen([[A4,IB14],[B4,IB24],[C4,IB34], [D4,IB44],[E4,IB54],[F4,IB64],[G4,IB74],[H4,IB84],[I4,IB94]]),
    pruefen([[A5,IB15],[B5,IB25],[C5,IB35], [D5,IB45],[E5,IB55],[F5,IB65],[G5,IB75],[H5,IB85],[I5,IB95]]),
    pruefen([[A6,IB16],[B6,IB26],[C6,IB36], [D6,IB46],[E6,IB56],[F6,IB66],[G6,IB76],[H6,IB86],[I6,IB96]]),
    pruefen([[A7,IB17],[B7,IB27],[C7,IB37], [D7,IB47],[E7,IB57],[F7,IB67],[G7,IB77],[H7,IB87],[I7,IB97]]),
    pruefen([[A8,IB18],[B8,IB28],[C8,IB38], [D8,IB48],[E8,IB58],[F8,IB68],[G8,IB78],[H8,IB88],[I8,IB98]]),
    pruefen([[A9,IB19],[B9,IB29],[C9,IB39], [D9,IB49],[E9,IB59],[F9,IB69],[G9,IB79],[H9,IB89],[I9,IB99]]),

所以,我为列表调用 pruefen。

首先我排除了所有黑色和未定义的字段,因为我没有need/want为它们设置约束:

  %exclude black and undefined lists
  exclude(isBlackAndEmpty,L,NewList),
  %Constraint 1 and 2, every list ins 1..9 and all different(list)
  constraintsFestlegen(NewList),

排除谓词:

isBlackAndEmpty([Variable|IsBlack]):- IsBlack=:=1, var(Variable).

设置约束的谓词:

    %set constraints for whole list(black and undefined excluded)
  variablenListeErstellen([],Variablen):-
      %jede Liste darf nur aus Zahlen von 1..9 bestehen
      Variablen ins 1..9,
      %es dürfen in der Liste keine Zahlen doppelt vorkommen
      %bibliothek von SWI-Prolog Bibliothek clpfd
      all_different(Variablen).

所以,这是针对约束 1 和 2 的。


约束 3:我将每个列表分成几组白色字段。

创建组的谓词:

%ausstiegspunkt für eine leere liste
  listGroupConstraints([]).

  %for a list with a black field
  listGroupConstraints(List):-
  append(Prefix, [[_,1]|Rest],List),
  %creates one dimensional list
  createOneDimensional(Prefix,OneDimensionalList),
  %rekursiv
  listGroupConstraints(Rest).

   %for a list without a black field
  listGroupConstraints(List):-
  %convert to one dimensional list
  createOneDimensional(List,OneDimensionalList),
  %set constraint for one dimensional list
  setGroupConstraints(OneDimensionalList).

我用来为所有白色字段组设置约束 3 的 setGroupConstraints。

用于检查无间隙并设置约束 3 的谓词:

  %check if group is gapless,
  listl(L) :-
    [Fst,Lst] ins 1..9,
    Fst #=< Lst,
    Len #= Lst - Fst + 1,
    length(L, Len),
    label([Fst,Lst]),
    L ins Fst..Lst,
    all_different(L).

设置 3 个约束后,我将整个输入列表过滤为仅标记白色字段:

排除(isBlack、List、ExcludedList)

 %check if black
  isBlack([Variable|IsBlack]):-
  IsBlack=:=1.

   %create one dimensional list from two dimensional list for labeling all
  %get the first variables from list
  createOneDimensionalForLabeling([],Variablen):-
  print(Variablen),
  labeling([ff],Variablen).
  createOneDimensionalForLabeling([X|Rest],Variablen):-
  listeInListe(X,Variable,IsBlack),
  append(Variablen,[Variable],MyList),
  createOneDimensionalForLabeling(Rest,MyList).

但是在标记时我得到:错误:参数没有充分实例化

有人知道这个问题吗?

示例输入:

puzzle([[9,1],[6,0],[8,0],[1,0],[_,0],[_,0],[_,0],[4,0],[_,0],[_,0],[_,0],[_,1],[_,1],[4,0],[_,0],[_,0],[7,1],[_,1],[5,0],[_,1],[_,1],[_,0],[3,0],[_,0],[_,1],[_,1],[_,0],[_,0],[_,1],[_,0],[_,0],[_,0],[4,0],[6,1],[_,0],[_,0],[_,1],[_,0],[_,0],[_,0],[_,1],[_,0],[_,0],[_,0],[_,1],[3,0],[_,0],[_,1],[_,0],[5,0],[8,0],[_,0],[_,1],[_,0],[_,0],[_,1],[_,1],[_,0],[_,0],[_,0],[_,1],[5,1],[_,0],[_,1],[_,1],[5,0],[_,0],[_,0],[_,1],[4,1],[1,0],[_,0],[_,0],[7,0],[_,0],[_,0],[_,0],[_,0],[_,0],[_,0],[1,1]]).

已编辑 我可以从变量中删除域吗? 当我从二维列表中创建一维列表时。在调用 i 时,变量列表有一个域:lists:append([6, 8, 1, _G5{clpfd = ...}, _G6{clpfd = ...}, _G7{clpfd = ...}, 4|...],

但是完成一维列表后,变量看起来像:

[6,8,1,_G5,_G6,_G7,4,_G8,_G9,_G10,4,...]

编辑 2

如果我打电话给constraintsFestlegen([[A,0],[B,0],[4,0],[C,0],[D,0],[7,1]]),listl([A,B]),listl([4,C,D]),labeling([ff],[A,B,C,D]).

它工作正常。但是当我打电话给 pruefen([[A,0],[1,1],[B,0],[3,0],[_,1],[6,0],[C,0],[D,0],[E,0]]),labeling([ff],[A,B,C,D,E]). 我运行出栈了。所以如果我是对的,错误必须在过滤列表中......

我在看str8ts拼图。这个谜题的难点在于编码一个事实,即有一组连续的数字,但不是有序的! 解决任务的一种方法是对集合进行排序,并说当Len是列表的长度时,列表的第一个和最后一个数字之间的差是Len-1。

集合中的所有数字都统一时,这很容易做到,但是当它们不统一时,我们该怎么办?

您可以 post 在 Prolog 中使用 when/2 约束:

所以你可以说当Seq的所有数字统一时,(例如在Prolog中:ground(Seq)),你会按照我上面解释的去做。

在序言中你将写:

    when(ground(Seq),
         ( sort(Seq, SSeq),
           reverse(SSeq, RSeq),
           SSEq = [F|_],
           RSeq = [L | _],
           L - F =:= Len - 1)))

编辑:我的解决方案

:- use_module(library(clpfd)).
:- use_module(library(lambda)).


str8ts(N) :-
    grille(N, Tableau),
    set_lines(Tableau, Vs1),
    clpfd:transpose(Tableau, R_T),
    set_lines(R_T, Vs2),
    flatten([Vs1, Vs2], Vs),
    label(Vs),
    maplist(writeln, Tableau).




set_lines(Tableau, Vs) :-
    maplist(set_one_line, Tableau, Vs).

set_one_line(Ligne, Vs) :-
    % we fetch forbidden numbers
    foldl(\X^Y^Z^((nonvar(X), X < 0)
             ->  Z = [X | Y]
             ;   Z = Y), Ligne, [], Interdites),
    set_one_line(Ligne, Interdites, [], [], Vs).



% @arg1 : line to study
% @arg2 : list of forbidden numbers for this line
% @arg3 : sequence of variables to unify
% @arg4 : Sequences allready seen
% @arg5 : final list of variables

% Line finished,
% all the numbers of the line must be different
set_one_line([],Forbidden, Tmp_Vs, Cur_Vs, Vs) :-
    flatten( [Tmp_Vs | Cur_Vs], Vs),
    all_distinct(Vs),
    init_sequence(Tmp_Vs,Forbidden).

set_one_line([H|T],Forbidden, Tmp_Vs, Cur_Vs, Vs) :-
    % nonvar must be tested because during backtrack
    % we may have error message :
    % ERROR: H > 0 : Arguments are not sufficiently instantiated
    (   var(H); nonvar(H), H > 0),
    set_one_line(T, Forbidden, [H | Tmp_Vs], Cur_Vs, Vs).


set_one_line([H|T],Forbidden, Tmp_Vs, Cur_Vs, Vs) :-
    nonvar(H),
    H =< 0,
    % here we must init a sequence
    init_sequence(Tmp_Vs,Forbidden),
    set_one_line(T, Forbidden, [], [Tmp_Vs |Cur_Vs], Vs).


% the sequence may be empty
init_sequence([], _).

% the sequence may have only one element
init_sequence([X], Forbidden) :-
    maplist(\Y^(X #\= -Y), Forbidden).

init_sequence(L, Forbidden) :-
    set_constraint(L),
        maplist(L +\X^maplist(X +\Y^(Y #\= -X), L), Forbidden).


set_constraint(Line) :-
    length(Line, Len),
    Line ins 1..9,
    all_distinct(Line),
    % we post a contraint on the set of elements
    when(ground(Line),
         (   sort(Line, [H | Tail]),
         reverse([H | Tail], [K |_]),
         K - H =:= Len-1)).


% 142,019,193 inferences, 17.394 CPU in 17.441 seconds (100% CPU, 8164786 Lips)
grille(1,[[0,0,_,_,5,_,_,-3,0],
      [_,6,_,_,0,0,1,_,_],
      [_,_,_,0,-8,_,_,_,_],
      [9,_,_,-4,_,_,_,0,-5],
      [0,_,_,_,_,3,_,_,0],
      [0,0,_,_,_,-9,_,4,_],
      [4,_,3,_,0,0,_,6,_],
      [_,_,1,0,0,_,_,_,_],
      [0,0,8,_,_,_,_,0,-2]]).

% 37,023,520 inferences, 3.900 CPU in 3.916 seconds (100% CPU, 9493149 Lips)
grille(2, [[0,-1,_,_,_,0,_,8,6],
       [_,4,_,_,8,7,_,_,0],
       [_,_,_,0,_,_,_,_,0],
       [0,0,3,_,_,-8,0,_,_],
       [_,_,_,_,1,_,_,_,_],
       [6,_,0,-4,_,_,_,-9,0],
       [-2,_,_,_,9,0,_,_,_],
       [0,_,_,_,_,_,6,_,_],
       [_,_,_,0,_,_,_,0,-3]]).