1
1
mirror of https://github.com/theoludwig/programming-challenges.git synced 2024-11-09 22:08:58 +01:00
programming-challenges/challenges/sudoku/solutions/python/function/Sudoku.py

144 lines
5.9 KiB
Python

from unittest import TestCase, main
from copy import deepcopy
from Cell import Cell
from Grid import Grid
from example import grid, grid_solved
class Sudoku:
def __init__(self, grid: Grid) -> None:
assert len(grid.data) == 9, 'Invalid Sudoku Grid'
assert len(grid.data[0]) == 9, 'Invalid Sudoku Grid'
self.grid = deepcopy(grid)
def __repr__(self) -> str:
result: str = '+' + '---+' * 9 + '\n'
for x in range(0, 9):
result += ('|' + ' {} {} {} |'*3).format(*
[y.number if y.number != 0 else ' ' for y in self.grid.data[x]])
result += '\n'
if x % 3 == 2:
result += '+' + '---+' * 9 + '\n'
else:
result += '+' + ' +' * 9 + '\n'
return result
def is_possible_x(self, cell: Cell, number: int) -> bool:
for x in range(0, 9):
if cell.number == number:
continue
elif self.grid.get_cell(x, cell.y).number == number:
return False
return True
def is_possible_y(self, cell: Cell, number: int) -> bool:
for y in range(0, 9):
if cell.number == number:
continue
elif self.grid.get_cell(cell.x, y).number == number:
return False
return True
def is_possible_square(self, cell: Cell, number: int) -> bool:
x_square_start = (cell.x // 3) * 3
y_square_start = (cell.y // 3) * 3
for x in range(0, 3):
for y in range(0, 3):
if cell.number == number:
continue
elif self.grid.get_cell(x_square_start + x, y_square_start + y).number == number:
return False
return True
def is_possible(self, cell: Cell, number: int) -> bool:
return self.is_possible_x(cell, number) and self.is_possible_y(cell, number) and self.is_possible_square(cell, number)
def is_solved(self) -> bool:
for y in range(0, 9):
for x in range(0, 9):
cell = self.grid.get_cell(x, y)
if cell.number == 0:
return False
if not self.is_possible(cell, cell.number):
return False
return True
def solve(self) -> None:
for y in range(0, 9):
for x in range(0, 9):
cell = self.grid.get_cell(x, y)
if cell.number == 0:
for number in range(1, 10):
if self.is_possible(cell, number):
cell.number = number
self.solve()
cell.number = 0
return
self.grid = deepcopy(self.grid)
class SudokuTest(TestCase):
def test_is_possible_x(self):
sudoku = Sudoku(grid)
self.assertFalse(sudoku.is_possible_x(grid.get_cell(2, 0), 5))
self.assertFalse(sudoku.is_possible_x(grid.get_cell(2, 0), 3))
self.assertFalse(sudoku.is_possible_x(grid.get_cell(2, 0), 7))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 4))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 6))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 8))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 1))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 2))
self.assertTrue(sudoku.is_possible_x(grid.get_cell(2, 0), 9))
def test_is_possible_y(self):
sudoku = Sudoku(grid)
self.assertFalse(sudoku.is_possible_y(grid.get_cell(0, 2), 5))
self.assertTrue(sudoku.is_possible_y(grid.get_cell(0, 2), 3))
self.assertFalse(sudoku.is_possible_y(grid.get_cell(0, 2), 7))
self.assertTrue(sudoku.is_possible_y(grid.get_cell(0, 2), 1))
self.assertTrue(sudoku.is_possible_y(grid.get_cell(0, 2), 2))
self.assertFalse(sudoku.is_possible_y(grid.get_cell(0, 2), 4))
self.assertFalse(sudoku.is_possible_y(grid.get_cell(0, 2), 6))
self.assertFalse(sudoku.is_possible_y(grid.get_cell(0, 2), 8))
self.assertTrue(sudoku.is_possible_y(grid.get_cell(0, 2), 9))
def test_is_possible_square(self):
sudoku = Sudoku(grid)
self.assertFalse(sudoku.is_possible_square(grid.get_cell(0, 2), 3))
self.assertFalse(sudoku.is_possible_square(grid.get_cell(0, 2), 5))
self.assertFalse(sudoku.is_possible_square(grid.get_cell(0, 2), 6))
self.assertFalse(sudoku.is_possible_square(grid.get_cell(0, 2), 8))
self.assertFalse(sudoku.is_possible_square(grid.get_cell(0, 2), 9))
self.assertTrue(sudoku.is_possible_square(grid.get_cell(0, 2), 1))
self.assertTrue(sudoku.is_possible_square(grid.get_cell(0, 2), 2))
self.assertTrue(sudoku.is_possible_square(grid.get_cell(0, 2), 4))
self.assertTrue(sudoku.is_possible_square(grid.get_cell(0, 2), 7))
def test_is_possible(self):
sudoku = Sudoku(grid)
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 8))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 1))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 7))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 9))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 6))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 4))
self.assertFalse(sudoku.is_possible(grid.get_cell(4, 6), 2))
self.assertTrue(sudoku.is_possible(grid.get_cell(4, 6), 3))
self.assertTrue(sudoku.is_possible(grid.get_cell(4, 6), 5))
def test_is_solved(self):
sudoku = Sudoku(grid)
self.assertFalse(sudoku.is_solved())
sudoku.grid = grid_solved
self.assertTrue(sudoku.is_solved())
def test_solve(self):
sudoku = Sudoku(grid)
sudoku.solve()
self.assertEqual(sudoku.grid.__repr__(), grid_solved.__repr__())
if __name__ == '__main__':
main()