From 1b856e92c51d7fc27ccda7264be255d302a35eaf Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 19:52:11 +0500 Subject: [PATCH 01/14] homework02 complete --- homework02/sudoku.py | 83 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index df78ab1..6032c70 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -1,5 +1,6 @@ import pathlib import typing as tp +import random T = tp.TypeVar("T") @@ -38,12 +39,16 @@ def group(values: tp.List[T], n: int) -> tp.List[tp.List[T]]: Сгруппировать значения values в список, состоящий из списков по n элементов >>> group([1,2,3,4], 2) - [[1, 2], [3, 4]] + [[1, 2], [3, 4]]) >>> group([1,2,3,4,5,6,7,8,9], 3) [[1, 2, 3], [4, 5, 6], [7, 8, 9]] """ - pass - + a = [] + i = 0 + for j in range(n, len(values) + 1, n): + a.append(values[i:j]) + i = j + return a def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: """Возвращает все значения для номера строки, указанной в pos @@ -55,7 +60,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]: @@ -68,7 +73,10 @@ 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 + column = [] + for i in range(len(grid)): + column.append(grid[i][pos[1]]) + return column def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -82,7 +90,13 @@ 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 + block = [] + number_of_string = pos[0] // 3 + number_of_column = pos[1] // 3 + for i in range(number_of_string * 3, number_of_string * 3 + 3): + for j in range(number_of_column * 3, number_of_column * 3 + 3): + block.append(grid[i][j]) + return block def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[int, int]]: @@ -95,7 +109,14 @@ 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 + x = -1 + for i in grid: + y = -1 + x += 1 + for j in i: + y += 1 + if j == ".": + return x, y def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]: @@ -109,7 +130,14 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) - >>> values == {'2', '5', '9'} True """ - pass + numbers = set("123456789") + string = set(get_row(grid, pos)) + column = set(get_col(grid, pos)) + block = set(get_block(grid, pos)) + numbers -= string + numbers -= column + numbers -= block + return numbers def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: @@ -125,13 +153,32 @@ def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: >>> 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 - + pos = find_empty_positions(grid) + if pos is None: + return grid + else: + possible_values = find_possible_values(grid, pos) + for number in possible_values: + grid[pos[0]][pos[1]] = number + res = solve(grid) + if res: + return res + grid[pos[0]][pos[1]] = "." def check_solution(solution: tp.List[tp.List[str]]) -> bool: """ Если решение solution верно, то вернуть True, в противном случае False """ # TODO: Add doctests with bad puzzles - pass + arr = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] + for i in range(0, len(solution)): + for j in range(0, len(solution)): + pos = i, j + if not ( + arr == sorted(get_row(solution, pos)) + and arr == sorted(get_col(solution, pos)) + and arr == sorted(get_block(solution, pos)) + ): + return False + return True def generate_sudoku(N: int) -> tp.List[tp.List[str]]: @@ -156,7 +203,14 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: >>> check_solution(solution) True """ - pass + grid = [["." for _ in range(9)] for _ in range(9)] + if N > 81: + N = 81 + dots = random.sample([i for i in range(81)], 81 - N) + solve(grid) + for elem in dots: + grid[elem // 9][elem % 9] = "." + return grid if __name__ == "__main__": @@ -168,3 +222,8 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: print(f"Puzzle {fname} can't be solved") else: display(solution) + if check_solution(solution): + print("Solution is correct") + else: + print("LoL") + display(generate_sudoku(1)) \ No newline at end of file From f37d8557811b871ce24df9bb0b9de4e387cb20c6 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 19:53:34 +0500 Subject: [PATCH 02/14] homework02 complete --- .github/workflows/cs102.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cs102.yml b/.github/workflows/cs102.yml index 4509ac4..cb286a1 100644 --- a/.github/workflows/cs102.yml +++ b/.github/workflows/cs102.yml @@ -10,7 +10,7 @@ jobs: - name: Set up Python 3.8.6 uses: actions/setup-python@v2 with: - python-version: '3.8.6' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip From dd52721cd37370487597c37d515c0cce805c8b1d Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 19:55:12 +0500 Subject: [PATCH 03/14] homework02 complete --- homework02/sudoku.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 6032c70..a34480c 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -1,6 +1,7 @@ import pathlib -import typing as tp import random +import typing as tp + T = tp.TypeVar("T") From e055df02dd6744642aeabe1475174caafb4b9db5 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 19:57:15 +0500 Subject: [PATCH 04/14] homework02 complete --- homework02/sudoku.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index a34480c..b1faed4 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -2,7 +2,6 @@ import random import typing as tp - T = tp.TypeVar("T") From b2e1d2a6d124aaa511a44fa5be5c95cbe253be6e Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 19:58:53 +0500 Subject: [PATCH 05/14] homework02 complete --- homework02/sudoku.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index b1faed4..a8b1548 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -6,7 +6,7 @@ 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() @@ -20,7 +20,7 @@ def create_grid(puzzle: str) -> tp.List[tp.List[str]]: def display(grid: tp.List[tp.List[str]]) -> None: - """Вывод Судоку """ + """Вывод Судоку""" width = 2 line = "+".join(["-" * (width * 3)] * 3) for row in range(9): @@ -60,7 +60,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'] """ - return(grid[pos[0]]) + return grid[pos[0]] def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: From 570c7e738e58f715235af3c2ab9c47af93af9192 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 20:02:18 +0500 Subject: [PATCH 06/14] homework02 complete --- homework02/sudoku.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index a8b1548..2bbab7d 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -141,7 +141,7 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) - def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: - """ Решение пазла, заданного в grid """ + """Решение пазла, заданного в grid""" """ Как решать Судоку? 1. Найти свободную позицию 2. Найти все возможные значения, которые могут находиться на этой позиции @@ -166,16 +166,16 @@ def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: grid[pos[0]][pos[1]] = "." def check_solution(solution: tp.List[tp.List[str]]) -> bool: - """ Если решение solution верно, то вернуть True, в противном случае False """ + """Если решение solution верно, то вернуть True, в противном случае False""" # TODO: Add doctests with bad puzzles arr = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] for i in range(0, len(solution)): for j in range(0, len(solution)): pos = i, j if not ( - arr == sorted(get_row(solution, pos)) - and arr == sorted(get_col(solution, pos)) - and arr == sorted(get_block(solution, pos)) + arr == sorted(get_row(solution, pos)) + and arr == sorted(get_col(solution, pos)) + and arr == sorted(get_block(solution, pos)) ): return False return True @@ -226,4 +226,4 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: print("Solution is correct") else: print("LoL") - display(generate_sudoku(1)) \ No newline at end of file + display(generate_sudoku(1)) \ No newline at end of file From fb07cc4ca5da7e87ab0d17684099b416174261f3 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 20:05:03 +0500 Subject: [PATCH 07/14] homework02 complete --- homework02/sudoku.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 2bbab7d..7c02bed 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -50,6 +50,7 @@ def group(values: tp.List[T], n: int) -> tp.List[tp.List[T]]: i = j return a + def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: """Возвращает все значения для номера строки, указанной в pos @@ -165,6 +166,7 @@ def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: return res grid[pos[0]][pos[1]] = "." + def check_solution(solution: tp.List[tp.List[str]]) -> bool: """Если решение solution верно, то вернуть True, в противном случае False""" # TODO: Add doctests with bad puzzles @@ -226,4 +228,4 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: print("Solution is correct") else: print("LoL") - display(generate_sudoku(1)) \ No newline at end of file + display(generate_sudoku(1)) From cbc4a2d0f4152ae478db8f25396c624a86ef89c1 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Thu, 9 Mar 2023 20:10:07 +0500 Subject: [PATCH 08/14] homework02 complete --- homework02/sudoku.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 7c02bed..1118752 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -100,7 +100,7 @@ def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[s return block -def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[int, int]]: +def find_empty_positions(grid: tp.List[tp.List[str]]): """Найти первую свободную позицию в пазле >>> find_empty_positions([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']]) @@ -141,7 +141,7 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) - return numbers -def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: +def solve(grid: tp.List[tp.List[str]]): """Решение пазла, заданного в grid""" """ Как решать Судоку? 1. Найти свободную позицию From 3b778cf77757c076ab022fb0cb15a704dbc1e888 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Fri, 10 Mar 2023 04:37:00 +0500 Subject: [PATCH 09/14] homework02 complete --- homework02/sudoku.py | 97 ++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 1118752..66be4e1 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -43,12 +43,14 @@ 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]] """ - a = [] i = 0 - for j in range(n, len(values) + 1, n): - a.append(values[i:j]) + j = n + s = [] + while j <= len(values): + s.append(values[i:j]) i = j - return a + j += n + return s def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -74,10 +76,10 @@ 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'] """ - column = [] + post = [] for i in range(len(grid)): - column.append(grid[i][pos[1]]) - return column + post.append(grid[i][pos[1]]) + return post def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -91,13 +93,11 @@ 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'] """ - block = [] - number_of_string = pos[0] // 3 - number_of_column = pos[1] // 3 - for i in range(number_of_string * 3, number_of_string * 3 + 3): - for j in range(number_of_column * 3, number_of_column * 3 + 3): - block.append(grid[i][j]) - return block + square = [] + 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): + square.append(grid[i][j]) + return square def find_empty_positions(grid: tp.List[tp.List[str]]): @@ -110,14 +110,14 @@ def find_empty_positions(grid: tp.List[tp.List[str]]): >>> find_empty_positions([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']]) (2, 0) """ - x = -1 - for i in grid: - y = -1 + x = - 1 + for i in range(len(grid)): x += 1 - for j in i: - y += 1 - if j == ".": + y = 0 + for j in range(len(grid[i])): + if grid[i][j] == ".": return x, y + y += 1 def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]: @@ -131,14 +131,9 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) - >>> values == {'2', '5', '9'} True """ - numbers = set("123456789") - string = set(get_row(grid, pos)) - column = set(get_col(grid, pos)) - block = set(get_block(grid, pos)) - numbers -= string - numbers -= column - numbers -= block - return numbers + full = set(get_row(grid, pos) + get_col(grid, pos) + get_block(grid, pos)) + possible_values = set("123456789") - full + return possible_values def solve(grid: tp.List[tp.List[str]]): @@ -154,31 +149,27 @@ def solve(grid: tp.List[tp.List[str]]): >>> 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']] """ - pos = find_empty_positions(grid) - if pos is None: + empty_positions = find_empty_positions(grid) + if empty_positions is None: return grid else: - possible_values = find_possible_values(grid, pos) - for number in possible_values: - grid[pos[0]][pos[1]] = number - res = solve(grid) - if res: - return res - grid[pos[0]][pos[1]] = "." + possible_values = find_possible_values(grid, empty_positions) + for i in possible_values: + grid[empty_positions[0]][empty_positions[1]] = i + next = solve(grid) + if next: + return next + grid[empty_positions[0]][empty_positions[1]] = '.' def check_solution(solution: tp.List[tp.List[str]]) -> bool: """Если решение solution верно, то вернуть True, в противном случае False""" # TODO: Add doctests with bad puzzles - arr = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] + all = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] for i in range(0, len(solution)): for j in range(0, len(solution)): pos = i, j - if not ( - arr == sorted(get_row(solution, pos)) - and arr == sorted(get_col(solution, pos)) - and arr == sorted(get_block(solution, pos)) - ): + if not sorted(get_row(solution, pos)) == all or not sorted(get_col(solution, pos)) == all or not sorted(get_block(solution, pos)) == all: return False return True @@ -205,13 +196,23 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: >>> check_solution(solution) True """ - grid = [["." for _ in range(9)] for _ in range(9)] + grid = [["." for i in range(9)] for i in range(9)] + print(N) if N > 81: N = 81 - dots = random.sample([i for i in range(81)], 81 - N) - solve(grid) - for elem in dots: - grid[elem // 9][elem % 9] = "." + print(grid) + grid = solve(grid) + print(grid) + k = 0 + while k != 81 - N: + i = random.randint(0, 8) + j = random.randint(0, 8) + if grid[i][j] == ".": + k = k + else: + grid[i][j] = "." + k += 1 + print(grid) return grid From fb26868b96fe344a7ee27e1efe405dd9c9f1beba Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Fri, 10 Mar 2023 04:42:01 +0500 Subject: [PATCH 10/14] homework02 complete --- homework02/sudoku.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 66be4e1..282ad0a 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -110,7 +110,7 @@ def find_empty_positions(grid: tp.List[tp.List[str]]): >>> find_empty_positions([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']]) (2, 0) """ - x = - 1 + x = -1 for i in range(len(grid)): x += 1 y = 0 @@ -159,7 +159,7 @@ def solve(grid: tp.List[tp.List[str]]): next = solve(grid) if next: return next - grid[empty_positions[0]][empty_positions[1]] = '.' + grid[empty_positions[0]][empty_positions[1]] = "." def check_solution(solution: tp.List[tp.List[str]]) -> bool: @@ -169,7 +169,11 @@ def check_solution(solution: tp.List[tp.List[str]]) -> bool: for i in range(0, len(solution)): for j in range(0, len(solution)): pos = i, j - if not sorted(get_row(solution, pos)) == all or not sorted(get_col(solution, pos)) == all or not sorted(get_block(solution, pos)) == all: + if ( + not sorted(get_row(solution, pos)) == all + or not sorted(get_col(solution, pos)) == all + or not sorted(get_block(solution, pos)) == all: + ): return False return True From d621fd1bf0c95d740a32ffc0e0622e8af5900fa6 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Fri, 10 Mar 2023 04:43:48 +0500 Subject: [PATCH 11/14] homework02 complete --- homework02/sudoku.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homework02/sudoku.py b/homework02/sudoku.py index 282ad0a..df02ea2 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -172,7 +172,7 @@ def check_solution(solution: tp.List[tp.List[str]]) -> bool: if ( not sorted(get_row(solution, pos)) == all or not sorted(get_col(solution, pos)) == all - or not sorted(get_block(solution, pos)) == all: + or not sorted(get_block(solution, pos)) == all ): return False return True From a6934b308653d06d50ccb71cca666e5860ee45f6 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Sat, 11 Mar 2023 19:09:28 +0500 Subject: [PATCH 12/14] homework03 complete --- homework03/life.py | 104 +++++++++++++++++++++++++++++---- homework03/life_console.py | 24 +++++++- homework03/life_gui.py | 86 +++++++++++++++++++++++++-- homework03/life_proto.py | 115 ++++++++++++++++++++++++++++++++----- 4 files changed, 295 insertions(+), 34 deletions(-) diff --git a/homework03/life.py b/homework03/life.py index 7aef0b6..9fb83fd 100644 --- a/homework03/life.py +++ b/homework03/life.py @@ -12,10 +12,10 @@ class GameOfLife: def __init__( - self, - size: tp.Tuple[int, int], - randomize: bool = True, - max_generations: tp.Optional[float] = float("inf"), + self, + size: tp.Tuple[int, int], + randomize: bool = True, + max_generations: tp.Optional[float] = float("inf"), ) -> None: # Размер клеточного поля self.rows, self.cols = size @@ -30,45 +30,125 @@ def __init__( def create_grid(self, randomize: bool = False) -> Grid: # Copy from previous assignment - pass + if randomize: + return [[random.randint(0, 1) for i in range(self.rows)] for i in range(self.cols)] + else: + return [[0 for i in range(self.rows)] for i in range(self.cols)] def get_neighbours(self, cell: Cell) -> Cells: # Copy from previous assignment - pass + height, width = cell + cells = [] + if height == 0 and width == 0: + cells.append(self.curr_generation[0][1]) + cells.append(self.curr_generation[1][0]) + cells.append(self.curr_generation[1][1]) + elif height == 0 and width == self.cols - 1: + cells.append(self.curr_generation[0][width - 1]) + cells.append(self.curr_generation[1][width]) + cells.append(self.curr_generation[1][width - 1]) + elif height == self.rows - 1 and width == 0: + cells.append(self.curr_generation[height - 1][0]) + cells.append(self.curr_generation[height - 1][1]) + cells.append(self.curr_generation[height][1]) + elif height == self.rows - 1 and width == self.cols - 1: + cells.append(self.curr_generation[height - 1][width - 1]) + cells.append(self.curr_generation[height][width - 1]) + cells.append(self.curr_generation[height - 1][width]) + elif height == 0: + cells.append(self.curr_generation[0][width - 1]) + cells.append(self.curr_generation[0][width + 1]) + cells.append(self.curr_generation[1][width]) + cells.append(self.curr_generation[1][width - 1]) + cells.append(self.curr_generation[1][width + 1]) + elif width == 0: + cells.append(self.curr_generation[height - 1][0]) + cells.append(self.curr_generation[height + 1][0]) + cells.append(self.curr_generation[height][1]) + cells.append(self.curr_generation[height - 1][1]) + cells.append(self.curr_generation[height + 1][1]) + elif height == self.rows - 1: + cells.append(self.curr_generation[height][width - 1]) + cells.append(self.curr_generation[height][width + 1]) + cells.append(self.curr_generation[height - 1][width]) + cells.append(self.curr_generation[height - 1][width - 1]) + cells.append(self.curr_generation[height - 1][width + 1]) + elif width == self.cols - 1: + cells.append(self.curr_generation[height - 1][width]) + cells.append(self.curr_generation[height + 1][width]) + cells.append(self.curr_generation[height][width - 1]) + cells.append(self.curr_generation[height - 1][width - 1]) + cells.append(self.curr_generation[height + 1][width - 1]) + else: + cells.append(self.curr_generation[height][width - 1]) + cells.append(self.curr_generation[height][width + 1]) + cells.append(self.curr_generation[height - 1][width]) + cells.append(self.curr_generation[height + 1][width]) + cells.append(self.curr_generation[height - 1][width - 1]) + cells.append(self.curr_generation[height - 1][width + 1]) + cells.append(self.curr_generation[height + 1][width + 1]) + cells.append(self.curr_generation[height + 1][width - 1]) + return cells def get_next_generation(self) -> Grid: # Copy from previous assignment - pass + next_grid = [[0 for i in range(self.cols)] for i in range(self.rows)] + for i in range(self.rows): + for j in range(self.cols): + if self.curr_generation[i][j] == 1 and (sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3): + next_grid[i][j] = 1 + elif self.curr_generation[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: + next_grid[i][j] = 1 + else: + next_grid[i][j] = 0 + return next_grid def step(self) -> None: """ Выполнить один шаг игры. """ - pass + self.prev_generation = self.curr_generation + self.curr_generation = self.get_next_generation() + self.generations += 1 @property def is_max_generations_exceeded(self) -> bool: """ Не превысило ли текущее число поколений максимально допустимое. """ - pass + if self.max_generations == self.generations: + return True + else: + return False @property def is_changing(self) -> bool: """ Изменилось ли состояние клеток с предыдущего шага. """ - pass + if self.curr_generation == self.prev_generation: + return False + else: + return True @staticmethod def from_file(filename: pathlib.Path) -> "GameOfLife": """ Прочитать состояние клеток из указанного файла. """ - pass + f = open(filename, "r").readlines() + grid = [] + for i in range(len(f)): + r = list(map(int, f[i].split())) + grid.append(r) + life = GameOfLife(size=(len(grid), len(grid[0])), randomize=False) + life.curr_generation = grid + return life def save(self, filename: pathlib.Path) -> None: """ Сохранить текущее состояние клеток в указанный файл. """ - pass + with open(filename, "w") as f: + for i in self.curr_generation: + f.write("".join([str(j) for j in i]) + "\n") diff --git a/homework03/life_console.py b/homework03/life_console.py index ddeb9ef..5fc3f81 100644 --- a/homework03/life_console.py +++ b/homework03/life_console.py @@ -10,13 +10,31 @@ def __init__(self, life: GameOfLife) -> None: def draw_borders(self, screen) -> None: """ Отобразить рамку. """ - pass + screen.border("|", "|", "-", "-", "+", "+", "+", "+") def draw_grid(self, screen) -> None: """ Отобразить состояние клеток. """ - pass + for i in range(self.life.rows): + for j in range(self.life.cols): + if self.life.curr_generation[i][j] == 0: + screen.addch(i + 1, j + 1, " ") + else: + screen.addch(i + 1, j + 1, "#") def run(self) -> None: screen = curses.initscr() # PUT YOUR CODE HERE - curses.endwin() + while True: + self.draw_borders(screen) + self.draw_grid(screen) + screen.refresh() + self.life.step() + if screen.getch() == 32: # space + curses.endwin() + break + + +if __name__ == "__main__": + life = GameOfLife((100, 100), max_generations=50) + ui = Console(life) + ui.run() diff --git a/homework03/life_gui.py b/homework03/life_gui.py index 1126b29..19b8bf5 100644 --- a/homework03/life_gui.py +++ b/homework03/life_gui.py @@ -7,15 +7,89 @@ class GUI(UI): def __init__(self, life: GameOfLife, cell_size: int = 10, speed: int = 10) -> None: super().__init__(life) + self.cell_size = cell_size + self.width = life.rows * cell_size + self.height = life.cols * cell_size + self.screen_size = self.width, self.height + self.screen = pygame.display.set_mode(self.screen_size) + self.cell_width = self.width // self.cell_size + self.cell_height = self.height // self.cell_size + self.speed = speed def draw_lines(self) -> None: - # Copy from previous assignment - pass + for x in range(0, self.width, self.cell_size): + pygame.draw.line(self.screen, pygame.Color("black"), (x, 0), (x, self.height)) + for y in range(0, self.height, self.cell_size): + pygame.draw.line(self.screen, pygame.Color("black"), (0, y), (self.width, y)) def draw_grid(self) -> None: - # Copy from previous assignment - pass + for i in range(self.cell_height): + for j in range(self.cell_width): + if self.life.curr_generation[i][j] == 1: + pygame.draw.rect( + self.screen, + pygame.Color("green"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + else: + pygame.draw.rect( + self.screen, + pygame.Color("white"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + + def myself(self, height, width) -> None: + col = height // self.cell_size + row = width // self.cell_size + if self.life.curr_generation[row][col] == 0: + self.life.curr_generation[row][col] = 1 + else: + self.life.curr_generation[row][col] = 0 def run(self) -> None: - # Copy from previous assignment - pass + pygame.init() + clock = pygame.time.Clock() + pygame.display.set_caption("Game of Life") + self.screen.fill(pygame.Color("white")) + running = True + pause = False + while running: + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_SPACE: + pause = not pause + elif event.type == pygame.MOUSEBUTTONDOWN: + height, width = event.pos + self.myself(height, width) + self.draw_grid() + self.draw_lines() + pygame.display.flip() + elif event.type == QUIT: + running = False + if not self.life.is_changing: + running = False + elif self.life.is_max_generations_exceeded: + running = False + if not pause: + self.life.step() + self.draw_lines() + self.draw_grid() + pygame.display.flip() + clock.tick(self.speed) + pygame.quit() + + +if __name__ == "__main__": + game = GameOfLife(size=(100, 100), randomize=True) + gui = GUI(life=game, cell_size=10, speed=10) + gui.run() diff --git a/homework03/life_proto.py b/homework03/life_proto.py index c6d6010..afc40fe 100644 --- a/homework03/life_proto.py +++ b/homework03/life_proto.py @@ -11,7 +11,7 @@ class GameOfLife: def __init__( - self, width: int = 640, height: int = 480, cell_size: int = 10, speed: int = 10 + self, width: int = 640, height: int = 480, cell_size: int = 10, speed: int = 10 ) -> None: self.width = width self.height = height @@ -42,21 +42,20 @@ def run(self) -> None: clock = pygame.time.Clock() pygame.display.set_caption("Game of Life") self.screen.fill(pygame.Color("white")) - # Создание списка клеток - # PUT YOUR CODE HERE - + # Добавил поле + self.grid = self.create_grid(randomize=True) + self.draw_grid(self.grid) running = True while running: for event in pygame.event.get(): if event.type == QUIT: running = False self.draw_lines() - # Отрисовка списка клеток # Выполнение одного шага игры (обновление состояния ячеек) - # PUT YOUR CODE HERE - + self.grid = self.get_next_generation() + self.draw_grid(self.grid) pygame.display.flip() clock.tick(self.speed) pygame.quit() @@ -79,14 +78,39 @@ def create_grid(self, randomize: bool = False) -> Grid: out : Grid Матрица клеток размером `cell_height` х `cell_width`. """ - pass + if randomize: + return [[random.randint(0, 1) for i in range(self.cell_width)] for i in range(self.cell_height)] + else: + return [[0 for i in range(self.cell_width)] for i in range(self.cell_height)] - def draw_grid(self) -> None: + def draw_grid(self, grid: list[list[int]]) -> None: """ Отрисовка списка клеток с закрашиванием их в соответствующе цвета. """ - pass - + for i in range(self.cell_height): + for j in range(self.cell_width): + if grid[i][j] == 1: + pygame.draw.rect( + self.screen, + pygame.Color("green"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + else: + pygame.draw.rect( + self.screen, + pygame.Color("white"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) def get_neighbours(self, cell: Cell) -> Cells: """ Вернуть список соседних клеток для клетки `cell`. @@ -105,7 +129,58 @@ def get_neighbours(self, cell: Cell) -> Cells: out : Cells Список соседних клеток. """ - pass + height, width = cell + cells = [] + if height == 0 and width == 0: + cells.append(self.grid[0][1]) + cells.append(self.grid[1][0]) + cells.append(self.grid[1][1]) + elif height == 0 and width == self.cell_width - 1: + cells.append(self.grid[0][width - 1]) + cells.append(self.grid[1][width]) + cells.append(self.grid[1][width - 1]) + elif height == self.cell_height - 1 and width == 0: + cells.append(self.grid[height - 1][0]) + cells.append(self.grid[height - 1][1]) + cells.append(self.grid[height][1]) + elif height == self.cell_height - 1 and width == self.cell_width - 1: + cells.append(self.grid[height - 1][width - 1]) + cells.append(self.grid[height][width - 1]) + cells.append(self.grid[height - 1][width]) + elif height == 0: + cells.append(self.grid[0][width - 1]) + cells.append(self.grid[0][width + 1]) + cells.append(self.grid[1][width]) + cells.append(self.grid[1][width - 1]) + cells.append(self.grid[1][width + 1]) + elif width == 0: + cells.append(self.grid[height - 1][0]) + cells.append(self.grid[height + 1][0]) + cells.append(self.grid[height][1]) + cells.append(self.grid[height - 1][1]) + cells.append(self.grid[height + 1][1]) + elif height == self.cell_height - 1: + cells.append(self.grid[height][width - 1]) + cells.append(self.grid[height][width + 1]) + cells.append(self.grid[height - 1][width]) + cells.append(self.grid[height - 1][width - 1]) + cells.append(self.grid[height - 1][width + 1]) + elif width == self.cell_width - 1: + cells.append(self.grid[height - 1][width]) + cells.append(self.grid[height + 1][width]) + cells.append(self.grid[height][width - 1]) + cells.append(self.grid[height - 1][width - 1]) + cells.append(self.grid[height + 1][width - 1]) + else: + cells.append(self.grid[height][width - 1]) + cells.append(self.grid[height][width + 1]) + cells.append(self.grid[height - 1][width]) + cells.append(self.grid[height + 1][width]) + cells.append(self.grid[height - 1][width - 1]) + cells.append(self.grid[height - 1][width + 1]) + cells.append(self.grid[height + 1][width + 1]) + cells.append(self.grid[height + 1][width - 1]) + return cells def get_next_generation(self) -> Grid: """ @@ -116,4 +191,18 @@ def get_next_generation(self) -> Grid: out : Grid Новое поколение клеток. """ - pass + next_grid = [[0 for i in range(self.cell_width)] for i in range(self.cell_height)] + for i in range(self.cell_height): + for j in range(self.cell_width): + if self.grid[i][j] == 1 and (sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3): + next_grid[i][j] = 1 + elif self.grid[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: + next_grid[i][j] = 1 + else: + next_grid[i][j] = 0 + return next_grid + + +if __name__ == "__main__": + game = GameOfLife(width=640, height=480, cell_size=10, speed=10) + game.run() From 1f2791f6b6d12bf57d760dfa35abac691bd8f749 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Sat, 11 Mar 2023 19:21:27 +0500 Subject: [PATCH 13/14] homework03 complete --- homework03/life.py | 12 +++++++----- homework03/life_console.py | 4 ++-- homework03/life_proto.py | 16 +++++++++++----- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/homework03/life.py b/homework03/life.py index 9fb83fd..44c6c32 100644 --- a/homework03/life.py +++ b/homework03/life.py @@ -12,10 +12,10 @@ class GameOfLife: def __init__( - self, - size: tp.Tuple[int, int], - randomize: bool = True, - max_generations: tp.Optional[float] = float("inf"), + self, + size: tp.Tuple[int, int], + randomize: bool = True, + max_generations: tp.Optional[float] = float("inf"), ) -> None: # Размер клеточного поля self.rows, self.cols = size @@ -95,7 +95,9 @@ def get_next_generation(self) -> Grid: next_grid = [[0 for i in range(self.cols)] for i in range(self.rows)] for i in range(self.rows): for j in range(self.cols): - if self.curr_generation[i][j] == 1 and (sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3): + if self.curr_generation[i][j] == 1 and ( + sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 + ): next_grid[i][j] = 1 elif self.curr_generation[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: next_grid[i][j] = 1 diff --git a/homework03/life_console.py b/homework03/life_console.py index 5fc3f81..e5a90b8 100644 --- a/homework03/life_console.py +++ b/homework03/life_console.py @@ -9,11 +9,11 @@ def __init__(self, life: GameOfLife) -> None: super().__init__(life) def draw_borders(self, screen) -> None: - """ Отобразить рамку. """ + """Отобразить рамку.""" screen.border("|", "|", "-", "-", "+", "+", "+", "+") def draw_grid(self, screen) -> None: - """ Отобразить состояние клеток. """ + """Отобразить состояние клеток.""" for i in range(self.life.rows): for j in range(self.life.cols): if self.life.curr_generation[i][j] == 0: diff --git a/homework03/life_proto.py b/homework03/life_proto.py index afc40fe..6af8cfb 100644 --- a/homework03/life_proto.py +++ b/homework03/life_proto.py @@ -11,7 +11,7 @@ class GameOfLife: def __init__( - self, width: int = 640, height: int = 480, cell_size: int = 10, speed: int = 10 + self, width: int = 640, height: int = 480, cell_size: int = 10, speed: int = 10 ) -> None: self.width = width self.height = height @@ -30,14 +30,14 @@ def __init__( self.speed = speed def draw_lines(self) -> None: - """ Отрисовать сетку """ + """Отрисовать сетку""" for x in range(0, self.width, self.cell_size): pygame.draw.line(self.screen, pygame.Color("black"), (x, 0), (x, self.height)) for y in range(0, self.height, self.cell_size): pygame.draw.line(self.screen, pygame.Color("black"), (0, y), (self.width, y)) def run(self) -> None: - """ Запустить игру """ + """Запустить игру""" pygame.init() clock = pygame.time.Clock() pygame.display.set_caption("Game of Life") @@ -79,7 +79,10 @@ def create_grid(self, randomize: bool = False) -> Grid: Матрица клеток размером `cell_height` х `cell_width`. """ if randomize: - return [[random.randint(0, 1) for i in range(self.cell_width)] for i in range(self.cell_height)] + return [ + [random.randint(0, 1) for i in range(self.cell_width)] + for i in range(self.cell_height) + ] else: return [[0 for i in range(self.cell_width)] for i in range(self.cell_height)] @@ -111,6 +114,7 @@ def draw_grid(self, grid: list[list[int]]) -> None: self.cell_size - 1, ), ) + def get_neighbours(self, cell: Cell) -> Cells: """ Вернуть список соседних клеток для клетки `cell`. @@ -194,7 +198,9 @@ def get_next_generation(self) -> Grid: next_grid = [[0 for i in range(self.cell_width)] for i in range(self.cell_height)] for i in range(self.cell_height): for j in range(self.cell_width): - if self.grid[i][j] == 1 and (sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3): + if self.grid[i][j] == 1 and ( + sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 + ): next_grid[i][j] = 1 elif self.grid[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: next_grid[i][j] = 1 From b10e67c307b9f56ef0a390a3e4662af12a05c760 Mon Sep 17 00:00:00 2001 From: NinjaTurtleWOW Date: Sat, 11 Mar 2023 19:22:38 +0500 Subject: [PATCH 14/14] homework03 complete --- homework03/life.py | 2 +- homework03/life_proto.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homework03/life.py b/homework03/life.py index 44c6c32..a95dcf8 100644 --- a/homework03/life.py +++ b/homework03/life.py @@ -96,7 +96,7 @@ def get_next_generation(self) -> Grid: for i in range(self.rows): for j in range(self.cols): if self.curr_generation[i][j] == 1 and ( - sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 + sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 ): next_grid[i][j] = 1 elif self.curr_generation[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: diff --git a/homework03/life_proto.py b/homework03/life_proto.py index 6af8cfb..a816204 100644 --- a/homework03/life_proto.py +++ b/homework03/life_proto.py @@ -199,7 +199,7 @@ def get_next_generation(self) -> Grid: for i in range(self.cell_height): for j in range(self.cell_width): if self.grid[i][j] == 1 and ( - sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 + sum(self.get_neighbours((i, j))) == 2 or sum(self.get_neighbours((i, j))) == 3 ): next_grid[i][j] = 1 elif self.grid[i][j] == 0 and sum(self.get_neighbours((i, j))) == 3: