Skip to content

Commit

Permalink
did labwork
Browse files Browse the repository at this point in the history
  • Loading branch information
Generalusus committed Jan 23, 2025
1 parent cd12616 commit a2aa839
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 29 deletions.
12 changes: 12 additions & 0 deletions homework02/.idea/homework02.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions homework02/.idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions homework02/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions homework02/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions homework02/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions homework02/.idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 89 additions & 29 deletions homework02/sudoku.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
"""Sudoku solving"""

import pathlib
import random
import typing as tp

T = tp.TypeVar("T")


def read_sudoku(path: tp.Union[str, pathlib.Path]) -> tp.List[tp.List[str]]:
""" Прочитать Судоку из указанного файла """
"""Прочитать Судоку из указанного файла"""
path = pathlib.Path(path)
with path.open() as f:
puzzle = f.read()
return create_grid(puzzle)


def create_grid(puzzle: str) -> tp.List[tp.List[str]]:
"""Creates grid for puzzle"""
digits = [c for c in puzzle if c in "123456789."]
grid = group(digits, 9)
return grid


def display(grid: tp.List[tp.List[str]]) -> None:
"""Вывод Судоку """
"""Вывод Судоку"""
width = 2
line = "+".join(["-" * (width * 3)] * 3)
for row in range(9):
print(
"".join(
grid[row][col].center(width) + ("|" if str(col) in "25" else "") for col in range(9)
)
)
print("".join(grid[row][col].center(width) + ("|" if str(col) in "25" else "") for col in range(9)))
if str(row) in "25":
print(line)
print()
Expand All @@ -41,7 +41,7 @@ def group(values: tp.List[T], n: int) -> tp.List[tp.List[T]]:
>>> group([1,2,3,4,5,6,7,8,9], 3)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
"""
pass
return [values[i * n : i * n + n] for i in range(len(values) // n)]


def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
Expand All @@ -53,7 +53,7 @@ def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str
>>> get_row([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (2, 0))
['.', '8', '9']
"""
pass
return grid[pos[0]]


def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
Expand All @@ -65,7 +65,7 @@ def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str
>>> get_col([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (0, 2))
['3', '6', '9']
"""
pass
return [i[pos[1]] for i in grid]


def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
Expand All @@ -78,7 +78,12 @@ def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[s
>>> get_block(grid, (8, 8))
['2', '8', '.', '.', '.', '5', '.', '7', '9']
"""
pass
array = [
grid[i][j]
for i in range(pos[0] // 3 * 3, pos[0] // 3 * 3 + 3)
for j in range(pos[1] // 3 * 3, pos[1] // 3 * 3 + 3)
]
return array


def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[int, int]]:
Expand All @@ -90,7 +95,11 @@ def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[in
>>> find_empty_positions([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']])
(2, 0)
"""
pass
for i, char in enumerate(grid):
for j, char1 in enumerate(char):
if char1 == ".":
return (i, j)
return None


def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]:
Expand All @@ -103,31 +112,63 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -
>>> values == {'2', '5', '9'}
True
"""
pass
set1 = set("123456789")
set2 = set(get_block(grid, pos)).union(get_row(grid, pos), get_col(grid, pos))
return set1 - set2


def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]:
""" Решение пазла, заданного в grid """
""" Как решать Судоку?
1. Найти свободную позицию
2. Найти все возможные значения, которые могут находиться на этой позиции
3. Для каждого возможного значения:
3.1. Поместить это значение на эту позицию
3.2. Продолжить решать оставшуюся часть пазла
"""Решение пазла, заданного в grid"""
"""
>>> grid = read_sudoku('puzzle1.txt')
>>> solve(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']]
"""
pass
spc = find_empty_positions(grid)
if not spc:
return grid
res_grid = [i.copy() for i in grid]
for i in find_possible_values(grid, spc):
res_grid[spc[0]][spc[1]] = i
next1 = solve(res_grid)
if next1:
return next1
return None


def check_solution(solution: tp.List[tp.List[str]]) -> bool:
""" Если решение solution верно, то вернуть True, в противном случае False """
# TODO: Add doctests with bad puzzles
pass


def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
"""Если решение solution верно, то вернуть True, в противном случае False"""
flag = True
for i in range(0, 9):
arr = get_row(solution, (i, 0))
used = [0] * 10
for j, val in enumerate(arr):
used[ord(val) - ord("0")] += 1
if used[ord(val) - ord("0")] > 1:
flag = False
break
for i in range(0, 9):
arr = get_col(solution, (i, 0))
used = [0] * 10
for j, row in enumerate(arr):
for z, val in enumerate(row):
used[ord(arr[j]) - ord("0")] += 1
if used[ord(arr[j][z]) - ord("0")] > 1:
flag = False
break
for i in range(0, 9, 3):
for j in range(0, 9, 3):
arr = get_block(solution, (i, j))
used = [0] * 10
for z, val in enumerate(arr):
used[ord(val) - ord("0")] += 1
if used[ord(val) - ord("0")] > 1:
flag = False
break
return flag


def generate_sudoku(n: int) -> tp.List[tp.List[str]]:
"""Генерация судоку заполненного на N элементов
>>> grid = generate_sudoku(40)
>>> sum(1 for row in grid for e in row if e == '.')
Expand All @@ -148,7 +189,26 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
>>> check_solution(solution)
True
"""
pass
cor_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"],
]
empty_grid = [["." for i in range(9)] for i in range(9)]
dot_list = [(i, j) for i in range(9) for j in range(9)]
n = min(n, 81)
for i in range(n):
replace_pos = random.randint(0, len(dot_list) - 1)
ch_pos = dot_list[replace_pos]
empty_grid[ch_pos[0]][ch_pos[1]] = cor_grid[ch_pos[0]][ch_pos[1]]
dot_list.pop(replace_pos)
return empty_grid


if __name__ == "__main__":
Expand All @@ -159,4 +219,4 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
if not solution:
print(f"Puzzle {fname} can't be solved")
else:
display(solution)
display(solution)

0 comments on commit a2aa839

Please sign in to comment.