Skip to content

Commit

Permalink
d
Browse files Browse the repository at this point in the history
  • Loading branch information
lezyonish committed Jan 21, 2025
1 parent 426412d commit 33255d0
Show file tree
Hide file tree
Showing 10 changed files with 493 additions and 100 deletions.
65 changes: 34 additions & 31 deletions homework01/caesar.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
def encrypt_caesar(plaintext: str, shift: int = 3) -> str:
"""
Encrypts plaintext using a Caesar cipher.
>>> encrypt_caesar("PYTHON")
'SBWKRQ'
"SBWKRQ"
>>> encrypt_caesar("python")
'sbwkrq'
"sbwkrq"
>>> encrypt_caesar("Python3.6")
'Sbwkrq3.6'
"Sbwkrq3.6"
>>> encrypt_caesar("")
''
""
"""
ciphertext = ""
for S in plaintext:
if "A" <= S <= "Z":
new_s = chr((ord(S) - ord("A") + shift) % 26 + ord("A"))
ciphertext += new_s
elif "a" <= S <= "z":
new_s = chr((ord(S) - ord("a") + shift) % 26 + ord("a"))
ciphertext += new_s
for char in plaintext:
if char.isalpha():
if char.islower():
if ord(char) < ord("z") - shift + 1:
ciphertext += chr(ord(char) + shift)
else:
ciphertext += chr(ord(char) + shift - 26)
else:
if ord(char) < ord("Z") - shift + 1:
ciphertext += chr(ord(char) + shift)
else:
ciphertext += chr(ord(char) + shift - 26)
else:
ciphertext += S
ciphertext += char
return ciphertext


Expand All @@ -29,28 +33,27 @@ def decrypt_caesar(ciphertext: str, shift: int = 3) -> str:
Decrypts a ciphertext using a Caesar cipher.
>>> decrypt_caesar("SBWKRQ")
'PYTHON'
"PYTHON"
>>> decrypt_caesar("sbwkrq")
'python'
"python"
>>> decrypt_caesar("Sbwkrq3.6")
'Python3.6'
"Python3.6"
>>> decrypt_caesar("")
''
""
"""
plaintext = ""
for S in ciphertext:
if "A" <= S <= "Z":
new_s = chr((ord(S) - ord("A") - shift) % 26 + ord("A"))
plaintext += new_s
elif "a" <= S <= "z":
new_s = chr((ord(S) - ord("a") - shift) % 26 + ord("a"))
plaintext += new_s
for char in ciphertext:
if char.isalpha():
if char.islower():
if ord(char) > ord("a") + shift - 1:
plaintext += chr(ord(char) - shift)
else:
plaintext += chr(ord(char) - shift + 26)
else:
if ord(char) > ord("A") + shift - 1:
plaintext += chr(ord(char) - shift)
else:
plaintext += chr(ord(char) - shift + 26)
else:
plaintext += S
plaintext += char
return plaintext


if __name__ == "__main__":
print(encrypt_caesar(input()))
print(decrypt_caesar(input()))

1 change: 0 additions & 1 deletion homework01/rsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,3 @@ def decrypt(pk: tp.Tuple[int, int], ciphertext: tp.List[int]) -> str:
print("Decrypting message with public key ", public, " . . .")
print("Your message is:")
print(decrypt(public, encrypted_msg))

1 change: 0 additions & 1 deletion homework01/vigenere.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,3 @@ def decrypt_vigenere(ciphertext: str, keyword: str) -> str:
else:
plaintext += ciphertext[i]
return plaintext

101 changes: 96 additions & 5 deletions homework02/sudoku.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pathlib
import random
import typing as tp

T = tp.TypeVar("T")
Expand Down Expand Up @@ -32,40 +33,55 @@ def display(grid: tp.List[tp.List[str]]) -> None:
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]]
>>> group([1,2,3,4,5,6,7,8,9], 3)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
"""
mas = []
for i in range(len(values) // n):
mas.append(values[i * n : i * n + n])

return mas
pass


def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
"""Возвращает все значения для номера строки, указанной в pos
>>> get_row([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']], (0, 0))
['1', '2', '.']
>>> get_row([['1', '2', '3'], ['4', '.', '6'], ['7', '8', '9']], (1, 0))
['4', '.', '6']
>>> get_row([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (2, 0))
['.', '8', '9']
"""
return grid[pos[0]]
pass


def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
"""Возвращает все значения для номера столбца, указанного в pos
>>> get_col([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']], (0, 0))
['1', '4', '7']
>>> get_col([['1', '2', '3'], ['4', '.', '6'], ['7', '8', '9']], (0, 1))
['2', '.', '8']
>>> get_col([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (0, 2))
['3', '6', '9']
"""
mas = []

for i in range(len(grid)):
mas.append(grid[i][pos[1]])
return mas
pass


def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]:
"""Возвращает все значения из квадрата, в который попадает позиция pos
>>> grid = read_sudoku('puzzle1.txt')
>>> get_block(grid, (0, 1))
['5', '3', '.', '6', '.', '.', '.', '9', '8']
Expand All @@ -74,23 +90,42 @@ 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']
"""
a = pos[0] // 3 * 3
b = pos[1] // 3 * 3
mas = []
mas.append(grid[a][b])
mas.append(grid[a][b + 1])
mas.append(grid[a][b + 2])
mas.append(grid[a + 1][b])
mas.append(grid[a + 1][b + 1])
mas.append(grid[a + 1][b + 2])
mas.append(grid[a + 2][b])
mas.append(grid[a + 2][b + 1])
mas.append(grid[a + 2][b + 2])
return mas
pass


def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[int, int]]:
"""Найти первую свободную позицию в пазле
>>> find_empty_positions([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']])
(0, 2)
>>> find_empty_positions([['1', '2', '3'], ['4', '.', '6'], ['7', '8', '9']])
(1, 1)
>>> find_empty_positions([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']])
(2, 0)
"""
pass
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] == ".":
return i, j
return None


def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]:
"""Вернуть множество возможных значения для указанной позиции
>>> grid = read_sudoku('puzzle1.txt')
>>> values = find_possible_values(grid, (0,2))
>>> values == {'1', '2', '4'}
Expand All @@ -99,7 +134,15 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -
>>> values == {'2', '5', '9'}
True
"""
pass
all = {"1", "2", "3", "4", "5", "6", "7", "8", "9"}

var1 = get_block(grid, pos)
var2 = get_col(grid, pos)
var3 = get_row(grid, pos)
all = all.difference(var1)
all = all.difference(var2)
all = all.difference(var3)
return all


def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]:
Expand All @@ -110,21 +153,54 @@ def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]:
3. Для каждого возможного значения:
3.1. Поместить это значение на эту позицию
3.2. Продолжить решать оставшуюся часть пазла
>>> 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

def sudokusolver(grid: tp.List[tp.List[str]]) -> bool:
p = find_empty_positions(grid)
if p is None:
return True
possible_values = find_possible_values(grid, p)
for value in possible_values:
grid[p[0]][p[1]] = value
if sudokusolver(grid): # Recursively solve the rest of the puzzle
return True
grid[p[0]][p[1]] = "." # Backtrack
return False

if sudokusolver(grid): # If solving is successful, return the grid
return grid
return None


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

for j in range(len(solution)):
if solution[i][j] == ".":
return False
pos = (i, j)
l1 = list(get_row(solution, pos))
l2 = list(get_col(solution, pos))
l3 = list(get_block(solution, pos))
s1 = set(l1)
s2 = set(l2)
s3 = set(l3)
if len(s1) != len(l1) or len(s2) != len(l2) or len(s3) != len(l3):
return False
return True


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 == '.')
41
Expand All @@ -144,7 +220,22 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]:
>>> check_solution(solution)
True
"""
pass

mas: tp.List[tp.List[str]] = [["."] * 9 for _ in range(9)]
solved_grid = solve(mas)
if solved_grid is None:
raise ValueError("Sudoku puzzle could not be solved")
mas = solved_grid
if N < 81:
k = 81 - N
else:
k = 0
for _ in range(k):
t, p = random.randint(0, 8), random.randint(0, 8)
while mas[t][p] == ".":
t, p = random.randint(0, 8), random.randint(0, 8)
mas[t][p] = "."
return mas


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit 33255d0

Please sign in to comment.