feat: add my hmwk grind from today
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 17 KiB |
|
@ -1,17 +0,0 @@
|
|||
from typing import Dict
|
||||
import re
|
||||
|
||||
def letterFrequency(text: str) -> Dict[str, int]:
|
||||
output = {}
|
||||
text = re.sub('[^a-zA-Z]+', '', text)
|
||||
|
||||
for letter in text:
|
||||
if letter in output:
|
||||
output[letter] += 1
|
||||
else:
|
||||
output[letter] = 1
|
||||
|
||||
return output
|
||||
|
||||
frequency = letterFrequency('I wish I wish with all my heart to fly with dragons in a land apart')
|
||||
print(frequency)
|
|
@ -1,92 +0,0 @@
|
|||
from time import sleep
|
||||
|
||||
# :eyes:
|
||||
def clearTerminal():
|
||||
print('\n' * 25)
|
||||
|
||||
def findPrimes(upperBound: int):
|
||||
"""
|
||||
Implementation of the Sieve of Eratosthenes.
|
||||
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
|
||||
"""
|
||||
mask = [True for _ in range(upperBound)]
|
||||
primes = []
|
||||
|
||||
mask[0] = False
|
||||
mask[1] = False
|
||||
|
||||
for i in range(2, upperBound):
|
||||
if mask[i]:
|
||||
primes.append(i)
|
||||
|
||||
j = 2 * i
|
||||
|
||||
while j < upperBound:
|
||||
mask[j] = False
|
||||
j += i
|
||||
|
||||
return primes
|
||||
|
||||
POSSIBLE_PRIMES = findPrimes(1_000_000) # Would be better to hardcode this list as it is constant, however I want good marks and to show complex algorithms I guess!!!
|
||||
inputtedPrimes = []
|
||||
|
||||
def getPrime(primeList):
|
||||
while True:
|
||||
try:
|
||||
value = int(input("Please enter a prime number to add to the list: "))
|
||||
|
||||
# Ensure that the value fits the requirements set out by the brief
|
||||
if value > 999_999 or value < 0:
|
||||
raise ValueError('Please ensure you enter an integer at most 6 digits long!')
|
||||
elif value not in POSSIBLE_PRIMES:
|
||||
raise ValueError('That is not a prime number! Please try again.')
|
||||
elif value in primeList:
|
||||
raise ValueError('You have already inputted that prime number! Please enter a different one.')
|
||||
|
||||
# Mutate the prime list and return it back to the caller
|
||||
primeList.append(value)
|
||||
return primeList
|
||||
except ValueError as e:
|
||||
# Check to see if the error was raised by Python or manually, and print messages accordingly
|
||||
if e.args[0].startswith("invalid literal"):
|
||||
print('Please enter a valid integer!')
|
||||
else:
|
||||
print(e)
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
print("""Welcome to the prime checker!
|
||||
What would you like to do?
|
||||
|
||||
1) Add a number to the list
|
||||
2) View the list of inputted primes
|
||||
3) Exit
|
||||
""")
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice = int(input("Please enter your choice: "))
|
||||
|
||||
if choice not in [1, 2, 3]:
|
||||
raise ValueError
|
||||
|
||||
break
|
||||
except ValueError:
|
||||
print("Please enter a valid option from the list (1-3)")
|
||||
|
||||
clearTerminal()
|
||||
|
||||
if choice == 1:
|
||||
inputtedPrimes = getPrime(inputtedPrimes)
|
||||
elif choice == 2:
|
||||
# Only print the list if there is values inside to print
|
||||
if len(inputtedPrimes) > 0:
|
||||
print(', '.join(map(lambda x: str(x), inputtedPrimes)))
|
||||
else:
|
||||
print('There is currently nothing in the list!')
|
||||
|
||||
sleep(2.5)
|
||||
elif choice == 3:
|
||||
exit()
|
||||
|
||||
clearTerminal()
|
|
@ -1,18 +0,0 @@
|
|||
import unittest
|
||||
import sys
|
||||
|
||||
from primeList import findPrimes
|
||||
|
||||
# My code can not be unit tested much with how I have structured it but here's proof I know how to do it I guess :D
|
||||
|
||||
class SieveTest(unittest.TestCase):
|
||||
def test_sieve(self):
|
||||
"""
|
||||
Test that the sieve correctly generates a list of primes up until 100.
|
||||
"""
|
||||
primes = findPrimes(100)
|
||||
self.assertEqual(primes, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97])
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.argv.append('-v')
|
||||
unittest.main()
|
|
@ -1,190 +0,0 @@
|
|||
from __future__ import annotations
|
||||
from random import uniform
|
||||
from typing import List, Iterable, Callable, Union
|
||||
from functools import reduce
|
||||
from operator import iconcat
|
||||
|
||||
class OperationError(Exception):
|
||||
pass
|
||||
|
||||
class MatrixRow:
|
||||
def __init__(self, length: int):
|
||||
self.__values: List[float] = [0 for _ in range(length)]
|
||||
self.__length = length
|
||||
|
||||
def __getitem__(self, column: int):
|
||||
"""Index the row."""
|
||||
if column <= 0 or column > self.__length:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
return self.__values[column - 1]
|
||||
|
||||
def __setitem__(self, column: int, newValue: float):
|
||||
"""Update a value in the row at a given column."""
|
||||
if column <= 0 or column > self.__length:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
self.__values[column - 1] = newValue
|
||||
|
||||
def __iter__(self) -> Iterable:
|
||||
processedValues = []
|
||||
|
||||
for value in self.__values:
|
||||
if type(value) == float and value.is_integer():
|
||||
processedValues.append(int(value))
|
||||
else:
|
||||
processedValues.append(value)
|
||||
|
||||
return iter(processedValues)
|
||||
|
||||
|
||||
class SquareMatrix:
|
||||
def __init__(self, n: int):
|
||||
self.__rows: List[MatrixRow] = [MatrixRow(n) for _ in range(n)]
|
||||
self.__n = n
|
||||
self.__rowFormatting = "{:^10}| " * n
|
||||
self.__divider = "-" * (n * 12)
|
||||
|
||||
@staticmethod
|
||||
def From(rows: List[List[float]]) -> SquareMatrix:
|
||||
n = len(rows)
|
||||
|
||||
if len(set([len(row) for row in rows])) != 1 or len(rows[0]) != n:
|
||||
raise ValueError("Rows do not form a valid square matrix.")
|
||||
|
||||
matrix = SquareMatrix(n)
|
||||
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
matrix[i + 1][j + 1] = rows[i][j]
|
||||
|
||||
return matrix
|
||||
|
||||
def size(self) -> int:
|
||||
"""Returns the size of the square matrix."""
|
||||
return self.__n
|
||||
|
||||
def populate(self, minimum: float, maximum: float) -> SquareMatrix:
|
||||
"""Populates the matrix with random values."""
|
||||
if minimum > maximum:
|
||||
raise ValueError('Minimum value must be less than maximum value!')
|
||||
|
||||
for i in range(1, self.__n + 1):
|
||||
for j in range(1, self.__n + 1):
|
||||
self[i][j] = uniform(minimum, maximum)
|
||||
|
||||
return self
|
||||
|
||||
def sumCorners(self) -> float:
|
||||
"""Computes the sum of the corners of the matrix."""
|
||||
return self[1][1] + self[1][self.__n] + self[self.__n][1] + self[self.__n][self.__n]
|
||||
|
||||
def values(self) -> float:
|
||||
"""Return a list of all of the values in a matrix."""
|
||||
return reduce(iconcat, self.__rows, [])
|
||||
|
||||
def averageValue(self) -> float:
|
||||
"""Computes the avaerage value in the matrix."""
|
||||
return sum(self.values()) / (self.__n ** 2)
|
||||
|
||||
def diagonalSum(self, left: bool = True) -> float:
|
||||
"""Computes a diagonal sum of the matrix."""
|
||||
sum = 0
|
||||
|
||||
for i, row in enumerate(self.__rows):
|
||||
if left:
|
||||
sum += row[i + 1]
|
||||
else:
|
||||
sum += row[self.__n - i]
|
||||
|
||||
return sum
|
||||
|
||||
def diagonalDifference(self) -> float:
|
||||
"""Computes the diagonal difference of the matrix."""
|
||||
left = self.diagonalSum()
|
||||
right = self.diagonalSum(False)
|
||||
|
||||
return abs(right - left)
|
||||
|
||||
def transpose(self) -> SquareMatrix:
|
||||
"""Transpose the matrix."""
|
||||
transposed = list(zip(*self.__rows))
|
||||
|
||||
for i in range(self.__n):
|
||||
for j in range(self.__n):
|
||||
self[i + 1][j + 1] = transposed[i][j]
|
||||
|
||||
return self
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Represents the matrix in a string."""
|
||||
out = self.__divider
|
||||
|
||||
for row in self.__rows:
|
||||
out += f"\n|{self.__rowFormatting.format(*row)}\n{self.__divider}"
|
||||
|
||||
return out
|
||||
|
||||
def __getitem__(self, row: int):
|
||||
"""Allows indexing of the matrix"""
|
||||
if row - 1 > self.__n:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
return self.__rows[row - 1]
|
||||
|
||||
def __applyToMatrices(self, matrix: SquareMatrix, method: Callable[[float, float], float]) -> SquareMatrix:
|
||||
"""Returns a new matrix containing the results of a method applied to the corresponding values of this matrix, and another one."""
|
||||
if matrix.size() != self.__n:
|
||||
raise OperationError("Matrix sizes are incompatible")
|
||||
|
||||
newMatrix = SquareMatrix(self.__n)
|
||||
|
||||
for i in range(1, self.__n + 1):
|
||||
for j in range(1, self.__n + 1):
|
||||
newMatrix[i][j] = method(self[i][j], matrix[i][j])
|
||||
|
||||
return newMatrix
|
||||
|
||||
def __applyToSelf(self, method: Callable[[float], float]) -> SquareMatrix:
|
||||
"""Returns a new matrix containing the results of a method applies to the value of this matrix."""
|
||||
newMatrix = SquareMatrix(self.__n)
|
||||
|
||||
for i in range(1, self.__n + 1):
|
||||
for j in range(1, self.__n + 1):
|
||||
newMatrix[i][j] = method(self[i][j])
|
||||
|
||||
return newMatrix
|
||||
|
||||
def __add__(self, value: Union[SquareMatrix, float]) -> SquareMatrix:
|
||||
"""Add two matrices."""
|
||||
if isinstance(value, SquareMatrix):
|
||||
return self.__applyToMatrices(value, lambda x, y: x + y)
|
||||
else:
|
||||
return self.__applyToSelf(lambda x: x + value)
|
||||
|
||||
def __sub__(self, value: Union[SquareMatrix, float]) -> SquareMatrix:
|
||||
"""Subtract two matrices."""
|
||||
if isinstance(value, SquareMatrix):
|
||||
return self.__applyToMatrices(value, lambda x, y: x - y)
|
||||
else:
|
||||
return self.__applyToSelf(lambda x: x - value)
|
||||
|
||||
def __mul__(self, scalar: float) -> SquareMatrix:
|
||||
"""Multiply the matrix by a scalar."""
|
||||
return self.__applyToSelf(lambda x: x * scalar)
|
||||
|
||||
def __floordiv__(self, scalar: float) -> SquareMatrix:
|
||||
"""Floor divide the matrix by a scalar."""
|
||||
return self.__applyToSelf(lambda x: x // scalar)
|
||||
|
||||
def __mod__(self, scalar: float) -> SquareMatrix:
|
||||
"""Modulo the matrix by a scalar."""
|
||||
return self.__applyToSelf(lambda x: x % scalar)
|
||||
|
||||
def __pow__(self, scalar: float) -> SquareMatrix:
|
||||
"""Power the matrix by a scalar."""
|
||||
return self.__applyToSelf(lambda x: x ** scalar)
|
||||
|
||||
a = SquareMatrix.From([[12.4,3,15],[4,7,8],[5,6,2]])
|
||||
|
||||
print(a)
|
|
@ -1,79 +0,0 @@
|
|||
from typing import List, Callable
|
||||
from random import randint
|
||||
from functools import reduce
|
||||
from operator import iconcat
|
||||
|
||||
def getInteger(prompt: str, err: str, validation: Callable[[int], bool] = None) -> int:
|
||||
"""Fetch an integer from the user and validate it if necessary."""
|
||||
while True:
|
||||
try:
|
||||
value = int(input(prompt))
|
||||
|
||||
if validation and validation(value):
|
||||
raise ValueError
|
||||
|
||||
return value
|
||||
except ValueError:
|
||||
print(err)
|
||||
|
||||
def generateMatrix(n: int, min: int, max: int) -> List[List[int]]:
|
||||
"""Generates an nxn square matrix and populates it with random integer values between two bounds."""
|
||||
if min > max:
|
||||
raise ValueError('Minimum value must be less than maximum value!')
|
||||
|
||||
return [[randint(min, max) for _ in range(n)] for _ in range(n)]
|
||||
|
||||
def printMatrix(matrix: List[List[int]]):
|
||||
n = len(matrix)
|
||||
rowFormatting = "{:^7}| " * n
|
||||
divider = '-' * (n * 9 - 1)
|
||||
|
||||
print(divider)
|
||||
|
||||
for row in matrix:
|
||||
print(rowFormatting.format(*row))
|
||||
print(divider)
|
||||
|
||||
def diagonalSum(matrix: List[List[int]], left: bool = True) -> int:
|
||||
"""Computes the diagonal sum of an nxn square matrix."""
|
||||
sum = 0
|
||||
n = len(matrix)
|
||||
|
||||
for i, row in enumerate(matrix):
|
||||
if left:
|
||||
sum += row[i]
|
||||
else:
|
||||
sum += row[n - i - 1]
|
||||
|
||||
return sum
|
||||
|
||||
def diagonalDifference(matrix: List[List[int]]) -> int:
|
||||
"""Computes the diagonal difference of an nxn square matrix."""
|
||||
left = diagonalSum(matrix)
|
||||
right = diagonalSum(matrix, False)
|
||||
|
||||
return abs(right - left)
|
||||
|
||||
def sumOfCorners(matrix: List[List[int]]) -> int:
|
||||
"""Computes the sum of the corners of an nxn square matrix."""
|
||||
n = len(matrix)
|
||||
|
||||
return matrix[0][0] + matrix[0][n - 1] + matrix[n - 1][0] + matrix[n - 1][n - 1]
|
||||
|
||||
def averageValue(matrix: List[List[int]]) -> int:
|
||||
"""Computes the average value in an nxn square matrix."""
|
||||
values = reduce(iconcat, matrix, [])
|
||||
|
||||
return sum(values) / (len(matrix) ** 2)
|
||||
|
||||
n = getInteger('Please enter the dimension of the square matrix: ', 'Please enter a natural number greater than 1.', lambda x: x <= 1)
|
||||
matrix = generateMatrix(n, 1, 100)
|
||||
# matrix = [[12,3,15],[4,7,8],[5,6,2]]
|
||||
difference = diagonalDifference(matrix)
|
||||
corners = sumOfCorners(matrix)
|
||||
average = averageValue(matrix)
|
||||
|
||||
printMatrix(matrix)
|
||||
print(f"""Diagonal difference: {difference}
|
||||
Sum of the corners: {corners}
|
||||
Average value: {average}""")
|
|
@ -0,0 +1,93 @@
|
|||
from typing import List
|
||||
import os.path
|
||||
|
||||
class Class:
|
||||
def __init__(self, name: str, marks: List[int] = []):
|
||||
self.__name = name
|
||||
self.__marks = marks
|
||||
self.__marks.sort()
|
||||
|
||||
def __add__(self, marks: int | List[int]):
|
||||
if type(marks) == int:
|
||||
self.__marks.append(marks)
|
||||
elif type(marks) == list:
|
||||
self.__marks.extend(marks)
|
||||
|
||||
self.__marks.sort()
|
||||
|
||||
return self
|
||||
|
||||
def __iadd__(self, marks: int | List[int]):
|
||||
return self.__add__(marks)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__marks)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.__name
|
||||
|
||||
def mean(self) -> int:
|
||||
return sum(self.__marks) / len(self.__marks)
|
||||
|
||||
def median(self) -> int:
|
||||
return self.__marks[len(self.__marks) // 2]
|
||||
|
||||
def above_median(self) -> int:
|
||||
return len([mark for mark in self.__marks if mark > self.median()])
|
||||
|
||||
def below_median(self) -> int:
|
||||
return len([mark for mark in self.__marks if mark < self.median()])
|
||||
|
||||
def mode(self) -> int:
|
||||
return max(set(self.__marks), key=self.__marks.count)
|
||||
|
||||
def save(self):
|
||||
name = self.__name.replace("/", "")
|
||||
with open(f"{name}.csv", "w") as file:
|
||||
file.write(",".join([str(mark) for mark in self.__marks]))
|
||||
|
||||
def get_class(name: str):
|
||||
sanitized_name = name.replace("/", "")
|
||||
marks = []
|
||||
|
||||
if os.path.exists(f"{sanitized_name}.csv"):
|
||||
with open(f"{sanitized_name}.csv", "r") as file:
|
||||
marks += [int(mark) for mark in file.read().split(",")]
|
||||
else:
|
||||
while True:
|
||||
try:
|
||||
marks = [int(x) for x in input(f"Please enter a comma separated list of the marks for class {name}: ").split(",") if x != ""]
|
||||
break
|
||||
except ValueError:
|
||||
print("Please enter a valid list of marks.")
|
||||
pass
|
||||
|
||||
_class = Class(name, marks)
|
||||
_class.save()
|
||||
|
||||
return _class
|
||||
|
||||
cs1 = get_class("12/CS1")
|
||||
cs2 = get_class("12/CS2")
|
||||
|
||||
highest_mean = "12/CS1" if cs1.mean() > cs2.mean() else "12/CS2"
|
||||
|
||||
print(f"""
|
||||
12/CS1
|
||||
-------
|
||||
Mean: {cs1.mean()}
|
||||
Median: {cs1.median()}
|
||||
Mode: {cs1.mode()}
|
||||
Above Median: {cs1.above_median()}
|
||||
Below Median: {cs1.below_median()}
|
||||
|
||||
12/CS2
|
||||
-------
|
||||
Mean: {cs2.mean()}
|
||||
Median: {cs2.median()}
|
||||
Mode: {cs2.mode()}
|
||||
Above Median: {cs2.above_median()}
|
||||
Below Median: {cs2.below_median()}
|
||||
|
||||
{highest_mean} has the highest mean.
|
||||
""")
|
|
@ -0,0 +1,157 @@
|
|||
from typing import List, Dict, TypedDict
|
||||
from enum import IntEnum
|
||||
from random import choice
|
||||
import pickle
|
||||
import bcrypt
|
||||
import os
|
||||
|
||||
class Permissions(IntEnum):
|
||||
Read = 1
|
||||
Write = 2
|
||||
|
||||
class AccountType(TypedDict):
|
||||
username: str
|
||||
password: str
|
||||
permissions: Dict[str, int]
|
||||
|
||||
class Account:
|
||||
def __init__(self, permissions: Dict[str, int]):
|
||||
self.__permissions = permissions
|
||||
|
||||
def __has_permission(self, filename: str, permission: Permissions) -> bool:
|
||||
if filename in self.__permissions:
|
||||
return self.__permissions[filename] & (1 << (permission - 1)) == permission
|
||||
|
||||
return False
|
||||
|
||||
def open_file(self, filename: str) -> str:
|
||||
if self.__has_permission(filename, Permissions.Read):
|
||||
with open(filename, "r") as file:
|
||||
return file.read()
|
||||
|
||||
return None
|
||||
|
||||
def write_file(self, filename: str, content: str) -> str:
|
||||
if self.__has_permission(filename, Permissions.Write):
|
||||
with open(filename, "w") as file:
|
||||
return file.write(content)
|
||||
|
||||
return None
|
||||
|
||||
class AuthManager:
|
||||
def __init__(self, filename: str = "accounts.pickle"):
|
||||
self.__filename = filename
|
||||
|
||||
if os.path.exists(filename):
|
||||
with open(filename, "rb") as file:
|
||||
self.__accounts: List[AccountType] = pickle.load(file)
|
||||
dead_files = []
|
||||
|
||||
for i, account in enumerate(self.__accounts):
|
||||
for file in account["permissions"]:
|
||||
if not os.path.exists(file):
|
||||
dead_files.append((i, file))
|
||||
|
||||
for i, file in dead_files:
|
||||
del self.__accounts[i]["permissions"][file]
|
||||
else:
|
||||
self.__accounts = []
|
||||
|
||||
def __save(self):
|
||||
with open(self.__filename, "wb") as file:
|
||||
pickle.dump(self.__accounts, file)
|
||||
|
||||
def register(self, username: str, password: str):
|
||||
for account in self.__accounts:
|
||||
if account["username"] == username:
|
||||
return
|
||||
|
||||
bytes = password.encode("utf-8")
|
||||
salt = bcrypt.gensalt()
|
||||
hash = bcrypt.hashpw(bytes, salt)
|
||||
|
||||
self.__accounts.append({
|
||||
"username": username,
|
||||
"password": hash,
|
||||
"permissions": {}
|
||||
})
|
||||
|
||||
self.__save()
|
||||
|
||||
def login(self, username: str, password: str) -> Account:
|
||||
hash = None
|
||||
permissions = None
|
||||
|
||||
for account in self.__accounts:
|
||||
if account["username"] == username:
|
||||
hash = account["password"]
|
||||
permissions = account["permissions"]
|
||||
|
||||
if hash is None:
|
||||
return None
|
||||
elif bcrypt.checkpw(password.encode("utf-8"), hash):
|
||||
return Account(permissions)
|
||||
else:
|
||||
return None
|
||||
|
||||
def add_permission(self, username: str, filename: str, permission: Permissions) -> bool:
|
||||
if not os.path.exists(filename):
|
||||
return False
|
||||
|
||||
foundAccount = False
|
||||
|
||||
for i, account in enumerate(self.__accounts):
|
||||
if account["username"] == username:
|
||||
foundAccount = True
|
||||
break
|
||||
|
||||
if not foundAccount:
|
||||
return False
|
||||
else:
|
||||
if filename in self.__accounts[i]["permissions"]:
|
||||
if self.__accounts[i]["permissions"][filename] & (1 << (permission - 1)) == permission:
|
||||
return False
|
||||
self.__accounts[i]["permissions"][filename] += permission
|
||||
else:
|
||||
self.__accounts[i]["permissions"][filename] = int(permission)
|
||||
|
||||
self.__save()
|
||||
|
||||
return True
|
||||
|
||||
def remove_permission(self, username: str, filename: str, permission: Permissions) -> bool:
|
||||
foundAccount = False
|
||||
|
||||
for i, account in enumerate(self.__accounts):
|
||||
if account["username"] == username:
|
||||
foundAccount = True
|
||||
break
|
||||
|
||||
if not foundAccount:
|
||||
return False
|
||||
else:
|
||||
if not filename in self.__accounts[i]["permissions"]:
|
||||
return False
|
||||
elif self.__accounts[i]["permissions"][filename] & (1 << (permission - 1)) != permission:
|
||||
return False
|
||||
|
||||
self.__accounts[i]["permissions"][filename] -= permission
|
||||
self.__save()
|
||||
|
||||
return True
|
||||
|
||||
auth = AuthManager()
|
||||
# auth.register("test", "password")
|
||||
# auth.add_permission("test", "test.txt", Permissions.Read)
|
||||
# auth.register("test2", "password")
|
||||
# auth.register("test3", "password")
|
||||
# auth.add_permission("test3", "test.txt", Permissions.Write)
|
||||
|
||||
acc = auth.login("test", "password") # has permission to read
|
||||
acc2 = auth.login("test2", "password") # does not have any permissions
|
||||
acc3 = auth.login("test3", "password") # has permission to write
|
||||
|
||||
acc3.write_file("test.txt", choice([f"test{i}" for i in range(20)]))
|
||||
|
||||
assert acc.open_file("test.txt") is not None
|
||||
assert acc2.open_file("test.txt") is None
|
|
@ -0,0 +1 @@
|
|||
bcrypt==4.0.1
|
|
@ -0,0 +1 @@
|
|||
test1
|
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 23 KiB |
|
@ -0,0 +1,20 @@
|
|||
from typing import List, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
def binary_search(arr: List[T], target: T) -> int:
|
||||
n = len(arr)
|
||||
l = 0
|
||||
r = n - 1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
|
||||
if arr[m] < target:
|
||||
l = m + 1
|
||||
elif arr[m] > target:
|
||||
r = m - 1
|
||||
else:
|
||||
return m
|
||||
|
||||
return -1
|
|
@ -0,0 +1,16 @@
|
|||
from typing import List, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
# optimised implementation of bubble sort, psuedocode from https://en.wikipedia.org/wiki/Bubble_sort
|
||||
def bubble_sort(arr: List[T], asc: bool = True) -> List[T]:
|
||||
n = len(arr)
|
||||
swapped = False
|
||||
|
||||
while not swapped:
|
||||
for i in range(1, n):
|
||||
if arr[i - 1] > arr[i]:
|
||||
arr[i - 1], arr[i] = arr[i], arr[i - 1]
|
||||
swapped = True
|
||||
|
||||
return arr if asc else arr[::-1]
|
|
@ -0,0 +1,20 @@
|
|||
from typing import List, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
# optimised implementation of insertion sort, psuedocode from https://en.wikipedia.org/wiki/Insertion_sort
|
||||
def insertion_sort(arr: List[T], asc: bool = True) -> List[T]:
|
||||
i = 1
|
||||
|
||||
while i < len(arr):
|
||||
x = arr[i]
|
||||
j = i - 1
|
||||
|
||||
while j >= 0 and arr[j] > x:
|
||||
arr[j + 1] = arr[j]
|
||||
j -= 1
|
||||
|
||||
arr[j + 1] = x
|
||||
i += 1
|
||||
|
||||
return arr if asc else arr[::-1]
|
|
@ -0,0 +1,10 @@
|
|||
from typing import List, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
def linear_search(arr: List[T], target: T) -> int:
|
||||
for i in range(len(arr)):
|
||||
if arr[i] == target:
|
||||
return i
|
||||
|
||||
return -1
|
|
@ -0,0 +1,66 @@
|
|||
from random import randint, choice
|
||||
from timeit import timeit
|
||||
from matplotlib import pyplot as plt
|
||||
from copy import copy
|
||||
import sys
|
||||
|
||||
sys.setrecursionlimit(1500) # this is required to run the recursive quicksort, but is usually not recommended
|
||||
|
||||
from linear import linear_search
|
||||
from binary import binary_search
|
||||
from bubble import bubble_sort
|
||||
from insertion import insertion_sort
|
||||
from quicksort import recursive_quick_sort, iterative_quick_sort
|
||||
|
||||
# config
|
||||
LOW = 0
|
||||
HIGH = 100
|
||||
TRIAL_COUNT = 10
|
||||
N_LIST = [50, 100, 1000]
|
||||
|
||||
times = {'Linear Search': [], 'Binary Search': [], 'Bubble Sort': [], 'Insertion Sort': [], 'Quicksort (Recursive)': [], 'Quicksort (Iterative)': []}
|
||||
N_LIST.sort()
|
||||
|
||||
for n in N_LIST:
|
||||
# generate the test data
|
||||
data = [randint(LOW, HIGH) for _ in range(n)]
|
||||
random_element = choice(data)
|
||||
|
||||
sorted_data = copy(data)
|
||||
sorted_data.sort()
|
||||
|
||||
# perform all of the computations
|
||||
linear_time = round(timeit(lambda: linear_search(data, random_element), number=TRIAL_COUNT) * 1000, 4)
|
||||
binary_time = round(timeit(lambda: binary_search(sorted_data, random_element), number=TRIAL_COUNT) * 1000, 4)
|
||||
bubble_time = round(timeit(lambda: bubble_sort(data), number=TRIAL_COUNT) * 1000, 4)
|
||||
insertion_time = round(timeit(lambda: insertion_sort(data), number=TRIAL_COUNT) * 1000, 4)
|
||||
quicksort_recursive_time = round(timeit(lambda: recursive_quick_sort(data), number=TRIAL_COUNT) * 1000, 4)
|
||||
quicksort_iterative_time = round(timeit(lambda: iterative_quick_sort(data), number=TRIAL_COUNT) * 1000, 4)
|
||||
|
||||
print(f"""n = {n}
|
||||
Linear Search: {linear_time}ms
|
||||
Binary Search: {binary_time}ms
|
||||
Bubble Sort: {bubble_time}ms
|
||||
Insertion Sort: {insertion_time}ms
|
||||
Recursive Quicksort: {quicksort_recursive_time}ms
|
||||
Iterative Quicksort: {quicksort_iterative_time}ms
|
||||
-------------------------------------""")
|
||||
|
||||
# store the times
|
||||
times['Linear Search'].append(linear_time)
|
||||
times['Binary Search'].append(binary_time)
|
||||
times['Bubble Sort'].append(bubble_time)
|
||||
times['Insertion Sort'].append(insertion_time)
|
||||
times['Quicksort (Recursive)'].append(quicksort_recursive_time)
|
||||
times['Quicksort (Iterative)'].append(quicksort_iterative_time)
|
||||
|
||||
# plot the times
|
||||
plt.xlabel('n')
|
||||
plt.ylabel('Time (ms)')
|
||||
|
||||
for key in times:
|
||||
plt.clf()
|
||||
plt.title(f"Time Complexity of {key}")
|
||||
print(key, times[key])
|
||||
plt.plot(N_LIST, times[key], linestyle='--', marker='o', color='b')
|
||||
plt.savefig(f"{key}.png")
|
|
@ -0,0 +1,65 @@
|
|||
from typing import List, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
def partition(arr: List[T], low: int, high: int) -> int:
|
||||
pivot = arr[high]
|
||||
i = low - 1
|
||||
|
||||
for j in range(low, high):
|
||||
if arr[j] <= pivot:
|
||||
i += 1
|
||||
arr[i], arr[j] = arr[j], arr[i]
|
||||
|
||||
arr[i + 1], arr[high] = arr[high], arr[i + 1]
|
||||
|
||||
return i + 1
|
||||
|
||||
# https://en.wikipedia.org/wiki/Quicksort
|
||||
def recursive_quick_sort(arr: List[T], asc: bool = True, low: int = 0, high: int = None) -> List[T]:
|
||||
if high is None or high > len(arr) - 1:
|
||||
high = len(arr) - 1
|
||||
|
||||
if low < high:
|
||||
p = partition(arr, low, high)
|
||||
|
||||
recursive_quick_sort(arr, asc, low, p - 1)
|
||||
recursive_quick_sort(arr, asc, p + 1, high)
|
||||
|
||||
return arr if asc else arr[::-1]
|
||||
|
||||
def iterative_quick_sort(arr: List[T], asc: bool = True, low: int = 0, high: int = None) -> List[T]:
|
||||
if high is None or high > len(arr) - 1:
|
||||
high = len(arr) - 1
|
||||
|
||||
if low < high:
|
||||
size = high - low + 1
|
||||
stack = [0] * size
|
||||
top = -1
|
||||
|
||||
top += 1
|
||||
stack[top] = low
|
||||
top += 1
|
||||
stack[top] = high
|
||||
|
||||
while top >= 0:
|
||||
high = stack[top]
|
||||
top -= 1
|
||||
low = stack[top]
|
||||
top -= 1
|
||||
|
||||
p = partition(arr, low, high)
|
||||
|
||||
if p - 1 > low:
|
||||
top += 1
|
||||
stack[top] = low
|
||||
top += 1
|
||||
stack[top] = p - 1
|
||||
|
||||
if p + 1 < high:
|
||||
top += 1
|
||||
stack[top] = p + 1
|
||||
top += 1
|
||||
stack[top] = high
|
||||
|
||||
return arr if asc else arr[::-1]
|
|
@ -1,16 +0,0 @@
|
|||
def intInput(name):
|
||||
while True:
|
||||
try:
|
||||
number = int(input(f'Please enter an integer for {name}: '))
|
||||
return number
|
||||
except ValueError:
|
||||
print('Please enter a valid integer.')
|
||||
|
||||
A = intInput('A')
|
||||
B = intInput('B')
|
||||
C = intInput('C')
|
||||
|
||||
if (A < B) or (B < C):
|
||||
A = B
|
||||
|
||||
print(A)
|