This commit is contained in:
tovjemam 2023-11-22 21:03:55 +01:00
commit 5bccd0df77
11 changed files with 422 additions and 0 deletions

26
game.py Normal file
View File

@ -0,0 +1,26 @@
from gameobject import *
from world import *
class Game:
def __init__(self, world: World, hero: GameObject, home: GameObject):
self.__world = world
self.__hero = hero
self.__home = home
def run(self) -> bool:
gui = Gui(self.__world.width, self.__world.height)
while True:
gui.clear()
self.__world.draw(gui)
self.__home.draw(gui)
self.__hero.draw(gui)
gui.show()
if self.__hero.position == self.__home.position:
return True
if not self.__world.is_empty(self.__hero.position):
return False
self.__hero.move(gui.input_direction())

17
gameobject.py Normal file
View File

@ -0,0 +1,17 @@
from vector2 import *
from gui import *
class GameObject:
def __init__(self, position: Vector2, symbol: str) -> None:
self.__position = position
self.__symbol = symbol
@property
def position(self):
return self.__position
def move(self, direction: Vector2):
self.__position += direction
def draw(self, gui: Gui):
gui.draw(self.__position.x, self.__position.y, self.__symbol)

35
gui.py Normal file
View File

@ -0,0 +1,35 @@
from vector2 import *
class Gui:
def __init__(self, width: int, height: int) -> None:
self.__width = width
self.__height = height
# self.__data = None
self.clear()
def draw(self, x: int, y: int, symbol: str):
self.__data[x + y * self.__width] = symbol
def show(self):
for y in range(self.__height):
for x in range(self.__width):
print(self.__data[x + y * self.__width], end="")
print("")
def clear(self):
self.__data = [" " for _ in range(self.__width * self.__height)]
def input_direction(self) -> Vector2:
match input("pohyb: "):
case "2":
return Vector2(0, 1)
case "4":
return Vector2(-1, 0)
case "6":
return Vector2(1, 0)
case "8":
return Vector2(0, -1)
case _:
return Vector2(0, 0)

23
main.py Normal file
View File

@ -0,0 +1,23 @@
from game import *
def main():
world = World(
[[1,1,1,1,1,1],
[1,0,0,1,0,1],
[1,0,0,1,0,1],
[1,0,0,0,0,1],
[1,1,1,1,1,1]],
[' ','#'])
hero = GameObject(Vector2(1,1),"@")
home = GameObject(Vector2(4,1),"^")
destination = Game(world,hero,home).run()
if destination:
print("Vitej doma!")
else:
print("... a uz ho nikdy nikdo nevidel... ")
if __name__ == "__main__":
main()

61
tests/game_test.py Normal file
View File

@ -0,0 +1,61 @@
import unittest
import builtins
import typing
from typing import Any
from typing import Optional
from game import Game
from world import World
from gameobject import GameObject
from vector2 import Vector2
class GameTest(unittest.TestCase):
class InputShim:
"""
Třída pro nahrazení standardní funkce input pro vstup dat
"""
__idx:int = 0
__lines:list[str] = []
@staticmethod
def set_input_data(lines:list[str]):
GameTest.InputShim.__idx = 0
GameTest.InputShim.__lines = lines
builtins.input = typing.cast(Any, GameTest.InputShim.__next)
@staticmethod
def get_latest_input() -> Optional[str]:
if GameTest.InputShim.__idx==0:
return None
else:
return GameTest.InputShim.__lines[GameTest.InputShim.__idx-1]
@staticmethod
def __next(prompt:str=""):
assert GameTest.InputShim.__idx<len(GameTest.InputShim.__lines), "| nejsou zadany dalsi hodnoty na vstupu"
result = GameTest.InputShim.__lines[GameTest.InputShim.__idx]
GameTest.InputShim.__idx += 1
return result
def test_run_lost(self):
world = World(
[[1,1,1,1],
[1,0,0,1],
[1,1,1,1]],
[' ','#'])
hero = GameObject(Vector2(1,1),"@")
home = GameObject(Vector2(2,1),"^")
GameTest.InputShim.set_input_data("4")
self.assertFalse(Game(world,hero,home).run())
def test_run_home(self):
world = World(
[[1,1,1,1],
[1,0,0,1],
[1,1,1,1]],
[' ','#'])
hero = GameObject(Vector2(1,1),"@")
home = GameObject(Vector2(2,1),"^")
GameTest.InputShim.set_input_data("6")
self.assertTrue(Game(world,hero,home).run())

