added some stuff
This commit is contained in:
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"python.analysis.typeCheckingMode": "basic"
|
||||||
|
}
|
Binary file not shown.
@ -3,27 +3,27 @@ from dataclasses import dataclass, InitVar
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MyList[T]:
|
class MyList[T]:
|
||||||
internal_list: InitVar[list[T]]
|
_internal_list: InitVar[list[T]]
|
||||||
length: InitVar[int]
|
_length: InitVar[int]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.__internal_list = []
|
self.__internal_list: list[T] = []
|
||||||
self.__length = 0
|
self.__length = 0
|
||||||
|
|
||||||
def add(self, item: T):
|
def add(self, item: T) -> None:
|
||||||
self.__internal_list += [item]
|
self.__internal_list += [item]
|
||||||
self.__length += 1
|
self.__length += 1
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def length(self) -> int:
|
def length(self) -> int:
|
||||||
return self.__length
|
return self.__length
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GameObject:
|
class GameObject:
|
||||||
position: InitVar[tuple[int, int]]
|
_position: InitVar[tuple[int, int]]
|
||||||
|
|
||||||
def __post_init__(self, position: tuple[int, int]):
|
def __post_init__(self, position: tuple[int, int]) -> None:
|
||||||
assert (0, 0) <= position
|
assert (0, 0) <= position
|
||||||
self.__position = position
|
self.__position = position
|
||||||
|
|
||||||
@ -32,16 +32,17 @@ class GameObject:
|
|||||||
return self.__position
|
return self.__position
|
||||||
|
|
||||||
@position.setter
|
@position.setter
|
||||||
def position(self, position: tuple[int, int]):
|
def position(self, position: tuple[int, int]) -> None:
|
||||||
if (0, 0) > position:
|
if (0, 0) > position:
|
||||||
return
|
return
|
||||||
self.__position = position
|
self.__position = position
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
xs: MyList[int] = MyList()
|
xs: MyList[int] = MyList()
|
||||||
xs.add(100)
|
xs.add(100)
|
||||||
assert xs.length == 1
|
assert xs.length == 1
|
||||||
position = (0, 0)
|
position: tuple[int, int] = (0, 0)
|
||||||
my_obj = GameObject(position)
|
my_obj = GameObject(position)
|
||||||
assert my_obj.position == (0, 0)
|
assert my_obj.position == (0, 0)
|
||||||
try:
|
try:
|
||||||
@ -49,7 +50,7 @@ if __name__ == "__main__":
|
|||||||
except AssertionError:
|
except AssertionError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise AssertionError(f"{my_obj} should have thrown a assertation error")
|
raise AssertionError(
|
||||||
|
f"{my_obj} should have thrown a assertation error")
|
||||||
my_obj.position = (-1, 0)
|
my_obj.position = (-1, 0)
|
||||||
assert my_obj.position == (0, 0)
|
assert my_obj.position == (0, 0)
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
marp: true
|
||||||
|
paginate: true
|
||||||
|
class: invert
|
||||||
|
# theme: uncover
|
||||||
|
footer: Tutorium 10 - 22.12.2023 - Nils Pukropp - https://s.narl.io/s/tutorium-10
|
||||||
|
header:
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tutorium 10 - 22.12.2023
|
||||||
|
|
||||||
|
Weihnachtsaufgabe :)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Aufgabe - SpaceArena
|
||||||
|
|
||||||
|
26
Tutorium/tut10/src/main.py
Normal file
26
Tutorium/tut10/src/main.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from result import Err, Ok, Panick, Result
|
||||||
|
from ui import run_command, Color
|
||||||
|
from spacearena import Difficulty, SpaceArena
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
difficulty: Difficulty | None = None
|
||||||
|
while not difficulty:
|
||||||
|
difficulty = Difficulty.get_difficulty(
|
||||||
|
input(f"Choose your difficulty {[e.name.lower() for e in list(Difficulty)]}\n> ").upper())
|
||||||
|
print(f"Difficulty: {difficulty} selected!")
|
||||||
|
game = SpaceArena(difficulty)
|
||||||
|
print("Starting game!")
|
||||||
|
while game.is_running:
|
||||||
|
Err("error value hehe").unwrap_or("yay still works")
|
||||||
|
match run_command(input("> "), game):
|
||||||
|
case Ok(value):
|
||||||
|
print(f"{Color.OK}{value}{Color.ENDC}")
|
||||||
|
case Err(value):
|
||||||
|
print(f"{Color.BOLD}{Color.FAIL}Error:{Color.ENDC} {Color.WARNING}{value}{Color.ENDC}")
|
||||||
|
|
||||||
|
|
92
Tutorium/tut10/src/result.py
Normal file
92
Tutorium/tut10/src/result.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from abc import ABC
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Callable, overload
|
||||||
|
|
||||||
|
class Panick(Exception):
|
||||||
|
def __init__(self, msg_res: 'Err | str') -> None:
|
||||||
|
match msg_res:
|
||||||
|
case str(msg):
|
||||||
|
super().__init__(msg)
|
||||||
|
case _:
|
||||||
|
super().__init__(f"thread `__main__` panicked:\ncalled `Result::unwrap()` on an `Err` value: \"{msg_res.value}\"")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Result[V, E](ABC):
|
||||||
|
def unwrap(self) -> V:
|
||||||
|
match self:
|
||||||
|
case Ok(value):
|
||||||
|
return value
|
||||||
|
raise Panick(self) # type: ignore
|
||||||
|
|
||||||
|
def expect(self, msg: str) -> V:
|
||||||
|
match self:
|
||||||
|
case Ok(value):
|
||||||
|
return value
|
||||||
|
raise Panick(msg)
|
||||||
|
|
||||||
|
def is_ok(self) -> bool:
|
||||||
|
return isinstance(self, Ok)
|
||||||
|
|
||||||
|
def is_err(self) -> bool:
|
||||||
|
return isinstance(self, Err)
|
||||||
|
|
||||||
|
def unwrap_or(self, value: V) -> V:
|
||||||
|
match self:
|
||||||
|
case Ok(val):
|
||||||
|
return val
|
||||||
|
return value
|
||||||
|
|
||||||
|
def and_[O](self, other: 'Result[O, E]') -> 'Result[O, E]':
|
||||||
|
match self, other:
|
||||||
|
case Err(value), _:
|
||||||
|
return Err(value)
|
||||||
|
return other
|
||||||
|
|
||||||
|
def and_then[O](self, func: Callable[[V], 'Result[O, E]']) -> 'Result[O, E]':
|
||||||
|
match self:
|
||||||
|
case Ok(value):
|
||||||
|
return func(value)
|
||||||
|
return Err(self.value) # type: ignore
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Ok[V, E](Result[V, E]):
|
||||||
|
value: V
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Err[V, E](Result[V, E]):
|
||||||
|
value: E
|
||||||
|
|
||||||
|
def __sqrt(num: float) -> Result[float, str]:
|
||||||
|
if num < 0:
|
||||||
|
return Err('negative sqrt')
|
||||||
|
return Ok(num ** 0.5)
|
||||||
|
|
||||||
|
def test_result() -> None:
|
||||||
|
assert Ok(4.0).and_then(__sqrt) == Ok(2.0)
|
||||||
|
assert Ok(-5.0).and_then(__sqrt) == Err('negative sqrt')
|
||||||
|
assert Err("haha error").and_then(__sqrt) == Err("haha error")
|
||||||
|
assert Ok("test").unwrap() == "test"
|
||||||
|
try:
|
||||||
|
Err("haha error").unwrap()
|
||||||
|
except Panick:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False, 'didn\'t throw Panick'
|
||||||
|
assert Err('haha error').unwrap_or("doch nicht") == 'doch nicht'
|
||||||
|
|
||||||
|
result = Ok('test result')
|
||||||
|
|
||||||
|
match result:
|
||||||
|
case Ok(res):
|
||||||
|
assert res == 'test result'
|
||||||
|
case Err():
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = Err('test result')
|
||||||
|
|
||||||
|
match result:
|
||||||
|
case Ok():
|
||||||
|
pass
|
||||||
|
case Err(res):
|
||||||
|
assert res == 'test result'
|
44
Tutorium/tut10/src/spacearena.py
Normal file
44
Tutorium/tut10/src/spacearena.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from dataclasses import dataclass, InitVar
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class Difficulty(Enum):
|
||||||
|
EASY = 0.5
|
||||||
|
NORMAL = 1.0
|
||||||
|
HARD = 2.0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_difficulty(input: str) -> Optional['Difficulty']:
|
||||||
|
for e in list(Difficulty):
|
||||||
|
if e.name == input:
|
||||||
|
return e
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SpaceArena:
|
||||||
|
_difficulty: InitVar[Difficulty] = Difficulty.NORMAL
|
||||||
|
|
||||||
|
def __post_init__(self, difficulty: Difficulty = Difficulty.NORMAL) -> None:
|
||||||
|
self.__difficulty = difficulty
|
||||||
|
self.__is_running = True
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def difficulty(self) -> Difficulty:
|
||||||
|
return self.__difficulty
|
||||||
|
|
||||||
|
@difficulty.setter
|
||||||
|
def difficulty(self, new_diff: Difficulty):
|
||||||
|
self.__difficulty = new_diff
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_running(self) -> bool:
|
||||||
|
return self.__is_running
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.__is_running = False
|
79
Tutorium/tut10/src/ui.py
Normal file
79
Tutorium/tut10/src/ui.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from enum import Enum
|
||||||
|
import re
|
||||||
|
from typing import override
|
||||||
|
from result import Ok, Err, Result
|
||||||
|
from spacearena import Difficulty, SpaceArena
|
||||||
|
|
||||||
|
class Color(Enum):
|
||||||
|
OK = '\033[92m'
|
||||||
|
FAIL = '\033[91m'
|
||||||
|
WARNING = '\033[93m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractCommand(ABC):
|
||||||
|
|
||||||
|
def matches(self, inp: str) -> Result[re.Match[str], None]:
|
||||||
|
if m := re.match(self.pattern(), inp):
|
||||||
|
return Ok(m)
|
||||||
|
return Err(None)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def pattern(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def run(self, game: SpaceArena, args: list[str]) -> Result[str, str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QuitCommand(AbstractCommand):
|
||||||
|
@override
|
||||||
|
def pattern(self) -> str:
|
||||||
|
return r"(quit)"
|
||||||
|
|
||||||
|
@override
|
||||||
|
def run(self, game: SpaceArena, _: list[str]) -> Result[str, str]:
|
||||||
|
game.stop()
|
||||||
|
return Ok('quitting game!')
|
||||||
|
|
||||||
|
class DifficultyCommand(AbstractCommand):
|
||||||
|
@override
|
||||||
|
def pattern(self) -> str:
|
||||||
|
return r"(difficulty|diff)\s+(increase|decrease)"
|
||||||
|
|
||||||
|
@override
|
||||||
|
def run(self, game: SpaceArena, args: list[str]) -> Result[str, str]:
|
||||||
|
diffs = list(Difficulty)
|
||||||
|
curr = diffs.index(game.difficulty)
|
||||||
|
|
||||||
|
match args[0]:
|
||||||
|
case 'increase' if curr + 1 < len(diffs):
|
||||||
|
game.difficulty = diffs[curr + 1]
|
||||||
|
return Ok(f"Increasing difficulty to {game.difficulty}")
|
||||||
|
case 'increase':
|
||||||
|
return Err("maximum difficulty")
|
||||||
|
case 'decrease' if curr - 1 >= 0:
|
||||||
|
game.difficulty = diffs[curr - 1]
|
||||||
|
return Ok(f"Decreasing difficulty to {game.difficulty}")
|
||||||
|
case 'decrease':
|
||||||
|
return Err("minimum difficulty")
|
||||||
|
return Err("invalid input")
|
||||||
|
|
||||||
|
ALL_COMMANDS: list[AbstractCommand] = [QuitCommand(), DifficultyCommand()]
|
||||||
|
|
||||||
|
def run_command(inp: str, game: SpaceArena, commands: list[AbstractCommand] = ALL_COMMANDS) -> Result[str, str]:
|
||||||
|
for command in commands:
|
||||||
|
match command.matches(inp):
|
||||||
|
case Ok(value):
|
||||||
|
args = [str(s) for s in value.groups()]
|
||||||
|
return command.run(game, args[1:])
|
||||||
|
|
||||||
|
|
||||||
|
return Err("command not found")
|
Reference in New Issue
Block a user