'''
Determine whether a 9x9 sudoku board is valid
# Attempt 1
Every iteration of n, add 3.
n = 0
C = ["5", "6", ".", "8", "4", "7", ".", ".", "."]
R = ["5", "3", ".", ".", "7", ".", ".", ".", "."]
T = [
["5", "3", "."],
["6", ".", "."],
[".", "9", "8"]
]
# Attempt 2
Every iteration of n, add 3
n = 0
R0 = ["5","3",".",".","7",".",".",".","."]
R1 = ["6",".",".","1","9","5",".",".","."]
R2 = [".","9","8",".",".",".",".","6","."]
T0 = [
["5","3","."],
["6",".","."],
[".","9","8"],
]
T1 = [
[".","7","."],
["1","9","5"],
[".",".","."],
]
T2 = [
[".",".","."],
[".",".","."],
[".","6","."],
]
'''
import collections
def isValidSudoku(board):
return isValidSudoku_etl(board) and isValidSudoku_hash(board)
def isValidSudoku_hash(board):
# Dictionaries where the values are hash sets
rows = collections.defaultdict(set)
cols = collections.defaultdict(set)
trip = collections.defaultdict(set)
for r in range(9):
for c in range(9):
val = board[r][c]
# Skip empty cells
if val == ".": continue
# Check for dupes
if (val in rows[r] or
val in cols[c] or
val in trip[ ( r//3, c//3) ]
): return False
# add to collection for persistence
rows[r].add(val)
cols[c].add(val)
trip[( r//3, c//3 )].add(val)
return True
def isValidSudoku_etl(board):
validBoard = True
for n in range(0, 3):
# Long Rows from the matrix
R0 = board[ 3*n ]
R1 = board[ 3*n + 1 ]
R2 = board[ 3*n + 2 ]
# Long Columns from the matrix
C0 = [ row[ 3*n ] for row in board ]
C1 = [ row[ 3*n + 1 ] for row in board ]
C2 = [ row[ 3*n + 2 ] for row in board ]
# Build 3x3 triples submatrix
T0 = [
R0[ 0:3 ],
R1[ 0:3 ],
R2[ 0:3 ],
]
T1 = [
R0[ 3:6 ],
R1[ 3:6 ],
R2[ 3:6 ],
]
T2 = [
R0[ 6:9 ],
R1[ 6:9 ],
R2[ 6:9 ],
]
# Build an object that tells us how many duplicates it ran into in a triple matrix
F0 = {
item: { "count": T0[ 0 ].count(item) + T0[ 1 ].count(item) + T0[ 2 ].count(item) }
# Flatten each triple to a list
for sublist in T0 for item in sublist if item != "."
}
F1 = {
item: { "count": T1[ 0 ].count(item) + T1[ 1 ].count(item) + T1[ 2 ].count(item) }
for sublist in T1 for item in sublist if item != "."
}
F2 = {
item: { "count": T2[ 0 ].count(item) + T2[ 1 ].count(item) + T2[ 2 ].count(item) }
for sublist in T2 for item in sublist if item != "."
}
# Find any repeated values in the triple
Tres0 = { k: v for k, v in F0.items() if v['count'] > 1 }
Tres1 = { k: v for k, v in F1.items() if v['count'] > 1 }
Tres2 = { k: v for k, v in F2.items() if v['count'] > 1 }
if Tres0:
validBoard = False
if Tres1:
validBoard = False
if Tres2:
validBoard = False
# Keep it Simple: Just recalculate the long vectors for validity
G0 = {
item: { "count": R0.count(item) }
for sublist in R0 for item in sublist if item != "."
}
G1 = {
item: { "count": R1.count(item) }
for sublist in R1 for item in sublist if item != "."
}
G2 = {
item: { "count": R2.count(item) }
for sublist in R2 for item in sublist if item != "."
}
# Column Problem: We recalculate this every iteration of n
H0 = {
item: { "count": C0.count(item) }
for sublist in C0 for item in sublist if item != "."
}
H1 = {
item: { "count": C1.count(item) }
for sublist in C1 for item in sublist if item != "."
}
H2 = {
item: { "count": C2.count(item) }
for sublist in C2 for item in sublist if item != "."
}
# Find any repeated values from the vectors
Ures0 = { k: v for k, v in G0.items() if v['count'] > 1 }
Ures1 = { k: v for k, v in G1.items() if v['count'] > 1 }
Ures2 = { k: v for k, v in G2.items() if v['count'] > 1 }
Vres0 = { k: v for k, v in H0.items() if v['count'] > 1 }
Vres1 = { k: v for k, v in H1.items() if v['count'] > 1 }
Vres2 = { k: v for k, v in H2.items() if v['count'] > 1 }
if (Ures0 or Vres0):
validBoard = False
if (Ures1 or Vres1):
validBoard = False
if (Ures2 or Vres2):
validBoard = False
return validBoard
# return True
print("Valid Board:")
board = [
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
if (isValidSudoku(board)):
print("Correct: board valid")
else:
print("Error: Board should have been valid")
print("Invalid Board:")
board = [
["8","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
if (isValidSudoku(board)):
print("Error: Board should have been INvalid")
else:
print("Correct: board invalid")
print("Valid Board")
board = [
[".",".",".",".","5",".","2",".","."],
[".",".","6",".",".",".",".","3","."],
[".","2",".","4",".",".",".",".","."],
["1",".",".",".",".","3",".",".","."],
[".",".",".","7",".",".","6",".","."],
[".",".",".",".","8",".",".",".","1"],
[".","9",".",".",".",".",".",".","."],
[".",".",".","6",".",".","4",".","."],
["3",".",".",".",".",".",".","8","."]
]
if (isValidSudoku(board)):
print("Valid Board")