魔法六角无法约束自己
Magic Hexagon can't constrain itself
我正在尝试解决 Prolog 中第 5 维的 Magic Hexagon 问题(?)。我首先使用二维列表创建布局。然后我尝试约束该列表(实际上是一个列表)的每个元素。
但是,我无法让它工作,这是我的代码,在所有更新之后:
:- use_module(library(clpfd)).
solve(Dim) :-
length(L, 5), % define 5 diagonals
Offset is Dim - 2,
Flag is 0,
fill(L, Offset, Dim, Flag),
writeln(L),
constraint_sum(L, 38),
writeln(L).
constraint_sum([], _).
constraint_sum([H|T], Sum) :-
label(H),
sum_list(H, Sum),
constraint_sum(T, Sum).
fill([], _, _, _).
fill([H|T], Len, Dim, Flag) :-
Flag == 0,
Len < Dim,
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len + 1,
fill(T, NewLen, Dim, Flag).
fill([H|T], Len, Dim, _) :-
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len - 1,
Flag is 1,
fill(T, NewLen, Dim, Flag).
我得到:
1 ?- solve(5).
[[_G2537,_G2581,_G2617],[_G2857,_G2893,_G2929,_G2965],
[_G3263,_G3299,_G3335,_G3371,_G3407],[_G3757,_G3793,_G3829,_G3865],
[_G4157,_G4193,_G4229]]
[[1,18,19],[1,2,16,19],[1,2,3,13,19],[1,2,16,19],[1,18,19]]
true .
..如您所见,问题是元素不是唯一的,因为我对每个列表分别使用了 all_different()
而不是整个列表,但我不知道该怎么做!
我敢打赌 - 但我认为存在错误,因为问题页面指出只有一个解决方案。
:- module(magic_exagon, [magic_exagon/0]).
:- use_module(library(clpfd)).
magic_exagon :-
magic_exagon(3, 38).
magic_exagon(N, Sum) :-
R is N*2-1,
findall(L, (between(1,R,C), c_cells(C,N,R,L)), Rows),
flatten(Rows, Cells),
length(Cells, Max),
Cells ins 1..Max,
all_different(Cells),
get_diags(Rows, N,R,1, LeftDiags),
reverse(Rows, Rev),
maplist(reverse, Rev, RevRows),
get_diags(RevRows, N,R,1, RightDiags),
maplist(sum_diags(Sum), Rows),
maplist(sum_diags(Sum), LeftDiags),
maplist(sum_diags(Sum), RightDiags),
label(Cells),
show(rows, Rows).
c_cells(C,N,R,L) :-
( C > N -> M is N+R-C ; M is N+C-1 ),
length(L,M).
sum_diags(Sum, Diag) :-
sum(Diag, #=, Sum).
get_diags([], _,_,_, []).
get_diags(Rows, N,R,C, [Diag|Diags]) :-
c_cells(C, N, R, Diag),
capture(Diag, Rows, RestWithEmpty),
drop_empties(RestWithEmpty, Rest),
C1 is C+1,
get_diags(Rest, N,R,C1, Diags).
capture([], Rest, Rest).
capture([Cell|Diag], [[Cell|Cs]|Rows], [Cs|Rest]) :-
capture(Diag, Rows, Rest).
drop_empties([[]|RestT], Rest) :- !, drop_empties(RestT, Rest).
drop_empties(Rest, Rest).
show(K,Ds) :- writeln(K), maplist(writeln, Ds).
get_diags/5 很难处理索引。我设计了一种算法来从操场上捕获诊断。我们不能在变量被赋予属性后使用 findall/3,因此递归循环。
编辑
显示对角线,一个简单的方法
...
label(Cells),
show(rows, Rows),
show(left, LeftDiags),
show(right, RightDiags).
我们得到
?- magic_exagon.
rows
[3,16,19]
[17,6,7,8]
[18,4,1,5,10]
[12,2,11,13]
[9,14,15]
left
[3,17,18]
[16,6,4,12]
[19,7,1,2,9]
[8,5,11,14]
[10,13,15]
right
[15,13,10]
[14,11,5,8]
[9,2,1,7,19]
[12,4,6,16]
[18,17,3]
我正在尝试解决 Prolog 中第 5 维的 Magic Hexagon 问题(?)。我首先使用二维列表创建布局。然后我尝试约束该列表(实际上是一个列表)的每个元素。 但是,我无法让它工作,这是我的代码,在所有更新之后:
:- use_module(library(clpfd)).
solve(Dim) :-
length(L, 5), % define 5 diagonals
Offset is Dim - 2,
Flag is 0,
fill(L, Offset, Dim, Flag),
writeln(L),
constraint_sum(L, 38),
writeln(L).
constraint_sum([], _).
constraint_sum([H|T], Sum) :-
label(H),
sum_list(H, Sum),
constraint_sum(T, Sum).
fill([], _, _, _).
fill([H|T], Len, Dim, Flag) :-
Flag == 0,
Len < Dim,
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len + 1,
fill(T, NewLen, Dim, Flag).
fill([H|T], Len, Dim, _) :-
length(H, Len),
H ins 1..19,
all_different(H),
NewLen is Len - 1,
Flag is 1,
fill(T, NewLen, Dim, Flag).
我得到:
1 ?- solve(5).
[[_G2537,_G2581,_G2617],[_G2857,_G2893,_G2929,_G2965],
[_G3263,_G3299,_G3335,_G3371,_G3407],[_G3757,_G3793,_G3829,_G3865],
[_G4157,_G4193,_G4229]]
[[1,18,19],[1,2,16,19],[1,2,3,13,19],[1,2,16,19],[1,18,19]]
true .
..如您所见,问题是元素不是唯一的,因为我对每个列表分别使用了 all_different()
而不是整个列表,但我不知道该怎么做!
我敢打赌 - 但我认为存在错误,因为问题页面指出只有一个解决方案。
:- module(magic_exagon, [magic_exagon/0]).
:- use_module(library(clpfd)).
magic_exagon :-
magic_exagon(3, 38).
magic_exagon(N, Sum) :-
R is N*2-1,
findall(L, (between(1,R,C), c_cells(C,N,R,L)), Rows),
flatten(Rows, Cells),
length(Cells, Max),
Cells ins 1..Max,
all_different(Cells),
get_diags(Rows, N,R,1, LeftDiags),
reverse(Rows, Rev),
maplist(reverse, Rev, RevRows),
get_diags(RevRows, N,R,1, RightDiags),
maplist(sum_diags(Sum), Rows),
maplist(sum_diags(Sum), LeftDiags),
maplist(sum_diags(Sum), RightDiags),
label(Cells),
show(rows, Rows).
c_cells(C,N,R,L) :-
( C > N -> M is N+R-C ; M is N+C-1 ),
length(L,M).
sum_diags(Sum, Diag) :-
sum(Diag, #=, Sum).
get_diags([], _,_,_, []).
get_diags(Rows, N,R,C, [Diag|Diags]) :-
c_cells(C, N, R, Diag),
capture(Diag, Rows, RestWithEmpty),
drop_empties(RestWithEmpty, Rest),
C1 is C+1,
get_diags(Rest, N,R,C1, Diags).
capture([], Rest, Rest).
capture([Cell|Diag], [[Cell|Cs]|Rows], [Cs|Rest]) :-
capture(Diag, Rows, Rest).
drop_empties([[]|RestT], Rest) :- !, drop_empties(RestT, Rest).
drop_empties(Rest, Rest).
show(K,Ds) :- writeln(K), maplist(writeln, Ds).
get_diags/5 很难处理索引。我设计了一种算法来从操场上捕获诊断。我们不能在变量被赋予属性后使用 findall/3,因此递归循环。
编辑
显示对角线,一个简单的方法
...
label(Cells),
show(rows, Rows),
show(left, LeftDiags),
show(right, RightDiags).
我们得到
?- magic_exagon.
rows
[3,16,19]
[17,6,7,8]
[18,4,1,5,10]
[12,2,11,13]
[9,14,15]
left
[3,17,18]
[16,6,4,12]
[19,7,1,2,9]
[8,5,11,14]
[10,13,15]
right
[15,13,10]
[14,11,5,8]
[9,2,1,7,19]
[12,4,6,16]
[18,17,3]