Sudoku
TL;DR
I’ve implemented a simple recursive algorithm to solve Sudoku puzzles and the results are here here.
The Idea
After watching the video in the Computerphile youtube channel about recursive algorithms that solves a Sudoku puzzle, I’ve decided to implement the same solution by myself.
A Problem to Test the Implementation
Following the video, I’ve tried the same puzzle in the video.
#!/usr/bin/env python
test_grid = [
[ 0, 0, 4, 0, 0, 0, 0, 6, 7 ],
[ 3, 0, 0, 4, 7, 0, 0, 0, 5 ],
[ 1, 5, 0, 8, 2, 0, 0, 0, 3 ],
[ 0, 0, 6, 0, 0, 0, 0, 3, 1 ],
[ 8, 0, 2, 1, 0, 5, 6, 0, 4 ],
[ 4, 1, 0, 0, 0, 0, 9, 0, 0 ],
[ 7, 0, 0, 0, 8, 0, 0, 4, 6 ],
[ 6, 0, 0, 0, 1, 2, 0, 0, 0 ],
[ 9, 3, 0, 0, 0, 0, 7, 1, 0 ],
]
When its working, I can test if the algorithm is good by trying a harder problem.
#!/usr/bin/env python
grid = [
[ 0, 0, 2, 0, 0, 4, 0, 0, 0 ],
[ 0, 7, 0, 0, 0, 2, 0, 0, 0 ],
[ 0, 0, 6, 3, 0, 0, 0, 8, 0 ],
[ 0, 9, 0, 0, 0, 0, 0, 0, 0 ],
[ 5, 2, 7, 9, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 8, 0, 4, 0 ],
[ 0, 0, 0, 0, 0, 0, 4, 0, 5 ],
[ 0, 4, 0, 0, 0, 1, 0, 6, 0 ],
[ 0, 0, 1, 0, 7, 0, 9, 0, 0 ],
];
Solutions
Following the videos idea, I’ve implemented the first version of the solution in python.
Python
This solution was written to be efficient, there are room for improvement.
Implementation
#!/usr/bin/env python
from numpy import matrix
test_grid = [
[ 0, 0, 4, 0, 0, 0, 0, 6, 7 ],
[ 3, 0, 0, 4, 7, 0, 0, 0, 5 ],
[ 1, 5, 0, 8, 2, 0, 0, 0, 3 ],
[ 0, 0, 6, 0, 0, 0, 0, 3, 1 ],
[ 8, 0, 2, 1, 0, 5, 6, 0, 4 ],
[ 4, 1, 0, 0, 0, 0, 9, 0, 0 ],
[ 7, 0, 0, 0, 8, 0, 0, 4, 6 ],
[ 6, 0, 0, 0, 1, 2, 0, 0, 0 ],
[ 9, 3, 0, 0, 0, 0, 7, 1, 0 ],
]
grid = [
[ 0, 0, 2, 0, 0, 4, 0, 0, 0 ],
[ 0, 7, 0, 0, 0, 2, 0, 0, 0 ],
[ 0, 0, 6, 3, 0, 0, 0, 8, 0 ],
[ 0, 9, 0, 0, 0, 0, 0, 0, 0 ],
[ 5, 2, 7, 9, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 8, 0, 4, 0 ],
[ 0, 0, 0, 0, 0, 0, 4, 0, 5 ],
[ 0, 4, 0, 0, 0, 1, 0, 6, 0 ],
[ 0, 0, 1, 0, 7, 0, 9, 0, 0 ],
];
def found_in_row(row, n):
""" (int, int) => boolean
Takes a row and a number and returns if the number can be placed in this row in the grid
>>> found_in_row(0, 2)
False
>>> found_in_row(0, 4)
True
"""
for column in range(0, 9):
if grid[row][column] == n:
return True
return False
def found_in_column(column, n):
""" (int, int) => boolean
Takes a column and a number and returns if the number can be placed in this column in the grid
>> found_in_column(0, 2)
False
>>> found_in_column(0, 4)
True
"""
for row in range(0, 9):
if grid[row][column] == n:
return True
return False
def found_in_subsquare(row, column, n):
""" (int, int) => boolean
Takes a row, a column and a number and returns if the number can be placed in this 3x3 subsquare in the grid
>>> found_in_subsquare(4, 4, 2)
False
>>> found_in_subsquare(4, 4, 1)
True
>>> found_in_subsquare(3, 3, 5)
True
>>> found_in_subsquare(3, 3, 8)
False
"""
ss_row = row // 3
ss_column = column // 3
for s_row in range (0, 3):
for s_column in range(0, 3):
if grid[3 * ss_row + s_row][3 * ss_column + s_column] == n:
return True
return False
def is_possible(row, column, n):
""" (int, int) => boolean
Takes a row, a column and a number and returns if the number can be placed in this 3x3 subsquare in the grid
>>> is_possible(4, 4, 3)
True
>>> is_possible(4, 4, 1)
False
>>> is_possible(4, 4, 9)
True
>>> is_possible(4, 4, 8)
False
"""
if found_in_row(row, n):
return False
if found_in_column(column, n):
return False
if found_in_subsquare(row, column, n):
return False
return True
def solve():
global grid
for row in range(0, 9):
for column in range(0, 9):
if grid[row][column] == 0:
for n in range(1, 10):
if is_possible(row, column, n):
grid[row][column] = n
solve()
grid[row][column] = 0
return
print(matrix(grid))
if __name__ == "__main__":
import doctest
tmp_grid = grid
grid = test_grid
doctest.testmod()
grid = tmp_grid
solve()
Execution Time
time ./index.py
[[3 8 2 6 9 4 1 5 7]
[4 7 5 8 1 2 3 9 6]
[9 1 6 3 5 7 2 8 4]
[8 9 4 1 3 5 6 7 2]
[5 2 7 9 4 6 8 3 1]
[1 6 3 7 2 8 5 4 9]
[7 3 8 2 6 9 4 1 5]
[2 4 9 5 8 1 7 6 3]
[6 5 1 4 7 3 9 2 8]]
58.032 secs
C++
Here I wanted to know what is possible using this algorithm, I’m looking for the fastest language I can use. I choose C++.
Implementation
#include <iostream>
#include <cmath>
#include <assert.h>
using namespace std;
int testGrid[9][9] = {
{ 0, 0, 4, 0, 0, 0, 0, 6, 7 },
{ 3, 0, 0, 4, 7, 0, 0, 0, 5 },
{ 1, 5, 0, 8, 2, 0, 0, 0, 3 },
{ 0, 0, 6, 0, 0, 0, 0, 3, 1 },
{ 8, 0, 2, 1, 0, 5, 6, 0, 4 },
{ 4, 1, 0, 0, 0, 0, 9, 0, 0 },
{ 7, 0, 0, 0, 8, 0, 0, 4, 6 },
{ 6, 0, 0, 0, 1, 2, 0, 0, 0 },
{ 9, 3, 0, 0, 0, 0, 7, 1, 0 }
};
int grid[9][9] = {
{ 0, 0, 2, 0, 0, 4, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 6, 3, 0, 0, 0, 8, 0 },
{ 0, 9, 0, 0, 0, 0, 0, 0, 0 },
{ 5, 2, 7, 9, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 8, 0, 4, 0 },
{ 0, 0, 0, 0, 0, 0, 4, 0, 5 },
{ 0, 4, 0, 0, 0, 1, 0, 6, 0 },
{ 0, 0, 1, 0, 7, 0, 9, 0, 0 }
};
bool foundInRow(int row, int number)
{
for (int column = 0; column < 9; column++)
if (grid[row][column] == number) return true;
return false;
}
bool foundInColumn(int column, int number)
{
for (int row = 0; row < 9; row++)
if (grid[row][column] == number) return true;
return false;
}
bool foundInSubsquare(int row, int column, int number)
{
int ssRow = floor(row / 3);
int ssColumn = floor(column / 3);
for (int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
if (grid[ssRow * 3 + r][ssColumn * 3 + c] == number) return true;
return false;
}
bool isPossible(int row, int column, int number)
{
if (foundInRow(row, number))
{
return false;
}
if (foundInColumn(column, number))
{
return false;
}
if (foundInSubsquare(row, column, number))
{
return false;
}
return true;
}
void printGrid()
{
for(int row = 0; row < 9; row++)
{
cout << "[ ";
for(int column = 0; column < 9; column++)
{
cout << grid[row][column] << " ";
}
cout << "]" << endl;
}
}
void test()
{
int tempGrid[9][9];
copy(&grid[0][0], &grid[0][0] + 81, &tempGrid[0][0]);
copy(&testGrid[0][0], &testGrid[0][0] + 81, &grid[0][0]);
assert(foundInRow(0, 2)==false);
assert(foundInRow(0, 4)==true);
assert(foundInColumn(0, 2)==false);
assert(foundInColumn(0, 4)==true);
assert(foundInSubsquare(4, 4, 2)==false);
assert(foundInSubsquare(4, 4, 1)==true);
assert(foundInSubsquare(3, 3, 5)==true);
assert(foundInSubsquare(3, 3, 8)==false);
assert(isPossible(4, 4, 3)==true);
assert(isPossible(4, 4, 1)==false);
assert(isPossible(4, 4, 9)==true);
assert(isPossible(4, 4, 8)==false);
copy(&tempGrid[0][0], &tempGrid[0][0] + 81, &grid[0][0]);
}
void solve()
{
for(int row = 0; row < 9; row++)
for(int column = 0; column < 9; column++)
if(grid[row][column] == 0)
{
for(int number = 1; number < 10; number++)
if(isPossible(row, column, number))
{
grid[row][column] = number;
solve();
grid[row][column] = 0;
}
return;
}
printGrid();
}
int main(int argc, char *argv[])
{
test();
solve();
return 0;
}
Execution Time
g++ main.cpp -o main -O3 && time ./main
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
0.281 secs
Without optimizations:
g++ main.cpp -o main && time ./main
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
1.307 secs
Rust
Another language designed for high performance. I was curious about what it can do.
Implementation
fn print_grid(grid: [[u8; 9]; 9]) -> () {
for row in 0..9 {
print!("[ ");
for column in 0..9 {
print!("{} ", grid[row][column]);
}
println!("]");
}
}
fn found_in_row(grid: [[u8; 9]; 9], row: usize, number: u8) -> bool {
for column in 0..9 {
if grid[row][column] == number {
return true;
}
}
return false;
}
fn found_in_column(grid: [[u8; 9]; 9], column: usize, number: u8) -> bool {
for row in 0..9 {
if grid[row][column] == number {
return true;
}
}
return false;
}
fn found_in_subsquare(grid: [[u8; 9]; 9], row: usize, column: usize, number: u8) -> bool {
let ss_row: usize = row / 3;
let ss_column: usize = column / 3;
for r in 0..3 {
for c in 0..3 {
if grid[ss_row * 3 + r][ss_column * 3 + c] == number {
return true;
}
}
}
return false;
}
fn is_possible(grid: [[u8; 9]; 9], row: usize, column: usize, number: u8) -> bool {
if found_in_row(grid, row, number) {
return false;
}
if found_in_column(grid, column, number) {
return false;
}
if found_in_subsquare(grid, row, column, number) {
return false;
}
return true;
}
fn solve(mut grid: [[u8; 9]; 9]) -> [[u8; 9]; 9] {
for row in 0..9 {
for column in 0..9 {
if grid[row][column] == 0 {
for number in 1..10 {
if is_possible(grid, row, column, number) {
grid[row][column] = number;
grid = solve(grid);
grid[row][column] = 0;
}
}
return grid;
}
}
}
print_grid(grid);
return grid;
}
fn main() {
let test: bool = true;
if test {
run_tests();
}
let grid: [[u8; 9]; 9] = [
[ 0, 0, 2, 0, 0, 4, 0, 0, 0 ],
[ 0, 7, 0, 0, 0, 2, 0, 0, 0 ],
[ 0, 0, 6, 3, 0, 0, 0, 8, 0 ],
[ 0, 9, 0, 0, 0, 0, 0, 0, 0 ],
[ 5, 2, 7, 9, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 8, 0, 4, 0 ],
[ 0, 0, 0, 0, 0, 0, 4, 0, 5 ],
[ 0, 4, 0, 0, 0, 1, 0, 6, 0 ],
[ 0, 0, 1, 0, 7, 0, 9, 0, 0 ]
];
solve(grid);
}
fn run_tests() -> () {
let test_grid: [[u8; 9]; 9] = [
[ 0, 0, 4, 0, 0, 0, 0, 6, 7 ],
[ 3, 0, 0, 4, 7, 0, 0, 0, 5 ],
[ 1, 5, 0, 8, 2, 0, 0, 0, 3 ],
[ 0, 0, 6, 0, 0, 0, 0, 3, 1 ],
[ 8, 0, 2, 1, 0, 5, 6, 0, 4 ],
[ 4, 1, 0, 0, 0, 0, 9, 0, 0 ],
[ 7, 0, 0, 0, 8, 0, 0, 4, 6 ],
[ 6, 0, 0, 0, 1, 2, 0, 0, 0 ],
[ 9, 3, 0, 0, 0, 0, 7, 1, 0 ],
];
println!("Running tests:");
test_found_in_row(test_grid);
test_found_in_column(test_grid);
test_found_in_subsquare(test_grid);
println!("ok");
}
fn test_found_in_row(grid: [[u8; 9]; 9]) -> () {
test_found_in_row_instance(grid, 0, 1, false);
test_found_in_row_instance(grid, 0, 4, true);
test_found_in_row_instance(grid, 8, 5, false);
test_found_in_row_instance(grid, 8, 1, true);
}
fn test_found_in_column(grid: [[u8; 9]; 9]){
test_found_in_column_instance(grid, 0, 1, true);
test_found_in_column_instance(grid, 0, 3, true);
test_found_in_column_instance(grid, 0, 4, true);
test_found_in_column_instance(grid, 0, 6, true);
test_found_in_column_instance(grid, 0, 7, true);
test_found_in_column_instance(grid, 0, 8, true);
test_found_in_column_instance(grid, 0, 9, true);
test_found_in_column_instance(grid, 0, 2, false);
test_found_in_column_instance(grid, 0, 5, false);
test_found_in_column_instance(grid, 8, 5, true);
test_found_in_column_instance(grid, 8, 2, false);
}
fn test_found_in_subsquare(grid: [[u8; 9]; 9]) -> () {
test_found_in_subsquare_instance(grid, 0, 0, 1, true);
test_found_in_subsquare_instance(grid, 0, 0, 4, true);
test_found_in_subsquare_instance(grid, 0, 0, 6, false);
}
fn test_found_in_row_instance(grid: [[u8; 9]; 9], row: usize, number: u8, expect: bool) -> () {
if found_in_row(grid, row, number) != expect {
print!("F");
panic!("found_in_row failed for {}, {}", row, number)
} else {
print!(".")
}
}
fn test_found_in_column_instance(grid: [[u8; 9]; 9], column: usize, number: u8, expect: bool) -> () {
if found_in_column(grid, column, number) != expect {
print!("F");
panic!("found_in_column failed for {}, {}", column, number);
} else {
print!(".")
}
}
fn test_found_in_subsquare_instance(grid: [[u8; 9]; 9], row: usize, column: usize, number: u8, expect: bool) -> () {
if found_in_subsquare(grid, row, column, number) != expect {
print!("F");
panic!("found_in_subsquare failed for {}, {}, {}", row, column, number);
} else {
print!(".")
}
}
Execution Time
cargo build --release && time cargo run --release
Finished release [optimized] target(s) in 0.01s
Finished release [optimized] target(s) in 0.00s
Running `target/release/sudoku`
Running tests:
..................ok
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
0.605 secs
Without compiler optimizations:
cargo build && time cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/sudoku`
Running tests:
..................ok
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
13.954 secs
C#
Is a language I use often. The performance did not impressed me.
Implementation
using System;
using System.IO;
using System.Threading.Tasks;
namespace ToyCSharp {
class Sudoku {
public static int[][] grid = new int[][]
{
new int[]{ 0, 0, 2, 0, 0, 4, 0, 0, 0 },
new int[]{ 0, 7, 0, 0, 0, 2, 0, 0, 0 },
new int[]{ 0, 0, 6, 3, 0, 0, 0, 8, 0 },
new int[]{ 0, 9, 0, 0, 0, 0, 0, 0, 0 },
new int[]{ 5, 2, 7, 9, 0, 0, 0, 0, 0 },
new int[]{ 0, 0, 0, 0, 0, 8, 0, 4, 0 },
new int[]{ 0, 0, 0, 0, 0, 0, 4, 0, 5 },
new int[]{ 0, 4, 0, 0, 0, 1, 0, 6, 0 },
new int[]{ 0, 0, 1, 0, 7, 0, 9, 0, 0 }
};
[STAThread]
public static void Main(string[] args)
{
Solve();
}
public static bool FoundInRow(int row, int number)
{
for(int column = 0; column < 9; column++)
{
if (grid[row][column] == number)
return true;
}
return false;
}
public static bool FoundInColumn(
int column,
int number
)
{
for(int row = 0; row < 9; row++)
{
if (grid[row][column] == number)
return true;
}
return false;
}
public static bool FoundInSubsquare(int row, int column, int number)
{
int ssRow = (int) Math.Floor((double) row / 3);
int ssColumn = (int) Math.Floor((double)column / 3);
for(int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
if (grid[ssRow * 3 + r][ssColumn * 3 + c] == number) return true;
return false;
}
public static bool IsPossible(int row, int column, int number)
{
if (FoundInRow(row, number)) return false;
if (FoundInColumn(column, number)) return false;
if (FoundInSubsquare(row, column, number)) return false;
return true;
}
public static void PrintGrid()
{
for(int row = 0; row < 9; row++)
{
Console.Write("[ ");
for(int column = 0; column < 9; column++)
{
Console.Write($"{grid[row][column]} ");
}
Console.Write("]\n");
}
}
public static void Solve()
{
for(var row = 0; row < 9; row++)
{
for(var column = 0; column < 9; column ++)
{
if (grid[row][column] == 0)
{
for(var number = 1; number < 10; number++)
{
if(IsPossible(row, column, number))
{
grid[row][column] = number;
Solve();
grid[row][column] = 0;
}
}
return;
}
}
}
PrintGrid();
}
}
}
Execution Time
/usr/bin/csc /optimize /out:sudoku *.cs && chmod 755 sudoku && time ./sudoku
Microsoft (R) Visual C# Compiler version 3.6.0-4.20224.5 (ec77c100)
Copyright (C) Microsoft Corporation. All rights reserved.
Wrong type argument: stringp, 755
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
1.506 secs
Turning off optimizations:
/usr/bin/csc /out:sudoku *.cs && chmod 755 sudoku && time ./sudoku
Microsoft (R) Visual C# Compiler version 3.6.0-4.20224.5 (ec77c100)
Copyright (C) Microsoft Corporation. All rights reserved.
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
1.798 secs
Golang
Another very nice language, Golang is well know to have a good concurrency model. I don’t believe this is a place to this language shine.
Implementation
module sudoku
go 1.16
package main
import (
"fmt"
"math"
)
var testGrid [9][9]int = [9][9]int {
{ 0, 0, 4, 0, 0, 0, 0, 6, 7 },
{ 3, 0, 0, 4, 7, 0, 0, 0, 5 },
{ 1, 5, 0, 8, 2, 0, 0, 0, 3 },
{ 0, 0, 6, 0, 0, 0, 0, 3, 1 },
{ 8, 0, 2, 1, 0, 5, 6, 0, 4 },
{ 4, 1, 0, 0, 0, 0, 9, 0, 0 },
{ 7, 0, 0, 0, 8, 0, 0, 4, 6 },
{ 6, 0, 0, 0, 1, 2, 0, 0, 0 },
{ 9, 3, 0, 0, 0, 0, 7, 1, 0 },
}
var grid [9][9]int = [9][9]int {
{ 0, 0, 2, 0, 0, 4, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 6, 3, 0, 0, 0, 8, 0 },
{ 0, 9, 0, 0, 0, 0, 0, 0, 0 },
{ 5, 2, 7, 9, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 8, 0, 4, 0 },
{ 0, 0, 0, 0, 0, 0, 4, 0, 5 },
{ 0, 4, 0, 0, 0, 1, 0, 6, 0 },
{ 0, 0, 1, 0, 7, 0, 9, 0, 0 },
}
func printGrid() {
for row := 0; row < 9; row++ {
fmt.Print("[ ")
for column := 0; column < 9; column++ {
fmt.Printf("%d ", grid[row][column])
}
fmt.Print("]\n")
}
}
func foundInRow(row int, number int) bool {
for column := 0; column < 9; column++ {
if (grid[row][column] == number){
return true
}
}
return false
}
func foundInColumn(column int, number int) bool {
for row := 0; row < 9; row++ {
if (grid[row][column] == number){
return true
}
}
return false
}
func foundInSubsquare(row int, column int, number int) bool {
ssRow := int(math.Floor(float64(row) / 3))
ssColumn := int(math.Floor(float64(column) / 3))
for r := 0; r < 3; r++ {
for c := 0; c < 3; c++ {
if (grid[ssRow * 3 + r][ssColumn * 3 + c] == number){
return true
}
}
}
return false
}
func isPossible(row int, column int, number int) bool {
if (foundInRow(row, number)) {
return false
}
if (foundInColumn(column, number)) {
return false
}
if (foundInSubsquare(row, column, number)) {
return false
}
return true
}
func solve() {
for row := 0; row < 9; row++ {
for column := 0; column < 9; column++ {
if (grid[row][column] == 0){
for number := 1; number < 10; number++ {
if (isPossible(row, column, number)){
grid[row][column] = number
solve()
grid[row][column] = 0
}
}
return
}
}
}
printGrid()
}
func main() {
solve()
}
package main
import (
"testing"
)
func TestFoundInRow(t *testing.T) {
rowCase(t, 0, 2, false)
rowCase(t, 0, 4, true)
rowCase(t, 0, 8, false)
}
func TestFoundInColumn(t *testing.T) {
columnCase(t, 0, 2, false)
columnCase(t, 1, 2, false)
columnCase(t, 0, 4, true)
columnCase(t, 1, 8, false)
}
func TestFoundInSubsquares(t *testing.T) {
subsquareCase(t, 0, 1, 2, false)
subsquareCase(t, 4, 4, 2, false)
subsquareCase(t, 4, 4, 1, true)
subsquareCase(t, 3, 3, 5, true)
subsquareCase(t, 3, 3, 8, false)
subsquareCase(t, 0, 1, 8, false)
}
func TestIsPossible(t *testing.T) {
isPossibleCase(t, 4, 4, 3, true)
isPossibleCase(t, 4, 4, 1, false)
isPossibleCase(t, 4, 4, 9, true)
isPossibleCase(t, 4, 4, 8, false)
isPossibleCase(t, 0, 1, 8, true)
}
func subsquareCase(t *testing.T, row, column, number int, want bool) {
got := foundInSubsquare(row, column, number)
AssertBoolean(t, got, want)
}
func rowCase(t *testing.T, row, number int, want bool) {
got := foundInRow(row, number)
AssertBoolean(t, got, want)
}
func columnCase(t *testing.T, column, number int, want bool) {
got := foundInColumn(column, number)
AssertBoolean(t, got, want)
}
func isPossibleCase(t *testing.T, row, column, number int, want bool) {
got := isPossible(row, column, number)
AssertBoolean(t, got, want)
}
func AssertInteger(t *testing.T, got, want int) {
t.Helper()
if got != want {
t.Errorf("got %d want %d", got, want)
}
}
func AssertBoolean(t *testing.T, got, want bool) {
t.Helper()
if got != want {
t.Errorf("got %t want %t", got, want)
}
}
Execution Time
go build && time ./sudoku
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
0.644 secs
Ruby
Ruby was one of my first programming languages. I seized the opportunity to touch it again after a long time.
Implementation
Using the conventional directory structure, I’ve used rspec for testing. The rpec library is also the only dependency in the Gemfile
.
Estrutura do projeto
tree
.
├── Gemfile
├── Gemfile.lock
├── lib
│ └── sudoku.rb
├── Makefile
├── spec
│ ├── spec_helper.rb
│ └── spec_sudoku.rb
└── sudoku.rb
Entrypoint
./sudoku.rb
(require './lib/sudoku')
sudoku = Sudoku.new
hardest_problem = [
[ 0, 0, 2, 0, 0, 4, 0, 0, 0 ],
[ 0, 7, 0, 0, 0, 2, 0, 0, 0 ],
[ 0, 0, 6, 3, 0, 0, 0, 8, 0 ],
[ 0, 9, 0, 0, 0, 0, 0, 0, 0 ],
[ 5, 2, 7, 9, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 8, 0, 4, 0 ],
[ 0, 0, 0, 0, 0, 0, 4, 0, 5 ],
[ 0, 4, 0, 0, 0, 1, 0, 6, 0 ],
[ 0, 0, 1, 0, 7, 0, 9, 0, 0 ],
]
sudoku.set_grid(hardest_problem)
sudoku.solve()
Solution
./lib/sudoku.rb
class Sudoku
def initialize()
@grid = [
[ 0, 0, 4, 0, 0, 0, 0, 6, 7 ],
[ 3, 0, 0, 4, 7, 0, 0, 0, 5 ],
[ 1, 5, 0, 8, 2, 0, 0, 0, 3 ],
[ 0, 0, 6, 0, 0, 0, 0, 3, 1 ],
[ 8, 0, 2, 1, 0, 5, 6, 0, 4 ],
[ 4, 1, 0, 0, 0, 0, 9, 0, 0 ],
[ 7, 0, 0, 0, 8, 0, 0, 4, 6 ],
[ 6, 0, 0, 0, 1, 2, 0, 0, 0 ],
[ 9, 3, 0, 0, 0, 0, 7, 1, 0 ],
]
end
def set_grid(grid)
@grid = grid
end
def found_in_row(row, number)
return @grid[row].include?(number)
end
def found_in_column(column, number)
return @grid.transpose[column].include?(number)
end
def found_in_subsquare(row, column, number)
return @grid.drop(3 * (row/3)).take(3).transpose.drop(3 * (column/3)).take(3).flatten.include?(number)
end
def is_possible(row, column, number)
if found_in_row(row, number)
return false
end
if found_in_column(column, number)
return false
end
if found_in_subsquare(row, column, number)
return false
end
return true
end
def print_grid()
for row in (0..8)
print("[ ")
for column in (0..8)
print("#{@grid[row][column]} ")
end
print("]\n")
end
end
def solve()
for row in (0..8)
for column in (0..8)
if(@grid[row][column] == 0)
for number in (1..9)
if is_possible(row, column, number)
@grid[row][column] = number
solve()
@grid[row][column] = 0
end
end
return
end
end
end
print_grid()
end
end
Tests
./spec/spec_sudoku.rb
require "spec_helper"
require('sudoku')
RSpec.describe Sudoku do
it 'creates a sudoku class' do
sudoku = Sudoku.new
expect(sudoku).to be_kind_of(Sudoku)
end
it 'should find row values' do
sudoku = Sudoku.new
expect(sudoku.found_in_row(0, 4)).to eq(true)
expect(sudoku.found_in_row(0, 7)).to eq(true)
expect(sudoku.found_in_row(4, 8)).to eq(true)
expect(sudoku.found_in_row(4, 1)).to eq(true)
expect(sudoku.found_in_row(4, 5)).to eq(true)
expect(sudoku.found_in_row(0, 1)).to eq(false)
expect(sudoku.found_in_row(6, 2)).to eq(false)
expect(sudoku.found_in_row(8, 2)).to eq(false)
end
it 'should find column values' do
sudoku = Sudoku.new
expect(sudoku.found_in_column(0, 2)).to eq(false)
expect(sudoku.found_in_column(1, 2)).to eq(false)
expect(sudoku.found_in_column(4, 8)).to eq(true)
expect(sudoku.found_in_column(4, 1)).to eq(true)
expect(sudoku.found_in_column(4, 5)).to eq(false)
expect(sudoku.found_in_column(0, 1)).to eq(true)
expect(sudoku.found_in_column(6, 2)).to eq(false)
expect(sudoku.found_in_column(8, 2)).to eq(false)
end
it 'should find subsquare values' do
sudoku = Sudoku.new
expect(sudoku.found_in_subsquare(0, 0, 2)).to eq(false)
expect(sudoku.found_in_subsquare(0, 1, 2)).to eq(false)
expect(sudoku.found_in_subsquare(0, 4, 8)).to eq(true)
expect(sudoku.found_in_subsquare(0, 4, 1)).to eq(false)
expect(sudoku.found_in_subsquare(6, 4, 5)).to eq(false)
expect(sudoku.found_in_subsquare(6, 0, 1)).to eq(false)
expect(sudoku.found_in_subsquare(6, 6, 2)).to eq(false)
expect(sudoku.found_in_subsquare(6, 8, 2)).to eq(false)
end
it 'should set possible if values were not found' do
sudoku = Sudoku.new
expect(sudoku.is_possible(0, 0, 2)).to eq(true)
expect(sudoku.is_possible(0, 1, 2)).to eq(true)
expect(sudoku.is_possible(0, 4, 8)).to eq(false)
expect(sudoku.is_possible(0, 4, 1)).to eq(false)
expect(sudoku.is_possible(6, 4, 5)).to eq(true)
expect(sudoku.is_possible(6, 0, 1)).to eq(false)
expect(sudoku.is_possible(6, 6, 2)).to eq(true)
expect(sudoku.is_possible(6, 8, 2)).to eq(true)
end
end
Execution Time
time ruby sudoku.rb
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
52.880 secs
Javascript
Is the simplest implementation alongside of python.
Implementation
const testGrid = [
[ 0, 0, 4, 0, 0, 0, 0, 6, 7 ],
[ 3, 0, 0, 4, 7, 0, 0, 0, 5 ],
[ 1, 5, 0, 8, 2, 0, 0, 0, 3 ],
[ 0, 0, 6, 0, 0, 0, 0, 3, 1 ],
[ 8, 0, 2, 1, 0, 5, 6, 0, 4 ],
[ 4, 1, 0, 0, 0, 0, 9, 0, 0 ],
[ 7, 0, 0, 0, 8, 0, 0, 4, 6 ],
[ 6, 0, 0, 0, 1, 2, 0, 0, 0 ],
[ 9, 3, 0, 0, 0, 0, 7, 1, 0 ],
]
const grid = [
[ 0, 0, 2, 0, 0, 4, 0, 0, 0 ],
[ 0, 7, 0, 0, 0, 2, 0, 0, 0 ],
[ 0, 0, 6, 3, 0, 0, 0, 8, 0 ],
[ 0, 9, 0, 0, 0, 0, 0, 0, 0 ],
[ 5, 2, 7, 9, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 8, 0, 4, 0 ],
[ 0, 0, 0, 0, 0, 0, 4, 0, 5 ],
[ 0, 4, 0, 0, 0, 1, 0, 6, 0 ],
[ 0, 0, 1, 0, 7, 0, 9, 0, 0 ]
];
const printGrid = () => {
for(let row = 0; row < 9; row++)
{
process.stdout.write("[ ")
for(let column = 0; column < 9; column++)
{
process.stdout.write(`${grid[row][column]} `)
}
process.stdout.write("]\n")
}
process.stdout.write("\n")
}
const foundInRow = (row, number) => {
for (let column = 0; column < 9; column++) {
if (grid[row][column] === number) return true
}
return false
}
const foundInColumn = (column, number) => {
for (let row = 0; row < 9; row++) {
if (grid[row][column] === number) return true
}
return false
}
const foundInSubsquare = (row, column, number) => {
ssRow = Math.floor(row/3)
ssColumn = Math.floor(column/3)
for (let r = 0; r < 3; r++) {
for (let c = 0; c < 3; c++) {
if (grid[ssRow * 3 + r][ssColumn * 3 + c] === number) return true
}
}
return false
}
const isPossible = (row, column, number) => {
if (foundInRow(row, number)) return false
if (foundInColumn(column, number)) return false
if (foundInSubsquare(row, column, number)) return false
return true
}
const solve = () => {
for (let row = 0; row < 9; row++) {
for (let column = 0; column < 9; column++) {
if(grid[row][column] === 0)
{
for (let number = 1; number < 10; number++) {
if (isPossible(row, column, number)){
grid[row][column] = number
solve()
grid[row][column] = 0
}
}
return
}
}
}
printGrid()
}
solve()
Execution Time
time node index.js
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
1.291 secs
Java
Java? Yes, why not!
Implementation
package moritz.algorithms;
public class Sudoku{
public static int[][] grid = new int[][]{
{ 0, 0, 2, 0, 0, 4, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 6, 3, 0, 0, 0, 8, 0 },
{ 0, 9, 0, 0, 0, 0, 0, 0, 0 },
{ 5, 2, 7, 9, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 8, 0, 4, 0 },
{ 0, 0, 0, 0, 0, 0, 4, 0, 5 },
{ 0, 4, 0, 0, 0, 1, 0, 6, 0 },
{ 0, 0, 1, 0, 7, 0, 9, 0, 0 }
};
public static void main(String[] args){
solve();
}
public static void printGrid(){
for (int row = 0; row < 9; row++) {
System.out.print("[ ");
for (int column = 0; column < 9; column++) {
System.out.print(grid[row][column] + " ");
}
System.out.print("]\n");
}
}
public static boolean foundInRow(int row, int number){
for (int column = 0; column < 9; column++) {
if (grid[row][column] == number){
return true;
}
}
return false;
}
public static boolean foundInColumn(int column, int number){
for (int row = 0; row < 9; row++) {
if (grid[row][column] == number){
return true;
}
}
return false;
}
public static boolean foundInSubsquare(int row, int column, int number){
int ssRow = (int)Math.floor(row / 3);
int ssColumn = (int)Math.floor(column / 3);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
if (grid[ssRow * 3 + r][ssColumn * 3 + c] == number){
return true;
}
}
}
return false;
}
public static boolean isPossible(int row, int column, int number){
if (foundInRow(row, number)){
return false;
}
if (foundInColumn(column, number)){
return false;
}
if (foundInSubsquare(row, column, number)){
return false;
}
return true;
}
public static void solve() {
for (int row = 0; row < 9; row++) {
for (int column = 0; column < 9; column++) {
if (grid[row][column] == 0){
for (int number = 1; number < 10; number++) {
if (isPossible(row, column, number)){
grid[row][column] = number;
solve();
grid[row][column] = 0;
}
}
return;
}
}
}
printGrid();
}
}
Execution Time
[ 3 8 2 6 9 4 1 5 7 ]
[ 4 7 5 8 1 2 3 9 6 ]
[ 9 1 6 3 5 7 2 8 4 ]
[ 8 9 4 1 3 5 6 7 2 ]
[ 5 2 7 9 4 6 8 3 1 ]
[ 1 6 3 7 2 8 5 4 9 ]
[ 7 3 8 2 6 9 4 1 5 ]
[ 2 4 9 5 8 1 7 6 3 ]
[ 6 5 1 4 7 3 9 2 8 ]
0.629 secs
Clojure
I couldn’t forget to include a funcional language. And just for fun, I’ve implemented in addition to a the same as all others, a more human approach.
Base Implementation
Code
(ns sudoku
(:require [java-time :as t]))
(def grid
'(
(0 0 2 0 0 4 0 0 0)
(0 7 0 0 0 2 0 0 0)
(0 0 6 3 0 0 0 8 0)
(0 9 0 0 0 0 0 0 0)
(5 2 7 9 0 0 0 0 0)
(0 0 0 0 0 8 0 4 0)
(0 0 0 0 0 0 4 0 5)
(0 4 0 0 0 1 0 6 0)
(0 0 1 0 7 0 9 0 0))
)
(defn grid-item [grid row column]
(nth (nth grid row) column))
(defn found-in-row
[grid row number]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false (nth grid row)))
(defn found-in-column
[grid
column
number]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false (map (fn [row] (nth row column)) grid)))
(defn found-in-subsquare
[grid
row
column
number]
(let [ss-row (int (/ row 3))
ss-column (int (/ column 3))]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false
(->> grid
(drop (* 3 ss-row))
(take 3)
(apply map list)
(drop (* 3 ss-column))
(take 3)
(apply map list)
(flatten)))))
(defn is-possible
([grid pos number] (is-possible grid (pos :row) (pos :column) number))
([grid row column number]
(cond
(found-in-row grid row number) false
(found-in-column grid column number) false
(found-in-subsquare grid row column number) false
:else true)))
(defn grid-set
([grid pos number] (grid-set grid (pos :row) (pos :column) number))
([grid row column number]
(apply list (update-in (vec (map vec grid)) [row column] (fn [itm] number)))))
(def start-pos
{:row 0 :column 0 :done false})
(defn next-pos
([pos] (next-pos (pos :row) (pos :column)))
([row column]
(cond
(and (= column 8) (= 8 row)) {:row row, :column (inc column) :done true}
(= column 8) {:row (inc row), :column 0 :done false}
:else {:row row, :column (inc column) :done false})))
(defn count-zeroes
[grid]
(count (filter (fn [n] (= n 0)) (flatten grid))))
(defn solve
([grid] (solve grid start-pos))
([grid pos]
(if (pos :done)
grid
(let [next (next-pos pos)]
(if (= (grid-item grid (pos :row) (pos :column)) 0)
(let [possibles (filter (fn [n] (is-possible grid pos n)) (range 1 10))]
(if (= (grid-item grid (pos :row) (pos :column)) 0)
(filter (fn [item] (not= item '())) (map (fn [p] (solve (grid-set grid pos p) next)) possibles))))
(solve grid next))))))
(defn run [options]
(let [solution (solve grid start-pos)
unwrap (fn [s]
(if (vector? (first s))
s
(recur (first s))))]
(doseq [item (unwrap solution)]
(println item))))
Execution Time
time clj -X sudoku/run
[3 8 2 6 9 4 1 5 7]
[4 7 5 8 1 2 3 9 6]
[9 1 6 3 5 7 2 8 4]
[8 9 4 1 3 5 6 7 2]
[5 2 7 9 4 6 8 3 1]
[1 6 3 7 2 8 5 4 9]
[7 3 8 2 6 9 4 1 5]
[2 4 9 5 8 1 7 6 3]
[6 5 1 4 7 3 9 2 8]
clj -X sudoku/run 100,44s user 0,67s system 111% cpu 1:30,51 total
Human Like Implementation
In this solution I created a matrix with all possible numbers in each position and start from the squared with less possibilities. Pretty much the way a human would solve the Sudoku puzzle.
Code
(ns order
(:require [java-time :as t]))
(def grid
'(
(0 0 2 0 0 4 0 0 0)
(0 7 0 0 0 2 0 0 0)
(0 0 6 3 0 0 0 8 0)
(0 9 0 0 0 0 0 0 0)
(5 2 7 9 0 0 0 0 0)
(0 0 0 0 0 8 0 4 0)
(0 0 0 0 0 0 4 0 5)
(0 4 0 0 0 1 0 6 0)
(0 0 1 0 7 0 9 0 0))
)
(def all-possibles-expected
'(((2) (2 8 9) () (3 5 9) (3 5 9) (1 3 9) (1 2 8) () ())
(() (2 6 8 9) (8 9) () () (1 6 9) (1 2 8) (2 8 9) ())
(() () (7 9) () () (6 9) (4) (9) ())
((5) (7 9) () (2 7 9) (4 9) (4 7 8 9) (2 5 8) () ())
(() (7 9) () () (3 9) () () (7) ())
(() () (3 5 7) (2 3 6 7) (3 6) (3 6 7 8) () (2 5 7 8) (2 8))
(() (2) (1 5) (3 5 9) () (3 9) (2 3 5) () ())
(() (4 8) (5 8) (3 5 7 9) () () (3 5 8) (5 8 9) (8 9))
(() () (5 8) (5 6) (4 5 6) (4 6) () () (2 8)))
)
(defn grid-item [grid row column]
(nth (nth grid row) column))
(defn found-in-row
[grid row number]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false (nth grid row)))
(defn found-in-column
[grid
column
number]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false (map (fn [row] (nth row column)) grid)))
(defn found-in-subsquare
[grid
row
column
number]
(let [ss-row (int (/ row 3))
ss-column (int (/ column 3))]
(reduce
#(if (= number %2)
(reduced true)
(or %1 (= number %2)))
false
(->> grid
(drop (* 3 ss-row))
(take 3)
(apply map list)
(drop (* 3 ss-column))
(take 3)
(apply map list)
(flatten)))))
(defn is-possible
([grid pos number] (is-possible grid (pos :row) (pos :column) number))
([grid row column number]
(cond
(found-in-row grid row number) false
(found-in-column grid column number) false
(found-in-subsquare grid row column number) false
:else true)))
(defn grid-set
([grid pos number] (grid-set grid (pos :row) (pos :column) number))
([grid row column number]
(apply list (update-in (vec (map vec grid)) [row column] (fn [itm] number)))))
(def start-pos
{:row 0, :column 0 :done false})
(defn next-pos
([] start-pos)
([pos]
(let [row (pos :row)
column (pos :column)]
(cond
(and (= column 8) (= 8 row)) {:row row, :column (inc column) :done true}
(= column 8) {:row (inc row), :column 0 :done false}
:else {:row row, :column (inc column) :done false}))))
(defn count-zeroes
[grid]
(count (filter (fn [n] (= n 0)) (flatten grid))))
(defn get-all-possibles-grid
[grid]
(map-indexed
(fn [row-index row]
(map-indexed
(fn [column-index column]
(filter (fn [n]
(and (= column 0)
(is-possible grid row-index column-index n))) (range 1 10)))
row))
grid))
(defn count-possibilities-grid
[grid]
(map
(fn [row] (map count row))
(get-all-possibles-grid grid)))
(defn least-possibilities-pos
[grid]
(if (= 0 (count-zeroes grid))
{:row 8 :column 8 :done true}
(let [value (apply
min-key
(fn [item]
(second (second item)))
(map-indexed
(fn [row-index row]
[row-index
(apply
min-key
second
(map-indexed
(fn [column-index column]
[column-index
(if (= column 0)
10
column)])
row))])
(count-possibilities-grid grid)))]
{:done false :row (first value) :column (first (second value))})))
(defn get-positions
[grid]
(let [items (sort-by
second
(filter
(fn [item]
(not (= 10 (second item))))
(reduce
concat
(map-indexed
(fn [row-index row]
(map-indexed
(fn [column-index column]
[(+ (* 9 row-index) column-index)
(if (= column 0)
10
column)])
row))
(count-possibilities-grid grid)))))]
(concat
(map-indexed
(fn [item-index item]
{:row (int (/ (first item) 9)) :column (mod (first item) 9) :done false})
items)
'({:done true}))))
(defn is-branch-valid
([grid] (is-branch-valid grid (count-possibilities-grid grid) start-pos))
([grid possibles pos]
(let [next (next-pos pos)
row (:row pos)
column (:column pos)
done (:done pos)]
(if done
true
(if (= (grid-item (count-possibilities-grid grid) row column)
(grid-item grid row column)
0)
false
(is-branch-valid grid possibles next))))))
(defn debug-solver
[pos ps new-grid]
(println pos)
(Thread/sleep 200)
(doseq [item ps]
(println item))
(doseq [item new-grid]
(println item)))
(defn debug-solution
[grid]
;; (Thread/sleep 1000)
(println "Found a solution!")
(doseq [item grid]
(println item)))
(defn solve
([grid positions possibilities]
(let [pos (first positions)]
(if (pos :done)
(do
(debug-solution grid)
grid
)
(if (is-branch-valid grid)
(if (= (grid-item grid (pos :row) (pos :column)) 0)
(let [possibles (grid-item possibilities
(pos :row) (pos :column))]
(filter (fn [item] (not= item '()))
(map (fn [p]
(let [new-grid (grid-set grid pos p)
ps (get-all-possibles-grid new-grid)]
;; (debug-solver pos ps new-grid)
(solve new-grid
(get-positions new-grid)
ps)))
possibles)))
(do
(println "something wrong..." pos)
(Thread/sleep 1000)
;; (solve grid (rest positions) (get-all-possibles-grid grid))
)))))))
(defn run [options]
(println (solve grid (get-positions grid) (get-all-possibles-grid grid))))
Execution Time
time clj -X order/run
[3 8 2 6 9 4 1 5 7]
[4 7 5 8 1 2 3 9 6]
[9 1 6 3 5 7 2 8 4]
[8 9 4 1 3 5 6 7 2]
[5 2 7 9 4 6 8 3 1]
[1 6 3 7 2 8 5 4 9]
[7 3 8 2 6 9 4 1 5]
[2 4 9 5 8 1 7 6 3]
[6 5 1 4 7 3 9 2 8]
clj -X order/run 56,59s user 0,48s system 121% cpu 46,836 total
Conclusion
No matter this language benchmark is not scientific, I display here my results.
Linguagem | Optimized Time (s) | Unoptimized Time (s) |
---|---|---|
Python | 58.032 | |
C++ | 0.281 | 1.307 |
Rust | 0.605 | 13.954 |
C# | 1.506 | 1.798 |
GoLang | 0.644 | |
Ruby | 52.880 | |
Javascript | 1.291 | |
Java | 0.629 | |
Clojure 1 | 100.44 | |
Clojure 2 | 56.59 |