/* Sumaddle puzzle in Picat. https://twitter.com/ozanerdem/status/1387426014221979655 """ My favorite new game on mobile is Sumaddle. Given an n-by-n grid, you have to place two blocks and numbers in 1…n-2 on each row and column. The sum of the numbers between each of the two blocks have to be equal to the given number on the side, if there is any. """ See a problem instance at https://sumaddle.com/index.html This model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import cp. % import sat. main => go. go ?=> nolog, % data(1,Puzzle,RowDiff,ColDiff), % data('1b',Puzzle,RowDiff,ColDiff), data(2,Puzzle,RowDiff,ColDiff), % data(3,Puzzle,RowDiff,ColDiff), B = 0, Rows = Puzzle.len, Cols = Puzzle[1].len, Puzzle :: 0..Rows-2, RowBlocks = [], foreach(I in 1..Rows) Row = [Puzzle[I,J] : J in 1..Cols], all_different_except_0(Row), count(B,Row) #= 2, min_max(Row, B, MinB,MaxB), RowBlocks := RowBlocks ++ [[MinB,MaxB]], RowDiff[I] #= sum([(J #>= MinB)*(J #<=MaxB)*Puzzle[I,J] : J in 1..Cols]) end, ColBlocks = [], foreach(J in 1..Cols) Col = [Puzzle[I,J] : I in 1..Rows], all_different_except_0(Col), count(B,Col) #= 2, min_max(Col,B,MinB,MaxB), ColBlocks := ColBlocks ++ [[MinB,MaxB]], ColDiff[J] #= sum([(I #>= MinB)*(I #<=MaxB)*Puzzle[I,J] : I in 1..Rows]) end, %Vars = Puzzle.vars ++ RowBlocks.vars ++ ColBlocks.vars, Vars = RowBlocks.vars ++ ColBlocks.vars ++ Puzzle.vars ++ RowDiff ++ ColDiff, println(solve), solve($[split],Vars), foreach(Row in Puzzle) println(Row) end, println(rowBlocks=RowBlocks), println(colBlocks=ColBlocks), println(rowDiff=RowDiff), println(colDiff=ColDiff), nl, fail, nl. go => true. % % Find min and max positions of the blocks % min_max(X,B,MinVal,MaxVal) => Len = X.length, MinVal :: 1..Len, MaxVal :: 1..Len, element(MinVal,X,B), element(MaxVal,X,B), MinVal #< MaxVal. % The puzzle (partial solution) at % https://sumaddle.com/index.html data(1,Puzzle,RowDiff,ColDiff) => B = 0, Puzzle = [ [_,_,_,B,_,B], [_,_,B,_,_,B], [_,B,B,_,_,_], [B,_,_,_,B,_], [_,B,_,B,_,_], [B,_,_,_,B,_] ], RowDiff = [3,5,0,6,4,8], ColDiff = [3,1,0,9,2,0]. % Same as 1 but without any hints data('1b',Puzzle,RowDiff,ColDiff) => % B = 0, Puzzle = [ [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_] ], RowDiff = [3,5,0,6,4,8], ColDiff = [3,1,0,9,2,0]. % % Puzzle from https://twitter.com/ozanerdem/status/1387426014221979655 % data(2,Puzzle,RowDiff,ColDiff) => B = 0, Puzzle = [ [_,_,_,_,_,_,_], [B,_,_,_,_,_,B], [_,_,_,_,_,_,_], [_,_,_,_,_,_,_], [_,_,_,_,_,_,_], [_,_,_,_,_,_,_], [_,_,_,_,_,_,_] ], RowDiff = [12,15,1,3,8,10,5], ColDiff = [0,5,4,8,6,5,9]. % % Another puzzle from https://twitter.com/ozanerdem/status/1387426014221979655 % data(3,Puzzle,RowDiff,ColDiff) => % B = 0, Puzzle = [ [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_], [_,_,_,_,_,_] ], RowDiff = [0,1,6,9,0,_], ColDiff = [3,_,2,_,4,_].