Minizinc에서 Tetris 솔버를 구현하려고합니다. 이는 내가 생각하는 "패킹"문제라고도합니다.Minizinc에서 Tetris 솔버 만들기 멈춤
저는 Minizinc에서 처음 접했고 현재 내가하고있는 일을 거의 이해하지 못했지만 현재는 코드의 특정 제약 조건을 고수하고 있습니다.
저는 4x4 사각형을 테트리스의 사각형에 4 개 배치하여 전체 사각형을 채울 수 있도록 4x4 사각형을 해결하려고합니다.
이 제약 조건이 먼저 제공하는 모든 블록을 통과하도록되어constraint forall(b in 1..total) %default
(
forall(x,y in 1..n)
(
(Type(TypeOf[b], 1) /\ Loc(b,x,y) /\ Rot(b, 1) /\ not Ref(b) /\ (y+3<=n))
-> (Has(x,y,b) /\ Has(x,y+1,b) /\ Has(x,y+2,b) /\ Has(x,y+3,b))
)
);
(4 "L"블록), 다음 실제 보드를 통해주기를 확인하는 방법은 다음과 같습니다 : 만약
내 하나 개의 큰 제약이있다 현재 블록은 유형 1 (유형 "l")이고 원점은 x, y에 있고 1의 회전 (이 경우 회전이 없음)이며 반사되지 않으며 3보다 큰 그 아래에 공간 블록이 있다면 x, y, y + 1, y + 2 및 y + 3에서 첫 번째 블록을 가져야합니다.
그러나 심지어이 제약 (내 모든 다른 제약), 난 아직도 솔버를 통해이 같은의 출력을 얻을과 :
블록은도 2 행에 배치되지 않는 것으로board:
4 4 4 4
3 2 2 2
2 1 1 1
1 3 3 3
loc:
0 0 0 0
1 1 1 1
0 0 0 0
0 0 0 0
왜냐하면 그것은 3 블록의 클리어링을 가지지 않기 때문에 보드는 원점과 전혀 일치하지 않기 때문에 블록을 똑바로 세우는 위의 제약 조건과 일치하지 않습니다.
저는이 문제를 해결하는 방법에 대한 아이디어가 없습니다. 논문에서 논리적 인 것처럼 보이지만 어디서 잘못되었는지 알 수는 없습니다. 내 모든 다른 제약 조건과 함께 전체 코드를 게시 할 것입니다. 유의하십시오. 저는 현재 하나의 방향에서 "l"블록에 대한 제약 조건 만 가지고 있음을 알고 있습니다. 그러나 "I"블록을 4 개의 "l"블록으로 해결하려고합니다. 이것은 한 방향으로 잘 맞아야하는데 이유가 없습니다. 출력중인 내용을 출력해야합니다.
도움 주셔서 감사합니다.
include "globals.mzn";
include "builtins.mzn";
%Given variables
int: n; %length of board size
set of int: ROW = 1..n;
int: m=n; %number of columns
set of int: COL = 1..m;
%Number of starting tetrominoes
int: nR; %ID 1 for R
int: nS; %ID 2 for S
int: nT; %ID 3 for T
int: nL; %ID 4 for L
int: total = nR+nS+nT+nL;
array[int] of int: R = [ 1 | i in 1..nR];
array[int] of int: S = [ 2 | i in 1..nS];
array[int] of int: T = [ 3 | i in 1..nT];
array[int] of int: L = [ 4 | i in 1..nL];
array[int] of int: TypeOf = R++S++T++L; %Array of all blocks
%Decision Variables
array[1..n*n] of var 1..total: board; %Stored via (y-1)*n+x, using 1D array for ease of access.
array[1..n*n] of var 0..4: loc; %A separate location board that maps the origin point of each block
array[1..total] of var 1..4: rot; %Block rotations
array[1..total] of var 0..1: ref; %Block reflections
constraint total*4 == n*n;
constraint 0 <= nR /\ nR <= n /\ 0 <= nS /\ nS <= n /\ 0 <= nT /\ nT<= n /\ 0 <= nL /\ nL <= n;
constraint forall(i in 1..total)(TypeOf[i] == 1 \/ TypeOf[i] == 2 \/ TypeOf[i] ==3 \/ TypeOf[i] == 4);
constraint count(TypeOf, 1, nR)/\count(TypeOf,2,nS)/\count(TypeOf,3,nT)/\count(TypeOf,4,nL);
predicate Has(int: x, int: y, int: b) = board[(y-1)*n+x] == b;
predicate IsBlock(int: b) = b == 1 \/ b==2 \/ b==3 \/ b==4;
% BOARD RECORDS BLOCK NUMBER
% LOC RECORDS TYPE
predicate Loc(int: b, int: x, int: y) = loc[(y-1)*n+x] == TypeOf[b];
predicate Type(int: b, int: x) = b == x;
predicate Ref(int: i) = ref[i] == 1;
predicate Rot(int: i, int: amt) = rot[i] == amt;
%Block type 1 ----
constraint forall(b in 1..total) %default
(
forall(x,y in 1..n)
(
(Type(TypeOf[b], 1) /\ Loc(b,x,y) /\ Rot(b, 1) /\ not Ref(b) /\ (y+3<=n))
-> (Has(x,y,b) /\ Has(x,y+1,b) /\ Has(x,y+2,b) /\ Has(x,y+3,b))
)
);
% constraint forall(b in 1..total) %90 degrees counterclockwise
% (
% forall(x in 1..n)
% (
% forall(y in 1..n)
% (
% ((Type(Blocks[b], 1) /\ Loc(b,x,y) /\ Rot(b, 2) /\ not Ref(b) /\ (x+3<=n)) ->
% (Has(x,y,b) /\ Has(x+1,y,b) /\ Has(x+2, y, b) /\ Has(x+3, y, b)))
% )
% )
%);
% constraint forall(b in 1..total) %180 degrees counterclockwise
% (
% forall(x in 1..n)
% (
% forall(y in 1..n)
% (
% ((Type(Blocks[b], 1) /\ Loc(b,x,y) /\ Rot(b, 3) /\ not Ref(b) /\ (y-3>=1)) ->
% (Has(x,y,b) /\ Has(x,y-1,b) /\ Has(x, y-2, b) /\ Has(x, y-3, b)))
% )
% )
%);
% constraint forall(b in 1..total) %270 degrees counterclockwise
% (
% forall(x in 1..n)
% (
% forall(y in 1..n)
% (
% ((Type(Blocks[b], 1) /\ Loc(b,x,y) /\ Rot(b, 4) /\ not Ref(b) /\ (x-3>=1)) ->
% (Has(x,y,b) /\ Has(x-1,y,b) /\ Has(x-2, y, b) /\ Has(x-3, y, b)))
% )
% )
%);
% Make sure loc board doesn't have more blocks of each type than given
constraint count(loc, 1, nR)/\count(loc,2,nS)/\count(loc,3,nT)/\count(loc,4,nL);
% % Make sure each block in board is only used once
constraint forall(x in 1..total)(count(board, x, 4));
% Make sure board contains valid blocks
constraint forall(x in 1..n)
(
forall(y in 1..n)
(
exists(b in 1..4)(IsBlock(b) /\ Has(x,y,b))
)
);
solve satisfy;
output[
"board: \n"]++[
show(board[(c-1)*n+p]) ++
if p == n then "\n" else " " endif
| c in ROW, p in COL
]++[
"\n loc: \n"]++[
show(loc[(c-1)*n+p]) ++
if p == n then "\n" else " " endif
| c in ROW, p in COL
]
++["\n rot: \n" ++ show(rot)];
나는'Loc()'함수가 일반적인 것으로 생각한다.동일한 유형의 블록이 체크 된 위치에 있는지 확인합니다. 이는 동일한 유형의 블록이 연속적인 필드에 위치 할 수있게합니다. (경계를 벗어나는 데이터에 액세스하는 함수가 있음을 주목하십시오. 일부 솔버가 충돌하여 매우 나쁜 모델링 사례입니다. – Dekker
저는 Minizinc (문자 그대로 첫 번째 프로젝트)를 처음 사용합니다. 범위 밖의 배열은 어떻게 처리하겠습니까? 배열 길이를 1에서 확인하고 있는데 어떻게 문제가 생길지 알 수 없습니다. 도움 주셔서 감사합니다, 나는 Loc() 함수를 수정합니다. 이 문제를 해결하는 방법에 대한 제안 사항이 있습니까? 내가 구현했을 구현은 Loc 전체를 스크랩하고 실제 보드의 2D 배열에 모든 점 정보를 넣었지만 2D 배열에서 count()와 같은 함수를 사용하는 방법을 알지 못하기 때문에 다음과 같이하십시오 :/다시 한번 감사드립니다! –