Skip to content

Instantly share code, notes, and snippets.

@possen
Last active June 29, 2020 07:39
Show Gist options
  • Save possen/b40d42b67cb897b8858ab548b9e20b3a to your computer and use it in GitHub Desktop.
Save possen/b40d42b67cb897b8858ab548b9e20b3a to your computer and use it in GitHub Desktop.
Functional Sudoku Validator
//
// main.swift
// SudokuValidator
//
// Created by Paul Ossenbruggen on 8/5/18.
// Copyright © 2018 Paul Ossenbruggen. All rights reserved.
//
import Foundation
struct SudokuSolve {
var board: [[Int]]
init(board: [[Int]]) {
self.board = board
}
mutating func solve() -> Bool {
func findEmpty() -> (Int, Int)? {
for row in 0..<9 {
for col in 0..<9 {
if board[row][col] == 0 {
return (row, col)
}
}
}
return nil
}
func checkLocationIsSafe(row: Int, col: Int, num: Int) -> Bool {
func usedInBox(row: Int, col: Int, num: Int) -> Bool {
for r in 0..<3 {
for c in 0..<3 {
if board[r+row][c+col] == num {
return true
}
}
}
return false
}
return board[row].first { $0 == num } == nil //used In Col
&& board.map { $0[col] }.first { $0 == num } == nil //used in Row
&& !usedInBox(row: row - (row % 3), col: col - (col % 3), num: num)
}
guard let (row, col) = findEmpty() else {
return true
}
for num in 1...9 {
if checkLocationIsSafe(row: row, col: col, num: num) {
board[row][col] = num
if solve() {
return true
}
board[row][col] = 0
}
}
return false
}
func validate() -> Bool {
let array = Array(board.joined())
func value(for val: (Int, Int)) -> Int {
array[val.0 * 9 + val.1]
}
func validate(_ group: [Int]) -> Bool {
group.reduce(into: Set<Int>()) { $0.insert($1) }.count == 9
}
let xy = (0..<9).reduce (true) { result, pos in
result
&& validate((0..<9).map { value(for: ($0, pos)) })
&& validate((0..<9).map { value(for: (pos, $0)) })
}
func innerBox(_ ox: Int, _ oy: Int) -> [Int] {
(0..<3).flatMap { x in (0..<3).map { y in
value(for: (x + ox * 3, y + oy * 3))
}}
}
func outerBox() -> [[Int]] {
(0..<3).flatMap { y in (0..<3).map { x in
innerBox(x, y)
}}
}
let boxes = outerBox()
let box = boxes.reduce(true) {
$0 && validate($1)
}
return xy && box
}
}
var ss1 = SudokuSolve(board: [
[3, 0, 6, 5, 0, 8, 4, 0, 0],
[5, 2, 0, 0, 0, 0, 0, 0, 0],
[0, 8, 7, 0, 0, 0, 0, 3, 1],
[0, 0, 3, 0, 1, 0, 0, 8, 0],
[9, 0, 0, 8, 6, 3, 0, 0, 5],
[0, 5, 0, 0, 9, 0, 6, 0, 0],
[1, 3, 0, 0, 0, 0, 2, 5, 0],
[0, 0, 0, 0, 0, 0, 0, 7, 4],
[0, 0, 5, 2, 0, 6, 3, 0, 0]
])
ss1.solve()
print(ss1.board)
ss1.validate()
var ss2 = SudokuSolve(board: [
[0, 4, 0, 0, 0, 6, 0, 0, 7],
[5, 0, 0, 4, 1, 0, 0, 3, 0],
[6, 0, 0, 0, 8, 7, 0, 0, 4],
[0, 0, 3, 0, 0, 4, 6, 9, 8],
[0, 0, 6, 0, 3, 0, 5, 0, 0],
[9, 8, 7, 1, 0, 0, 3, 0, 0],
[3, 0, 0, 9, 7, 0, 0, 0, 5],
[0, 9, 0, 0, 5, 1, 0, 0, 3],
[7, 0, 0, 2, 0, 0, 0, 8, 0]
])
ss2.solve()
print(ss2.board)
ss2.validate()
var ss3 = SudokuSolve(board: [
[0, 4, 0, 0, 0, 6, 0, 0, 7],
[5, 0, 0, 4, 1, 0, 0, 3, 0],
[6, 0, 0, 0, 8, 7, 0, 0, 4],
[0, 0, 3, 0, 0, 4, 6, 9, 8],
[0, 0, 6, 0, 3, 0, 5, 0, 0],
[9, 8, 7, 1, 0, 2, 3, 0, 0],
[3, 0, 0, 9, 7, 0, 0, 0, 5],
[0, 9, 0, 0, 5, 1, 0, 0, 3],
[7, 0, 0, 2, 0, 0, 0, 8, 0]
])
ss3.solve()
print(ss3.board)
ss3.validate() // should fail
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment