chore(school): a level dump again

This commit is contained in:
newt 2024-10-09 18:02:48 +01:00
parent 268b752fef
commit c157b419b1
23 changed files with 1225 additions and 14 deletions

6
.gitignore vendored
View file

@ -21,5 +21,7 @@ _deps
bin
ignored
maths/**/*.pdf
maths/**/*.synctex.gz
*.docx
*.pptx
*.doc
*.pdf

View file

@ -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()

View 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()

View file

@ -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()

View file

@ -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()

View file

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

View file

@ -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}""")

View file

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

View 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()

View 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

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

View file

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

View file

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

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

Binary file not shown.

View file

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

View file

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

View file

@ -1,2 +0,0 @@
17,22,8,31,30,29,16,17,23,32
23,6,25,44,19,21,8,18,29,41
1 17 22 8 31 30 29 16 17 23 32
2 23 6 25 44 19 21 8 18 29 41