2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
70
Task/Sudoku/PARI-GP/sudoku-1.pari
Normal file
70
Task/Sudoku/PARI-GP/sudoku-1.pari
Normal 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 */
|
||||
}
|
||||
1
Task/Sudoku/PARI-GP/sudoku-2.pari
Normal file
1
Task/Sudoku/PARI-GP/sudoku-2.pari
Normal file
|
|
@ -0,0 +1 @@
|
|||
install("plug_sudoku", "G", "sudoku", "~/libsudoku.so")
|
||||
125
Task/Sudoku/PHP/sudoku.php
Normal file
125
Task/Sudoku/PHP/sudoku.php
Normal 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();
|
||||
257
Task/Sudoku/Pascal/sudoku.pascal
Normal file
257
Task/Sudoku/Pascal/sudoku.pascal
Normal 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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
47
Task/Sudoku/SAS/sudoku.sas
Normal file
47
Task/Sudoku/SAS/sudoku.sas
Normal 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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue