added some stuff
This commit is contained in:
Binary file not shown.
@ -3,27 +3,27 @@ from dataclasses import dataclass, InitVar
|
||||
|
||||
@dataclass
|
||||
class MyList[T]:
|
||||
internal_list: InitVar[list[T]]
|
||||
length: InitVar[int]
|
||||
|
||||
def __init__(self):
|
||||
self.__internal_list = []
|
||||
_internal_list: InitVar[list[T]]
|
||||
_length: InitVar[int]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__internal_list: list[T] = []
|
||||
self.__length = 0
|
||||
|
||||
def add(self, item: T):
|
||||
|
||||
def add(self, item: T) -> None:
|
||||
self.__internal_list += [item]
|
||||
self.__length += 1
|
||||
|
||||
|
||||
@property
|
||||
def length(self) -> int:
|
||||
return self.__length
|
||||
|
||||
|
||||
@dataclass
|
||||
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
|
||||
self.__position = position
|
||||
|
||||
@ -32,16 +32,17 @@ class GameObject:
|
||||
return self.__position
|
||||
|
||||
@position.setter
|
||||
def position(self, position: tuple[int, int]):
|
||||
def position(self, position: tuple[int, int]) -> None:
|
||||
if (0, 0) > position:
|
||||
return
|
||||
self.__position = position
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
xs: MyList[int] = MyList()
|
||||
xs.add(100)
|
||||
assert xs.length == 1
|
||||
position = (0, 0)
|
||||
position: tuple[int, int] = (0, 0)
|
||||
my_obj = GameObject(position)
|
||||
assert my_obj.position == (0, 0)
|
||||
try:
|
||||
@ -49,7 +50,7 @@ if __name__ == "__main__":
|
||||
except AssertionError:
|
||||
pass
|
||||
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)
|
||||
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