feat: dump stuff from school again ig

This commit is contained in:
newt 2024-10-09 18:02:48 +01:00
parent c157b419b1
commit 090fd7caf4
46 changed files with 1662 additions and 45 deletions

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

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

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

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

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

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

View file

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

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

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

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

View file

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

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

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

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

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

View file

@ -0,0 +1,3 @@
exec(bytes('ⱩⱲⱺⱬⱧ㵡湩ⱴ慲杮ⱥ楢Ɱ敬Ɱ慬扭慤砠洬戬⠺㩹氽獩⡴慭⡰慬扭慤琠椺琨Ⱙ∨∰晩砨㴾⤰汥敳ㄢ⤢稫砨洦嬩㨲⥝Ⱙ祛椮獮牥⡴ⰰ⤰潦⁲ 湩爠ㄨ〰椩⁦⡬⥹戼ⱝ⥹せ孝㨺ㄭⱝ慬扭慤砠礬⠺㩢洽硡氨稨砨嬩㨲⥝氬稨礨嬩㨲⥝⬩ⰱ㩭椽∨∱截㈬Ⱙ㩰朽砨洬戬Ⱙ㩱朽礨洬戬Ⱙ㩷〽漬㴺⡛幷愨扞Ⱙ㩷⠽♡⥢⡼♷⠨慾戦簩愨縦⥢⤩嬩崰潦⡲ⱡ⥢湩稠灩瀨焬崩漬愮灰湥⡤⥷晩砨〾愩摮礨〾攩獬⡥Ⱙ㩯漽㩛ⴺ崱猬㴺‰晩漨せ㵝〽攩獬ⵥ㈨⨪氨漨⴩⤱Ⱙ㩯漽ㅛ㨺孝㨺ㄭⱝ獛㴺⭳㈨⨪⁩晩漨楛㵝ㄽ攩獬⁥⤰潦⡲⥩湩爠氨漨⤩孝ㄭ⥝ㅛ崰','u16')[2:])
print(a(5,-6))

Binary file not shown.

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,12 +27,13 @@ class CashRegister:
for coinType in self.__coins: for coinType in self.__coins:
# Set an initial value for the change # Set an initial value for the change
if changeValue - coinType > 0: if changeValue - coinType >= 0:
change[coinType] = 0 change[coinType] = 0
# Keep attempting to provide change from the tray until we overpay # Keep attempting to provide change from the tray until we overpay
while changeValue - coinType > 0: while changeValue - coinType >= 0:
changeValue -= coinType changeValue -= coinType
changeValue = round(changeValue, 2)
self.__coins[coinType] -= 1 self.__coins[coinType] -= 1
change[coinType] += 1 change[coinType] += 1
@ -44,4 +45,4 @@ print(
register.checkout(5.99, { register.checkout(5.99, {
10: 1 10: 1
}) })
) )

View 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

View 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

View file

@ -1,41 +1,41 @@
# Operating Systems # Operating Systems
## The Kernel ## The Kernel
The kernel is the central module of an OS. It is the part of the operating system that loads first, and it remains in memory - usually in a protected area. Typically, it is responsible for management of the CPU and memory. The kernel is the central module of an OS. It is the part of the operating system that loads first, and it remains in memory - usually in a protected area. Typically, it is responsible for management of the CPU and memory.
The kernel connects the system hardware to the application software. The Linux kernel is used in numerous operating systems including Android, Ubuntu, and firmware for devices such as routers. The kernel connects the system hardware to the application software. The Linux kernel is used in numerous operating systems including Android, Ubuntu, and firmware for devices such as routers.
## Types of Operating Systems ## Types of Operating Systems
### Single User - Single Application ### Single User - Single Application
Only has to deal with one person running one application at a time. For example, a Nokia brick. Only has to deal with one person running one application at a time. For example, a Nokia brick.
### Single User - Multi-application ### Single User - Multi-application
Only has to deal with one person, but must be able to handle running multiple applications concurrently. For example, Android tablets. Only has to deal with one person, but must be able to handle running multiple applications concurrently. For example, Android tablets.
### Multi-user - Multi-tasking ### Multi-user - Multi-tasking
Must be able to handle multiple users running multiple applications concurrently. For example, Windows as you can stay logged in as many different users who have different states on the computer simultaneously. Must be able to handle multiple users running multiple applications concurrently. For example, Windows as you can stay logged in as many different users who have different states on the computer simultaneously.
### Real-Time ### Real-Time
Real-Time operating systems must process tasks in a set time which is critical to it's operation. These are not needed in computers, but may be needed in something like a car which has to react incredibly quickly to prevent accidents. Real-Time operating systems must process tasks in a set time which is critical to it's operation. These are not needed in computers, but may be needed in something like a car which has to react incredibly quickly to prevent accidents.
### Batch-Op ### Batch-Op
A batch is a small job repeated many times. For each iteration, a small change is made to the data; for example, printing gas bills/bank statements. They are designed to be left running with little user interactions. A batch is a small job repeated many times. For each iteration, a small change is made to the data; for example, printing gas bills/bank statements. They are designed to be left running with little user interactions.
## Process Manager ## Process Manager
The process manager is a part of the kernel. Jobs can consist of many processes (one-to-many). This is the job of the process scheduler. The process manager is a part of the kernel. Jobs can consist of many processes (one-to-many). This is the job of the process scheduler.
### Process States ### Process States
- HOLD - HOLD
- READY - READY
- RUNNING - RUNNING
- WAIT - WAIT
- FINISHED/FAIL - FINISHED/FAIL