chore(school): a level dump again
This commit is contained in:
parent
268b752fef
commit
c157b419b1
23 changed files with 1225 additions and 14 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -21,5 +21,7 @@ _deps
|
|||
bin
|
||||
ignored
|
||||
|
||||
maths/**/*.pdf
|
||||
maths/**/*.synctex.gz
|
||||
*.docx
|
||||
*.pptx
|
||||
*.doc
|
||||
*.pdf
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
from tkinter import *
|
||||
|
||||
def addCat(event):
|
||||
global cat
|
||||
cat = cat + 1
|
||||
updateDisplay()
|
||||
|
||||
def addDog(event):
|
||||
global dog
|
||||
dog += 1
|
||||
updateDisplay()
|
||||
|
||||
def resetCat(event, update = True):
|
||||
global cat
|
||||
cat = 0
|
||||
|
||||
if update: updateDisplay()
|
||||
|
||||
def resetDog(event, update = True):
|
||||
global dog
|
||||
dog = 0
|
||||
|
||||
if update: updateDisplay()
|
||||
|
||||
def reset(event):
|
||||
resetCat(False)
|
||||
resetDog(False)
|
||||
|
||||
updateDisplay()
|
||||
|
||||
def updateDisplay():
|
||||
global cat, dog
|
||||
|
||||
cats = f'{cat} ' + ('cat' if cat == 1 else 'cats')
|
||||
dogs = f'{dog} ' + ('dog' if dog == 1 else 'dogs')
|
||||
isAre = 'is' if cat == 1 else 'are'
|
||||
|
||||
outputLabel.configure(text = f'There {isAre} {cats}, and {dogs}.')
|
||||
|
||||
cat = 0
|
||||
dog = 0
|
||||
|
||||
window = Tk("Cat or Dog")
|
||||
|
||||
topFrame = Frame(window)
|
||||
topFrame.pack()
|
||||
|
||||
bottomFrame = Frame(window)
|
||||
bottomFrame.pack(side = BOTTOM, pady = 10)
|
||||
|
||||
welcome = Label(topFrame, fg="red", font=("Helvetica", 16), text = "Welcome to Cat or Dog Selector")
|
||||
welcome.pack()
|
||||
|
||||
outputLabel = Label(topFrame, text = "0")
|
||||
outputLabel.pack()
|
||||
|
||||
catButton = Button(bottomFrame, text='Cat')
|
||||
catButton.bind("<1>", addCat)
|
||||
catButton.bind("<3>", resetCat)
|
||||
catButton.grid(row = 0, column = 0, padx = 10)
|
||||
|
||||
dogButton = Button(bottomFrame, text='Dog')
|
||||
dogButton.bind("<1>", addDog)
|
||||
dogButton.bind("<3>", resetDog)
|
||||
dogButton.grid(row = 0, column = 2, padx = 20)
|
||||
|
||||
resetButton = Button(bottomFrame, text='Reset', bg='#000000', fg='#ffffff')
|
||||
resetButton.bind("<1>", reset)
|
||||
resetButton.grid(row = 0, column = 3)
|
||||
|
||||
updateDisplay()
|
||||
|
||||
window.mainloop()
|
81
school/a-level/Y12 2022-2024/GUI Programming/GUI Dice.py
Normal file
81
school/a-level/Y12 2022-2024/GUI Programming/GUI Dice.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
import tkinter as tk
|
||||
from tkinter.font import Font, BOLD
|
||||
from random import randint
|
||||
|
||||
class Window(tk.Tk):
|
||||
def __init__(self):
|
||||
tk.Tk.__init__(self)
|
||||
|
||||
self.sides = 6
|
||||
self.sum = 0
|
||||
self.geometry('500x500')
|
||||
self.updateTitle()
|
||||
|
||||
self.grid_rowconfigure(0, weight = 1)
|
||||
self.grid_columnconfigure(0, weight = 1)
|
||||
self.option_add('*font', Font(self, size = 12))
|
||||
self.tk_setPalette(background = 'white')
|
||||
|
||||
container = tk.Frame()
|
||||
container.grid(row = 0, column = 0, sticky = '')
|
||||
|
||||
sideController = tk.Frame(master=container)
|
||||
sideController.grid(row = 3, column = 0)
|
||||
|
||||
self.outputLabel = tk.Label(container, font=Font(self, size = 25, weight = BOLD))
|
||||
self.sumLabel = tk.Label(container, font=Font(self, size = 20))
|
||||
self.sidesLabel = tk.Label(sideController)
|
||||
|
||||
rollButton = tk.Button(container, text='Roll!')
|
||||
decrementSides = tk.Button(sideController, text = '←', borderwidth = 0)
|
||||
incrementSides = tk.Button(sideController, text = '→', borderwidth = 0)
|
||||
|
||||
self.outputLabel.grid(row = 0, column = 0, pady=(0, 20))
|
||||
self.updateOutput()
|
||||
|
||||
self.sumLabel.grid(row = 1, column = 0, pady=(0, 50))
|
||||
self.updateSum()
|
||||
|
||||
rollButton.bind("<1>", self.roll)
|
||||
rollButton.grid(row = 2, column = 0, pady=(0, 30))
|
||||
|
||||
decrementSides.bind("<1>", self.decrementSides)
|
||||
decrementSides.grid(row = 0, column = 0)
|
||||
|
||||
self.sidesLabel.grid(row = 0, column = 1)
|
||||
self.updateSides()
|
||||
|
||||
incrementSides.bind("<1>", self.incrementSides)
|
||||
incrementSides.grid(row = 0, column = 2)
|
||||
|
||||
def updateOutput(self, roll = 'N/A'):
|
||||
self.outputLabel.configure(text = roll)
|
||||
|
||||
def updateSum(self):
|
||||
self.sumLabel.configure(text = f'Sum: {self.sum}')
|
||||
|
||||
def roll(self, _):
|
||||
number = randint(1, self.sides)
|
||||
self.updateOutput(number)
|
||||
|
||||
def updateTitle(self):
|
||||
self.wm_title(f'{self.sides}-sided Dice')
|
||||
|
||||
def updateSides(self):
|
||||
self.sidesLabel.configure(text = self.sides)
|
||||
self.updateTitle()
|
||||
|
||||
def decrementSides(self, _):
|
||||
self.sides -= 1
|
||||
|
||||
if self.sides < 2:
|
||||
self.sides = 2
|
||||
|
||||
self.updateSides()
|
||||
|
||||
def incrementSides(self, _):
|
||||
self.sides += 1
|
||||
|
||||
self.updateSides()
|
||||
|
||||
Window().mainloop()
|
|
@ -1,5 +1,6 @@
|
|||
from time import sleep
|
||||
|
||||
# :eyes:
|
||||
def clearTerminal():
|
||||
print('\n' * 25)
|
||||
|
||||
|
@ -26,25 +27,27 @@ def findPrimes(upperBound: int):
|
|||
|
||||
return primes
|
||||
|
||||
possiblePrimes = findPrimes(1_000_000)
|
||||
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 askForPrime():
|
||||
global possiblePrimes, 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 possiblePrimes:
|
||||
elif value not in POSSIBLE_PRIMES:
|
||||
raise ValueError('That is not a prime number! Please try again.')
|
||||
elif value in inputtedPrimes:
|
||||
elif value in primeList:
|
||||
raise ValueError('You have already inputted that prime number! Please enter a different one.')
|
||||
|
||||
return inputtedPrimes.append(value)
|
||||
# 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:
|
||||
|
@ -69,14 +72,19 @@ What would you like to do?
|
|||
|
||||
break
|
||||
except ValueError:
|
||||
print("Please enter a valid integer that is at most six digits long.")
|
||||
print("Please enter a valid option from the list (1-3)")
|
||||
|
||||
clearTerminal()
|
||||
|
||||
if choice == 1:
|
||||
askForPrime()
|
||||
inputtedPrimes = getPrime(inputtedPrimes)
|
||||
elif choice == 2:
|
||||
print(', '.join(map(lambda x: str(x), inputtedPrimes)))
|
||||
# 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()
|
|
@ -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,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,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)
|
89
school/a-level/Y12 2022-2024/Logic/Custom Expressions.py
Normal file
89
school/a-level/Y12 2022-2024/Logic/Custom Expressions.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
from enum import Enum
|
||||
from typing import Tuple, List
|
||||
|
||||
class Gate(Enum):
|
||||
AND = '^'
|
||||
OR = '∨'
|
||||
XOR = '⊕'
|
||||
NAND = '↑'
|
||||
NOR = '↓'
|
||||
XNOR = '⊙'
|
||||
|
||||
class Symbol:
|
||||
def __init__(self, character):
|
||||
self.char = character
|
||||
|
||||
def __str__(self):
|
||||
return self.char
|
||||
|
||||
class Expression:
|
||||
def __init__(self, symbol):
|
||||
self.tree: List[Tuple[Gate, Expression]] = []
|
||||
self.initialSymbol = symbol
|
||||
|
||||
def AND(self, symbol):
|
||||
self.tree.append((Gate.AND, symbol))
|
||||
return self
|
||||
|
||||
def OR(self, symbol):
|
||||
self.tree.append((Gate.OR, symbol))
|
||||
return self
|
||||
|
||||
def XOR(self, symbol):
|
||||
self.tree.append((Gate.XOR, symbol))
|
||||
return self
|
||||
|
||||
def NAND(self, symbol):
|
||||
self.tree.append((Gate.NAND, symbol))
|
||||
return self
|
||||
|
||||
def NOR(self, symbol):
|
||||
self.tree.append((Gate.NOR, symbol))
|
||||
return self
|
||||
|
||||
def XNOR(self, symbol):
|
||||
self.tree.append((Gate.XNOR, symbol))
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def treeSymbols(tree):
|
||||
symbols = set([])
|
||||
|
||||
for _, value in tree:
|
||||
if isinstance(value, Expression):
|
||||
if str(value.initialSymbol) not in symbols:
|
||||
symbols.add(str(value.initialSymbol))
|
||||
symbols.update(Expression.treeSymbols(value.tree))
|
||||
elif str(value) not in symbols:
|
||||
symbols.add(str(value))
|
||||
|
||||
return symbols
|
||||
|
||||
|
||||
def compile(self):
|
||||
# Count symbols
|
||||
symbols = Expression.treeSymbols(self.tree)
|
||||
|
||||
def run(*values):
|
||||
for gate, value in self._tree:
|
||||
|
||||
def __str__(self):
|
||||
out = str(self.initialSymbol)
|
||||
|
||||
for gate, value in self.tree:
|
||||
if isinstance(value, Expression) and len(value.tree) > 0:
|
||||
expression = f'({value})'
|
||||
else:
|
||||
expression = str(value)
|
||||
|
||||
out += f' {gate.value} {expression}'
|
||||
|
||||
return out
|
||||
|
||||
A = Symbol('A')
|
||||
B = Symbol('B')
|
||||
C = Symbol('C')
|
||||
D = Symbol('D')
|
||||
# A.AND(B).execute()
|
||||
|
||||
Expression(A).AND(Expression(B).AND(A)).OR(Expression(C).XOR(Expression(A).OR(D))).compile()
|
30
school/a-level/Y12 2022-2024/Logic/Framework.py
Normal file
30
school/a-level/Y12 2022-2024/Logic/Framework.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
from __future__ import annotations
|
||||
from enum import Enum
|
||||
|
||||
class Gate(Enum):
|
||||
AND = '^'
|
||||
OR = '∨'
|
||||
XOR = '⊕'
|
||||
NAND = '↑'
|
||||
NOR = '↓'
|
||||
XNOR = '⊙'
|
||||
|
||||
class Symbol():
|
||||
def __init__(self, symbol, initialValue):
|
||||
self._symbol = symbol
|
||||
self._value = initialValue
|
||||
self._tree = []
|
||||
|
||||
def setValue(self, newValue):
|
||||
self._value = newValue
|
||||
return self
|
||||
|
||||
def AND(self, symbol: Symbol):
|
||||
self._tree.append((Gate.AND, symbol))
|
||||
return self
|
||||
|
||||
def compute():
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self._symbol
|
84
school/a-level/Y12 2022-2024/Logic/Full Adder.py
Normal file
84
school/a-level/Y12 2022-2024/Logic/Full Adder.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
from typing import List
|
||||
|
||||
def getInt():
|
||||
while True:
|
||||
try:
|
||||
value = int(input("Please enter a natural number: "))
|
||||
|
||||
return value
|
||||
except ValueError:
|
||||
print("Please enter a valid natural number.")
|
||||
|
||||
def getBin(x: int) -> List[int]:
|
||||
return list(map(lambda x: int(x), bin(abs(x))[2:]))
|
||||
|
||||
def twosComplementToInt(bits: List[int]) -> int:
|
||||
sum = 0 if bits[0] == 0 else -(2 ** (len(bits) - 1))
|
||||
del bits[0]
|
||||
bits.reverse()
|
||||
|
||||
for i in range(len(bits)):
|
||||
if bits[i] == 1:
|
||||
sum += 2 ** i
|
||||
|
||||
return sum
|
||||
|
||||
def add(x: int, y: int) -> int:
|
||||
bits = max(len(bin(x)[2:]), len(bin(y)[2:])) + 1
|
||||
mask = int("1" * bits, 2)
|
||||
xBin = list(map(lambda x: int(x), ("0" if x >= 0 else "1") + bin(x & mask)[2:]))
|
||||
yBin = list(map(lambda x: int(x), ("0" if y >= 0 else "1") + bin(y & mask)[2:]))
|
||||
|
||||
print(xBin, yBin)
|
||||
|
||||
# Pad the shortner binary number
|
||||
while len(xBin) < bits:
|
||||
xBin.insert(0, 0)
|
||||
while len(yBin) < bits:
|
||||
yBin.insert(0, 0)
|
||||
|
||||
# We add from right to left
|
||||
xBin.reverse(); yBin.reverse()
|
||||
|
||||
# Iteratively apply the full adder
|
||||
cout = 0
|
||||
outBin = []
|
||||
|
||||
for a, b in zip(xBin, yBin):
|
||||
sum = cout ^ (a ^ b)
|
||||
cout = (a & b) | (cout & ((~a & b) | (a & ~b)))
|
||||
outBin.append(sum)
|
||||
|
||||
if x > 0 and y > 0: outBin.append(cout)
|
||||
|
||||
# We read from left to right
|
||||
outBin.reverse()
|
||||
print(outBin)
|
||||
|
||||
return twosComplementToInt(outBin)
|
||||
|
||||
def subtract(x: int, y: int) -> int:
|
||||
return add(x, -y)
|
||||
|
||||
def multiply(x: int, y: int) -> int:
|
||||
if x == 1:
|
||||
return y
|
||||
elif x == -1:
|
||||
return -y
|
||||
elif y == 1:
|
||||
return x
|
||||
elif y == -1:
|
||||
return -x
|
||||
|
||||
sgn = -1 if (x > 0 and y < 0) or (y > 0 and x < 0) else 1
|
||||
product = 0
|
||||
|
||||
for num in [abs(x) for _ in range(abs(y))]:
|
||||
product = add(product, num)
|
||||
|
||||
return multiply(sgn, product)
|
||||
|
||||
x, y = getInt(), getInt()
|
||||
|
||||
# Compare the results
|
||||
print(x + y, add(x, y))
|
|
@ -0,0 +1,51 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Dict, List
|
||||
|
||||
class VariableMismatchError(Exception):
|
||||
pass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Node:
|
||||
"""Represents a row of a truth table"""
|
||||
variables: Dict[str, bool]
|
||||
value: bool
|
||||
|
||||
class KMap:
|
||||
def __init__(self, variables: List[str]):
|
||||
self.__nodes: List[Node] = []
|
||||
self.__variables = variables
|
||||
|
||||
def addNode(self, node: Node):
|
||||
variableCount = len(self.__variables)
|
||||
nodeVariableCount = len(node.variables.keys())
|
||||
|
||||
if variableCount < nodeVariableCount:
|
||||
raise VariableMismatchError(f"You tried assigning a node with {nodeVariableCount} variables to a K-Map that supports {variableCount} variables.")
|
||||
|
||||
for variable, _ in node.variables:
|
||||
if variable not in self.__variables:
|
||||
raise VariableMismatchError(f"{variable} is not a variable in this K-Map!")
|
||||
|
||||
self.__nodes.append(node)
|
||||
return self
|
||||
|
||||
map = [
|
||||
Node({
|
||||
"A": False,
|
||||
"B": False
|
||||
}, True),
|
||||
Node({
|
||||
"A": True,
|
||||
"B": False
|
||||
}, True),
|
||||
Node({
|
||||
"A": False,
|
||||
"B": True
|
||||
}, False),
|
||||
Node({
|
||||
"A": True,
|
||||
"B": True
|
||||
}, True),
|
||||
]
|
||||
|
||||
print(map)
|
Binary file not shown.
|
@ -82,10 +82,13 @@ print('-' * (len(header) - 15 - (8 * inputQuantity)))
|
|||
# Find the cartesian product to generate pairs
|
||||
# https://en.wikipedia.org/wiki/Cartesian_product
|
||||
sets = [(0, 1)] * inputQuantity
|
||||
print(sets)
|
||||
pairs = [[]]
|
||||
|
||||
for set in sets:
|
||||
pairs = [x+[y] for x in pairs for y in set]
|
||||
|
||||
print(pairs)
|
||||
|
||||
for i, pair in enumerate(pairs):
|
||||
print(formatString.format(red(i + 1), *pair, bold(applyGate(*pair))))
|
196
school/a-level/Y12 2022-2024/Storage/Pickle Shop.py
Normal file
196
school/a-level/Y12 2022-2024/Storage/Pickle Shop.py
Normal file
|
@ -0,0 +1,196 @@
|
|||
from __future__ import annotations
|
||||
from pickle import load, dump
|
||||
from dataclasses import dataclass
|
||||
from sys import path as sysPath
|
||||
from os.path import join as pathJoin, exists as pathExists
|
||||
from typing import List, Callable, TypeVar
|
||||
from time import sleep
|
||||
|
||||
class ExistsError(Exception):
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class Product:
|
||||
name: str
|
||||
price: float
|
||||
formatString = " {:^30} | {:^10} "
|
||||
currency = "£"
|
||||
|
||||
@staticmethod
|
||||
def format(product: Product, currency: str) -> str:
|
||||
return Product.formatString.format(product.name, f"{currency}{product.price:.2f}")
|
||||
|
||||
class Products:
|
||||
def __init__(self, friendlyName: str, currency: str = "£"):
|
||||
self.__products: List[Product] = []
|
||||
self.__file = self.getPath(friendlyName)
|
||||
self.__currency = currency
|
||||
|
||||
@staticmethod
|
||||
def getPath(friendlyName: str) -> str:
|
||||
return pathJoin(sysPath[0], f"{friendlyName}.products")
|
||||
|
||||
@staticmethod
|
||||
def From(friendlyName: str, currency: str = "£"):
|
||||
path = Products.getPath(friendlyName)
|
||||
|
||||
if not pathExists(path):
|
||||
return Products(friendlyName, currency)
|
||||
|
||||
with open(path, "rb") as f:
|
||||
data = load(f)
|
||||
products = Products(friendlyName, data["currency"])
|
||||
|
||||
for product in data["products"]:
|
||||
products.add(product)
|
||||
|
||||
return products
|
||||
|
||||
def __save(self) -> Products:
|
||||
"""Save all of the products to a file."""
|
||||
with open(self.__file, "wb") as f:
|
||||
dump({
|
||||
"products": self.__products,
|
||||
"currency": self.__currency
|
||||
}, f)
|
||||
|
||||
return self
|
||||
|
||||
def exists(self, name: str) -> Product:
|
||||
"""Checks if a product with that name already exists"""
|
||||
for product in self.__products:
|
||||
if product.name.lower() == name.lower():
|
||||
return product
|
||||
|
||||
return None
|
||||
|
||||
def setCurrency(self, currency: str) -> Products:
|
||||
self.__currency = currency
|
||||
return self.__save()
|
||||
|
||||
def add(self, product: Product) -> Products:
|
||||
"""Add a product to the list."""
|
||||
if self.exists(product.name):
|
||||
raise ExistsError(f"A product called {product.name} already exists!")
|
||||
|
||||
self.__products.append(product)
|
||||
return self.__save()
|
||||
|
||||
def remove(self, name: str) -> Products:
|
||||
"""Remove a product from the list"""
|
||||
for i, product in enumerate(self.__products):
|
||||
if product.name.lower() == name.lower():
|
||||
del self.__products[i]
|
||||
|
||||
return self.__save()
|
||||
|
||||
def clear(self) -> Products:
|
||||
"""Clear the list of products"""
|
||||
self.__products = []
|
||||
return self.__save()
|
||||
|
||||
def __str__(self) -> str:
|
||||
header = Product.formatString.format("Name", "Price")
|
||||
divider = "-" * len(header)
|
||||
out = f"{header}\n{divider}"
|
||||
|
||||
for product in self.__products:
|
||||
out += f"\n{Product.format(product, self.__currency)}"
|
||||
|
||||
return out
|
||||
|
||||
def __add__(self, product: Product) -> Products:
|
||||
return self.add(product)
|
||||
|
||||
def __getitem__(self, index: int) -> Product:
|
||||
return self.__products[index]
|
||||
|
||||
def __setitem__(self, index: int, product: Product):
|
||||
self.__products[index] = product
|
||||
self.__save()
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__products)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
def getInput(caster: Callable[[str], T], prompt: str, error: str, validator: Callable[[T], bool] = None) -> T:
|
||||
while True:
|
||||
try:
|
||||
value = caster(input(prompt))
|
||||
|
||||
if validator and validator(value):
|
||||
raise ValueError
|
||||
|
||||
return value
|
||||
except ValueError:
|
||||
print(error)
|
||||
|
||||
def getProduct() -> Product:
|
||||
name = input("Please enter a name for the product: ")
|
||||
price = getInput(float, "Please enter a price for the product: ", "Please ensure that your input was a valid float!", lambda x: x <= 0)
|
||||
|
||||
return Product(name, price)
|
||||
|
||||
def clear():
|
||||
print('\n' * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Load a product list
|
||||
name = input("Please enter the name of a list of products: ")
|
||||
products = Products.From(name.lower())
|
||||
|
||||
if len(products) == 0:
|
||||
print(f"Created new products list \"{name}\"")
|
||||
else:
|
||||
print(f"Loaded pre-existing product list \"{name}\"")
|
||||
|
||||
# Main menu loop
|
||||
while True:
|
||||
clear()
|
||||
print("""1) View the list of products
|
||||
2) Add a product
|
||||
3) Remove a product
|
||||
4) Update currency
|
||||
5) Clear the list of products
|
||||
6) Exit
|
||||
""")
|
||||
|
||||
choice = getInput(int, "What would you like to do? (1-5): ", "Please choose a valid option.", lambda x: x < 1 or x > 6)
|
||||
print()
|
||||
|
||||
if choice == 1:
|
||||
print(products)
|
||||
elif choice == 2:
|
||||
while True:
|
||||
try:
|
||||
product = getProduct()
|
||||
products.add(product)
|
||||
break
|
||||
except ExistsError:
|
||||
print("Please make sure the product's name is unique!")
|
||||
|
||||
print(f"Added product {product}")
|
||||
elif choice == 3:
|
||||
while True:
|
||||
name = input("Please enter the name of a product to remove: ")
|
||||
product = products.exists(name)
|
||||
|
||||
if product:
|
||||
break
|
||||
|
||||
print("Make sure you enter the name of a valid product!")
|
||||
|
||||
products.remove(name)
|
||||
print(f"Removed product {product}")
|
||||
elif choice == 4:
|
||||
currency = input("Please enter a new currency symbol: ")
|
||||
products.setCurrency(currency)
|
||||
print(f"Currency symbol updated to {currency}")
|
||||
elif choice == 5:
|
||||
products.clear()
|
||||
print("Cleared list of products.")
|
||||
elif choice == 6:
|
||||
exit()
|
||||
|
||||
sleep(1)
|
BIN
school/a-level/Y12 2022-2024/Storage/main.products
Normal file
BIN
school/a-level/Y12 2022-2024/Storage/main.products
Normal file
Binary file not shown.
|
@ -0,0 +1,92 @@
|
|||
from typing import Generic, TypeVar
|
||||
from math import ceil
|
||||
|
||||
K, V = TypeVar('K'), TypeVar('V')
|
||||
|
||||
class HashItem(Generic[K, V]):
|
||||
def __init__(self, key: K, value: V):
|
||||
self.key = key
|
||||
self.value = value
|
||||
|
||||
class HashTable(Generic[K, V]):
|
||||
def __init__(self):
|
||||
self.__size = 256
|
||||
self.__count = 0
|
||||
self.__slots: list[HashItem[K, V]] = [None for _ in range(self.__size)]
|
||||
|
||||
def __hash(self, key: K):
|
||||
multiplier = 1
|
||||
hashValue = 0
|
||||
|
||||
for character in key:
|
||||
hashValue += multiplier * ord(character)
|
||||
multiplier += 1
|
||||
|
||||
return hashValue % self.__size
|
||||
|
||||
def __filledSlots(self):
|
||||
return list(filter(lambda x: x is not None, self.__slots))
|
||||
|
||||
def __load(self):
|
||||
return len(list(self.__filledSlots())) / self.__size
|
||||
|
||||
def __grow(self, newSize: int):
|
||||
self.__slots += [None for _ in range(newSize - self.__size)]
|
||||
self.__size = newSize
|
||||
|
||||
def put(self, key: K, value: V):
|
||||
item = HashItem(key, value)
|
||||
hashValue = self.__hash(key)
|
||||
|
||||
while self.__slots[hashValue] != None:
|
||||
if self.__slots[hashValue].key == key:
|
||||
break
|
||||
|
||||
hashValue += 1
|
||||
hashValue %= self.__size
|
||||
|
||||
if self.__slots[hashValue] == None:
|
||||
self.__count += 1
|
||||
|
||||
# If the hash table is nearing its maximum load, increase the size of the hash table by 10%
|
||||
if self.__load() >= 0.75:
|
||||
self.__grow(ceil(self.__size * 1.1))
|
||||
|
||||
self.__slots[hashValue] = item
|
||||
|
||||
def get(self, key: K):
|
||||
hashValue = self.__hash(key)
|
||||
|
||||
for slot in self.__filledSlots():
|
||||
if hashValue == self.__hash(slot.key):
|
||||
return slot.value
|
||||
|
||||
return None
|
||||
|
||||
def __setitem__(self, key: K, value: V):
|
||||
self.put(key, value)
|
||||
|
||||
def __getitem__(self, key: K):
|
||||
return self.get(key)
|
||||
|
||||
def __str__(self):
|
||||
template = " {: ^10} | {: ^10}"
|
||||
out = template.format("Key", "Value")
|
||||
out += "\n" + ("-" * (len(out) // 2)) + "|" + ("-" * (len(out) // 2)) + "\n"
|
||||
|
||||
slots = self.__filledSlots()
|
||||
|
||||
for i, slot in enumerate(slots):
|
||||
out += template.format(slot.key, slot.value)
|
||||
|
||||
if i + 1 != len(slots):
|
||||
out += "\n"
|
||||
|
||||
return out
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__slots)
|
||||
|
||||
ages = HashTable[str, int]()
|
||||
ages["John Doe"] = 16
|
||||
print(ages)
|
|
@ -0,0 +1,201 @@
|
|||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Generic, TypeVar, Iterable, Union, List
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@dataclass
|
||||
class Node(Generic[T]):
|
||||
data: T
|
||||
next: Node[T] = None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self.data)
|
||||
|
||||
class LinkedList(Generic[T]):
|
||||
def __init__(self, initialValues: Iterable[T]):
|
||||
self.head: Node[T] = None
|
||||
self.tail: Node[T] = None
|
||||
|
||||
self.extend(initialValues)
|
||||
|
||||
def __iter__(self) -> Iterable[T]:
|
||||
"""Traverse the linked list."""
|
||||
node = self.head
|
||||
|
||||
while node is not None:
|
||||
yield node
|
||||
node = node.next
|
||||
|
||||
def __getitem__(self, index: int) -> Node[T]:
|
||||
"""Get an item by its index."""
|
||||
if index > len(self) - 1:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
for i, node in enumerate(self):
|
||||
if i == index:
|
||||
return node
|
||||
|
||||
def __setitem__(self, index: int, data: T):
|
||||
"""Set an item by its index."""
|
||||
if index > len(self) - 1:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
for i in range(len(self)):
|
||||
if i == index:
|
||||
self[i].data = data
|
||||
break
|
||||
|
||||
def __delitem__(self, index: int):
|
||||
"""Delete an item using its index."""
|
||||
if index > len(self) - 1:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
for i in range(len(self)):
|
||||
if i == index:
|
||||
for j in range(1, len(self) - i):
|
||||
self[i + j - 1] = self[i + j].data
|
||||
|
||||
self[len(self) - 2].next = None
|
||||
break
|
||||
|
||||
def __add__(self, data: Union[T, List[T], LinkedList[T]]) -> LinkedList[T]:
|
||||
copy = self.copy()
|
||||
|
||||
if isinstance(data, LinkedList) or type(data) == list:
|
||||
return copy.extend(iter(data) if type(data) == list else iter(map(lambda x: x.data, data)))
|
||||
else:
|
||||
return copy.append(data)
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Get the length of the linked list."""
|
||||
count = 0
|
||||
|
||||
for _ in self:
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
def append(self, value: T) -> LinkedList[T]:
|
||||
"""Append data to the end of the linked list."""
|
||||
node = Node(value)
|
||||
|
||||
if self.head is None:
|
||||
self.head = node
|
||||
return self
|
||||
|
||||
for currentNode in self:
|
||||
pass
|
||||
|
||||
currentNode.next = node
|
||||
|
||||
return self
|
||||
|
||||
def clear(self) -> LinkedList[T]:
|
||||
"""Clear the linked list."""
|
||||
self.head = None
|
||||
self.tail = None
|
||||
return self
|
||||
|
||||
def count(self, value: T) -> int:
|
||||
"""Count the number of occurrences of a value."""
|
||||
count = 0
|
||||
|
||||
for node in self:
|
||||
if node.data == value:
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
def extend(self, iterable: Iterable[T]) -> LinkedList[T]:
|
||||
"""Extend the list from an iterable."""
|
||||
for value in iterable:
|
||||
self.append(value)
|
||||
|
||||
return self
|
||||
|
||||
def index(self, value: T) -> int:
|
||||
"""Finds the first index of a value. Returns -1 if the value is not in the list."""
|
||||
for i, node in enumerate(self):
|
||||
if node.data == value:
|
||||
return i
|
||||
|
||||
return -1
|
||||
|
||||
def insert(self, index: int, value: T) -> LinkedList[T]:
|
||||
"""Inserts a value before an index."""
|
||||
if index > len(self) - 1:
|
||||
raise IndexError("Out of bounds")
|
||||
|
||||
for i in range(len(self)):
|
||||
if i == index:
|
||||
container = value
|
||||
|
||||
for j in range(len(self)):
|
||||
try:
|
||||
temp = self[i + j].data
|
||||
self[i + j].data = container
|
||||
container = temp
|
||||
except IndexError:
|
||||
self.append(container)
|
||||
|
||||
break
|
||||
|
||||
return self
|
||||
|
||||
def pop(self) -> Node[T]:
|
||||
"""Pop and return the final element of the list."""
|
||||
for node in self:
|
||||
pass
|
||||
|
||||
del self[len(self) - 1]
|
||||
|
||||
return node
|
||||
|
||||
def remove(self, value: T) -> LinkedList[T]:
|
||||
for i, node in enumerate(self):
|
||||
if node.data == value:
|
||||
del self[i]
|
||||
return self
|
||||
|
||||
raise ValueError("Value not found")
|
||||
|
||||
def copy(self) -> LinkedList[T]:
|
||||
"""Returns a copy of the list."""
|
||||
return LinkedList[T](iter(map(lambda x: x.data, self)))
|
||||
|
||||
def sort(self) -> LinkedList[T]:
|
||||
n = len(self)
|
||||
swapped = False
|
||||
|
||||
for i in range(n - 1):
|
||||
for j in range(0, n - i - 1):
|
||||
if self[j].data > self[j + 1].data:
|
||||
swapped = True
|
||||
self[j], self[j + 1] = self[j + 1].data, self[j].data
|
||||
|
||||
if not swapped:
|
||||
break
|
||||
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
out = "["
|
||||
|
||||
for i, node in enumerate(self):
|
||||
value = node.data
|
||||
|
||||
out += f'"{value}"' if type(value) == str else value
|
||||
|
||||
if i != len(self) - 1:
|
||||
out += ", "
|
||||
|
||||
return out + "]"
|
||||
|
||||
names = LinkedList[str](["Harold", "Janet"])
|
||||
names.extend(["Alfred", "Sophie"]).insert(1, "John Snow")
|
||||
names.remove("Alfred")
|
||||
names += "Woody"
|
||||
names.sort()
|
||||
|
||||
print(names)
|
Binary file not shown.
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
17,22,8,31,30,29,16,17,23,32
|
||||
23,6,25,44,19,21,8,18,29,41
|
|
Loading…
Reference in a new issue