Skip to content

Instantly share code, notes, and snippets.

@j-po
Last active August 29, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save j-po/10998acf5318682e0bd2 to your computer and use it in GitHub Desktop.
Save j-po/10998acf5318682e0bd2 to your computer and use it in GitHub Desktop.
# From Udacity's Software Testing class (problem set 3, problem 1)
#
# SPECIFICATION:
#
# check_sudoku() determines whether its argument is a valid Sudoku
# grid. It can handle grids that are completely filled in, and also
# grids that hold some empty cells where the player has not yet
# written numbers.
#
# First, your code must do some sanity checking to make sure that its
# argument:
#
# - is a 9x9 list of lists
#
# - contains, in each of its 81 elements, an integer in the range 0..9
#
# If either of these properties does not hold, check_sudoku must
# return None.
#
# If the sanity checks pass, your code should return True if all of
# the following hold, and False otherwise:
#
# - each number in the range 1..9 occurs only once in each row
#
# - each number in the range 1..9 occurs only once in each column
#
# - each number the range 1..9 occurs only once in each of the nine
# 3x3 sub-grids, or "boxes", that make up the board
#
# This diagram (which depicts a valid Sudoku grid) illustrates how the
# grid is divided into sub-grids:
#
# 5 3 4 | 6 7 8 | 9 1 2
# 6 7 2 | 1 9 5 | 3 4 8
# 1 9 8 | 3 4 2 | 5 6 7
# ---------------------
# 8 5 9 | 7 6 1 | 4 2 3
# 4 2 6 | 8 5 3 | 7 9 1
# 7 1 3 | 9 2 4 | 8 5 6
# ---------------------
# 9 6 1 | 5 3 7 | 0 0 0
# 2 8 7 | 4 1 9 | 0 0 0
# 3 4 5 | 2 8 6 | 0 0 0
#
# Please keep in mind that a valid grid (i.e., one for which your
# function returns True) may contain 0 multiple times in a row,
# column, or sub-grid. Here we are using 0 to represent an element of
# the Sudoku grid that the player has not yet filled in.
# check_sudoku should return None
ill_formed = [[5,3,4,6,7,8,9,1,2],
[6,7,2,1,9,5,3,4,8],
[1,9,8,3,4,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9], # <---
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,2,8,6,1,7,9]]
# check_sudoku should return True
valid = [[5,3,4,6,7,8,9,1,2],
[6,7,2,1,9,5,3,4,8],
[1,9,8,3,4,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9,1],
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,2,8,6,1,7,9]]
# check_sudoku should return False
invalid = [[5,3,4,6,7,8,9,1,2],
[6,7,2,1,9,5,3,4,8],
[1,9,8,3,8,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9,1],
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,2,8,6,1,7,9]]
# check_sudoku should return True
easy = [[2,9,0,0,0,0,0,7,0],
[3,0,6,0,0,8,4,0,0],
[8,0,0,0,4,0,0,0,2],
[0,2,0,0,3,1,0,0,7],
[0,0,0,0,8,0,0,0,0],
[1,0,0,9,5,0,0,6,0],
[7,0,0,0,9,0,0,0,1],
[0,0,1,2,0,0,3,0,6],
[0,3,0,0,0,0,0,5,9]]
# check_sudoku should return True
hard = [[1,0,0,0,0,7,0,9,0],
[0,3,0,0,2,0,0,0,8],
[0,0,9,6,0,0,5,0,0],
[0,0,5,3,0,0,9,0,0],
[0,1,0,0,8,0,0,0,2],
[6,0,0,0,0,4,0,0,0],
[3,0,0,0,0,0,0,1,0],
[0,4,0,0,0,0,0,0,7],
[0,0,7,0,0,0,3,0,0]]
# check_sudoku should return False
subg = [[9,8,7,6,5,4,3,2,1],
[8,7,6,5,4,3,2,1,9],
[7,6,5,4,3,2,1,9,8],
[6,5,4,3,2,1,9,8,7],
[5,4,3,2,1,9,8,7,6],
[4,3,2,1,9,8,7,6,5],
[3,2,1,9,8,7,6,5,4],
[2,1,9,8,7,6,5,4,3],
[1,9,8,7,6,5,4,3,2]]
def check_sudoku(grid):
RANGE = range(10)
# Sanity checks
assert len(grid) == 9
try:
for r in grid:
assert len(r) == 9
for i in r:
assert i in RANGE
except AssertionError:
return None
# Check for repeats
try:
assert no_repeats(grid)
assert no_repeats(transpose(grid))
assert no_repeats(boxen(grid))
except AssertionError:
return False
return True
def transpose(grid):
return [ [r[n] for r in grid] for n in xrange(9) ]
# Spent way too long trying to get something like this working. If it ever started outputting
# the right row segments, I would group each box's rows and itertools.chain them together. Sadly, wasn't meant to be.
#def boxes(grid):
# return [ grid[i+k][j:+3] for k in xrange(3) for j in [0,3,6] for i in [0,3,6] ]
def boxen(grid):
boxes = []
for i in [0, 3, 6]:
for j in [0, 3, 6]:
box = []
for k in range(3):
box.extend(grid[i+k][j:j+3])
boxes.append(box)
return boxes
def no_repeats(zones):
RANGE = range(9)
for z in zones:
for n in RANGE:
if z.count(n) > 1:
return False
return True
print check_sudoku(ill_formed) # --> None
print check_sudoku(valid) # --> True
print check_sudoku(invalid) # --> False
print check_sudoku(easy) # --> True
print check_sudoku(hard) # --> True
print check_sudoku(subg) # --> False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment