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