44
tests/gameobject_test.py Normal file
View File

@ -0,0 +1,44 @@
import unittest
import random
from vector2 import Vector2
from gameobject import GameObject
from gui import Gui
class GameObjectTest(unittest.TestCase):
def test_draw(self):
def mock_draw(tx:int, ty:int, tc:str):
self.assertEqual(x,tx)
self.assertEqual(y,ty)
self.assertEqual(c,tc)
x = random.randrange(1,100)
y = random.randrange(1,100)
c = chr(random.randint(65,90))
obj = GameObject(Vector2(x,y), c)
gui = Gui(100,100)
gui.draw = mock_draw
obj.draw(gui)
def test_move(self):
def mock_draw(tx:int, ty:int, tc:str):
self.assertEqual(x,tx)
self.assertEqual(y,ty)
self.assertEqual(c,tc)
x = random.randrange(1,100)
y = random.randrange(1,100)
mx = random.randrange(1,10)
my = random.randrange(1,10)
c = chr(random.randint(65,90))
obj = GameObject(Vector2(x,y), c)
gui = Gui(100,100)
gui.draw = mock_draw
obj.draw(gui)
obj.move(Vector2(mx,my))
x += mx
y += my
obj.draw(gui)

63
tests/gui_test.py Normal file
View File

@ -0,0 +1,63 @@
import unittest
import random
import builtins
import typing
from typing import Any
from typing import Optional
from gui import Gui
from vector2 import Vector2
class GuiTest(unittest.TestCase):
class InputShim:
"""
Třída pro nahrazení standardní funkce input pro vstup dat
"""
__idx:int = 0
__lines:list[str] = []
@staticmethod
def set_input_data(lines:list[str]):
GuiTest.InputShim.__idx = 0
GuiTest.InputShim.__lines = lines
builtins.input = typing.cast(Any, GuiTest.InputShim.__next)
@staticmethod
def get_latest_input() -> Optional[str]:
if GuiTest.InputShim.__idx==0:
return None
else:
return GuiTest.InputShim.__lines[GuiTest.InputShim.__idx-1]
@staticmethod
def __next(prompt:str=""):
assert GuiTest.InputShim.__idx<len(GuiTest.InputShim.__lines), "| nejsou zadany dalsi hodnoty na vstupu"
result = GuiTest.InputShim.__lines[GuiTest.InputShim.__idx]
GuiTest.InputShim.__idx += 1
return result
def test_input_direction(self):
gui = Gui(1,1)
GuiTest.InputShim.set_input_data("2")
v = gui.input_direction()
self.assertEqual(Vector2(0,1),v)
GuiTest.InputShim.set_input_data("4")
v = gui.input_direction()
self.assertEqual(Vector2(-1,0),v)
GuiTest.InputShim.set_input_data("8")
v = gui.input_direction()
self.assertEqual(Vector2(0,-1),v)
GuiTest.InputShim.set_input_data("6")
v = gui.input_direction()
self.assertEqual(Vector2(1,0),v)
GuiTest.InputShim.set_input_data("9")
v = gui.input_direction()
self.assertEqual(Vector2(0,0),v)

41
tests/vector2_test.py Normal file
View File

