Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Instructions: Please complete board.py, a3.py and a3_test.py board.py import csv

ID: 3884888 • 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)))

4.2.1 Board.makeMove This function should take a space tuple (r, c) where r and c are a row and column index respectively and a valid value assignment for the space. It should: 1. Save the value in board at the appropriate location 2. Record that the value is in now in the appropriate row, column, and box 3. Remove the space from unSolved 4.2.2 Board.removeMove This function should take a space tuple (r, c) where r and c are a row and column index respectively and a valid value assignment for the space. It should: 1. Remove the value from board at the appropriate location 2. Record that the value is no longer in the appropriate row, column, and box 3. Add the space to unSolved 4.2.3 Board.isValidMove This function should take a space tuple (r, c) where r and c are a row and column index respectively and a valid value assignment for the space. It should return True iff placing the value in the indicated space does not conflict with any of the constraints of Sudoku.

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.

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)))