1
This commit is contained in:
commit
5bccd0df77
26
game.py
Normal file
26
game.py
Normal 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
17
gameobject.py
Normal 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
35
gui.py
Normal 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
23
main.py
Normal 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
61
tests/game_test.py
Normal 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
44
tests/gameobject_test.py
Normal 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
63
tests/gui_test.py
Normal 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
41
tests/vector2_test.py
Normal 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
62
tests/world_test.py
Normal 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
25
vector2.py
Normal 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
25
world.py
Normal 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]])
|
||||||
Loading…
x
Reference in New Issue
Block a user