Last active
August 29, 2015 14:09
-
-
Save j-po/10998acf5318682e0bd2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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