diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.5.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.5.PNG deleted file mode 100644 index 844cd83..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.5.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.6.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.6.PNG deleted file mode 100644 index c84aa95..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.6.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.7.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.7.PNG deleted file mode 100644 index 85db6b9..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.7.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.8.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.8.PNG deleted file mode 100644 index 0306421..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.8.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.9.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.9.PNG deleted file mode 100644 index 696a5fa..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.2.9.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.4.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.4.PNG deleted file mode 100644 index 63f3c8f..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.4.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.5.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.5.PNG deleted file mode 100644 index fbe5e84..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.3.5.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.3.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.3.PNG deleted file mode 100644 index 4821eac..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.3.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.4.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.4.PNG deleted file mode 100644 index 5c7da17..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.4.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.5.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.5.PNG deleted file mode 100644 index 23b13d7..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.5.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.6.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.6.PNG deleted file mode 100644 index 59bbe0f..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.6.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.7.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.7.PNG deleted file mode 100644 index 9736ff5..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.4.2.7.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.5.2.PNG b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.5.2.PNG deleted file mode 100644 index d35107e..0000000 Binary files a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/11.5.2.PNG and /dev/null differ diff --git a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/Letter Frequency.py b/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/Letter Frequency.py deleted file mode 100644 index 0b714ab..0000000 --- a/school/a-level/Y12 2022-2024/Homework/07-12-22 - Dictionaries/Letter Frequency.py +++ /dev/null @@ -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) diff --git a/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/primeList/__init__.py b/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/primeList/__init__.py deleted file mode 100644 index 85353c2..0000000 --- a/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/primeList/__init__.py +++ /dev/null @@ -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() diff --git a/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/test.py b/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/test.py deleted file mode 100644 index 292103c..0000000 --- a/school/a-level/Y12 2022-2024/Homework/11-01-23 - Code and test a program/test.py +++ /dev/null @@ -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() diff --git a/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference OOP.py b/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference OOP.py deleted file mode 100644 index 28611ca..0000000 --- a/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference OOP.py +++ /dev/null @@ -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) diff --git a/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference.py b/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference.py deleted file mode 100644 index dce65f4..0000000 --- a/school/a-level/Y12 2022-2024/Homework/15-03-23 Code and test/Diagonal Difference.py +++ /dev/null @@ -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}""") diff --git a/school/a-level/Y12 2022-2024/Homework/20 - Strings and Accumulators/marks.py b/school/a-level/Y12 2022-2024/Homework/20 - Strings and Accumulators/marks.py new file mode 100644 index 0000000..f60abc2 --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/20 - Strings and Accumulators/marks.py @@ -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. +""") diff --git a/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/accounts.pickle b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/accounts.pickle new file mode 100644 index 0000000..be56358 Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/accounts.pickle differ diff --git a/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/bitmasks.py b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/bitmasks.py new file mode 100644 index 0000000..1ca267d --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/bitmasks.py @@ -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 diff --git a/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/requirements.txt b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/requirements.txt new file mode 100644 index 0000000..82d95ac --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/requirements.txt @@ -0,0 +1 @@ +bcrypt==4.0.1 diff --git a/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/test.txt b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/test.txt new file mode 100644 index 0000000..f079749 --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/23 - Algorithms/test.txt @@ -0,0 +1 @@ +test1 \ No newline at end of file diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Binary Search.png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Binary Search.png new file mode 100644 index 0000000..5bee232 Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Binary Search.png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Bubble Sort.png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Bubble Sort.png new file mode 100644 index 0000000..d9e64a9 Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Bubble Sort.png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Insertion Sort.png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Insertion Sort.png new file mode 100644 index 0000000..8f03fb4 Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Insertion Sort.png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Linear Search.png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Linear Search.png new file mode 100644 index 0000000..43d94fe Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Linear Search.png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Iterative).png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Iterative).png new file mode 100644 index 0000000..28310d4 Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Iterative).png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Recursive).png b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Recursive).png new file mode 100644 index 0000000..978760b Binary files /dev/null and b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/Quicksort (Recursive).png differ diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/binary.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/binary.py new file mode 100644 index 0000000..5b857ef --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/binary.py @@ -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 diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/bubble.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/bubble.py new file mode 100644 index 0000000..0c3f3cf --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/bubble.py @@ -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] diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/insertion.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/insertion.py new file mode 100644 index 0000000..d2fa827 --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/insertion.py @@ -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] diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/linear.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/linear.py new file mode 100644 index 0000000..471c73c --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/linear.py @@ -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 diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/main.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/main.py new file mode 100644 index 0000000..72b0fc9 --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/main.py @@ -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") diff --git a/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/quicksort.py b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/quicksort.py new file mode 100644 index 0000000..271a08c --- /dev/null +++ b/school/a-level/Y12 2022-2024/Homework/24 - Sorting Algorithms/quicksort.py @@ -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] diff --git a/school/a-level/Y12 2022-2024/Homework/30-01-23 - Logic Gates/Worksheet Program.py b/school/a-level/Y12 2022-2024/Homework/30-01-23 - Logic Gates/Worksheet Program.py deleted file mode 100644 index c1fb938..0000000 --- a/school/a-level/Y12 2022-2024/Homework/30-01-23 - Logic Gates/Worksheet Program.py +++ /dev/null @@ -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)