feat: dump stuff from school again ig
|
@ -0,0 +1,57 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
def parseValue(value: str):
|
||||||
|
value = value.strip()
|
||||||
|
|
||||||
|
if value.lower() == "true":
|
||||||
|
return True
|
||||||
|
elif value.lower() == "false":
|
||||||
|
return False
|
||||||
|
elif len(value.split(".")) == 2:
|
||||||
|
return float(value)
|
||||||
|
elif value.isnumeric():
|
||||||
|
return int(value)
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
class Data:
|
||||||
|
def __init__(self, fileName: str):
|
||||||
|
with open(fileName, "r") as file:
|
||||||
|
out = [[parseValue(value) for value in line.strip().split(",")] for line in file.readlines()]
|
||||||
|
self.__data = { header: lst for (header, lst) in zip(out[0], zip(*out[1::])) }
|
||||||
|
|
||||||
|
def getHeaderData(self, header: str):
|
||||||
|
"""Get the data under a header, CaSe insensitive"""
|
||||||
|
for realHeader in self.__data.keys():
|
||||||
|
if header.lower() == realHeader.lower():
|
||||||
|
return self.__data[realHeader]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def bubbleSort(lst: list, asc: bool = True) -> list:
|
||||||
|
n = len(lst)
|
||||||
|
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(0, n - i - 1):
|
||||||
|
if lst[j] > lst[j + 1]:
|
||||||
|
lst[j], lst[j + 1] = lst[j + 1], lst[j]
|
||||||
|
|
||||||
|
return lst if asc else lst[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def getHeights(data: Data, male: bool) -> tuple:
|
||||||
|
heights = data.getHeaderData("height")
|
||||||
|
males = data.getHeaderData("male")
|
||||||
|
|
||||||
|
return [height for height, isMale in zip(heights, males) if male == isMale]
|
||||||
|
|
||||||
|
def meanHeight(data: Data, male: bool):
|
||||||
|
heights = getHeights(data, male)
|
||||||
|
return sum(heights) / len(heights)
|
||||||
|
|
||||||
|
sports = Data("sports_data.csv")
|
||||||
|
femaleHeights = bubbleSort(getHeights(sports, False))
|
||||||
|
|
||||||
|
plt.bar([i for i in range(len(femaleHeights))], femaleHeights)
|
||||||
|
plt.savefig('yes.png')
|
BIN
school/a-level/Y12 2022-2024/Algorithms/Data Analysis/yes.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
|
@ -0,0 +1,29 @@
|
||||||
|
from math import log, floor
|
||||||
|
|
||||||
|
class Memoize:
|
||||||
|
"""Helper class to memoize a decorated function."""
|
||||||
|
def __init__(self, function):
|
||||||
|
self.function = function
|
||||||
|
self.memo = {}
|
||||||
|
|
||||||
|
def __call__(self, *args):
|
||||||
|
if not args in self.memo:
|
||||||
|
self.memo[args] = self.function(*args)
|
||||||
|
return self.memo[args]
|
||||||
|
|
||||||
|
@Memoize
|
||||||
|
def pdi(power: int, base: int, number: int) -> int:
|
||||||
|
"""Computes the perfect digital invariant."""
|
||||||
|
return sum(pow((number % pow(base, i + 1) - number % pow(base, i)) / pow(base, i), power) for i in range(0, floor(log(number, base)) + 1))
|
||||||
|
|
||||||
|
def isHappy(number: int, base: int = 10) -> bool:
|
||||||
|
"""Check if a number is happy in a given base. Defaults to base 10."""
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
while number > 1 and number not in seen:
|
||||||
|
seen.add(number)
|
||||||
|
number = pdi(2, base, number)
|
||||||
|
|
||||||
|
return number == 1
|
||||||
|
|
||||||
|
print(isHappy(19))
|
10
school/a-level/Y12 2022-2024/Algorithms/Happy Numbers.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
def happyCheck(number: int):
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
while number > 1 and number not in seen:
|
||||||
|
seen.add(number)
|
||||||
|
number = sum(int(digit) ** 2 for digit in list(str(number)))
|
||||||
|
|
||||||
|
return number == 1
|
||||||
|
|
||||||
|
print(happyCheck(19))
|
20
school/a-level/Y12 2022-2024/Algorithms/Merge Sort.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
def mergeSort(lst: list) -> list:
|
||||||
|
if len(lst) > 1:
|
||||||
|
mid = len(lst) // 2
|
||||||
|
left = lst[:mid]
|
||||||
|
right = lst[mid:]
|
||||||
|
|
||||||
|
mergeSort(left)
|
||||||
|
mergeSort(right)
|
||||||
|
|
||||||
|
i = j = k = 0
|
||||||
|
|
||||||
|
while i < len(left) and j < len(right):
|
||||||
|
if left[i] <= right[j]:
|
||||||
|
lst[k] = left[i]
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
lst[k] = right[j]
|
||||||
|
|
||||||
|
|
||||||
|
print(mergeSort([3,5,2,1]))
|
57
school/a-level/Y12 2022-2024/Algorithms/bitwise/apply.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
from typing import Callable
|
||||||
|
from operator import and_, or_, xor
|
||||||
|
|
||||||
|
def applyOperator(binary: list, mask: list, operator: Callable[[int, int], list]) -> list:
|
||||||
|
return [operator(a, b) for a, b in zip(binary, mask)]
|
||||||
|
|
||||||
|
def getBinary(prompt: str, length: int = None) -> list:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
bits = list(input(f"{prompt} "))
|
||||||
|
|
||||||
|
for bit in bits:
|
||||||
|
if bit not in ["0", "1"]:
|
||||||
|
raise ValueError("Invalid binary number. Please try again.")
|
||||||
|
|
||||||
|
if len(bits) == 0:
|
||||||
|
raise ValueError("Please make sure you enter a value.")
|
||||||
|
elif length and len(bits) != length:
|
||||||
|
raise ValueError(f"Please make sure the value is {length} bits long.")
|
||||||
|
|
||||||
|
return [int(x) for x in bits]
|
||||||
|
except ValueError as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
def makeChoice(prompt: str, choiceCount: int):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
choice = int(input(f"{prompt} "))
|
||||||
|
|
||||||
|
if choice < 1 or choice > choiceCount:
|
||||||
|
raise ValueError("Please make a choice that is within bounds.")
|
||||||
|
|
||||||
|
return choice
|
||||||
|
except ValueError as error:
|
||||||
|
print(error)
|
||||||
|
|
||||||
|
operators = {
|
||||||
|
'AND': ('&', lambda binary, mask: applyOperator(binary, mask, and_)),
|
||||||
|
'OR': ('|', lambda binary, mask: applyOperator(binary, mask, or_)),
|
||||||
|
'XOR': ('^', lambda binary, mask: applyOperator(binary, mask, xor))
|
||||||
|
}
|
||||||
|
|
||||||
|
# take in the binary values
|
||||||
|
binary = getBinary("Please enter your binary number:")
|
||||||
|
mask = getBinary("Please enter the mask:", len(binary))
|
||||||
|
|
||||||
|
# choose an operation
|
||||||
|
choices = [(i + 1, operator) for i, operator in enumerate(operators.keys())]
|
||||||
|
|
||||||
|
for i, operator in choices:
|
||||||
|
print(f'{i}. {operator}')
|
||||||
|
|
||||||
|
symbol, operation = operators.get(choices[makeChoice("Please choose a logical operation:", len(choices)) - 1][1])
|
||||||
|
output = "".join(str(x) for x in operation(binary, mask))
|
||||||
|
binary, mask = "".join(str(x) for x in binary), "".join(str(x) for x in mask)
|
||||||
|
|
||||||
|
print(f"{binary} {symbol} {mask} = {output}")
|
141
school/a-level/Y12 2022-2024/Algorithms/bitwise/applyCurses.py
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
# windows: pip install windows-curses
|
||||||
|
import curses
|
||||||
|
from operator import and_, or_, xor
|
||||||
|
|
||||||
|
def initCurses() -> tuple:
|
||||||
|
"""Initialise curses and any necessary colour pairs"""
|
||||||
|
screen = curses.initscr()
|
||||||
|
screen.keypad(True)
|
||||||
|
|
||||||
|
curses.cbreak()
|
||||||
|
curses.noecho()
|
||||||
|
curses.start_color()
|
||||||
|
|
||||||
|
# default
|
||||||
|
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
||||||
|
default = curses.color_pair(1)
|
||||||
|
|
||||||
|
# highlighted
|
||||||
|
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||||||
|
highlighted = curses.color_pair(2)
|
||||||
|
|
||||||
|
# error
|
||||||
|
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||||
|
error = curses.color_pair(3)
|
||||||
|
|
||||||
|
return (screen, (default, highlighted, error))
|
||||||
|
|
||||||
|
def destroyCurses(screen):
|
||||||
|
"""Close out of curses and reverse any destructive changes to the terminal"""
|
||||||
|
curses.nocbreak()
|
||||||
|
screen.keypad(False)
|
||||||
|
curses.echo()
|
||||||
|
curses.endwin()
|
||||||
|
|
||||||
|
def selectMenu(screen, options: list, header: str = "Pick an option:"):
|
||||||
|
selectedIndex = 0
|
||||||
|
optionCount = len(options)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr(f"{header}\n\n", curses.A_BOLD)
|
||||||
|
|
||||||
|
for i in range(optionCount):
|
||||||
|
screen.addstr(f"{i + 1}. ")
|
||||||
|
screen.addstr(f"{options[i]}\n", highlighted if i == selectedIndex else default)
|
||||||
|
|
||||||
|
c = screen.getch()
|
||||||
|
|
||||||
|
if c == curses.KEY_UP or c == curses.KEY_LEFT:
|
||||||
|
selectedIndex -= 1 - optionCount
|
||||||
|
selectedIndex %= optionCount
|
||||||
|
|
||||||
|
elif c == curses.KEY_DOWN or c == curses.KEY_RIGHT:
|
||||||
|
selectedIndex += 1
|
||||||
|
selectedIndex %= optionCount
|
||||||
|
|
||||||
|
elif c == curses.KEY_ENTER or chr(c) in '\n\r':
|
||||||
|
return selectedIndex + 1
|
||||||
|
|
||||||
|
def getBinary(screen, prompt: str, length: int = None) -> list:
|
||||||
|
errorMessage = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr(0, 0, f"{prompt}", curses.A_BOLD)
|
||||||
|
|
||||||
|
# display an error message if necessary
|
||||||
|
if errorMessage:
|
||||||
|
screen.addstr(3, 0, errorMessage, error | curses.A_BOLD)
|
||||||
|
errorMessage = None
|
||||||
|
|
||||||
|
# fetch the inputted data
|
||||||
|
curses.echo()
|
||||||
|
bits = list(screen.getstr(1, 0, 50).decode("utf-8"))
|
||||||
|
curses.noecho()
|
||||||
|
|
||||||
|
# validate that a binary value was entered
|
||||||
|
for bit in bits:
|
||||||
|
if bit not in ["0", "1"]:
|
||||||
|
errorMessage = "Invalid binary number. Please try again."
|
||||||
|
|
||||||
|
if len(bits) == 0:
|
||||||
|
errorMessage = "Please make sure you enter a value."
|
||||||
|
|
||||||
|
elif length and len(bits) != length:
|
||||||
|
errorMessage = f"Please make sure the value is {length} bits long."
|
||||||
|
|
||||||
|
if errorMessage:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return [int(x) for x in bits]
|
||||||
|
|
||||||
|
def applyOperator(screen, binary: list, mask: list) -> list:
|
||||||
|
# todo: fix
|
||||||
|
# operatorList = list(OPERATORS.keys())
|
||||||
|
# symbol, operator = OPERATORS[operatorList[selectMenu(screen, operatorList) - 1]]
|
||||||
|
# output = "".join(str(operator(a, b)) for a, b in zip(binary, mask))
|
||||||
|
binary = "".join(str(x) for x in binary)
|
||||||
|
mask = "".join(str(x) for x in mask)
|
||||||
|
print(binary, mask, screen)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr(0, 0, f"{binary} {mask}", curses.A_BOLD)
|
||||||
|
screen.addstr(3, 0, "Press the backspace key to get back to the main menu.")
|
||||||
|
screen.addstr(4, 0, "")
|
||||||
|
|
||||||
|
# get pressed key
|
||||||
|
c = screen.getch()
|
||||||
|
|
||||||
|
if c == 8 or c == 127 or c == curses.KEY_BACKSPACE:
|
||||||
|
break
|
||||||
|
|
||||||
|
OPERATORS = {
|
||||||
|
'AND': ('&', lambda binary, mask: applyOperator(binary, mask, and_)),
|
||||||
|
'OR': ('|', lambda binary, mask: applyOperator(binary, mask, or_)),
|
||||||
|
'XOR': ('^', lambda binary, mask: applyOperator(binary, mask, xor))
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# init curses
|
||||||
|
screen, (default, highlighted, error) = initCurses()
|
||||||
|
binary, mask = [], []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
binaryStr = "[NONE]" if len(binary) == 0 else "".join(str(x) for x in binary)
|
||||||
|
maskStr = "[NONE]" if len(mask) == 0 else "".join(str(x) for x in mask)
|
||||||
|
|
||||||
|
choice = selectMenu(screen, ["Apply a gate", "Change the binary number", "Change the mask", "Exit"], f"Current binary number: {binaryStr}\nCurrent mask: {maskStr}\n\nWhat would you like to do?")
|
||||||
|
|
||||||
|
if choice == 1:
|
||||||
|
applyOperator(screen, binary, mask)
|
||||||
|
elif choice == 2:
|
||||||
|
binary = getBinary(screen, "Please enter a new binary value:", None if len(mask) == 0 else len)
|
||||||
|
elif choice == 3:
|
||||||
|
mask = getBinary(screen, "Please enter a new mask:", None if len(binary) == 0 else len(binary))
|
||||||
|
elif choice == 4:
|
||||||
|
break
|
||||||
|
|
||||||
|
# destroy curses
|
||||||
|
destroyCurses(screen)
|
|
@ -0,0 +1,6 @@
|
||||||
|
def xorCipher(text: str, key: int) -> str:
|
||||||
|
"""Encrypts/decrypts with the XOR cipher"""
|
||||||
|
if key > 2**8 - 1:
|
||||||
|
raise ValueError("Key can not be greater than 255.")
|
||||||
|
|
||||||
|
return "".join(chr(ord(c) ^ key) for c in text)
|
9
school/a-level/Y12 2022-2024/Algorithms/caesar.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# def encode(text: str, key: int) -> str:
|
||||||
|
# return ''.join(chr(ord(c) + (key % 26)) for c in text)
|
||||||
|
|
||||||
|
# def decode(ciphertext: str, key: int) -> str:
|
||||||
|
# return ''.join(chr(ord(c) - (key % 26)) for c in ciphertext)
|
||||||
|
|
||||||
|
c,o,e,d=chr,ord,lambda t,k:''.join(c(o(x)+k%26)for x in t),lambda t,k:''.join(c(o(x)-k%26)for x in t)
|
||||||
|
|
||||||
|
print(e("cats", 6))
|
|
@ -0,0 +1,15 @@
|
||||||
|
def recursive_factorial(n):
|
||||||
|
if n == 1:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return n * recursive_factorial(n - 1)
|
||||||
|
|
||||||
|
def iterative_factorial(n):
|
||||||
|
out = 1
|
||||||
|
|
||||||
|
for i in range(2, n + 1):
|
||||||
|
out *= i
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
assert iterative_factorial(5) == recursive_factorial(5)
|
|
@ -0,0 +1,43 @@
|
||||||
|
from timeit import timeit
|
||||||
|
from random import randint
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
TRIAL_COUNT = 100
|
||||||
|
n = randint(2, 20)
|
||||||
|
|
||||||
|
# non-memoized
|
||||||
|
def fib(n):
|
||||||
|
if n in {0, 1}:
|
||||||
|
return n
|
||||||
|
|
||||||
|
return fib(n - 1) + fib(n - 2)
|
||||||
|
|
||||||
|
# memoized
|
||||||
|
def memoize(func):
|
||||||
|
cache = {}
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args):
|
||||||
|
if args not in cache:
|
||||||
|
cache[args] = func(*args)
|
||||||
|
return cache[args]
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
memo_fib = memoize(fib)
|
||||||
|
|
||||||
|
# output
|
||||||
|
a = fib(n)
|
||||||
|
b = memo_fib(n)
|
||||||
|
|
||||||
|
assert a == b
|
||||||
|
|
||||||
|
time_a = timeit(lambda: fib(n), number=TRIAL_COUNT)
|
||||||
|
time_b = timeit(lambda: memo_fib(n), number=TRIAL_COUNT)
|
||||||
|
time_diff = time_a - time_b
|
||||||
|
|
||||||
|
print(f"""fib({n}) = {a}
|
||||||
|
non-memo: {time_a} seconds
|
||||||
|
memo: {time_b} seconds
|
||||||
|
|
||||||
|
difference of {time_diff} seconds ({round(time_diff / time_a * 100, 3)}% of non-memo)""")
|
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,17 @@
|
||||||
|
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)
|
|
@ -0,0 +1,92 @@
|
||||||
|
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()
|
|
@ -0,0 +1,18 @@
|
||||||
|
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()
|
|
@ -0,0 +1,16 @@
|
||||||
|
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)
|
|
@ -0,0 +1,190 @@
|
||||||
|
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)
|
|
@ -0,0 +1,79 @@
|
||||||
|
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,34 @@
|
||||||
|
from random import randint as r
|
||||||
|
from functools import reduce
|
||||||
|
from operator import iconcat
|
||||||
|
a,p=range,print
|
||||||
|
|
||||||
|
def q(p,e,v):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
value = int(input(p))
|
||||||
|
if v and v(value):raise ValueError
|
||||||
|
return value
|
||||||
|
except ValueError:p(e)
|
||||||
|
|
||||||
|
def g(n,a,b):
|
||||||
|
if a > b:raise ValueError('Minimum value must be less than maximum value!');return[[r(a,b)for _ in a(n)]for _ in a(n)]
|
||||||
|
|
||||||
|
def o(m):
|
||||||
|
n,r,d=len(m),"{:^7}| "*n,'-'*(n*9-1);p(d);[p(f'{r.format(*x)}\n{d}')for x in m]
|
||||||
|
|
||||||
|
def s(m,l=True):
|
||||||
|
s,n=0,len(m);[(s:=s+x[i])if l else(s:=s+x[n-i-1])for i,x in enumerate(m)];return s
|
||||||
|
|
||||||
|
def d(m):
|
||||||
|
l,x=s(m),s(m, False)
|
||||||
|
|
||||||
|
return abs(x-l)
|
||||||
|
|
||||||
|
def c(m):
|
||||||
|
n=len(m)-1;return m[0][0]+m[0][n]+m[n][0]+m[n][n]
|
||||||
|
|
||||||
|
a,n=lambda m:sum(reduce(iconcat,m,[]))/(len(m)**2),q('Please enter the dimension of the square matrix: ','Please enter a natural number greater than 1.',lambda x:x<=1);m=g(n,1,100);z,x,k=d(m),c(m),a(m);o(m)
|
||||||
|
p(f"""Diagonal difference: {z}
|
||||||
|
Sum of the corners: {x}
|
||||||
|
Average value: {k}""")
|
215
school/a-level/Y12 2022-2024/Video Playlist.py
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
# note: On Windows, pip install windows-curses
|
||||||
|
from __future__ import annotations
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from json import loads as loadJson
|
||||||
|
from webbrowser import open_new_tab as browserOpen
|
||||||
|
from typing import List
|
||||||
|
from re import search as searchRegex
|
||||||
|
from pickle import load as pickleLoad, dump as pickleDump
|
||||||
|
from os.path import join as pathJoin, exists as pathExists
|
||||||
|
from sys import path as sysPath
|
||||||
|
import curses
|
||||||
|
|
||||||
|
class InvalidID(Exception): pass
|
||||||
|
|
||||||
|
class Playlist:
|
||||||
|
def __init__(self, nickname: str):
|
||||||
|
self.__nickname = nickname
|
||||||
|
self.__videos: List[Video] = []
|
||||||
|
self.__file = Playlist.getPath(nickname)
|
||||||
|
|
||||||
|
if pathExists(self.__file):
|
||||||
|
with open(self.__file, "rb") as f:
|
||||||
|
self.__videos = pickleLoad(f)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getPath(nickname: str) -> str:
|
||||||
|
return pathJoin(sysPath[0], f"{nickname}.playlist")
|
||||||
|
|
||||||
|
def getName(self) -> str:
|
||||||
|
return self.__nickname
|
||||||
|
|
||||||
|
def addVideo(self, video: Video):
|
||||||
|
self.__videos.append(video)
|
||||||
|
return self.__save()
|
||||||
|
|
||||||
|
def __save(self):
|
||||||
|
with open(self.__file, "wb") as f:
|
||||||
|
pickleDump(self.__videos, f)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __getitem__(self, index: int):
|
||||||
|
if index > len(self.__videos) - 1:
|
||||||
|
raise IndexError("Out of bounds")
|
||||||
|
|
||||||
|
return self.__videos[index]
|
||||||
|
|
||||||
|
def __delitem__(self, index: int):
|
||||||
|
if index > len(self.__videos) - 1:
|
||||||
|
raise IndexError("Out of bounds")
|
||||||
|
|
||||||
|
del self.__videos[index]
|
||||||
|
self.__save()
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.__videos)
|
||||||
|
|
||||||
|
class Video:
|
||||||
|
def __init__(self, id: str):
|
||||||
|
self.__id = id
|
||||||
|
self.__url = f"https://youtu.be/{self.__id}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urlopen(f"https://www.youtube.com/oembed?url=https://youtu.be/{self.__id}&format=json") as response:
|
||||||
|
data = response.read()
|
||||||
|
|
||||||
|
data = loadJson(data)
|
||||||
|
self.__title = data["title"]
|
||||||
|
self.__author = data["author_name"]
|
||||||
|
except:
|
||||||
|
raise InvalidID(f"{id} is not a valid ID!")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.__author} - {self.__title}"
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
browserOpen(self.__url)
|
||||||
|
|
||||||
|
# Initialise curses
|
||||||
|
screen = curses.initscr()
|
||||||
|
screen.keypad(True)
|
||||||
|
curses.cbreak()
|
||||||
|
curses.noecho()
|
||||||
|
|
||||||
|
# Initialise colours
|
||||||
|
curses.start_color()
|
||||||
|
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||||||
|
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
||||||
|
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||||
|
|
||||||
|
black, white, red = curses.color_pair(1), curses.color_pair(2), curses.color_pair(3)
|
||||||
|
|
||||||
|
def selectMenu(screen, options: List[str]):
|
||||||
|
selectedIndex = 0
|
||||||
|
optionCount = len(options)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr("Pick an option:\n\n", curses.A_BOLD)
|
||||||
|
|
||||||
|
for i in range(optionCount):
|
||||||
|
screen.addstr(f"{i + 1}. ")
|
||||||
|
screen.addstr(f"{options[i]}\n", black if i == selectedIndex else white)
|
||||||
|
|
||||||
|
c = screen.getch()
|
||||||
|
|
||||||
|
if c == curses.KEY_UP or c == curses.KEY_LEFT:
|
||||||
|
selectedIndex -= 1 - optionCount
|
||||||
|
selectedIndex %= optionCount
|
||||||
|
|
||||||
|
elif c == curses.KEY_DOWN or c == curses.KEY_RIGHT:
|
||||||
|
selectedIndex += 1
|
||||||
|
selectedIndex %= optionCount
|
||||||
|
|
||||||
|
elif c == curses.KEY_ENTER or chr(c) in '\n\r':
|
||||||
|
return selectedIndex + 1
|
||||||
|
|
||||||
|
def addVideo(screen, playlist: Playlist):
|
||||||
|
hasErrored = False
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr(0, 0, "Please enter a YouTube URL/ID:", curses.A_BOLD)
|
||||||
|
|
||||||
|
# Display the error message if necessary
|
||||||
|
if hasErrored:
|
||||||
|
screen.addstr(3, 0, "Please make sure you have entered a valid URL/ID.", red | curses.A_BOLD)
|
||||||
|
|
||||||
|
# Fetch the inputted data
|
||||||
|
curses.echo()
|
||||||
|
videoId = screen.getstr(1, 0, 50).decode("utf-8")
|
||||||
|
curses.noecho()
|
||||||
|
|
||||||
|
# Attempt to extract a video ID
|
||||||
|
parsed = searchRegex(r"(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\/user\/\S+|\/ytscreeningroom\?v=))([\w\-]{10,12})\b", videoId)
|
||||||
|
|
||||||
|
if parsed:
|
||||||
|
videoId = parsed.group(1)
|
||||||
|
|
||||||
|
# Attempt to add the video to the playlist
|
||||||
|
try:
|
||||||
|
video = Video(str(videoId))
|
||||||
|
playlist.addVideo(video)
|
||||||
|
|
||||||
|
break
|
||||||
|
except InvalidID:
|
||||||
|
hasErrored = True
|
||||||
|
|
||||||
|
def viewPlaylist(screen, playlist: Playlist):
|
||||||
|
selectedIndex = 0
|
||||||
|
selectedPlay = True
|
||||||
|
playlistLength = len(playlist)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr(f"{playlist.getName()} playlist\n", curses.A_BOLD)
|
||||||
|
screen.addstr("Press the backspace key to exit this menu.\n\n")
|
||||||
|
|
||||||
|
if playlistLength == 0:
|
||||||
|
screen.addstr("There is nothing here!\n")
|
||||||
|
c = screen.getch()
|
||||||
|
else:
|
||||||
|
for i in range(playlistLength):
|
||||||
|
screen.addstr(f"{i + 1}. {playlist[i]} ")
|
||||||
|
screen.addstr("[PLAY]", black if selectedPlay and selectedIndex == i else white)
|
||||||
|
screen.addstr(" ")
|
||||||
|
screen.addstr("[DELETE]\n", black if not selectedPlay and selectedIndex == i else white)
|
||||||
|
|
||||||
|
c = screen.getch()
|
||||||
|
|
||||||
|
if c == curses.KEY_UP:
|
||||||
|
selectedIndex -= 1 - playlistLength
|
||||||
|
selectedIndex %= playlistLength
|
||||||
|
|
||||||
|
elif c == curses.KEY_DOWN:
|
||||||
|
selectedIndex += 1
|
||||||
|
selectedIndex %= playlistLength
|
||||||
|
|
||||||
|
elif c == curses.KEY_LEFT:
|
||||||
|
selectedPlay = True
|
||||||
|
|
||||||
|
elif c == curses.KEY_RIGHT:
|
||||||
|
selectedPlay = False
|
||||||
|
|
||||||
|
elif c == curses.KEY_ENTER or chr(c) in '\n\r':
|
||||||
|
if selectedPlay:
|
||||||
|
playlist[selectedIndex].open()
|
||||||
|
else:
|
||||||
|
del playlist[selectedIndex]
|
||||||
|
playlistLength -= 1
|
||||||
|
selectedIndex = 0 if selectedIndex == 0 else selectedIndex - 1
|
||||||
|
|
||||||
|
if c == 8 or c == 127 or c == curses.KEY_BACKSPACE:
|
||||||
|
break
|
||||||
|
|
||||||
|
# todo: add custom playlist names
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
playlist = Playlist("main")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
choice = selectMenu(screen, ["Add a video to the playlist", "View the playlist", "Exit"])
|
||||||
|
|
||||||
|
if choice == 1:
|
||||||
|
addVideo(screen, playlist)
|
||||||
|
elif choice == 2:
|
||||||
|
viewPlaylist(screen, playlist)
|
||||||
|
elif choice == 3:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Exit curses
|
||||||
|
curses.nocbreak()
|
||||||
|
screen.keypad(False)
|
||||||
|
curses.echo()
|
||||||
|
curses.endwin()
|
25
school/a-level/Y12 2022-2024/curry.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import functools
|
||||||
|
import inspect
|
||||||
|
from copy import copy
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
def curry(function: Callable) -> Callable:
|
||||||
|
# call functools.partial recursively in order to curry a function
|
||||||
|
def inner(*args, **kwargs):
|
||||||
|
partial = functools.partial(function, *args, **kwargs)
|
||||||
|
signature = inspect.signature(partial.func)
|
||||||
|
|
||||||
|
try:
|
||||||
|
signature.bind(*partial.args, **partial.keywords)
|
||||||
|
except TypeError:
|
||||||
|
return curry(copy(partial)) # there must be more arguments to curry
|
||||||
|
else:
|
||||||
|
return partial()
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
def add(a, b):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
x = curry(add)(2)
|
||||||
|
print(x)
|
50
school/a-level/Y12 2022-2024/curses wrapper maybe.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import curses
|
||||||
|
from typing import List, Tuple, Callable, Any
|
||||||
|
|
||||||
|
class Application:
|
||||||
|
def __init__(self):
|
||||||
|
# Initialise curses
|
||||||
|
self.__curses = curses.initscr()
|
||||||
|
self.__curses.keypad(True)
|
||||||
|
|
||||||
|
curses.start_color() # todo: check for colour support
|
||||||
|
curses.cbreak()
|
||||||
|
curses.noecho()
|
||||||
|
|
||||||
|
# Default colours
|
||||||
|
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) # default
|
||||||
|
curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_WHITE) # selected
|
||||||
|
|
||||||
|
def selectMenu(self, options: List[Tuple[str, Callable[[], Any]]]):
|
||||||
|
selectedIndex = 0
|
||||||
|
optionCount = len(options)
|
||||||
|
screen = self.__curses
|
||||||
|
|
||||||
|
while True:
|
||||||
|
screen.clear()
|
||||||
|
screen.addstr("Pick an option:\n\n", curses.A_BOLD)
|
||||||
|
|
||||||
|
for i in range(optionCount):
|
||||||
|
colour = curses.color_pair(2) if i == selectedIndex else curses.color_pair(1)
|
||||||
|
screen.addstr(f"{i + 1}. ")
|
||||||
|
screen.addstr(f"{options[i][0]}\n", colour)
|
||||||
|
|
||||||
|
c = screen.getch()
|
||||||
|
|
||||||
|
if c in [curses.KEY_UP, curses.KEY_LEFT]:
|
||||||
|
selectedIndex = (selectedIndex + optionCount - 1) % optionCount
|
||||||
|
elif c in [curses.KEY_DOWN, curses.KEY_RIGHT]:
|
||||||
|
selectedIndex = (selectedIndex + 1) % optionCount
|
||||||
|
elif c == curses.KEY_ENTER or chr(c) in '\n\r':
|
||||||
|
break
|
||||||
|
|
||||||
|
options[selectedIndex][1]()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
curses.nocbreak()
|
||||||
|
self.__curses.keypad(False)
|
||||||
|
curses.echo()
|
||||||
|
curses.endwin()
|
||||||
|
|
||||||
|
app = Application()
|
||||||
|
app.selectMenu([("yes", lambda: (app.quit(),print("i dont think so"))), ("no", lambda: (app.quit(), print("no need to be a cynic")))])
|
3
school/a-level/Y12 2022-2024/golfed full adder.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
exec(bytes('ⱩⱲⱺⱬⱧ㵡湩ⱴ慲杮ⱥ楢Ɱ敬Ɱ慬扭慤砠洬戬⠺㩹氽獩⡴慭⡰慬扭慤琠椺琨Ⱙ∨∰晩砨㴾⤰汥敳ㄢ⤢稫砨洦嬩㨲⥝Ⱙ祛椮獮牥⡴ⰰ⤰潦 湩爠ㄨ〰椩⡬⥹戼ⱝ⥹せ孝㨺ㄭⱝ慬扭慤砠礬⠺㩢洽硡氨稨砨嬩㨲⥝氬稨礨嬩㨲⥝⬩ⰱ㩭椽∨∱截㈬Ⱙ㩰朽砨洬戬Ⱙ㩱朽礨洬戬Ⱙ㩷〽漬㴺⡛幷愨扞Ⱙ㩷⠽♡⥢⡼♷⠨慾戦簩愨縦⥢⤩嬩崰潦⡲ⱡ⥢湩稠灩瀨焬崩漬愮灰湥⡤⥷晩砨〾愩摮礨〾攩獬⡥Ⱙ㩯漽㩛ⴺ崱猬㴺‰晩漨せ㵝〽攩獬ⵥ㈨⨪氨漨⤱Ⱙ㩯漽ㅛ㨺孝㨺ㄭⱝ獛㴺⭳㈨⨪晩漨楛㵝ㄽ攩獬⤰潦⡲⥩湩爠氨漨⤩孝ㄭ⥝ㅛ崰','u16')[2:])
|
||||||
|
|
||||||
|
print(a(5,-6))
|
BIN
school/a-level/Y12 2022-2024/main.playlist
Normal file
10
school/a-level/Y12 2022-2024/q13 sol.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from random import choice
|
||||||
|
|
||||||
|
def randomDigit(dateOfBirth):
|
||||||
|
return choice("".join(dateOfBirth.split("/")))
|
||||||
|
|
||||||
|
def getUsername(firstName, lastName, dateOfBirth):
|
||||||
|
day, month, year = dateOfBirth.split("/")
|
||||||
|
return f"{firstName[0:3]}{randomDigit(dateOfBirth)}{randomDigit(dateOfBirth)}{lastName[len(lastName)-3:len(lastName)]}{day}{month}{year[len(year)-2:len(year)]}"
|
||||||
|
|
||||||
|
print(getUsername("John", "Smith", "19/03/1989"))
|
|
@ -0,0 +1,215 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Generic, TypeVar, Tuple, List
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Node(Generic[T]):
|
||||||
|
data: T
|
||||||
|
left: Node[T] = None
|
||||||
|
right: Node[T] = None
|
||||||
|
|
||||||
|
class BST(Generic[T]):
|
||||||
|
"""Full implementation of a Binary Search Tree"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__root: Node[T] = None
|
||||||
|
|
||||||
|
def findMinimum(self) -> Node[T]:
|
||||||
|
"""Find the minimum node in the tree."""
|
||||||
|
current = self.__root
|
||||||
|
|
||||||
|
# Keep traversing left when possible - smaller numbers will always be on the left!
|
||||||
|
while current.left:
|
||||||
|
current = current.left
|
||||||
|
|
||||||
|
return current
|
||||||
|
|
||||||
|
def findMaximum(self) -> Node[T]:
|
||||||
|
"""Find the maximum node in the tree."""
|
||||||
|
current = self.__root
|
||||||
|
|
||||||
|
# Keep traversing right when possible - larger numbers will always be on the right!
|
||||||
|
while current.right:
|
||||||
|
current = current.right
|
||||||
|
|
||||||
|
return current
|
||||||
|
|
||||||
|
def insert(self, data: T) -> BST[T]:
|
||||||
|
"""Inserts a new piece of data into the tree."""
|
||||||
|
node = Node(data)
|
||||||
|
|
||||||
|
if self.__root == None:
|
||||||
|
# Ensure there is a root node in the first place!
|
||||||
|
self.__root = node
|
||||||
|
return self
|
||||||
|
else:
|
||||||
|
current = self.__root
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
parent = current
|
||||||
|
|
||||||
|
# If the currently selected node has a greater value than the newly created node, move left to a smaller valued node
|
||||||
|
if node.data < current.data:
|
||||||
|
current = current.left
|
||||||
|
|
||||||
|
# If there is no node to the left, insert the newly made node!
|
||||||
|
if current == None:
|
||||||
|
parent.left = node
|
||||||
|
return self
|
||||||
|
# Do the same thing but to the right if the selected node has a lesser value than the newly created node.
|
||||||
|
else:
|
||||||
|
current = current.right
|
||||||
|
|
||||||
|
if current == None:
|
||||||
|
parent.right = node
|
||||||
|
return self
|
||||||
|
|
||||||
|
def getNodeWithParent(self, data: T) -> Tuple[Node[T], Node[T]]:
|
||||||
|
"""Find a node containing the data point, and return it alongside its parent. Returns (parent, child)"""
|
||||||
|
parent = None
|
||||||
|
current = self.__root
|
||||||
|
|
||||||
|
# If there is no root node, there is also no parent node
|
||||||
|
if current == None:
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# If the node containing the data has been found, return the (parent, child) pair!
|
||||||
|
if current.data == data:
|
||||||
|
return (parent, current)
|
||||||
|
# If the selected node has a greater value than the one being searched for, traverse left!
|
||||||
|
elif current.data > data:
|
||||||
|
parent = current
|
||||||
|
current = current.left
|
||||||
|
# Otherwise, traverse right!
|
||||||
|
else:
|
||||||
|
parent = current
|
||||||
|
current = current.right
|
||||||
|
|
||||||
|
def remove(self, data: T) -> BST[T]:
|
||||||
|
parent, node = self.getNodeWithParent(data)
|
||||||
|
|
||||||
|
# If there is no node with that data, just do nothing
|
||||||
|
if parent == None and node == None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
# Determine the amount of children that the node has
|
||||||
|
childrenCount = 0
|
||||||
|
|
||||||
|
if node.left and node.right:
|
||||||
|
childrenCount = 2
|
||||||
|
elif (node.left == None) and (node.rightChild == None):
|
||||||
|
childrenCount = 0
|
||||||
|
else:
|
||||||
|
childrenCount = 1
|
||||||
|
|
||||||
|
# Remove the node from the tree
|
||||||
|
if childrenCount == 0:
|
||||||
|
if parent:
|
||||||
|
if parent.right == node:
|
||||||
|
parent.right = None
|
||||||
|
else:
|
||||||
|
parent.left = None
|
||||||
|
else:
|
||||||
|
self.__root = None
|
||||||
|
elif childrenCount == 1:
|
||||||
|
nextNode = None
|
||||||
|
|
||||||
|
if node.left:
|
||||||
|
nextNode = node.left
|
||||||
|
else:
|
||||||
|
nextNode = node.right
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
if parent.left == node:
|
||||||
|
parent.left = nextNode
|
||||||
|
else:
|
||||||
|
parent.right = nextNode
|
||||||
|
else:
|
||||||
|
self.__root = nextNode
|
||||||
|
else:
|
||||||
|
leftmostParent = node
|
||||||
|
leftmostNode = node.right
|
||||||
|
|
||||||
|
while leftmostNode.left:
|
||||||
|
leftmostParent = leftmostNode
|
||||||
|
leftmostNode = leftmostNode.left
|
||||||
|
|
||||||
|
node.data = leftmostNode.data
|
||||||
|
|
||||||
|
if leftmostParent.left == leftmostNode:
|
||||||
|
leftmostParent.left = leftmostNode.rightChild
|
||||||
|
else:
|
||||||
|
leftmostNode.rightChild = leftmostNode.rightChild
|
||||||
|
|
||||||
|
def search(self, data: T) -> T:
|
||||||
|
"""Search through the binary tree. Returns the data value if found, otherwise returns None."""
|
||||||
|
current = self.__root
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# If the final node has been reached, return None
|
||||||
|
if current == None:
|
||||||
|
return None
|
||||||
|
# If the node has been found, return the data!
|
||||||
|
elif current.data == data:
|
||||||
|
return data
|
||||||
|
# If the currently selected node has a higher value than the data being searched for, traverse left
|
||||||
|
elif current.data > data:
|
||||||
|
current = current.left
|
||||||
|
# Otherwise, traverse right
|
||||||
|
else:
|
||||||
|
current = current.right
|
||||||
|
|
||||||
|
def rootNode(self) -> Node[T]:
|
||||||
|
return self.__root
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def inOrder(root: Node[T] | BST[T]) -> List[T]:
|
||||||
|
if isinstance(root, BST):
|
||||||
|
root = root.rootNode()
|
||||||
|
|
||||||
|
out = []
|
||||||
|
|
||||||
|
if root:
|
||||||
|
out = BST.inOrder(root.left)
|
||||||
|
out.append(root.data)
|
||||||
|
out = out + BST.inOrder(root.right)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def preOrder(root: Node[T] | BST[T]) -> List[T]:
|
||||||
|
if isinstance(root, BST):
|
||||||
|
root = root.rootNode()
|
||||||
|
|
||||||
|
out = []
|
||||||
|
|
||||||
|
if root:
|
||||||
|
out.append(root.data)
|
||||||
|
out = out + BST.preOrder(root.left)
|
||||||
|
out = out + BST.preOrder(root.right)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def postOrder(root: Node[T] | BST[T]) -> List[T]:
|
||||||
|
if isinstance(root, BST):
|
||||||
|
root = root.rootNode()
|
||||||
|
|
||||||
|
out =[]
|
||||||
|
|
||||||
|
if root:
|
||||||
|
out = BST.postOrder(root.left)
|
||||||
|
out = out + BST.postOrder(root.right)
|
||||||
|
out.append(root.data)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
tree = BST[int]()
|
||||||
|
|
||||||
|
tree.insert(12).insert(14).insert(8).insert(2).insert(8).insert(7).insert(23).insert(19).insert(6).insert(22)
|
||||||
|
|
||||||
|
print(tree.postOrder(tree.rootNode()))
|
|
@ -0,0 +1,171 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Generic, TypeVar, Tuple
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Node(Generic[T]):
|
||||||
|
data: T
|
||||||
|
leftChild: Node[T] = None
|
||||||
|
rightChild: Node[T] = None
|
||||||
|
|
||||||
|
class BinarySearchTree(Generic[T]):
|
||||||
|
"""Full implementation of a Binary Search Tree"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.__rootNode: Node[T] = None
|
||||||
|
|
||||||
|
def findMinimum(self) -> Node[T]:
|
||||||
|
"""Find the minimum node in the tree."""
|
||||||
|
current = self.__rootNode
|
||||||
|
|
||||||
|
# Keep traversing left when possible - smaller numbers will always be on the left!
|
||||||
|
while current.leftChild:
|
||||||
|
current = current.leftChild
|
||||||
|
|
||||||
|
return current
|
||||||
|
|
||||||
|
def findMaximum(self) -> Node[T]:
|
||||||
|
"""Find the maximum node in the tree."""
|
||||||
|
current = self.__rootNode
|
||||||
|
|
||||||
|
# Keep traversing right when possible - larger numbers will always be on the right!
|
||||||
|
while current.rightChild:
|
||||||
|
current = current.rightChild
|
||||||
|
|
||||||
|
return current
|
||||||
|
|
||||||
|
def insert(self, data: T) -> BinarySearchTree[T]:
|
||||||
|
"""Inserts a new piece of data into the tree."""
|
||||||
|
node = Node(data)
|
||||||
|
|
||||||
|
if self.__rootNode == None:
|
||||||
|
# Ensure there is a root node in the first place!
|
||||||
|
self.__rootNode = node
|
||||||
|
return self
|
||||||
|
else:
|
||||||
|
current = self.__rootNode
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
parent = current
|
||||||
|
|
||||||
|
# If the currently selected node has a greater value than the newly created node, move left to a smaller valued node
|
||||||
|
if node.data < current.data:
|
||||||
|
current = current.leftChild
|
||||||
|
|
||||||
|
# If there is no node to the left, insert the newly made node!
|
||||||
|
if current == None:
|
||||||
|
parent.leftChild = node
|
||||||
|
return self
|
||||||
|
# Do the same thing but to the right if the selected node has a lesser value than the newly created node.
|
||||||
|
else:
|
||||||
|
current = current.rightChild
|
||||||
|
|
||||||
|
if current == None:
|
||||||
|
parent.rightChild = node
|
||||||
|
return self
|
||||||
|
|
||||||
|
def getNodeWithParent(self, data: T) -> Tuple[Node[T], Node[T]]:
|
||||||
|
"""Find a node containing the data point, and return it alongside its parent. Returns (parent, child)"""
|
||||||
|
parent = None
|
||||||
|
current = self.__rootNode
|
||||||
|
|
||||||
|
# If there is no root node, there is also no parent node
|
||||||
|
if current == None:
|
||||||
|
return (None, None)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# If the node containing the data has been found, return the (parent, child) pair!
|
||||||
|
if current.data == data:
|
||||||
|
return (parent, current)
|
||||||
|
# If the selected node has a greater value than the one being searched for, traverse left!
|
||||||
|
elif current.data > data:
|
||||||
|
parent = current
|
||||||
|
current = current.leftChild
|
||||||
|
# Otherwise, traverse right!
|
||||||
|
else:
|
||||||
|
parent = current
|
||||||
|
current = current.rightChild
|
||||||
|
|
||||||
|
def remove(self, data: T) -> BinarySearchTree[T]:
|
||||||
|
parent, node = self.getNodeWithParent(data)
|
||||||
|
|
||||||
|
# If there is no node with that data, just do nothing
|
||||||
|
if parent == None and node == None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
# Determine the amount of children that the node has
|
||||||
|
childrenCount = 0
|
||||||
|
|
||||||
|
if node.leftChild and node.rightChild:
|
||||||
|
childrenCount = 2
|
||||||
|
elif (node.leftChild == None) and (node.rightChild == None):
|
||||||
|
childrenCount = 0
|
||||||
|
else:
|
||||||
|
childrenCount = 1
|
||||||
|
|
||||||
|
# Remove the node from the tree
|
||||||
|
if childrenCount == 0:
|
||||||
|
if parent:
|
||||||
|
if parent.rightChild == node:
|
||||||
|
parent.rightChild = None
|
||||||
|
else:
|
||||||
|
parent.leftChild = None
|
||||||
|
else:
|
||||||
|
self.__rootNode = None
|
||||||
|
elif childrenCount == 1:
|
||||||
|
nextNode = None
|
||||||
|
|
||||||
|
if node.leftChild:
|
||||||
|
nextNode = node.leftChild
|
||||||
|
else:
|
||||||
|
nextNode = node.rightChild
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
if parent.leftChild == node:
|
||||||
|
parent.leftChild = nextNode
|
||||||
|
else:
|
||||||
|
parent.rightChild = nextNode
|
||||||
|
else:
|
||||||
|
self.__rootNode = nextNode
|
||||||
|
else:
|
||||||
|
leftmostParent = node
|
||||||
|
leftmostNode = node.rightChild
|
||||||
|
|
||||||
|
while leftmostNode.leftChild:
|
||||||
|
leftmostParent = leftmostNode
|
||||||
|
leftmostNode = leftmostNode.leftChild
|
||||||
|
|
||||||
|
node.data = leftmostNode.data
|
||||||
|
|
||||||
|
if leftmostParent.leftChild == leftmostNode:
|
||||||
|
leftmostParent.leftChild = leftmostNode.rightChild
|
||||||
|
else:
|
||||||
|
leftmostNode.rightChild = leftmostNode.rightChild
|
||||||
|
|
||||||
|
def search(self, data: T) -> T:
|
||||||
|
"""Search through the binary tree. Returns the data value if found, otherwise returns None."""
|
||||||
|
current = self.__rootNode
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# If the final node has been reached, return None
|
||||||
|
if current == None:
|
||||||
|
return None
|
||||||
|
# If the node has been found, return the data!
|
||||||
|
elif current.data == data:
|
||||||
|
return data
|
||||||
|
# If the currently selected node has a higher value than the data being searched for, traverse left
|
||||||
|
elif current.data > data:
|
||||||
|
current = current.leftChild
|
||||||
|
# Otherwise, traverse right
|
||||||
|
else:
|
||||||
|
current = current.rightChild
|
||||||
|
|
||||||
|
tree = BinarySearchTree[int]()
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
tree.insert(i)
|
||||||
|
found = tree.search(i)
|
||||||
|
print(found)
|
|
@ -0,0 +1,39 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Node:
|
||||||
|
character: str = None
|
||||||
|
frequency: int = None
|
||||||
|
left: Node = None
|
||||||
|
right: Node = None
|
||||||
|
|
||||||
|
def buildTree(message: str):
|
||||||
|
frequencies = { k: v for k, v in sorted([(i, message.count(i)) for i in set(message)], key = lambda x: x[1], reverse = True )}
|
||||||
|
frequencies = list(frequencies.items())
|
||||||
|
|
||||||
|
subtrees = Queue()
|
||||||
|
|
||||||
|
for i in range(len(frequencies)):
|
||||||
|
subtree = Node(None, sum(map(lambda x: x[1], frequencies[i:])))
|
||||||
|
subtree.right = Node(frequencies[i][0], frequencies[i][1])
|
||||||
|
subtrees.put(subtree)
|
||||||
|
|
||||||
|
tree = subtrees.get()
|
||||||
|
current = tree
|
||||||
|
|
||||||
|
for _ in range(subtrees.qsize()):
|
||||||
|
subtree = subtrees.get()
|
||||||
|
current.left = subtree
|
||||||
|
current = current.left
|
||||||
|
|
||||||
|
return tree
|
||||||
|
|
||||||
|
def encode(message: str):
|
||||||
|
tree = buildTree(message)
|
||||||
|
print(tree)
|
||||||
|
frequencies = { i: message.count(i) for i in set(message) }
|
||||||
|
frequencies = { k: v for k, v in sorted(frequencies.items(), key = lambda x: x[1] )}
|
||||||
|
|
||||||
|
print(encode("Hello World"))
|
|
@ -192,7 +192,7 @@ class LinkedList(Generic[T]):
|
||||||
|
|
||||||
return out + "]"
|
return out + "]"
|
||||||
|
|
||||||
names = LinkedList[str](["Harold", "Janet"])
|
names = LinkedList[str](["John Doe", "Jane Doe"])
|
||||||
names.extend(["Alfred", "Sophie"]).insert(1, "John Snow")
|
names.extend(["Alfred", "Sophie"]).insert(1, "John Snow")
|
||||||
names.remove("Alfred")
|
names.remove("Alfred")
|
||||||
names += "Woody"
|
names += "Woody"
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# node -> (character, frequency, left, right)
|
||||||
|
import queue,operator;b=lambda m:(f:={i:m.count(i)for i in set(m)},f:={k:v for(k,v)in sorted(f.items(),key=lambda x:x[1],reverse=True)},f:=list(f.items()),s:=queue.Queue(),[s.put([None,sum(map(lambda x:x[1],f[i:])),None,[f[i][0],f[i][1],None,None]])for i in range(len(f))],t:=s.get(),c:=t,[(operator.setitem(c,2,s.get()),c:=c[2])for _ in range(s.qsize())],t)[8]
|
||||||
|
print(b("Hello World"))
|
|
@ -27,12 +27,13 @@ class CashRegister:
|
||||||
|
|
||||||
for coinType in self.__coins:
|
for coinType in self.__coins:
|
||||||
# Set an initial value for the change
|
# Set an initial value for the change
|
||||||
if changeValue - coinType > 0:
|
if changeValue - coinType >= 0:
|
||||||
change[coinType] = 0
|
change[coinType] = 0
|
||||||
|
|
||||||
# Keep attempting to provide change from the tray until we overpay
|
# Keep attempting to provide change from the tray until we overpay
|
||||||
while changeValue - coinType > 0:
|
while changeValue - coinType >= 0:
|
||||||
changeValue -= coinType
|
changeValue -= coinType
|
||||||
|
changeValue = round(changeValue, 2)
|
||||||
self.__coins[coinType] -= 1
|
self.__coins[coinType] -= 1
|
||||||
change[coinType] += 1
|
change[coinType] += 1
|
||||||
|
|
||||||
|
@ -44,4 +45,4 @@ print(
|
||||||
register.checkout(5.99, {
|
register.checkout(5.99, {
|
||||||
10: 1
|
10: 1
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
30
school/a-level/Y13 2021-2023/LMC/LMC Higher or Lower.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
INP
|
||||||
|
STA toGuess
|
||||||
|
|
||||||
|
loop INP
|
||||||
|
STA guess
|
||||||
|
|
||||||
|
LDA toGuess
|
||||||
|
SUB guess
|
||||||
|
|
||||||
|
BRZ equal
|
||||||
|
BRP small
|
||||||
|
BRA big
|
||||||
|
|
||||||
|
small LDA higher
|
||||||
|
OUT
|
||||||
|
BRA loop
|
||||||
|
|
||||||
|
big LDA lower
|
||||||
|
OUT
|
||||||
|
BRA loop
|
||||||
|
|
||||||
|
equal LDA win
|
||||||
|
OUT
|
||||||
|
HLT
|
||||||
|
|
||||||
|
toGuess DAT
|
||||||
|
guess DAT
|
||||||
|
higher DAT 1
|
||||||
|
lower DAT 0
|
||||||
|
win DAT 9
|
22
school/a-level/Y13 2021-2023/LMC/LMC Triangular numbers.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
INP
|
||||||
|
STA quant
|
||||||
|
|
||||||
|
loop LDA number
|
||||||
|
ADD counter
|
||||||
|
OUT
|
||||||
|
STA number
|
||||||
|
|
||||||
|
LDA counter
|
||||||
|
ADD one
|
||||||
|
STA counter
|
||||||
|
|
||||||
|
LDA quant
|
||||||
|
SUB counter
|
||||||
|
|
||||||
|
BRP loop
|
||||||
|
HLT
|
||||||
|
|
||||||
|
quant DAT
|
||||||
|
counter DAT 1
|
||||||
|
number DAT 0
|
||||||
|
one DAT 1
|
|
@ -1,41 +1,41 @@
|
||||||
# Operating Systems
|
# Operating Systems
|
||||||
|
|
||||||
## The Kernel
|
## The Kernel
|
||||||
|
|
||||||
The kernel is the central module of an OS. It is the part of the operating system that loads first, and it remains in memory - usually in a protected area. Typically, it is responsible for management of the CPU and memory.
|
The kernel is the central module of an OS. It is the part of the operating system that loads first, and it remains in memory - usually in a protected area. Typically, it is responsible for management of the CPU and memory.
|
||||||
|
|
||||||
The kernel connects the system hardware to the application software. The Linux kernel is used in numerous operating systems including Android, Ubuntu, and firmware for devices such as routers.
|
The kernel connects the system hardware to the application software. The Linux kernel is used in numerous operating systems including Android, Ubuntu, and firmware for devices such as routers.
|
||||||
|
|
||||||
## Types of Operating Systems
|
## Types of Operating Systems
|
||||||
|
|
||||||
### Single User - Single Application
|
### Single User - Single Application
|
||||||
|
|
||||||
Only has to deal with one person running one application at a time. For example, a Nokia brick.
|
Only has to deal with one person running one application at a time. For example, a Nokia brick.
|
||||||
|
|
||||||
### Single User - Multi-application
|
### Single User - Multi-application
|
||||||
|
|
||||||
Only has to deal with one person, but must be able to handle running multiple applications concurrently. For example, Android tablets.
|
Only has to deal with one person, but must be able to handle running multiple applications concurrently. For example, Android tablets.
|
||||||
|
|
||||||
### Multi-user - Multi-tasking
|
### Multi-user - Multi-tasking
|
||||||
|
|
||||||
Must be able to handle multiple users running multiple applications concurrently. For example, Windows as you can stay logged in as many different users who have different states on the computer simultaneously.
|
Must be able to handle multiple users running multiple applications concurrently. For example, Windows as you can stay logged in as many different users who have different states on the computer simultaneously.
|
||||||
|
|
||||||
### Real-Time
|
### Real-Time
|
||||||
|
|
||||||
Real-Time operating systems must process tasks in a set time which is critical to it's operation. These are not needed in computers, but may be needed in something like a car which has to react incredibly quickly to prevent accidents.
|
Real-Time operating systems must process tasks in a set time which is critical to it's operation. These are not needed in computers, but may be needed in something like a car which has to react incredibly quickly to prevent accidents.
|
||||||
|
|
||||||
### Batch-Op
|
### Batch-Op
|
||||||
|
|
||||||
A batch is a small job repeated many times. For each iteration, a small change is made to the data; for example, printing gas bills/bank statements. They are designed to be left running with little user interactions.
|
A batch is a small job repeated many times. For each iteration, a small change is made to the data; for example, printing gas bills/bank statements. They are designed to be left running with little user interactions.
|
||||||
|
|
||||||
## Process Manager
|
## Process Manager
|
||||||
|
|
||||||
The process manager is a part of the kernel. Jobs can consist of many processes (one-to-many). This is the job of the process scheduler.
|
The process manager is a part of the kernel. Jobs can consist of many processes (one-to-many). This is the job of the process scheduler.
|
||||||
|
|
||||||
### Process States
|
### Process States
|
||||||
|
|
||||||
- HOLD
|
- HOLD
|
||||||
- READY
|
- READY
|
||||||
- RUNNING
|
- RUNNING
|
||||||
- WAIT
|
- WAIT
|
||||||
- FINISHED/FAIL
|
- FINISHED/FAIL
|
||||||
|
|