@ -0,0 +1,41 @@
import unittest
import random
from vector2 import Vector2
class Vector2Test(unittest.TestCase):
def test_init_str(self):
x = random.randrange(1,100)
y = random.randrange(1,100)
v = Vector2(x,y)
self.assertEqual(f"{x}; {y}",v.__str__())
def test_init_properties(self):
x = random.randrange(1,100)
y = random.randrange(1,100)
v = Vector2(x,y)
self.assertEqual(x, v.x)
self.assertEqual(y, v.y)
def test_eq_same(self):
x = random.randrange(1,100)
y = random.randrange(1,100)
v1 = Vector2(x,y)
v2 = Vector2(x,y)
self.assertTrue(v1==v2)
def test_eq_not_same(self):
x = random.randrange(1,100)
y = random.randrange(1,100)
v1 = Vector2(x,y)
v2 = Vector2(x+1,y)
self.assertFalse(v1==v2)
def test_add(self):
x = random.randrange(1,100)
y = random.randrange(1,100)
v1 = Vector2(x,y)
v2 = Vector2(-x, -y)
self.assertTrue(v1+v2==Vector2(0,0))
self.assertTrue(v1+v1==Vector2(2*x,2*y))

62
tests/world_test.py Normal file
View File

@ -0,0 +1,62 @@
import unittest
import random
from world import World
from vector2 import Vector2
from gui import Gui
class WorldTest(unittest.TestCase):
def test_is_empty(self):
width = random.randrange(5,10)
height = random.randrange(5,10)
data:list[list[int]] = []
empty = []
nonempty = []
for y in range(height):
data.append([])
for x in range(width):
val = random.randrange(5)
data[y].append(val)
if val==0:
empty.append(Vector2(x,y))
else:
nonempty.append(Vector2(x,y))
world = World(data, [' ']*5)
for vec in empty:
self.assertTrue(world.is_empty(vec))
for vec in nonempty:
self.assertFalse(world.is_empty(vec))
def test_draw_horizontal(self):
def mock_draw(tx:int, ty:int, tc:str):
self.assertEqual(ty,0)
self.assertEqual(tc, chr(65 + tx % 3))
distinctX.add(tx)
gui = Gui(100,100)
gui.draw = mock_draw
distinctX = set()
tests = random.randint(10,20)
data = [[i%3 for i in range(tests)]]
world = World(data, [chr(65), chr(66), chr(67)])
world.draw(gui)
self.assertGreaterEqual(len(distinctX), tests)
def test_draw_vertical(self):
def mock_draw(tx:int, ty:int, tc:str):
self.assertEqual(tx,0)
self.assertEqual(tc, chr(80 + ty % 3))
distinctY.add(ty)
gui = Gui(100,100)
gui.draw = mock_draw
distinctY = set()
tests = random.randint(10,20)
data = [[i%3] for i in range(tests)]
world = World(data, [chr(80), chr(81), chr(82)])
world.draw(gui)
self.assertGreaterEqual(len(distinctY), tests)

25
vector2.py Normal file
View File

@ -0,0 +1,25 @@
from __future__ import annotations
class Vector2:
def __init__(self, x, y) -> None:
self.__x = x
self.__y = y
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
def __add__(self, other: Vector2) -> Vector2:
return Vector2(self.x + other.x, self.y + other.y)
def __eq__(self, other) -> bool:
return self.x == other.x and self.y == other.y
def __str__(self) -> str:
return f"{self.x}; {self.y}"

25
world.py Normal file
View File

@ -0,0 +1,25 @@
from gui import *
from vector2 import *
class World:
def __init__(self, data: list[list[int]], symbols: list[str]) -> None:
self.__width = len(data[0])
self.__height = len(data)
self.__data = data
self.__symbols = symbols
@property
def width(self):
return self.__width
@property
def height(self):
return self.__height
def is_empty(self, position: Vector2):
return self.__data[position.y][position.x] == 0
def draw(self, gui: Gui) -> None:
for y in range(self.height):
for x in range(self.width):
gui.draw(x, y, self.__symbols[self.__data[y][x]])