/* * author: Jean-Noël Monette */ include "globals.mzn"; %cubes set of int: cubes=1..8; int: ud=0; int: lr=8; int: fb=16; set of int: pos=1..24; set of int: symbols=0..4*4*4-1; array[cubes] of var cubes: cube_at; array[pos] of var symbols: symbol_at; %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]])); 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]])); %Sym break constraint cube_at[1] = 1; constraint cube_at[2] < cube_at[3]; constraint cube_at[2] < cube_at[5]; %better to search on symbol_at first rather than cube_at solve :: int_search(symbol_at, first_fail, indomain_min, complete) satisfy; %introduced because of limitation in output. array[pos] of var 0..3: color_at = [color(symbol_at[i]) |i in pos]; array[pos] of var 0..3: shape_at = [shape(symbol_at[i]) |i in pos]; array[pos] of var 0..3: fill_at = [fill(symbol_at[i]) |i in pos]; %names (for output) array[1..4] of string: colorname = ["blue","red","yellow","black"]; array[1..4] of string: fillname = ["half","plain","empty","grid"]; array[1..4] of string: shapename = ["triangle","circle","square","heart"]; output [show(cube_at), "\n", show(symbol_at), "\n"] ++ ["pos " ++ show(i) ++ ": cube " ++ show(cube_at[i]) ++ "\n" ++ "u/d:\t"++fillname[fix(fill_at[i+ud])+1]++"\t"++colorname[fix(color_at[i+ud])+1]++"\t"++shapename[fix(shape_at[i+ud])+1]++"\n" ++ "f/b:\t"++fillname[fix(fill_at[i+fb])+1]++"\t"++colorname[fix(color_at[i+fb])+1]++"\t"++shapename[fix(shape_at[i+fb])+1]++"\n" ++ "l/r:\t"++fillname[fix(fill_at[i+lr])+1]++"\t"++colorname[fix(color_at[i+lr])+1]++"\t"++shapename[fix(shape_at[i+lr])+1]++"\n" | i in 1..8];%fill 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. 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(array[1..4] of var int: cs) ::presolve = let{ var 1..24: pos; var int: cube = cs[1]; } in forall(i in 1..3)(data[cube,pp[pos,i]]=cs[i+1]); %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)); %For parameters function 0..3: shape(int: symbol) = symbol mod 4; function 0..3: color(int: symbol) = symbol mod 16 div 4; function 0..3: fill(int:symbol) = symbol div 16; array[1..8,1..24] of int: data; %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 |];