Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

homework02 К24 Юров Кирилл 1.3 #272

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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."]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно упростить и объединить две строки (20 и 21) в grid = [int(char) for char in puzzle if char 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):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Немного усложнил перебор массива с лишним enumerate, тк z не использовалась

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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

мне кажется, что данный код не генерирует случайный массив, а только выбирает случайные точки из этого массива и, допустим, на n>=81 ответ будет один и тот же и массив не будет отличаться



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