mirror of https://github.com/01-edu/public.git
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
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") |
|
} |
|
}
|
|
|