mirror of
https://github.com/theoludwig/programming-challenges.git
synced 2024-10-29 22:17:23 +01:00
feat(solutions): add sudoku/python/function
This commit is contained in:
parent
08ba65ad6e
commit
face9ed698
8
challenges/sudoku/solutions/python/function/Cell.py
Normal file
8
challenges/sudoku/solutions/python/function/Cell.py
Normal file
@ -0,0 +1,8 @@
|
||||
class Cell:
|
||||
def __init__(self, number: int, x: int, y: int) -> None:
|
||||
self.number = number
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self.number)
|
32
challenges/sudoku/solutions/python/function/Grid.py
Normal file
32
challenges/sudoku/solutions/python/function/Grid.py
Normal file
@ -0,0 +1,32 @@
|
||||
from typing import List
|
||||
|
||||
from Cell import Cell
|
||||
|
||||
|
||||
class Grid:
|
||||
def __init__(self, grid: List[List[int]]) -> None:
|
||||
data: List[List[Cell]] = []
|
||||
for x in range(len(grid)):
|
||||
column: List[Cell] = []
|
||||
for y in range(len(grid[x])):
|
||||
column.append(Cell(grid[x][y], y, x))
|
||||
data.append(column)
|
||||
self.data = data
|
||||
|
||||
def __repr__(self) -> str:
|
||||
result: str = '['
|
||||
for y in range(len(self.data)):
|
||||
result += '['
|
||||
for x in range(len(self.data[y])):
|
||||
result += str(self.get_cell(x, y).number)
|
||||
is_last_x = x == (len(self.data[y]) - 1)
|
||||
if not is_last_x:
|
||||
result += ', '
|
||||
result += ']'
|
||||
is_last_y = y == len(self.data) - 1
|
||||
if not is_last_y:
|
||||
result += ',\n'
|
||||
return result + ']'
|
||||
|
||||
def get_cell(self, x: int, y: int) -> Cell:
|
||||
return self.data[y][x]
|
3
challenges/sudoku/solutions/python/function/README.md
Normal file
3
challenges/sudoku/solutions/python/function/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# sudoku/python/function
|
||||
|
||||
Created by [@Divlo](https://github.com/Divlo) on 6 July 2021.
|
143
challenges/sudoku/solutions/python/function/Sudoku.py
Normal file
143
challenges/sudoku/solutions/python/function/Sudoku.py
Normal file
@ -0,0 +1,143 @@
|
||||
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()
|
11
challenges/sudoku/solutions/python/function/application.py
Normal file
11
challenges/sudoku/solutions/python/function/application.py
Normal file
@ -0,0 +1,11 @@
|
||||
from Sudoku import Sudoku
|
||||
from example import grid
|
||||
|
||||
sudoku = Sudoku(grid)
|
||||
|
||||
print(f'\nSudoku | is_solved = {sudoku.is_solved()}\n')
|
||||
print(sudoku)
|
||||
print('-------------------------------------\n')
|
||||
sudoku.solve()
|
||||
print(f'Sudoku | is_solved = {sudoku.is_solved()}\n')
|
||||
print(sudoku)
|
21
challenges/sudoku/solutions/python/function/example.py
Normal file
21
challenges/sudoku/solutions/python/function/example.py
Normal file
@ -0,0 +1,21 @@
|
||||
from Grid import Grid
|
||||
|
||||
grid = Grid([[5, 3, 0, 0, 7, 0, 0, 0, 0],
|
||||
[6, 0, 0, 1, 9, 5, 0, 0, 0],
|
||||
[0, 9, 8, 0, 0, 0, 0, 6, 0],
|
||||
[8, 0, 0, 0, 6, 0, 0, 0, 3],
|
||||
[4, 0, 0, 8, 0, 3, 0, 0, 1],
|
||||
[7, 0, 0, 0, 2, 0, 0, 0, 6],
|
||||
[0, 6, 0, 0, 0, 0, 2, 8, 0],
|
||||
[0, 0, 0, 4, 1, 9, 0, 0, 5],
|
||||
[0, 0, 0, 0, 8, 0, 0, 7, 9]])
|
||||
|
||||
grid_solved = Grid([[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]])
|
23
challenges/sudoku/solutions/python/function/solution.py
Normal file
23
challenges/sudoku/solutions/python/function/solution.py
Normal file
@ -0,0 +1,23 @@
|
||||
from typing import List
|
||||
import sys
|
||||
|
||||
from Sudoku import Sudoku
|
||||
from Grid import Grid
|
||||
|
||||
grid_values: List[List[int]] = []
|
||||
for value in sys.stdin:
|
||||
row_values = value.rstrip('\n').split(' ')
|
||||
current_row: List[int] = []
|
||||
for row_value in row_values:
|
||||
current_row.append(int(row_value))
|
||||
grid_values.append(current_row)
|
||||
|
||||
grid = Grid(grid_values)
|
||||
sudoku = Sudoku(grid)
|
||||
sudoku.solve()
|
||||
|
||||
for row in sudoku.grid.data:
|
||||
column_string = ''
|
||||
for column in row:
|
||||
column_string += str(column) + ' '
|
||||
print(column_string.strip())
|
Loading…
Reference in New Issue
Block a user