diff --git a/.github/workflows/cs102.yml b/.github/workflows/cs102.yml
index 4509ac4..8e1e8be 100644
--- a/.github/workflows/cs102.yml
+++ b/.github/workflows/cs102.yml
@@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- - name: Set up Python 3.8.6
+ - name: Set up Python 3.10.7
uses: actions/setup-python@v2
with:
- python-version: '3.8.6'
+ python-version: '3.10.7'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..b15c5a4
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+sudoku.py
\ No newline at end of file
diff --git a/.idea/Chzh.iml b/.idea/Chzh.iml
new file mode 100644
index 0000000..8e5446a
--- /dev/null
+++ b/.idea/Chzh.iml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..cc2518d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..adbc062
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1673962365428
+
+
+ 1673962365428
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/main.py
+ 8
+
+
+
+
+
+
\ No newline at end of file
diff --git a/homework02/sudoku.py b/homework02/sudoku.py
index df78ab1..87139b0 100644
--- a/homework02/sudoku.py
+++ b/homework02/sudoku.py
@@ -1,11 +1,12 @@
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()
@@ -19,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):
@@ -42,7 +43,16 @@ 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
+ t: tp.List[T] = []
+ res = []
+ length = len(values)
+ for i in range(length):
+ if i % n == 0 and i != 0:
+ res.append(t)
+ t = []
+ t.append(values[i])
+ res.append(t)
+ return res
def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
@@ -55,7 +65,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 +78,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
+ res = []
+ for arr in grid:
+ res.append(arr[pos[1]])
+ return res
def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
@@ -82,10 +95,16 @@ 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
+ res = []
+ r = pos[0] // 3 * 3
+ c = pos[1] // 3 * 3
+ for i in range(r, r + 3):
+ for j in range(c, c + 3):
+ res.append(grid[i][j])
+ return res
-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]]) -> tp.Tuple[int, int]:
"""Найти первую свободную позицию в пазле
>>> find_empty_positions([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']])
@@ -95,7 +114,13 @@ 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
+ if grid != 0:
+ for i in range(len(grid)):
+ for j in range(len(grid[i])):
+ if not grid[i][j].isdigit():
+ r, c = i, j
+ return r, c
+ return -1, -1
def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]:
@@ -109,11 +134,20 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -
>>> values == {'2', '5', '9'}
True
"""
- pass
+ res = []
+ for arr in range(1, 10):
+ s = str(arr)
+ if (
+ s not in get_block(grid, pos)
+ and s not in get_col(grid, pos)
+ and s not in get_row(grid, pos)
+ ):
+ res.append(s)
+ return set(res)
def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]:
- """ Решение пазла, заданного в grid """
+ """Решение пазла, заданного в grid"""
""" Как решать Судоку?
1. Найти свободную позицию
2. Найти все возможные значения, которые могут находиться на этой позиции
@@ -125,13 +159,36 @@ 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
+ empty = find_empty_positions(grid) # type: tp.Tuple[int, int]
+ if empty[0] < 0:
+ return grid
+ possible = find_possible_values(grid, empty) # type: tp.Set[str]
+ if not possible:
+ return None
+ for i in possible:
+ grid[empty[0]][empty[1]] = i
+ if solve(grid):
+ return grid
+ grid[empty[0]][empty[1]] = "."
+ return None
def check_solution(solution: tp.List[tp.List[str]]) -> bool:
- """ Если решение solution верно, то вернуть True, в противном случае False """
+ """Если решение solution верно, то вернуть True, в противном случае False"""
# TODO: Add doctests with bad puzzles
- pass
+ g = solution
+ for i in range(9):
+ if len(get_row(g, (i, 0))) != len(set(get_row(g, (i, 0)))) or len(
+ get_col(g, (0, i))
+ ) != len(set(get_col(g, (0, i)))):
+ return False
+ if i == 0 or i == 3 or i == 6:
+ for j in range(0, 9, 3):
+ if len(get_block(g, (i, j))) != len(set(get_block(g, (i, j)))):
+ return False
+ if "." in g[i]:
+ return False
+ return True
def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
@@ -156,7 +213,15 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
>>> check_solution(solution)
True
"""
- pass
+ grid = [["."] * 9 for _ in range(9)]
+ solve(grid)
+ count, N = 0, min(81, N)
+ while count < 81 - N:
+ i, j = random.randint(0, 8), random.randint(0, 8)
+ if grid[i][j] != ".":
+ grid[i][j] = "."
+ count += 1
+ return grid
if __name__ == "__main__":
diff --git a/homework03/life.py b/homework03/life.py
index 7aef0b6..0ef18e3 100644
--- a/homework03/life.py
+++ b/homework03/life.py
@@ -2,9 +2,6 @@
import random
import typing as tp
-import pygame
-from pygame.locals import *
-
Cell = tp.Tuple[int, int]
Cells = tp.List[int]
Grid = tp.List[Cells]
@@ -15,7 +12,7 @@ def __init__(
self,
size: tp.Tuple[int, int],
randomize: bool = True,
- max_generations: tp.Optional[float] = float("inf"),
+ max_generations: float = float("inf"),
) -> None:
# Размер клеточного поля
self.rows, self.cols = size
@@ -29,46 +26,80 @@ def __init__(
self.generations = 1
def create_grid(self, randomize: bool = False) -> Grid:
- # Copy from previous assignment
- pass
+ if randomize:
+ grid = [[random.randint(0, 1) for _ in range(self.cols)] for _ in range(self.rows)]
+ else:
+ grid = [[0 for _ in range(self.cols)] for _ in range(self.rows)]
+
+ return grid
def get_neighbours(self, cell: Cell) -> Cells:
- # Copy from previous assignment
- pass
+ neighbours = []
+ y_borders = [max(0, cell[0] - 1), min(self.rows, cell[0] + 2)]
+ x_borders = [max(0, cell[1] - 1), min(self.cols, cell[1] + 2)]
+ for i in range(*y_borders):
+ neighbours += self.curr_generation[i][x_borders[0] : x_borders[1]]
+ neighbours.remove(self.curr_generation[cell[0]][cell[1]])
+ return neighbours
def get_next_generation(self) -> Grid:
- # Copy from previous assignment
- pass
+ new_generation = self.create_grid(randomize=False)
+ for i in range(self.rows):
+ for j in range(self.cols):
+ n_neighbours = sum(self.get_neighbours((i, j)))
+ if self.curr_generation[i][j] and 2 <= n_neighbours <= 3:
+ new_generation[i][j] = 1
+ elif not self.curr_generation[i][j] and n_neighbours == 3:
+ new_generation[i][j] = 1
+
+ return new_generation
def step(self) -> None:
"""
Выполнить один шаг игры.
"""
- pass
+ self.generations += 1
+ self.prev_generation = self.curr_generation
+ self.curr_generation = self.get_next_generation()
@property
def is_max_generations_exceeded(self) -> bool:
"""
Не превысило ли текущее число поколений максимально допустимое.
"""
- pass
+ return self.generations >= self.max_generations
@property
def is_changing(self) -> bool:
"""
Изменилось ли состояние клеток с предыдущего шага.
"""
- pass
+ return self.prev_generation != self.curr_generation or self.generations == 1
@staticmethod
def from_file(filename: pathlib.Path) -> "GameOfLife":
"""
Прочитать состояние клеток из указанного файла.
"""
- pass
+ try:
+ with filename.open() as f:
+ grid = list(map(lambda x: list(map(int, list(x))), f.read().split()))
+ loaded_game = GameOfLife((len(grid), len(grid[0])), randomize=False)
+ loaded_game.curr_generation = grid
+
+ except (ValueError, IndexError):
+ print("Something wrong with file")
+ return GameOfLife((13, 13))
+ except Exception as error:
+ print(error)
+ return GameOfLife((13, 13))
+ else:
+ return loaded_game
def save(self, filename: pathlib.Path) -> None:
"""
Сохранить текущее состояние клеток в указанный файл.
"""
- pass
+ with filename.open("w") as f:
+ for cells in self.curr_generation:
+ f.write("".join(map(str, cells)) + "\n")
diff --git a/homework03/life_console.py b/homework03/life_console.py
index ddeb9ef..79ab954 100644
--- a/homework03/life_console.py
+++ b/homework03/life_console.py
@@ -1,22 +1,71 @@
import curses
+import pygame
from life import GameOfLife
from ui import UI
class Console(UI):
- def __init__(self, life: GameOfLife) -> None:
+ def __init__(self, life: GameOfLife, speed=10) -> None:
super().__init__(life)
+ self.speed = speed
def draw_borders(self, screen) -> None:
- """ Отобразить рамку. """
- pass
+ """Отобразить рамку."""
+ screen.addstr(f"+{'-' * self.life.cols}+\n")
+ for i in range(self.life.rows):
+ screen.addstr("|")
+ screen.addstr(i + 1, self.life.cols + 1, "|\n")
+ screen.addstr(f"+{'-' * self.life.cols}+\n")
def draw_grid(self, screen) -> None:
- """ Отобразить состояние клеток. """
- pass
+ """Отобразить состояние клеток."""
+ for row in range(self.life.rows):
+ for col in range(self.life.cols):
+ if self.life.curr_generation[row][col]:
+ screen.move(row + 1, col + 1)
+ screen.addstr("*")
def run(self) -> None:
+ clock = pygame.time.Clock()
+
screen = curses.initscr()
- # PUT YOUR CODE HERE
- curses.endwin()
+ curses.noecho()
+ curses.cbreak()
+ screen.nodelay(True)
+ curses.curs_set(False)
+ try:
+ running = True
+ pause = False
+ while running:
+ key = screen.getch()
+ while key != -1:
+ if key == 113:
+ running = False
+ elif key == 32:
+ pause = not pause
+ key = screen.getch()
+ screen.clear()
+ self.draw_borders(screen)
+ self.draw_grid(screen)
+ if not pause:
+ self.life.step()
+ screen.refresh()
+ clock.tick(self.speed)
+
+ if not self.life.is_changing or self.life.is_max_generations_exceeded:
+ running = False
+ curses.echo()
+ curses.nocbreak()
+ curses.endwin()
+
+ except Exception as err:
+ print(f"{err}\n{type(err)}")
+ curses.echo()
+ curses.nocbreak()
+ curses.endwin()
+
+
+if __name__ == "__main__":
+ life = Console(GameOfLife((32, 32)))
+ life.run()
diff --git a/homework03/life_gui.py b/homework03/life_gui.py
index 1126b29..c7d054d 100644
--- a/homework03/life_gui.py
+++ b/homework03/life_gui.py
@@ -7,15 +7,72 @@
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 = self.cell_size * self.life.cols
+ self.height = self.cell_size * self.life.rows
+
+ # Создание нового окна
+ self.screen = pygame.display.set_mode((self.width, self.height))
+
+ # Вычисляем количество ячеек по вертикали и горизонтали
+ 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
+ """
+ Отрисовка списка клеток с закрашиванием их в соответствующе цвета.
+ """
+ color = (0, 255, 0)
+ for i in range(self.life.rows):
+ for j in range(self.life.cols):
+ if self.life.curr_generation[i][j]:
+ pygame.draw.rect(
+ self.screen,
+ color,
+ pygame.Rect(
+ self.cell_size * j,
+ self.cell_size * i,
+ self.cell_size,
+ self.cell_size,
+ ),
+ )
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
+ while running:
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ running = False
+ self.screen.fill(pygame.Color("white"))
+
+ self.draw_grid()
+ self.draw_lines()
+ self.life.step()
+
+ pygame.display.flip()
+ clock.tick(self.speed)
+
+ if not self.life.is_changing or self.life.is_max_generations_exceeded:
+ running = False
+ pygame.quit()
+
+
+if __name__ == "__main__":
+ life = GUI(GameOfLife((32, 32)))
+ life.run()
diff --git a/homework03/life_proto.py b/homework03/life_proto.py
index c6d6010..7ad76d8 100644
--- a/homework03/life_proto.py
+++ b/homework03/life_proto.py
@@ -30,32 +30,32 @@ 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")
self.screen.fill(pygame.Color("white"))
# Создание списка клеток
- # PUT YOUR CODE HERE
+ self.grid = self.create_grid(randomize=True)
running = True
while running:
for event in pygame.event.get():
- if event.type == QUIT:
+ if event.type == pygame.QUIT:
running = False
- self.draw_lines()
+ self.screen.fill(pygame.Color("white"))
- # Отрисовка списка клеток
- # Выполнение одного шага игры (обновление состояния ячеек)
- # PUT YOUR CODE HERE
+ self.draw_grid()
+ self.draw_lines()
+ self.grid = self.get_next_generation()
pygame.display.flip()
clock.tick(self.speed)
@@ -79,13 +79,34 @@ def create_grid(self, randomize: bool = False) -> Grid:
out : Grid
Матрица клеток размером `cell_height` х `cell_width`.
"""
- pass
+ if randomize:
+ grid = [
+ [random.randint(0, 1) for _ in range(self.cell_width)]
+ for _ in range(self.cell_height)
+ ]
+ else:
+ grid = [[0 for _ in range(self.cell_width)] for _ in range(self.cell_height)]
+
+ return grid
def draw_grid(self) -> None:
"""
Отрисовка списка клеток с закрашиванием их в соответствующе цвета.
"""
- pass
+ color = (0, 255, 0)
+ for i in range(self.cell_height):
+ for j in range(self.cell_width):
+ if self.grid[i][j]:
+ pygame.draw.rect(
+ self.screen,
+ color,
+ pygame.Rect(
+ self.cell_size * j,
+ self.cell_size * i,
+ self.cell_size,
+ self.cell_size,
+ ),
+ )
def get_neighbours(self, cell: Cell) -> Cells:
"""
@@ -105,7 +126,13 @@ def get_neighbours(self, cell: Cell) -> Cells:
out : Cells
Список соседних клеток.
"""
- pass
+ neighbours = []
+ y_borders = [max(0, cell[0] - 1), min(self.cell_height, cell[0] + 2)]
+ x_borders = [max(0, cell[1] - 1), min(self.cell_width, cell[1] + 2)]
+ for i in range(*y_borders):
+ neighbours += self.grid[i][x_borders[0] : x_borders[1]]
+ neighbours.remove(self.grid[cell[0]][cell[1]])
+ return neighbours
def get_next_generation(self) -> Grid:
"""
@@ -116,4 +143,18 @@ def get_next_generation(self) -> Grid:
out : Grid
Новое поколение клеток.
"""
- pass
+ new_generation = self.create_grid(randomize=False)
+ for i in range(self.cell_height):
+ for j in range(self.cell_width):
+ n_neighbours = sum(self.get_neighbours((i, j)))
+ if self.grid[i][j] and 2 <= n_neighbours <= 3:
+ new_generation[i][j] = 1
+ elif not self.grid[i][j] and n_neighbours == 3:
+ new_generation[i][j] = 1
+
+ return new_generation
+
+
+if __name__ == "__main__":
+ life = GameOfLife()
+ life.run()
diff --git a/homework03/test.py b/homework03/test.py
new file mode 100644
index 0000000..e69de29
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..5596b44
--- /dev/null
+++ b/main.py
@@ -0,0 +1,16 @@
+# This is a sample Python script.
+
+# Press Shift+F10 to execute it or replace it with your code.
+# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
+
+
+def print_hi(name):
+ # Use a breakpoint in the code line below to debug your script.
+ print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint.
+
+
+# Press the green button in the gutter to run the script.
+if __name__ == '__main__':
+ print_hi('PyCharm')
+
+# See PyCharm help at https://www.jetbrains.com/help/pycharm/