2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,2 +1,6 @@
Solve a partially filled-in normal 9x9 [[wp:Sudoku|Sudoku]] grid and display the result in a human-readable format.
[[wp:Algorithmics_of_sudoku|Algorithmics of Sudoku]] may help implement this.
;Task:
Solve a partially filled-in normal   9x9   [[wp:Sudoku|Sudoku]] grid   and display the result in a human-readable format.
[[wp:Algorithmics_of_sudoku|Algorithmics of Sudoku]]   may help implement this.
<br><br>

View file

@ -1,6 +1,7 @@
// This can be run using Cintcode BCPL freely available from www.cl.cam.ac.uk/users/mr10.
// Implemented by Martin Richards.
// This is a really naive program to solve Su Doku problems. Even so it is usually quite fast.
// This is a really naive program to solve SuDoku problems. Even so it is usually quite fast.
// SuDoku consists of a 9x9 grid of cells. Each cell should contain
// a digit in the range 1..9. Every row, column and major 3x3

View file

@ -1,33 +1,21 @@
defmodule Sudoku do
def display( grid ), do: ( for y <- 1..9, do: display_row(y, grid) )
def start( knowns ), do: :dict.from_list( knowns )
def start( knowns ), do: Enum.into( knowns, Map.new )
def solve( grid ) do
sure = solve_all_sure( grid )
solve_unsure( potentials(sure), sure )
end
def task do
simple = [{{1, 1}, 3}, {{2, 1}, 9}, {{3, 1},4}, {{6, 1}, 2}, {{7, 1}, 6}, {{8, 1}, 7},
{{4, 2}, 3}, {{7, 2}, 4},
{{1, 3}, 5}, {{4, 3}, 6}, {{5, 3}, 9}, {{8, 3}, 2},
{{2, 4}, 4}, {{3, 4}, 5}, {{7, 4}, 9},
{{1, 5}, 6}, {{9, 5}, 7},
{{3, 6}, 7}, {{7, 6}, 5}, {{8, 6}, 8},
{{2, 7}, 1}, {{5, 7}, 6}, {{6, 7}, 7}, {{9, 7}, 8},
{{3, 8}, 9}, {{6, 8}, 8},
{{2, 9}, 2}, {{3, 9}, 6}, {{4, 9}, 4}, {{7, 9}, 7}, {{8, 9}, 3}, {{9, 9}, 5}]
task( simple )
difficult = [{{6, 2}, 3}, {{8, 2}, 8}, {{9, 2}, 5},
{{3, 3}, 1}, {{5, 3}, 2},
{{4, 4}, 5}, {{6, 4}, 7},
{{3, 5}, 4}, {{7, 5}, 1},
{{2, 6}, 9},
{{1, 7}, 5}, {{8, 7}, 7}, {{9, 7}, 3},
{{3, 8}, 2}, {{5, 8}, 1},
{{5, 9}, 4}, {{9, 9}, 9}]
task( difficult )
def task( knowns ) do
IO.puts "start"
start = start( knowns )
display( start )
IO.puts "solved"
solved = solve( start )
display( solved )
IO.puts ""
end
defp bt( grid ), do: bt_reject( is_not_allowed(grid), grid )
@ -35,7 +23,7 @@ defmodule Sudoku do
defp bt_accept( true, board ), do: throw( {:ok, board} )
defp bt_accept( false, grid ), do: bt_loop( potentials_one_position(grid), grid )
defp bt_loop( {position, values}, grid ), do: ( for x <- values, do: bt( :dict.store(position, x, grid) ) )
defp bt_loop( {position, values}, grid ), do: ( for x <- values, do: bt( Map.put(grid, position, x) ) )
defp bt_reject( true, _grid ), do: :backtrack
defp bt_reject( false, grid ), do: bt_accept( is_all_correct(grid), grid )
@ -46,99 +34,96 @@ defmodule Sudoku do
end
defp display_row_group( start, row, grid ) do
for x <- [start, start+1, start+2], do: :io.fwrite(" ~c", [display_value(x, row, grid)])
IO.write( " " )
Enum.each(start..start+2, &IO.write " #{Map.get( grid, {&1, row}, ".")}")
IO.write " "
end
defp display_row_nl( n ) when n == 3 or n == 6 or n == 9, do: IO.puts "\n"
defp display_row_nl( _N ), do: IO.puts ""
defp display_row_nl( n ) when n in [3,6,9], do: IO.puts "\n"
defp display_row_nl( _n ), do: IO.puts ""
defp display_value( x, y, grid ), do: display_value( :dict.find({x, y}, grid) )
defp display_value( :error ), do: ?.
defp display_value( {:ok, value} ), do: value + ?0
defp is_all_correct( grid ), do: :dict.size( grid ) == 81
defp is_all_correct( grid ), do: map_size( grid ) == 81
defp is_not_allowed( grid ) do
is_not_allowed_rows( grid ) or is_not_allowed_columns( grid ) or is_not_allowed_groups( grid )
end
defp is_not_allowed_columns( grid ), do: Enum.any?( values_all_columns(grid), fn x-> is_not_allowed_values(x) end)
defp is_not_allowed_columns( grid ), do: values_all_columns(grid) |> Enum.any?(&is_not_allowed_values/1)
defp is_not_allowed_groups( grid ), do: Enum.any?( values_all_groups(grid), fn x-> is_not_allowed_values(x) end)
defp is_not_allowed_groups( grid ), do: values_all_groups(grid) |> Enum.any?(&is_not_allowed_values/1)
defp is_not_allowed_rows( grid ), do: Enum.any?( values_all_rows(grid), fn x-> is_not_allowed_values(x) end)
defp is_not_allowed_rows( grid ), do: values_all_rows(grid) |> Enum.any?(&is_not_allowed_values/1)
defp is_not_allowed_values( values ), do: length( values ) != length( Enum.uniq(values) )
defp group_positions( {x, y} ), do: ( for colum <- group_positions_close(x), row <- group_positions_close(y), do: {colum, row} )
defp group_positions( {x, y} ) do
for colum <- group_positions_close(x), row <- group_positions_close(y), do: {colum, row}
end
defp group_positions_close( n ) when n < 4, do: [1,2,3]
defp group_positions_close( n ) when n < 7, do: [4,5,6]
defp group_positions_close( _n ) , do: [7,8,9]
defp positions_not_in_grid( grid ) do
keys = :dict.fetch_keys( grid )
for x <- 1..9, y <- 1..9, not Enum.member?(keys, {x, y}), do: {x, y}
keys = Map.keys( grid )
for x <- 1..9, y <- 1..9, not {x, y} in keys, do: {x, y}
end
defp potentials_one_position( grid ) do
[{_shortest, position, values} | _t] = Enum.sort( for {position, values} <- potentials( grid ), do: {length(values), position, values} )
{position, values}
Enum.min_by( potentials( grid ), fn {_position, values} -> length(values) end )
end
defp potentials( grid ), do: List.flatten( for x <- positions_not_in_grid(grid), do: potentials(x, grid) )
defp potentials( position, grid ) do
useds = potentials_used_values( position, grid )
{position, (for value <- :lists.seq(1, 9) -- useds, do: value) }
{position, Enum.to_list(1..9) -- useds }
end
defp potentials_used_values( {x, y}, grid ) do
row_values = (for row <- 1..9, row != x, do: {row, y}) |> potentials_values( grid )
column_values = (for column <- 1..9, column != y, do: {x, column}) |> potentials_values( grid )
group_values = List.delete( group_positions({x, y}), {x, y} ) |> potentials_values( grid )
group_values = group_positions({x, y}) -- [ {x, y} ] |> potentials_values( grid )
row_values ++ column_values ++ group_values
end
defp potentials_values( keys, grid ) do
row_values_unfiltered = for x <- keys, do: :dict.find(x, grid)
for {:ok, value} <- row_values_unfiltered, do: value
for x <- keys, val = grid[x], do: val
end
defp values_all_columns( grid ), do: ( for x <- 1..9, do: values_all_columns(x, grid) )
defp values_all_columns( x, grid ) do
( for y <- 1..9, do: {x, y} ) |> potentials_values( grid )
defp values_all_columns( grid ) do
for x <- 1..9, do:
( for y <- 1..9, do: {x, y} ) |> potentials_values( grid )
end
defp values_all_groups( grid ) do
[[g1,g2,g3], [g4,g5,g6], [g7,g8,g9]] = for x <- [1, 4, 7], do: values_all_groups(x, grid)
[[g1,g2,g3], [g4,g5,g6], [g7,g8,g9]] = for x <- [1,4,7], do: values_all_groups(x, grid)
[g1,g2,g3,g4,g5,g6,g7,g8,g9]
end
defp values_all_groups( x, grid ), do: ( for x_offset <- [x, x+1, x+2], do: values_all_groups(x, x_offset, grid) )
defp values_all_groups( x, grid ) do
for x_offset <- x..x+2, do: values_all_groups(x, x_offset, grid)
end
defp values_all_groups( _x, x_offset, grid ) do
( for y_offset <- group_positions_close(x_offset), do: {x_offset, y_offset} )
|> potentials_values( grid )
end
defp values_all_rows( grid ), do: ( for y <- 1..9, do: values_all_rows(y, grid) )
defp values_all_rows( y, grid ) do
( for x <- 1..9, do: {x, y} ) |> potentials_values( grid )
defp values_all_rows( grid ) do
for y <- 1..9, do:
( for x <- 1..9, do: {x, y} ) |> potentials_values( grid )
end
defp solve_all_sure( grid ), do: solve_all_sure( solve_all_sure_values(grid), grid )
defp solve_all_sure( [], grid ), do: grid
defp solve_all_sure( sures, grid ), do: solve_all_sure( List.foldl(sures, grid, fn(x,acc)-> solve_all_sure_store(x,acc) end) )
defp solve_all_sure( sures, grid ) do
solve_all_sure( Enum.reduce(sures, grid, &solve_all_sure_store/2) )
end
defp solve_all_sure_values( grid ), do: (for{position, [value]} <- potentials(grid), do: {position, value} )
defp solve_all_sure_store( {position, value}, acc ), do: :dict.store( position, value, acc )
defp solve_all_sure_store( {position, value}, acc ), do: Map.put( acc, position, value )
defp solve_unsure( [], grid ), do: grid
defp solve_unsure( _potentials, grid ) do
@ -148,16 +133,25 @@ defmodule Sudoku do
{:ok, board} -> board
end
end
defp task( knowns ) do
IO.puts "start"
start = start( knowns )
display( start )
IO.puts "solved"
solved = solve( start )
display( solved )
IO.puts ""
end
end
Sudoku.task
simple = [{{1, 1}, 3}, {{2, 1}, 9}, {{3, 1},4}, {{6, 1}, 2}, {{7, 1}, 6}, {{8, 1}, 7},
{{4, 2}, 3}, {{7, 2}, 4},
{{1, 3}, 5}, {{4, 3}, 6}, {{5, 3}, 9}, {{8, 3}, 2},
{{2, 4}, 4}, {{3, 4}, 5}, {{7, 4}, 9},
{{1, 5}, 6}, {{9, 5}, 7},
{{3, 6}, 7}, {{7, 6}, 5}, {{8, 6}, 8},
{{2, 7}, 1}, {{5, 7}, 6}, {{6, 7}, 7}, {{9, 7}, 8},
{{3, 8}, 9}, {{6, 8}, 8},
{{2, 9}, 2}, {{3, 9}, 6}, {{4, 9}, 4}, {{7, 9}, 7}, {{8, 9}, 3}, {{9, 9}, 5}]
Sudoku.task( simple )
difficult = [{{6, 2}, 3}, {{8, 2}, 8}, {{9, 2}, 5},
{{3, 3}, 1}, {{5, 3}, 2},
{{4, 4}, 5}, {{6, 4}, 7},
{{3, 5}, 4}, {{7, 5}, 1},
{{2, 6}, 9},
{{1, 7}, 5}, {{8, 7}, 7}, {{9, 7}, 3},
{{3, 8}, 2}, {{5, 8}, 1},
{{5, 9}, 4}, {{9, 9}, 9}]
Sudoku.task( difficult )

View file

@ -8,7 +8,7 @@ def sudokus = [
//Used in Fortran solution: ~ 0.1 seconds
'..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..',
//Used in many other solutions, notably Ada: ~ 0.1 seconds
//Used in many other solutions, notably Algol 68: ~ 0.1 seconds
'394..267....3..4..5..69..2..45...9..6.......7..7...58..1..67..8..9..8....264..735',
//Used in C# solution: ~ 0.2 seconds

View file

@ -0,0 +1,70 @@
#include <pari/pari.h>
typedef int SUDOKU [9][9];
static inline int check_num(SUDOKU s, int row, int col, int num)
{
int i, r = (row/3)*3, c = (col/3)*3;
for (i = 0; i < 9; i++)
if (s[row][i] == num || s[i][col] == num || s[i%3 + r][i/3 + c] == num)
return 0;
return 1;
}
static int sudoku_solve(SUDOKU s, int row, int col)
{
int num;
if (row < 9 && col < 9) {
if (s[row][col]) {
if (col < 8)
return sudoku_solve(s, row, col+1);
if (row < 8)
return sudoku_solve(s, row+1, 0);
return 1;
}
else
for (num = 1; num < 10; num++)
if (check_num(s, row, col, num)) {
s[row][col] = num;
if (sudoku_solve(s, row, col))
return 1;
else
s[row][col] = 0;
}
return 0;
}
return 1;
}
GEN plug_sudoku(GEN M)
{
SUDOKU s;
GEN S;
int i, k;
if (typ(M) != t_MAT)
pari_err(e_MISC, "parameter not matrix");
S = matsize(M);
if (itos(gel(S, 1)) < 9 || itos(gel(S, 2)) < 9)
pari_err(e_MISC, "parameter not 9x9 matrix");
for (i = 0; i < 9; i++)
for (k = 0; k < 9; k++)
s[i][k] = itos(gcoeff(M, i+1, k+1)); /* get sudoku */
if (sudoku_solve(s, 0, 0)) { /* solve sudoku */
S = cgetg(10, t_MAT);
for (k = 0; k < 9; k++) { /* create 9x9 matrix */
gel(S, k+1) = cgetg(10, t_COL);
for (i = 0; i < 9; i++)
gcoeff(S, i+1, k+1) = stoi(s[i][k]); /* fill in elements */
}
return S;
}
return gen_0; /* no solution */
}

View file

@ -0,0 +1 @@
install("plug_sudoku", "G", "sudoku", "~/libsudoku.so")

125
Task/Sudoku/PHP/sudoku.php Normal file
View file

@ -0,0 +1,125 @@
class SudokuSolver {
protected $grid = [];
protected $emptySymbol;
public static function parseString($str, $emptySymbol = '0')
{
$grid = str_split($str);
foreach($grid as &$v)
{
if($v == $emptySymbol)
{
$v = 0;
}
else
{
$v = (int)$v;
}
}
return $grid;
}
public function __construct($str, $emptySymbol = '0') {
if(strlen($str) !== 81)
{
throw new \Exception('Error sudoku');
}
$this->grid = static::parseString($str, $emptySymbol);
$this->emptySymbol = $emptySymbol;
}
public function solve()
{
try
{
$this->placeNumber(0);
return false;
}
catch(\Exception $e)
{
return true;
}
}
protected function placeNumber($pos)
{
if($pos == 81)
{
throw new \Exception('Finish');
}
if($this->grid[$pos] > 0)
{
$this->placeNumber($pos+1);
return;
}
for($n = 1; $n <= 9; $n++)
{
if($this->checkValidity($n, $pos%9, floor($pos/9)))
{
$this->grid[$pos] = $n;
$this->placeNumber($pos+1);
$this->grid[$pos] = 0;
}
}
}
protected function checkValidity($val, $x, $y)
{
for($i = 0; $i < 9; $i++)
{
if(($this->grid[$y*9+$i] == $val) || ($this->grid[$i*9+$x] == $val))
{
return false;
}
}
$startX = (int) ((int)($x/3)*3);
$startY = (int) ((int)($y/3)*3);
for($i = $startY; $i<$startY+3;$i++)
{
for($j = $startX; $j<$startX+3;$j++)
{
if($this->grid[$i*9+$j] == $val)
{
return false;
}
}
}
return true;
}
public function display() {
$str = '';
for($i = 0; $i<9; $i++)
{
for($j = 0; $j<9;$j++)
{
$str .= $this->grid[$i*9+$j];
$str .= " ";
if($j == 2 || $j == 5)
{
$str .= "| ";
}
}
$str .= PHP_EOL;
if($i == 2 || $i == 5)
{
$str .= "------+-------+------".PHP_EOL;
}
}
echo $str;
}
public function __toString() {
foreach ($this->grid as &$item)
{
if($item == 0)
{
$item = $this->emptySymbol;
}
}
return implode('', $this->grid);
}
}
$solver = new SudokuSolver('009170000020600001800200000200006053000051009005040080040000700006000320700003900');
$solver->solve();
$solver->display();

View file

@ -0,0 +1,257 @@
Program soduko;
{$IFDEF FPC}
{$CODEALIGN proc=16,loop=8}
{$ENDIF}
uses
sysutils,crt;
const
carreeSize = 3;
maxCoor = carreeSize*carreeSize;
maxValue = maxCoor;
maxMask = 1 shl (maxCoor+1)-1;
type
tLimit = 0..maxCoor-1;
tValue = 0..maxCoor;
tSteps = 0..maxCoor*maxCoor;
tValField = array[tLimit,tLimit] of NativeInt;//tValue;
tBitrepr = 0..maxMask;
tcol = array[tLimit] of NativeInt;// tBitrepr;
trow = array[tLimit] of NativeInt;// tBitrepr;
tcar = array[tLimit] of NativeInt;// tBitrepr;
tpValue = ^NativeInt;//^tValue;
tpLimit = ^tLimit;
tpBitrepr= ^NativeInt;//^tBitrepr;
tchgVal = record
cvCol,
cvRow,
cvCar : tpBitrepr;
cvVal : tpValue;
end;
tpChgVal = ^tchgVal;
tchgList = array[tSteps] of tchgVal;
tField = record
fdChgList: tchgList;
fdCol : tcol;
fdRow : trow;
fdcar : tcar;
fdVal : tValField;
fdChgIdx : tSteps;
end;
const
Expl0:tValField = ((9,0,7,0,0,0,3,0,0),
(0,0,0,1,0,0,2,0,0),
(6,0,0,0,0,8,0,0,0),
(0,0,5,0,3,0,0,0,0),
(0,0,0,0,0,0,0,8,4),
(0,0,0,0,0,0,0,6,0),
(0,0,0,2,7,0,0,0,0),
(8,4,0,0,0,0,0,0,0),
(0,6,0,0,0,0,0,0,0));
Expl1:tValField=((0,0,0,1,0,0,0,3,8),
(2,0,0,0,0,5,0,0,0),
(0,0,0,0,0,0,0,0,0),
(0,5,0,0,0,0,4,0,0),
(4,0,0,0,3,0,0,0,0),
(0,0,0,7,0,0,0,0,6),
(0,0,1,0,0,0,0,5,0),
(0,0,0,0,6,0,2,0,0),
(0,6,0,0,0,4,0,0,0));
var
F,
solF : TField;
solCnt,
callCnt: NativeUint;
solFound : Boolean;
procedure OutField(const F:tField);
var
rw,cl : tLimit;
rowS: AnsiString;
Begin
GotoXy(1,1);
For rw := low(tLimit) to High(tLimit) do
Begin
rowS := ' ';
For cl := low(tLimit) to High(tLimit) do
RowS :=RowS+IntToStr(F.fdVal[rw,cl]);
writeln(RowS);
end;
end;
function CarIdx(rw,cl: NativeInt):NativeInt;
begin
CarIdx:= (rw DIV carreeSize)*carreeSize +cl DIV carreeSize;
end;
function InsertTest(const F:tField;rw,cl:tLimit;value:tValue):boolean;
var
msk: tBitrepr;
Begin
result := (Value = 0);
IF result then
EXIT;
msk := 1 shl (value-1);
with F do
Begin
result := fdRow[rw] AND msk = 0;
result := result AND (fdCol[cl] AND msk = 0);
rw :=CarIdx(rw,cl);
result := result AND (fdCar[rw] AND msk = 0);
end;
end;
function InitField(var F:tField;const InFd:tValField;DoReverse:boolean):boolean;
var
TmpchgVal:tchgVal;
rw,cl,
value,
msk : NativeInt;
leftSteps:tSteps;
Begin
Fillchar(F,SizeOf(F),#0);
leftSteps := High(tSteps)-1;
//unknown fields inserted from end
For rw := low(tLimit) to High(tLimit) do
For cl := low(tLimit) to High(tLimit) do
Begin
value := InFd[rw,cl];
IF InsertTest(F,rw,cl,value) then
Begin
with F do
Begin
if value > 0 then
Begin
msk := 1 shl (value-1);
//given state
//use pointer to the relevant places and mark as occupied
with fdChgList[fdChgIdx] do
begin
cvCol := @fdCol[cl];
cvCol^ +=Msk;
cvRow := @fdRow[rw];
cvRow^ +=Msk;
cvCar := @fdCar[CarIdx(rw,cl)];
cvCar^ +=Msk;
cvVal := @fdVal[rw,cl];
cvVal^ := value;
end;
inc(fdChgIdx);
end
else
Begin
//use pointer to the relevant places
with fdChgList[leftSteps] do
begin
cvCol := @fdCol[cl];
cvRow := @fdRow[rw];
cvCar := @fdCar[CarIdx(rw,cl)];
cvVal := @fdVal[rw,cl];
end;
dec(leftSteps);
end;
end
end
else
Begin
writeln(rw:10,cl:10,value:10);
Writeln(' not solvable SuDoKu ');
delay(2000);
result := false;
EXIT;
end;
end;
//reverse direction of left over
IF DoReverse then
Begin
leftSteps := High(tSteps)-1;
rw := F.fdChgIdx;
repeat
TmpchgVal:= F.fdChgList[leftSteps];
F.fdChgList[leftSteps]:= F.fdChgList[rw];
F.fdChgList[rw] :=TmpchgVal;
dec(leftSteps);
inc(rw);
until rw>=leftSteps;
end;
//OutField(F);
solFound := false;
result := true;
end;
procedure SolIsFound;
begin
solF := F;
inc(solCnt);
solFound := True;
end;
procedure TryCell(var ChgVal:tpchgVal);
var
value :NativeInt;
poss,msk: NativeInt;
Begin
IF solFound then EXIT;
with ChgVal^ do
poss:= (cvRow^ OR cvCol^ OR cvCar^) XOR maxMask;
IF Poss = 0 then
EXIT;
value := 1;
msk := 1;
repeat
IF Poss AND MSK <>0 then
Begin
inc(callCnt);
//insert test value
with ChgVal^ do
Begin
cvCol^ := cvCol^ OR msk;
cvRow^ := cvRow^ OR msk;
cvCar^ := cvCar^ OR msk;
cvVAl^ := value;
end;
//try next in list, if beyond last
inc(ChgVal);
IF ChgVal^.cvCol <> NIL then
TryCell(ChgVal)
else
SolIsFound;
//remove test value
dec(ChgVal);
with ChgVal^ do
Begin
cvCol^ := cvCol^ XOR msk;
cvRow^ := cvRow^ XOR msk;
cvCar^ := cvCar^ XOR msk;
cvVAl^ := 0;
end;
end;
inc(msk,msk);
inc(value);
until value> maxValue;
end;
var
ChangeBegin : tpChgVal;
k : NativeInt;
T1,T0: TDateTime;
begin
randomize;
ClrScr;
solCnt := 0;
callCnt:= 0;
T0 := time;
k := 0;
repeat
InitField(F,Expl1,FALSE);
ChangeBegin := @F.fdChgList[F.fdChgIdx];
TryCell(ChangeBegin);
inc(k);
until k >= 5;
T1 := time;
Outfield(solF);
writeln(86400*1000*(T1-T0)/k:10:3,' ms Test calls :',callCnt/k:8:0);
end.

View file

@ -28,7 +28,7 @@ use v6;
#
# keep a list with all the cells, handy for traversal
my @cells = do for 0..8 X 0..8 -> $x, $y { [ $x, $y ] };
my @cells = do for (flat 0..8 X 0..8) -> $x, $y { [ $x, $y ] };
#
# Try to solve this puzzle and return the resolved puzzle if it is at
@ -129,7 +129,7 @@ sub solution-complexity-factor($sudoku, Int $x, Int $y) {
}
# the number of possible values should take precedence
my Int $f = 1000 * count-values($sudoku[$x][$y]);
for 0..2 X 0..2 -> $lx, $ly {
for (flat 0..2 X 0..2) -> $lx, $ly {
$f += count-values($sudoku[$lx+$bx*3][$ly+$by*3])
}
for 0..^($by*3), (($by+1)*3)..8 -> $ly {
@ -152,7 +152,7 @@ sub matches-in-competing-cells($sudoku, Int $x, Int $y, Int $val) {
return $cell.grep({ $val == $_ }) ?? 1 !! 0;
}
my Int $c = 0;
for 0..2 X 0..2 -> $lx, $ly {
for (flat 0..2 X 0..2) -> $lx, $ly {
$c += cell-matching($sudoku[$lx+$bx*3][$ly+$by*3])
}
for 0..^($by*3), (($by+1)*3)..8 -> $ly {
@ -208,7 +208,7 @@ sub trace(Int $level, Str $message) {
sub clone-sudoku($sudoku) {
my $clone;
for 0..8 X 0..8 -> $x, $y {
for (flat 0..8 X 0..8) -> $x, $y {
$clone[$x][$y] = $sudoku[$x][$y];
}
return $clone;

View file

@ -1,26 +1,19 @@
def read_matrix(data)
lines = data.each_line.to_a # ver 2.0 later data.lines
lines = data.lines
9.times.collect { |i| 9.times.collect { |j| lines[i][j].to_i } }
end
def permissible(matrix, i, j)
ok = [nil, *1..9]
check = ->(x,y) { ok[matrix[x][y]] = nil if matrix[x][y].nonzero? }
# Same as another in the column isn't permissible...
9.times do |i2|
ok[matrix[i2][j]] = nil if matrix[i2][j].nonzero?
end
9.times { |x| check[x, j] }
# Same as another in the row isn't permissible...
9.times do |j2|
ok[matrix[i][j2]] = nil if matrix[i][j2].nonzero?
end
9.times { |y| check[i, y] }
# Same as another in the 3x3 block isn't permissible...
irange = (ig = (i / 3) * 3) .. ig + 2
jrange = (jg = (j / 3) * 3) .. jg + 2
irange.each do |i2|
jrange.each do |j2|
ok[matrix[i2][j2]] = nil if matrix[i2][j2].nonzero?
end
end
xary = [ *(x = (i / 3) * 3) .. x + 2 ] #=> [0,1,2], [3,4,5] or [6,7,8]
yary = [ *(y = (j / 3) * 3) .. y + 2 ]
xary.product(yary).each { |x, y| check[x, y] }
# Gathering only permitted one
ok.compact
end

View file

@ -0,0 +1,47 @@
/* define SAS data set */
data Indata;
input C1-C9;
datalines;
. . 5 . . 7 . . 1
. 7 . . 9 . . 3 .
. . . 6 . . . . .
. . 3 . . 1 . . 5
. 9 . . 8 . . 2 .
1 . . 2 . . 4 . .
. . 2 . . 6 . . 9
. . . . 4 . . 8 .
8 . . 1 . . 5 . .
;
/* call OPTMODEL procedure in SAS/OR */
proc optmodel;
/* declare variables */
set ROWS = 1..9;
set COLS = ROWS;
var X {ROWS, COLS} >= 1 <= 9 integer;
/* declare nine row constraints */
con RowCon {i in ROWS}:
alldiff({j in COLS} X[i,j]);
/* declare nine column constraints */
con ColCon {j in COLS}:
alldiff({i in ROWS} X[i,j]);
/* declare nine 3x3 block constraints */
con BlockCon {s in 0..2, t in 0..2}:
alldiff({i in 3*s+1..3*s+3, j in 3*t+1..3*t+3} X[i,j]);
/* fix variables to cell values */
/* X[i,j] = c[i,j] if c[i,j] is not missing */
num c {ROWS, COLS};
read data indata into [_N_] {j in COLS} <c[_N_,j]=col('C'||j)>;
for {i in ROWS, j in COLS: c[i,j] ne .}
fix X[i,j] = c[i,j];
/* call CLP solver */
solve;
/* print solution */
print X;
quit;