Instructions: Please complete board.py, a3.py and a3_test.py board.py import csv
ID: 3884883 • Letter: I
Question
Instructions:
Please complete board.py, a3.py and a3_test.py
board.py
import csv
import itertools
class Board():
##########################################
#### Constructor
##########################################
def __init__(self, filename):
#initialize all of the variables
self.n2 = 0
self.n = 0
self.spaces = 0
self.board = None
self.valsInRows = None
self.valsInCols = None
self.valsInBoxes = None
self.unSolved = None
#load the file and initialize the in-memory board with the data
self.loadSudoku(filename)
#loads the sudoku board from the given file
def loadSudoku(self, filename):
with open(filename) as csvFile:
self.n = -1
reader = csv.reader(csvFile)
for row in reader:
#Assign the n value and construct the approriately sized dependent data
if self.n == -1:
self.n = int(len(row) ** (1/2))
if not self.n ** 2 == len(row):
raise Exception('Each row must have n^2 values! (See row 0)')
else:
self.n2 = len(row)
self.spaces = self.n ** 4
self.board = {}
self.valsInRows = [set() for _ in range(self.n2)]
self.valsInCols = [set() for _ in range(self.n2)]
self.valsInBoxes = [set() for _ in range(self.n2)]
self.unSolved = set(itertools.product(range(self.n2), range(self.n2)))
#check if each row has the correct number of values
else:
if len(row) != self.n2:
raise Exception('Each row mus have the same number of values. (See row ' + str(reader.line_num - 1) + ')')
#add each value to the correct place in the board; record that the row, col, and box contains value
for index, item in enumerate(row):
if not item == '':
self.board[(reader.line_num-1, index)] = int(item)
self.valsInRows[reader.line_num-1].add(int(item))
self.valsInCols[index].add(int(item))
self.valsInBoxes[self.rcToBox(reader.line_num-1, index)].add(int(item))
self.unSolved.remove((reader.line_num-1, index))
##########################################
#### Move Functions - YOUR IMPLEMENTATIONS GO HERE
##########################################
#gets the unsolved space with the most current constraints
def getMostConstrainedUnsolvedSpace(self):
pass
#returns True if the move is not blocked by any constraints
def isValidMove(self,space,val):
pass
#makes a move, records that its in the row, col, and box, and removes the space from unSolved
def makeMove(self, space, val):
pass
#removes the move, its record in its row, col, and box, and adds the space back to unSolved
def removeMove(self, space, val):
pass
##########################################
#### Utility Functions
##########################################
#converts a given row and column to its inner box number
def rcToBox(self, row, col):
return self.n * (row // self.n) + col // self.n
#prints out a command line representation of the board
def print(self):
for r in range(self.n2):
#add row divider
if r % self.n == 0 and not r == 0:
print(" " + "---" * self.n2)
row = ""
for c in range(self.n2):
if (r,c) in self.board:
val = self.board[(r,c)]
else:
val = None
#add column divider
if c % self.n == 0 and not c == 0:
row += " | "
else:
row += " "
#add value placeholder
if val is None:
row += "_"
else:
row += str(val)
print(row)
a3.py
from board import Board
class Solver:
##########################################
#### Constructor
##########################################
def __init__(self,filename):
self.board = Board(filename)
self.solve()
##########################################
#### Solver
##########################################
#recursively selects the most constrained unsolved space and attempts
#to assign a value to it
#
#upon completion, it will leave the board in the solved state (or original
#state if a solution does not exist)
def solve(self):
pass
if __name__ == "__main__":
#change this to the input file that you'd like to test
s = Solver('testBoard_dastardly.csv')
Please create at least one additional test for each section below.
a3_test.py
import unittest
def TestFactory(module):
class TestA3(unittest.TestCase):
def __init__(self, test):
super(TestA3,self).__init__(test)
#bind module functions to tester class
self.Board = module.Board
self.Solver = module.Solver
#################################
# Board.makeMove
#################################
def test_makeMove(self):
b = self.Board("testBoard_singletonsOnly.csv")
b.makeMove((0,0), 3)
self.assertSequenceEqual({3,7,4,8,1,9}, b.valsInCols[0])
self.assertSequenceEqual({3, 4, 5}, b.valsInRows[0])
self.assertSequenceEqual({2,3,4,5,7,8,9}, b.valsInBoxes[0])
self.assertNotIn((0,0), b.unSolved)
self.assertEqual(b.board[(0,0)], 3)
b.makeMove((8, 8), 1)
self.assertSequenceEqual({1,2,3,4,6,7}, b.valsInCols[8])
self.assertSequenceEqual({1,6,9}, b.valsInRows[8])
self.assertSequenceEqual({1,2,3,4,5,6,9}, b.valsInBoxes[8])
self.assertNotIn((8, 8), b.unSolved)
self.assertEqual(b.board[(8, 8)], 1)
b.makeMove((4, 4), 5)
self.assertSequenceEqual({1, 4, 5}, b.valsInCols[4])
self.assertSequenceEqual({2,3,4,5,6,7,8}, b.valsInRows[4])
self.assertSequenceEqual({8,1,4,5,6}, b.valsInBoxes[4])
self.assertNotIn((4,4), b.unSolved)
self.assertEqual(b.board[(4,4)], 5)
#################################
# Board.removeMove
#################################
def test_removeMove(self):
b = self.Board("testBoard_med.csv")
b.removeMove((0, 0), 5)
self.assertSequenceEqual({8,3}, b.valsInCols[0])
self.assertSequenceEqual({9,2,4,7}, b.valsInRows[0])
self.assertSequenceEqual({8,7}, b.valsInBoxes[0])
self.assertIn((0, 0), b.unSolved)
self.assertNotIn((0,0), b.board)
b.removeMove((5, 3), 8)
self.assertSequenceEqual({2,4,6}, b.valsInCols[3])
self.assertSequenceEqual({9, 3,4}, b.valsInRows[5])
self.assertSequenceEqual({5}, b.valsInBoxes[4])
self.assertIn((5, 3), b.unSolved)
self.assertNotIn((5, 3), b.board)
b.removeMove((8, 8), 2)
self.assertSequenceEqual({6,7}, b.valsInCols[8])
self.assertSequenceEqual({8,3,6,7}, b.valsInRows[8])
self.assertSequenceEqual({8,6}, b.valsInBoxes[8])
self.assertIn((8, 8), b.unSolved)
self.assertNotIn((8, 8), b.board)
#################################
# Board.isValidMove
#################################
def test_isValidMove(self):
b = self.Board("testBoard_med.csv")
self.assertFalse(b.isValidMove((1, 2), 5))
self.assertFalse(b.isValidMove((1, 2), 8))
self.assertFalse(b.isValidMove((1, 2), 9))
self.assertFalse(b.isValidMove((4, 3), 5))
self.assertFalse(b.isValidMove((8, 4), 5))
self.assertFalse(b.isValidMove((6, 4), 4))
self.assertFalse(b.isValidMove((8, 8), 8))
self.assertTrue(b.isValidMove((0, 8), 1))
self.assertTrue(b.isValidMove((4, 1), 5))
self.assertTrue(b.isValidMove((4, 8), 5))
self.assertTrue(b.isValidMove((6, 8), 1))
self.assertTrue(b.isValidMove((6, 8), 3))
#################################
# Board.getMostConstrainedUnsolvedSpace
#################################
def test_getMostConstrainedUnsolvedSpace(self):
a = self.Board("testBoard_singletonsOnly.csv")
a_space = a.getMostConstrainedUnsolvedSpace()
self.assertIn(a_space, [(4,8), (6,6), (4,0), (2,2)])
b = self.Board("testBoard_med.csv")
b_space = b.getMostConstrainedUnsolvedSpace()
self.assertIn(b_space, [(8,2), (0,6)])
c = self.Board("testBoard_hard.csv")
c_space = c.getMostConstrainedUnsolvedSpace()
self.assertIn(c_space, [(5, 6), (3, 2)])
d = self.Board("testBoard_dastardly.csv")
d_space = d.getMostConstrainedUnsolvedSpace()
self.assertIn(d_space, [(7, 8), (1, 0), (6,4), (1,5), (2,4), (7,3)])
#################################
# Solver.solve
#################################
def test_solve_easy(self):
a = self.Solver("testBoard_singletonsOnly.csv")
a_solved = self.Board("testBoard_singletonsOnly_solution.csv")
self.assertDictEqual(a.board.board, a_solved.board)
def test_solve_med(self):
b = self.Solver("testBoard_med.csv")
b_solved = self.Board("testBoard_med_solution.csv")
self.assertDictEqual(b.board.board, b_solved.board)
def test_solve_hard(self):
c = self.Solver("testBoard_hard.csv")
c_solved = self.Board("testBoard_hard_solution.csv")
self.assertDictEqual(c.board.board, c_solved.board)
def test_solve_dastardly(self):
d = self.Solver("testBoard_dastardly.csv")
d_solved = self.Board("testBoard_dastardly_solution.csv")
self.assertDictEqual(d.board.board, d_solved.board)
return TestA3
if __name__ == "__main__":
#CHANGE THE IMPORT TO BE THE MAIN FILE NAME (i.e., a1)
mod = __import__("a3")
unittest.TextTestRunner(verbosity=0).run(
unittest.TestLoader()
.loadTestsFromTestCase(testCaseClass=TestFactory(mod)))
Explanation / Answer
import csv
import itertools
class Board():
##########################################
#### Constructor
##########################################
def __init__(self, filename):
#initialize all of the variables
self.n2 = 0
self.n = 0
self.spaces = 0
self.board = None
self.valsInRows = None
self.valsInCols = None
self.valsInBoxes = None
self.unSolved = None
#load the file and initialize the in-memory board with the data
self.loadSudoku(filename)
#loads the sudoku board from the given file
def loadSudoku(self, filename):
with open(filename) as csvFile:
self.n = -1
reader = csv.reader(csvFile)
for row in reader:
#Assign the n value and construct the approriately sized dependent data
if self.n == -1:
self.n = int(len(row) ** (1/2))
if not self.n ** 2 == len(row):
raise Exception('Each row must have n^2 values! (See row 0)')
else:
self.n2 = len(row)
self.spaces = self.n ** 4
self.board = {}
self.valsInRows = [set() for _ in range(self.n2)]
self.valsInCols = [set() for _ in range(self.n2)]
self.valsInBoxes = [set() for _ in range(self.n2)]
self.unSolved = set(itertools.product(range(self.n2), range(self.n2)))
#check if each row has the correct number of values
else:
if len(row) != self.n2:
raise Exception('Each row mus have the same number of values. (See row ' + str(reader.line_num - 1) + ')')
#add each value to the correct place in the board; record that the row, col, and box contains value
for index, item in enumerate(row):
if not item == '':
self.board[(reader.line_num-1, index)] = int(item)
self.valsInRows[reader.line_num-1].add(int(item))
self.valsInCols[index].add(int(item))
self.valsInBoxes[self.rcToBox(reader.line_num-1, index)].add(int(item))
self.unSolved.remove((reader.line_num-1, index))
##########################################
#### Move Functions - YOUR IMPLEMENTATIONS GO HERE
##########################################
#gets the unsolved space with the most current constraints
def getMostConstrainedUnsolvedSpace(self):
pass
#returns True if the move is not blocked by any constraints
def isValidMove(self,space,val):
pass
#makes a move, records that its in the row, col, and box, and removes the space from unSolved
def makeMove(self, space, val):
pass
#removes the move, its record in its row, col, and box, and adds the space back to unSolved
def removeMove(self, space, val):
pass
##########################################
#### Utility Functions
##########################################
#converts a given row and column to its inner box number
def rcToBox(self, row, col):
return self.n * (row // self.n) + col // self.n
#prints out a command line representation of the board
def print(self):
for r in range(self.n2):
#add row divider
if r % self.n == 0 and not r == 0:
print(" " + "---" * self.n2)
row = ""
for c in range(self.n2):
if (r,c) in self.board:
val = self.board[(r,c)]
else:
val = None
#add column divider
if c % self.n == 0 and not c == 0:
row += " | "
else:
row += " "
#add value placeholder
if val is None:
row += "_"
else:
row += str(val)
print(row)
a3.py
from board import Board
class Solver:
##########################################
#### Constructor
##########################################
def __init__(self,filename):
self.board = Board(filename)
self.solve()
##########################################
#### Solver
##########################################
#recursively selects the most constrained unsolved space and attempts
#to assign a value to it
#
#upon completion, it will leave the board in the solved state (or original
#state if a solution does not exist)
def solve(self):
pass
if __name__ == "__main__":
#change this to the input file that you'd like to test
s = Solver('testBoard_dastardly.csv')
Please create at least one additional test for each section below.
test.py
import unittest
def TestFactory(module):
class TestA3(unittest.TestCase):
def __init__(self, test):
super(TestA3,self).__init__(test)
#bind module functions to tester class
self.Board = module.Board
self.Solver = module.Solver
#################################
# Board.makeMove
#################################
def test_makeMove(self):
b = self.Board("testBoard_singletonsOnly.csv")
b.makeMove((0,0), 3)
self.assertSequenceEqual({3,7,4,8,1,9}, b.valsInCols[0])
self.assertSequenceEqual({3, 4, 5}, b.valsInRows[0])
self.assertSequenceEqual({2,3,4,5,7,8,9}, b.valsInBoxes[0])
self.assertNotIn((0,0), b.unSolved)
self.assertEqual(b.board[(0,0)], 3)
b.makeMove((8, 8), 1)
self.assertSequenceEqual({1,2,3,4,6,7}, b.valsInCols[8])
self.assertSequenceEqual({1,6,9}, b.valsInRows[8])
self.assertSequenceEqual({1,2,3,4,5,6,9}, b.valsInBoxes[8])
self.assertNotIn((8, 8), b.unSolved)
self.assertEqual(b.board[(8, 8)], 1)
b.makeMove((4, 4), 5)
self.assertSequenceEqual({1, 4, 5}, b.valsInCols[4])
self.assertSequenceEqual({2,3,4,5,6,7,8}, b.valsInRows[4])
self.assertSequenceEqual({8,1,4,5,6}, b.valsInBoxes[4])
self.assertNotIn((4,4), b.unSolved)
self.assertEqual(b.board[(4,4)], 5)
#################################
# Board.removeMove
#################################
def test_removeMove(self):
b = self.Board("testBoard_med.csv")
b.removeMove((0, 0), 5)
self.assertSequenceEqual({8,3}, b.valsInCols[0])
self.assertSequenceEqual({9,2,4,7}, b.valsInRows[0])
self.assertSequenceEqual({8,7}, b.valsInBoxes[0])
self.assertIn((0, 0), b.unSolved)
self.assertNotIn((0,0), b.board)
b.removeMove((5, 3), 8)
self.assertSequenceEqual({2,4,6}, b.valsInCols[3])
self.assertSequenceEqual({9, 3,4}, b.valsInRows[5])
self.assertSequenceEqual({5}, b.valsInBoxes[4])
self.assertIn((5, 3), b.unSolved)
self.assertNotIn((5, 3), b.board)
b.removeMove((8, 8), 2)
self.assertSequenceEqual({6,7}, b.valsInCols[8])
self.assertSequenceEqual({8,3,6,7}, b.valsInRows[8])
self.assertSequenceEqual({8,6}, b.valsInBoxes[8])
self.assertIn((8, 8), b.unSolved)
self.assertNotIn((8, 8), b.board)
#################################
# Board.isValidMove
#################################
def test_isValidMove(self):
b = self.Board("testBoard_med.csv")
self.assertFalse(b.isValidMove((1, 2), 5))
self.assertFalse(b.isValidMove((1, 2), 8))
self.assertFalse(b.isValidMove((1, 2), 9))
self.assertFalse(b.isValidMove((4, 3), 5))
self.assertFalse(b.isValidMove((8, 4), 5))
self.assertFalse(b.isValidMove((6, 4), 4))
self.assertFalse(b.isValidMove((8, 8), 8))
self.assertTrue(b.isValidMove((0, 8), 1))
self.assertTrue(b.isValidMove((4, 1), 5))
self.assertTrue(b.isValidMove((4, 8), 5))
self.assertTrue(b.isValidMove((6, 8), 1))
self.assertTrue(b.isValidMove((6, 8), 3))
#################################
# Board.getMostConstrainedUnsolvedSpace
#################################
def test_getMostConstrainedUnsolvedSpace(self):
a = self.Board("testBoard_singletonsOnly.csv")
a_space = a.getMostConstrainedUnsolvedSpace()
self.assertIn(a_space, [(4,8), (6,6), (4,0), (2,2)])
b = self.Board("testBoard_med.csv")
b_space = b.getMostConstrainedUnsolvedSpace()
self.assertIn(b_space, [(8,2), (0,6)])
c = self.Board("testBoard_hard.csv")
c_space = c.getMostConstrainedUnsolvedSpace()
self.assertIn(c_space, [(5, 6), (3, 2)])
d = self.Board("testBoard_dastardly.csv")
d_space = d.getMostConstrainedUnsolvedSpace()
self.assertIn(d_space, [(7, 8), (1, 0), (6,4), (1,5), (2,4), (7,3)])
#################################
# Solver.solve
#################################
def test_solve_easy(self):
a = self.Solver("testBoard_singletonsOnly.csv")
a_solved = self.Board("testBoard_singletonsOnly_solution.csv")
self.assertDictEqual(a.board.board, a_solved.board)
def test_solve_med(self):
b = self.Solver("testBoard_med.csv")
b_solved = self.Board("testBoard_med_solution.csv")
self.assertDictEqual(b.board.board, b_solved.board)
def test_solve_hard(self):
c = self.Solver("testBoard_hard.csv")
c_solved = self.Board("testBoard_hard_solution.csv")
self.assertDictEqual(c.board.board, c_solved.board)
def test_solve_dastardly(self):
d = self.Solver("testBoard_dastardly.csv")
d_solved = self.Board("testBoard_dastardly_solution.csv")
self.assertDictEqual(d.board.board, d_solved.board)
return TestA3
if __name__ == "__main__":
#CHANGE THE IMPORT TO BE THE MAIN FILE NAME (i.e., a1)
mod = __import__("a3")
unittest.TextTestRunner(verbosity=0).run(
unittest.TestLoader()
.loadTestsFromTestCase(testCaseClass=TestFactory(mod)))