1
0
This repository has been archived on 2025-03-03. You can view files and clone it, but cannot push or open issues or pull requests.
2016-11-21 17:54:04 +01:00

160 lines
4.9 KiB
MiniZinc

/*
* author: Jean-Noël Monette
*/
include "globals.mzn";
set of int: cubes=1..8;
set of int: pos=1..24;
set of int: symbols=0..4*4*4-1;
set of int: places=1..8*24;
set of int: faces= 1..6;
array[faces] of set of pos: face = [{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16},{17,18,19,20},{21,22,23,24}];
set of int: chars = 0..3;
array[cubes,pos] of var symbols: data;
constraint global_cardinality_closed(array1d(data),symbols,[3|i in symbols])::domain;
constraint forall(c in 7..8)(all_different([data[c,i]|i in pos])::domain);
%redundant constraint for the previous ones
array[cubes,symbols] of var 0..1: cnt;
constraint forall(c in 1..8)(global_cardinality_closed([data[c,i]|i in pos],symbols,[cnt[c,i]|i in symbols])::domain);
constraint forall(s in symbols)(sum(c in cubes)(cnt[c,s])=3);
constraint forall(c in cubes, f in faces)(
global_cardinality_low_up_closed([color(data[c,p])|p in face[f]],chars,[0|i in chars],[3|i in chars])::domain
/\
global_cardinality_low_up_closed([fill(data[c,p])|p in face[f]],chars,[0|i in chars],[3|i in chars])::domain
/\
global_cardinality_low_up_closed([shape(data[c,p])|p in face[f]],chars,[0|i in chars],[3|i in chars])::domain
);
%I believe this set of constraints is redundant with the previous one
constraint forall(c in cubes, f in faces)(
nvalue([color(data[c,p])|p in face[f]]) >= 2
/\
nvalue([fill(data[c,p])|p in face[f]]) >= 2
/\
nvalue([shape(data[c,p])|p in face[f]]) >= 2
);
solve
::seq_search([
int_search(cube_at,input_order,indomain_random,complete),
int_search(symbol_at,input_order,indomain_random,complete),
int_search(rotation,input_order,indomain_random,complete),
int_search(array1d(data),input_order,indomain_random,complete),
])
satisfy;
output ["data =",show2d(data),";\n","% cubes: ",show(cube_at),"\n% symbols: ",show(symbol_at),"\n% rotations: ",show(rotation)];
%How to implement linking functions with the advantages of CSE.
function array[1..3] of var 0..3: fcs(var 0..63:symbol) :: promise_total =
let { var 0..3: color; var 0..3:shape;var 0..3: fill;
constraint symbol = 4*4*fill+4*color+shape; }
in [fill,color,shape];
function var 0..3: color_help(array[1..3] of var 0..3: fcs) :: promise_total = fcs[2];
function var 0..3: color(var int:symbol) ::promise_total = color_help(fcs(symbol));
function var 0..3: fill_help(array[1..3] of var 0..3: fcs) :: promise_total = fcs[1];
function var 0..3: fill(var int:symbol) ::promise_total = fill_help(fcs(symbol));
function var 0..3: shape_help(array[1..3] of var 0..3: fcs) :: promise_total = fcs[3];
function var 0..3: shape(var int:symbol) ::promise_total = shape_help(fcs(symbol));
int: ud=0;
int: lr=8;
int: fb=16;
array[cubes] of var cubes: cube_at;
array[pos] of var symbols: symbol_at;
array[cubes] of var 1..24: rotation;
%Each cube is placed once.
constraint alldifferent(cube_at);
%Party constraints on the 6 faces
constraint party([symbol_at[i] | i in 1..4]);
constraint party([symbol_at[i + 4] | i in 1..4]);
constraint party([symbol_at[(i - 1) * 2 + 1 + lr] | i in 1..4]);
constraint party([symbol_at[i * 2 + lr] | i in 1..4]);
constraint party([symbol_at[if i < 3 then i else i+2 endif + fb] | i in 1..4]);
constraint party([symbol_at[if i < 3 then i else i+2 endif + 2 + fb] | i in 1..4]);
%Linking cubes and symbols
constraint forall(i in {1,4,6,7})(
link_cube_and_symbols(cube_at[i],[symbol_at[i+ud],symbol_at[i+lr],symbol_at[i+fb]],rotation[i],data));
constraint forall(i in {2,3,5,8})(
link_cube_and_symbols(cube_at[i],[symbol_at[i+ud],symbol_at[i+fb],symbol_at[i+lr]],rotation[i],data));
%Note: this presolve does not change much
predicate diff_or_equal(array[1..4] of var 0..3: x) =
forall(i in 1..4,j in i+1..4)(x[i]!=x[j])
\/
forall(i in 1..4,j in i+1..4)(x[i]=x[j]);
% A party is alldiff or allequal for each of the three characteristics.
% Note: I never tried to (manually) presolve this one but it might be worth trying it as well...
predicate party(array[1..4] of var 0..63: symbols) = (
diff_or_equal([color(symbols[i]) | i in 1..4])
/\ diff_or_equal([shape(symbols[i]) | i in 1..4])
/\ diff_or_equal([fill(symbols[i]) | i in 1..4]) );
%Linking cube IDs with the three symbols appearing in relevant positions
predicate link_cube_and_symbols(var int: cube, array[1..3] of var int: symbols,var 1..24: pos,array[cubes,pos] of var symbols:data) =
forall(i in 1..3)(data[cube,pp[pos,i]]=symbols[i]);
%Which symbol positions on a cube are next to each other on the same corner.
%Made by hand, I do not think there is any hope for finding a simple formula that could be used in precomputation :-)
%Actually it might be divided by three and have a disjunction in link_cube_and_symbols
array[1..24,1..3] of int: pp = [|21,12,7
|23,17,11
|24,4,18
|22,8,3
|1,6,16
|2,14,20
|4,18,24
|3,22,8
|7,21,12
|5,10,15
|6,16,1
|8,3,22
|16,1,6
|15,5,10
|13,9,19
|14,20,2
|18,24,4
|20,2,14
|19,13,9
|17,11,23
|12,7,21
|11,23,17
|9,19,13
|10,15,5
|];