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
|
||||||
|
|
||||||
|
|
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
|