You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

166 lines
3.3 KiB

package main
import (
"fmt"
"os"
"github.com/01-edu/z01"
)
// Prints in standard output the sudoku board
func printBoard(board [][]rune) {
for _, row := range board {
for i, e := range row {
z01.PrintRune(e)
if i != len(row)-1 {
z01.PrintRune(' ')
}
}
z01.PrintRune('\n')
}
}
// Return true if the value 'value' is in the row 'y' of the board 'board'
func isInRow(board [][]rune, value rune, x, y int) bool {
for i, v := range board[y] {
if i != x && v == value {
return true
}
}
return false
}
// Returns true if the value 'value' is in the column 'x' of the board 'board'
func isInColumn(board [][]rune, value rune, x, y int) bool {
for i := 0; i < 9; i++ {
if i != y && board[i][x] == value {
return true
}
}
return false
}
// Receives an int 'x' and returns the beginning and the end
// of the interval of consecutive pairs of multiples of three 'x' is in.
// Ex. for x = 2, x is in (0, 3)
// for x = 4, x is in (3, 6)
func intervalThree(x int, max int) (int, int) {
var i int
for i = 0; i < max; i += 3 {
if x >= i && x < i+3 {
break
}
}
endi := 3 + i
return i, endi
}
// Returns true if the value 'value' is allowed in the possition (x,y) of the board 'board'
func isAllowedInBox(board [][]rune, value rune, x, y int) bool {
n := len(board)
begi, endi := intervalThree(x, n)
begj, endj := intervalThree(y, n)
for j := begj; j < endj; j++ {
for i := begi; i < endi; i++ {
if (j != y || i != i) && board[j][i] == value {
return false
}
}
}
return true
}
// Returns true if the value 'val' is allowed in the position (x, y) of the board
func isAllowed(board [][]rune, val rune, x, y int) bool {
return !isInRow(board, val, x, y) &&
!isInColumn(board, val, x, y) &&
isAllowedInBox(board, val, x, y)
}
// Returns true if the position doesn't have any value defined
// That is, if the character is a dot '.'
func isEmpty(board [][]rune, x, y int) bool {
return board[y][x] == '.'
}
// Returns all the empty positions in the board
func availablePos(board [][]rune) [][]int {
var ava [][]int
for y, row := range board {
for x, e := range row {
if e == '.' {
ava = append(ava, []int{x, y})
}
}
}
return ava
}
func validBoard(board [][]rune) bool {
size := 9
if len(board) != size {
return false
}
for y, row := range board {
if len(row) != size {
return false
}
for x, e := range row {
if (e < '1' || e > '9') && e != '.' {
return false
}
if e != '.' && !isAllowed(board, e, x, y) {
return false
}
}
}
return true
}
// Returns true if the sudoku has a solution
func sudokuH(board [][]rune, available [][]int, i int) bool {
n := len(available)
if i >= n {
return true
}
x := available[i][0]
y := available[i][1]
for c := '1'; c <= '9'; c++ {
if isAllowed(board, c, x, y) {
board[y][x] = c
if sudokuH(board, available, i+1) {
return true
}
board[y][x] = '.'
}
}
return false
}
// Receives a board and fills the empty positions with the correct
// value
func solveSudoku(board [][]rune) {
available := availablePos(board)
if sudokuH(board, available, 0) {
printBoard(board)
} else {
fmt.Println("Error")
}
}
func main() {
var board [][]rune
for _, v := range os.Args[1:] {
board = append(board, []rune(v))
}
if validBoard(board) {
solveSudoku(board)
} else {
fmt.Println("Error")
}
}