]> Untitled Git - axy/ft/a-maze-ing.git/commitdiff
Minor refactor
authorAxy <gilliardmarthey.axel@gmail.com>
Mon, 23 Mar 2026 02:16:10 +0000 (03:16 +0100)
committerAxy <gilliardmarthey.axel@gmail.com>
Mon, 23 Mar 2026 02:16:10 +0000 (03:16 +0100)
21 files changed:
__main__.py
amazeing/__init__.py
amazeing/config/config_parser.py
amazeing/maze/__init__.py [moved from amazeing/maze_class/__init__.py with 54% similarity]
amazeing/maze/maze.py [moved from amazeing/maze_class/maze.py with 98% similarity]
amazeing/maze/maze_coords.py [moved from amazeing/maze_class/maze_coords.py with 99% similarity]
amazeing/maze/maze_dirty_tracker.py [moved from amazeing/maze_class/maze_dirty_tracker.py with 88% similarity]
amazeing/maze/maze_network_tracker.py [moved from amazeing/maze_class/maze_network_tracker.py with 98% similarity]
amazeing/maze/maze_pacman_tracker.py [moved from amazeing/maze_class/maze_pacman_tracker.py with 90% similarity]
amazeing/maze/maze_pattern.py [moved from amazeing/maze_class/maze_pattern.py with 98% similarity]
amazeing/maze_display/TTYdisplay.py
amazeing/maze_display/__init__.py
amazeing/maze_display/backend.py
amazeing/maze_display/layout.py
amazeing/maze_make_empty.py
amazeing/maze_make_pacman.py
amazeing/maze_make_perfect.py
amazeing/utils/__init__.py
amazeing/utils/ivec2.py [new file with mode: 0644]
amazeing/utils/quadtree.py
tmp2 [new file with mode: 0644]

index 4e1593122391e9cb598e324af93acccb77608d5c..963a1b106d726e1b198f86b7e50acc1678d54202 100644 (file)
@@ -10,12 +10,14 @@ import random
 
 
 from amazeing.config.config_parser import Config
-from amazeing.maze_class.maze_network_tracker import MazeNetworkTracker
-from amazeing.maze_class.maze_coords import CellCoord
-from amazeing.maze_class.maze_dirty_tracker import MazeDirtyTracker
-from amazeing.maze_class.maze_pacman_tracker import MazePacmanTracker
+from amazeing.maze import (
+    MazeNetworkTracker,
+    CellCoord,
+    MazeDirtyTracker,
+    MazePacmanTracker,
+)
 from amazeing.maze_display.TTYdisplay import TileCycle, TileMaps, extract_pairs
-from amazeing.maze_display.backend import CloseRequested, IVec2
+from amazeing.utils import IVec2
 
 config = Config.parse(open("./example.conf").read())
 
@@ -98,7 +100,7 @@ def poll_events(timeout_ms: int = -1) -> None:
             if timeout() == 0 and not event:
                 return
             continue
-        if isinstance(event, CloseRequested) or event.sym == "q":
+        if event.sym == "q":
             exit(0)
         if event.sym == "c":
             filler.cycle()
index a68e0eb92fe146c31737180ebd9a6c3804663767..b0d39187e8e2874ac9d94372201568a463a548bd 100644 (file)
@@ -1,19 +1,21 @@
 __version__ = "0.0.0"
 __author__ = "luflores & agilliar"
 
-from amazeing.maze_class import WallCoord, Maze, Pattern
-from amazeing.maze_display import IVec2, TTYBackend
-from .maze_make_pacman import maze_make_pacman
-from .maze_make_perfect import maze_make_perfect
+
+from .maze.maze_coords import WallCoord
+from .maze.maze import Maze
+from .maze.maze_pattern import Pattern
+from .maze_display.TTYdisplay import TTYBackend
 from .maze_make_empty import maze_make_empty
+from .maze_make_perfect import maze_make_perfect
+from .maze_make_pacman import maze_make_pacman
 
 __all__ = [
-    "WallCoord",
     "Maze",
-    "Pattern",
-    "IVec2",
+    "WallCoord",
     "TTYBackend",
-    "maze_make_pacman",
-    "maze_make_perfect",
+    "Pattern",
     "maze_make_empty",
+    "maze_make_perfect",
+    "maze_make_pacman",
 ]
index a18e305bb65137086f1c06f183b4a032ae4a1251..f868827fbbb83bb30b4faa39c024767e9d345449 100644 (file)
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
 from collections.abc import Callable
 from typing import Any, Type, cast
 
-from amazeing.maze_display.backend import IVec2
+from amazeing.utils import IVec2
 from .parser_combinator import (
     ParseResult,
     Parser,
@@ -390,7 +390,7 @@ class Config:
 
     @staticmethod
     def parse(s: str) -> "Config":
-        from amazeing.maze_class import maze_pattern
+        from amazeing.maze import Pattern
 
         fields = parser_complete(
             fields_parser(
@@ -431,7 +431,7 @@ class Config:
                         ['"{BLACK:BLACK}    "', '"{BLACK:BLACK}    "'],
                     ),
                     "MAZE_PATTERN": DefaultedField(
-                        PatternField, maze_pattern.Pattern.FT_PATTERN
+                        PatternField, Pattern.FT_PATTERN
                     ),
                 }
             )
similarity index 54%
rename from amazeing/maze_class/__init__.py
rename to amazeing/maze/__init__.py
index f7d4856b1753c50eb82448cd635596ac481c00c4..59f7cbf6d28e0bc4467d5ff762f677d248e754b6 100644 (file)
@@ -3,6 +3,9 @@ __author__ = "agilliar & luflores"
 from .maze import Maze
 from .maze_pattern import Pattern
 from .maze_coords import Cardinal, Orientation, WallCoord, CellCoord
+from .maze_dirty_tracker import MazeDirtyTracker
+from .maze_pacman_tracker import MazePacmanTracker
+from .maze_network_tracker import MazeNetworkTracker
 
 __all__ = [
     "Maze",
@@ -11,4 +14,7 @@ __all__ = [
     "Orientation",
     "WallCoord",
     "CellCoord",
+    "MazeDirtyTracker",
+    "MazePacmanTracker",
+    "MazeNetworkTracker",
 ]
similarity index 98%
rename from amazeing/maze_class/maze.py
rename to amazeing/maze/maze.py
index 4acb454a417ffa651f0aa68b011233ee076837de..1e75f008a61baa991c17d70b172e8a5c29b47723 100644 (file)
@@ -1,5 +1,5 @@
 from typing import Callable, Generator, Iterable
-from amazeing.maze_display.backend import IVec2
+from amazeing.utils import IVec2
 from .maze_coords import (
     CellCoord,
     Orientation,
similarity index 99%
rename from amazeing/maze_class/maze_coords.py
rename to amazeing/maze/maze_coords.py
index 30c32ead33a9c9028218900984944a2e677c4e31..07fc6a84295dab03c2a73ec58d37a7e75d6a8c13 100644 (file)
@@ -1,6 +1,6 @@
 from enum import Enum, auto
 from typing import Iterable, cast, overload
-from ..maze_display import IVec2
+from amazeing.utils import IVec2
 
 
 class Orientation(Enum):
similarity index 88%
rename from amazeing/maze_class/maze_dirty_tracker.py
rename to amazeing/maze/maze_dirty_tracker.py
index ed8c91a0c17e5ebcb2bdb3cefeffde17c82c6e1c..060879929a68635da9fceb3989914007d0f22e1a 100644 (file)
@@ -1,6 +1,6 @@
 from collections.abc import Iterable
-from amazeing.maze_class.maze import Maze
-from amazeing.maze_class.maze_coords import WallCoord
+from amazeing.maze import Maze
+from amazeing.maze import WallCoord
 
 
 class MazeDirtyTracker:
similarity index 98%
rename from amazeing/maze_class/maze_network_tracker.py
rename to amazeing/maze/maze_network_tracker.py
index 8b0297b570249157727910d5aa4f26a4db19d3af..dc5d4f5c0a70da02a90f0748a8e0cf8803cae93c 100644 (file)
@@ -1,5 +1,5 @@
-from amazeing.maze_class.maze import Maze
-from amazeing.maze_class.maze_coords import (
+from amazeing.maze import Maze
+from amazeing.maze.maze_coords import (
     SplitWall,
     WallCoord,
     split_wall_ccw,
similarity index 90%
rename from amazeing/maze_class/maze_pacman_tracker.py
rename to amazeing/maze/maze_pacman_tracker.py
index 559f8d0f9fc856fed0fdc675d0db78df1d174d27..b33a3b9d6ee41807be2a196aeadb165efca96199 100644 (file)
@@ -1,6 +1,6 @@
 from collections.abc import Iterable
-from amazeing.maze_class.maze import Maze
-from amazeing.maze_class.maze_coords import WallCoord
+from amazeing.maze import Maze
+from amazeing.maze import WallCoord
 from amazeing.utils.randset import Randset
 
 
similarity index 98%
rename from amazeing/maze_class/maze_pattern.py
rename to amazeing/maze/maze_pattern.py
index 62cd09fcd606fca9cc7985ad24a6b92e4e253dcd..ee73ac6d4ee8bfc352bd8e3828edcd7cb4cdef36 100644 (file)
@@ -1,5 +1,5 @@
 from collections.abc import Iterable, Generator, Callable
-from amazeing.maze_display.backend import IVec2
+from amazeing.utils import IVec2
 from .maze import Maze
 from .maze_coords import CellCoord
 
index 5dead97b42281c21b3258fb44e08333085133108..ad6b08aae1a626babc2a409c7416a9635f42d9a6 100644 (file)
@@ -1,5 +1,6 @@
 from abc import ABC, abstractmethod
 from collections.abc import Callable, Generator, Iterable
+from dataclasses import dataclass
 from amazeing.utils import BiMap
 from amazeing.config.config_parser import Color, Config, ColoredLine, ColorPair
 from amazeing.maze_display.layout import (
@@ -14,8 +15,7 @@ from amazeing.maze_display.layout import (
     layout_sort_chunked,
     layout_split,
 )
-from amazeing.utils import Rect, QuadTree
-from .backend import IVec2, BackendEvent, KeyboardInput
+from amazeing.utils import Rect, QuadTree, IVec2
 import curses
 
 
@@ -23,6 +23,11 @@ class BackendException(Exception):
     pass
 
 
+@dataclass
+class KeyboardInput:
+    sym: str
+
+
 class ITile(ABC):
     @abstractmethod
     def size(self) -> IVec2: ...
@@ -552,7 +557,7 @@ class TTYBackend:
         self.__layout.laid_out(IVec2(0, 0), IVec2(x, y))
         self.__scratch.overwrite(self.__screen)
 
-    def event(self, timeout_ms: int = -1) -> BackendEvent | bool:
+    def event(self, timeout_ms: int = -1) -> KeyboardInput | bool:
         self.__screen.timeout(timeout_ms)
         try:
             key = self.__screen.getkey()
index 0964b48dbdec282d7a02bde5cf0f036a4177cb07..33dd1237422fa3878f0ef98ac3a3fff483404176 100644 (file)
@@ -1,10 +1,4 @@
 __version__ = "0.0.0"
 __author__ = "luflores & agilliar"
 
-from .backend import IVec2
-from .TTYdisplay import TTYBackend
-
-__all__ = [
-    "IVec2",
-    "TTYBackend",
-]
+__all__ = []
index 184e76ff520ef872078e9ffb56538fa4f4117567..fc0ee6823b6740d3024ce0852990314e6adf10c6 100644 (file)
@@ -1,5 +1,4 @@
 from collections.abc import Callable
-from dataclasses import dataclass
 from typing import Type, cast
 
 
@@ -67,15 +66,3 @@ class IVec2[T = int]:
 
     def yx(self) -> tuple[T, T]:
         return (self.y, self.x)
-
-
-@dataclass
-class KeyboardInput:
-    sym: str
-
-
-class CloseRequested:
-    pass
-
-
-type BackendEvent = KeyboardInput | CloseRequested
index 44435a1dba6f5980c21c1e3ac447520f2af611f2..7d7155ec2ea9f1e5c1c6aef02abd4105a2387a33 100644 (file)
@@ -1,6 +1,6 @@
 from abc import ABC, abstractmethod
 from collections.abc import Callable
-from .backend import IVec2
+from amazeing.utils import IVec2
 
 
 class BInt:
index 336ac5b81402e449c8ec3214c547c091bd4ab526..aed31e8e0ce3810d58f7bec5e0434784a2d7484d 100644 (file)
@@ -1,6 +1,6 @@
 from collections.abc import Callable
-from amazeing.maze_class.maze import Maze
-from amazeing.maze_class.maze_coords import WallCoord
+from amazeing.maze import Maze
+from amazeing.maze import WallCoord
 import random
 
 
index 8fe2e000831cce24cbeb711871aa400af2001310..9ee10fdc7b76e760e171508c545ac0cdfda5510e 100644 (file)
@@ -1,8 +1,8 @@
 from typing import Callable
-from amazeing import Maze, WallCoord
+from amazeing.maze import Maze, WallCoord
 import random
 
-from amazeing.maze_class.maze_pacman_tracker import MazePacmanTracker
+from amazeing.maze import MazePacmanTracker
 
 
 def maze_make_pacman(
index bfb629f9e3e739ead81dc4ba3143a58adef8e061..790110846bb52c8c5e7fb16e60f3e7cdeb09947c 100644 (file)
@@ -1,8 +1,8 @@
 from typing import Callable
-from amazeing import Maze
+from amazeing.maze import Maze
 import random
 
-from amazeing.maze_class.maze_network_tracker import MazeNetworkTracker
+from amazeing.maze import MazeNetworkTracker
 
 
 def maze_make_perfect(
index 5db6856780502c609a21da1999df46d71462585c..59cd57d43658121cf8aa2beaf3c08ef8b6270456 100644 (file)
@@ -1,5 +1,6 @@
 from .bi_map import BiMap
 from .avl import Tree as AVLTree, Leaf as AVLLeaf
 from .quadtree import Tree as QuadTree, Rect
+from .ivec2 import IVec2
 
-__all__ = ["BiMap", "AVLTree", "AVLLeaf", "QuadTree", "Rect"]
+__all__ = ["BiMap", "AVLTree", "AVLLeaf", "QuadTree", "Rect", "IVec2"]
diff --git a/amazeing/utils/ivec2.py b/amazeing/utils/ivec2.py
new file mode 100644 (file)
index 0000000..fc0ee68
--- /dev/null
@@ -0,0 +1,68 @@
+from collections.abc import Callable
+from typing import Type, cast
+
+
+class IVec2[T = int]:
+    def copy(self, inner_copy: Callable[[T], T] = lambda e: e) -> "IVec2[T]":
+        return IVec2(inner_copy(self.x), inner_copy(self.y))
+
+    def __init__(self, x: T, y: T) -> None:
+        self.x: T = x
+        self.y: T = y
+
+    @staticmethod
+    def splat(n: T) -> "IVec2[T]":
+        return IVec2(n, n)
+
+    def __repr__(self) -> str:
+        return f"{self.x, self.y}"
+
+    @staticmethod
+    def with_op[T2](
+        op: Callable[[T, T], T2],
+    ) -> Callable[["IVec2[T]", "T | IVec2[T]"], "IVec2[T2]"]:
+        return lambda self, other: IVec2(
+            op(
+                self.x,
+                (
+                    other
+                    if isinstance(other, IVec2)
+                    else (other := type(self).splat(other))
+                ).x,
+            ),
+            op(self.y, cast(IVec2[T], other).y),
+        )
+
+    def innertype(self) -> Type[T]:
+        return type(self.x)
+
+    def __mul__(self, other: "IVec2[T]") -> "IVec2[T]":
+        return IVec2(self.x * other.x, self.y * other.y)  # type:ignore
+
+    def __add__(self, other: "IVec2[T]") -> "IVec2[T]":
+        return IVec2(self.x + other.x, self.y + other.y)  # type:ignore
+
+    def __sub__(self, other: "IVec2[T]") -> "IVec2[T]":
+        return IVec2(self.x - other.x, self.y - other.y)  # type:ignore
+
+    def __floordiv__(self, other: "IVec2[T]") -> "IVec2[T]":
+        return IVec2(self.x // other.x, self.y // other.y)  # type:ignore
+
+    def __mod__(self, other: "IVec2[T]") -> "IVec2[T]":
+        return IVec2(self.x % other.x, self.y % other.y)  # type:ignore
+
+    def __eq__(self, value: object, /) -> bool:
+        return (
+            isinstance(value, IVec2)
+            and self.x == value.x
+            and self.y == value.y
+        )
+
+    def __hash__(self) -> int:
+        return hash((self.x, self.y))
+
+    def xy(self) -> tuple[T, T]:
+        return (self.x, self.y)
+
+    def yx(self) -> tuple[T, T]:
+        return (self.y, self.x)
index 9a2de7ae6b7df7caadd0a5980352b2138e6e22cc..9af28293a2899fc5b88486737ed5b1f3dacacbb0 100644 (file)
@@ -1,5 +1,5 @@
 from collections.abc import Callable, Generator
-from amazeing.maze_display.backend import IVec2
+from .ivec2 import IVec2
 from functools import partial
 from itertools import chain
 
diff --git a/tmp2 b/tmp2
new file mode 100644 (file)
index 0000000..0ec98cf
--- /dev/null
+++ b/tmp2
@@ -0,0 +1,530 @@
+(10, 2)
+(10, 3)
+(10, 4)
+(14, 6)
+(15, 6)
+(16, 6)
+(10, 8)
+(11, 8)
+(12, 8)
+(12, 14)
+(12, 15)
+(12, 16)
+(2, 12)
+(2, 13)
+(2, 14)
+(0, 2)
+(0, 3)
+(0, 4)
+(12, 0)
+(12, 1)
+(12, 2)
+(14, 10)
+(15, 10)
+(16, 10)
+(16, 12)
+(17, 12)
+(18, 12)
+(12, 4)
+(12, 5)
+(12, 6)
+(8, 14)
+(9, 14)
+(10, 14)
+(2, 2)
+(2, 3)
+(2, 4)
+(0, 14)
+(0, 15)
+(0, 16)
+(6, 0)
+(6, 1)
+(6, 2)
+(14, 8)
+(14, 9)
+(14, 10)
+(8, 8)
+(9, 8)
+(10, 8)
+(10, 16)
+(11, 16)
+(12, 16)
+(18, 6)
+(18, 7)
+(18, 8)
+(4, 10)
+(5, 10)
+(6, 10)
+(2, 10)
+(2, 11)
+(2, 12)
+(8, 6)
+(9, 6)
+(10, 6)
+(6, 4)
+(6, 5)
+(6, 6)
+(18, 10)
+(18, 11)
+(18, 12)
+(6, 14)
+(7, 14)
+(8, 14)
+(0, 16)
+(1, 16)
+(2, 16)
+(10, 8)
+(10, 9)
+(10, 10)
+(0, 12)
+(0, 13)
+(0, 14)
+(10, 12)
+(11, 12)
+(12, 12)
+(2, 8)
+(3, 8)
+(4, 8)
+(4, 16)
+(5, 16)
+(6, 16)
+(18, 0)
+(18, 1)
+(18, 2)
+(2, 4)
+(2, 5)
+(2, 6)
+(4, 12)
+(4, 13)
+(4, 14)
+(6, 2)
+(7, 2)
+(8, 2)
+(0, 6)
+(0, 7)
+(0, 8)
+(14, 0)
+(14, 1)
+(14, 2)
+(8, 10)
+(8, 11)
+(8, 12)
+(2, 16)
+(3, 16)
+(4, 16)
+(2, 2)
+(3, 2)
+(4, 2)
+(10, 0)
+(11, 0)
+(12, 0)
+(4, 6)
+(4, 7)
+(4, 8)
+(0, 10)
+(1, 10)
+(2, 10)
+(10, 4)
+(11, 4)
+(12, 4)
+(12, 8)
+(13, 8)
+(14, 8)
+(4, 6)
+(5, 6)
+(6, 6)
+(14, 12)
+(14, 13)
+(14, 14)
+(0, 0)
+(1, 0)
+(2, 0)
+(12, 12)
+(12, 13)
+(12, 14)
+(12, 6)
+(13, 6)
+(14, 6)
+(8, 0)
+(9, 0)
+(10, 0)
+(16, 8)
+(17, 8)
+(18, 8)
+(6, 8)
+(6, 9)
+(6, 10)
+(18, 14)
+(18, 15)
+(18, 16)
+(6, 12)
+(7, 12)
+(8, 12)
+(14, 2)
+(14, 3)
+(14, 4)
+(4, 0)
+(4, 1)
+(4, 2)
+(16, 0)
+(16, 1)
+(16, 2)
+(12, 10)
+(12, 11)
+(12, 12)
+(14, 14)
+(15, 14)
+(16, 14)
+(8, 16)
+(9, 16)
+(10, 16)
+(16, 4)
+(17, 4)
+(18, 4)
+(2, 8)
+(2, 9)
+(2, 10)
+(14, 14)
+(14, 15)
+(14, 16)
+(8, 2)
+(8, 3)
+(8, 4)
+(16, 16)
+(17, 16)
+(18, 16)
+(2, 4)
+(3, 4)
+(4, 4)
+(0, 0)
+(1, 0)
+(0, 1)
+(1, 1)
+(2, 0)
+(3, 0)
+(2, 1)
+(3, 1)
+(0, 2)
+(1, 2)
+(0, 3)
+(1, 3)
+(2, 2)
+(3, 2)
+(2, 3)
+(3, 3)
+(4, 0)
+(5, 0)
+(4, 1)
+(5, 1)
+(6, 0)
+(7, 0)
+(6, 1)
+(7, 1)
+(4, 2)
+(5, 2)
+(4, 3)
+(5, 3)
+(6, 2)
+(7, 2)
+(6, 3)
+(7, 3)
+(0, 4)
+(1, 4)
+(0, 5)
+(1, 5)
+(2, 4)
+(3, 4)
+(2, 5)
+(3, 5)
+(0, 6)
+(1, 6)
+(0, 7)
+(1, 7)
+(2, 6)
+(3, 6)
+(2, 7)
+(3, 7)
+(4, 4)
+(5, 4)
+(4, 5)
+(5, 5)
+(6, 4)
+(7, 4)
+(6, 5)
+(7, 5)
+(4, 6)
+(5, 6)
+(4, 7)
+(5, 7)
+(6, 6)
+(7, 6)
+(6, 7)
+(7, 7)
+(8, 0)
+(9, 0)
+(8, 1)
+(9, 1)
+(10, 0)
+(11, 0)
+(10, 1)
+(11, 1)
+(8, 2)
+(9, 2)
+(8, 3)
+(9, 3)
+(10, 2)
+(11, 2)
+(10, 3)
+(11, 3)
+(12, 0)
+(13, 0)
+(12, 1)
+(13, 1)
+(14, 0)
+(15, 0)
+(14, 1)
+(15, 1)
+(12, 2)
+(13, 2)
+(12, 3)
+(13, 3)
+(14, 2)
+(15, 2)
+(14, 3)
+(15, 3)
+(8, 4)
+(9, 4)
+(8, 5)
+(9, 5)
+(10, 4)
+(11, 4)
+(10, 5)
+(11, 5)
+(8, 6)
+(9, 6)
+(8, 7)
+(9, 7)
+(10, 6)
+(11, 6)
+(10, 7)
+(11, 7)
+(12, 4)
+(13, 4)
+(12, 5)
+(13, 5)
+(14, 4)
+(15, 4)
+(14, 5)
+(15, 5)
+(12, 6)
+(13, 6)
+(12, 7)
+(13, 7)
+(14, 6)
+(15, 6)
+(14, 7)
+(15, 7)
+(0, 8)
+(1, 8)
+(0, 9)
+(1, 9)
+(2, 8)
+(3, 8)
+(2, 9)
+(3, 9)
+(0, 10)
+(1, 10)
+(0, 11)
+(1, 11)
+(2, 10)
+(3, 10)
+(2, 11)
+(3, 11)
+(4, 8)
+(5, 8)
+(4, 9)
+(5, 9)
+(6, 8)
+(7, 8)
+(6, 9)
+(7, 9)
+(4, 10)
+(5, 10)
+(4, 11)
+(5, 11)
+(6, 10)
+(7, 10)
+(6, 11)
+(7, 11)
+(0, 12)
+(1, 12)
+(0, 13)
+(1, 13)
+(2, 12)
+(3, 12)
+(2, 13)
+(3, 13)
+(0, 14)
+(1, 14)
+(0, 15)
+(1, 15)
+(2, 14)
+(3, 14)
+(2, 15)
+(3, 15)
+(4, 12)
+(5, 12)
+(4, 13)
+(5, 13)
+(6, 12)
+(7, 12)
+(6, 13)
+(7, 13)
+(4, 14)
+(5, 14)
+(4, 15)
+(5, 15)
+(6, 14)
+(7, 14)
+(6, 15)
+(7, 15)
+(8, 8)
+(9, 8)
+(8, 9)
+(9, 9)
+(10, 8)
+(11, 8)
+(10, 9)
+(11, 9)
+(8, 10)
+(9, 10)
+(8, 11)
+(9, 11)
+(10, 10)
+(11, 10)
+(10, 11)
+(11, 11)
+(12, 8)
+(13, 8)
+(12, 9)
+(13, 9)
+(14, 8)
+(15, 8)
+(14, 9)
+(15, 9)
+(12, 10)
+(13, 10)
+(12, 11)
+(13, 11)
+(14, 10)
+(15, 10)
+(14, 11)
+(15, 11)
+(8, 12)
+(9, 12)
+(8, 13)
+(9, 13)
+(10, 12)
+(11, 12)
+(10, 13)
+(11, 13)
+(8, 14)
+(9, 14)
+(8, 15)
+(9, 15)
+(10, 14)
+(11, 14)
+(10, 15)
+(11, 15)
+(12, 12)
+(13, 12)
+(12, 13)
+(13, 13)
+(14, 12)
+(15, 12)
+(14, 13)
+(15, 13)
+(12, 14)
+(13, 14)
+(12, 15)
+(13, 15)
+(14, 14)
+(15, 14)
+(14, 15)
+(15, 15)
+(16, 0)
+(17, 0)
+(16, 1)
+(17, 1)
+(18, 0)
+(18, 1)
+(16, 2)
+(17, 2)
+(16, 3)
+(17, 3)
+(18, 2)
+(18, 3)
+(16, 4)
+(17, 4)
+(16, 5)
+(17, 5)
+(18, 4)
+(18, 5)
+(16, 6)
+(17, 6)
+(16, 7)
+(17, 7)
+(18, 6)
+(18, 7)
+(16, 8)
+(17, 8)
+(16, 9)
+(17, 9)
+(18, 8)
+(18, 9)
+(16, 10)
+(17, 10)
+(16, 11)
+(17, 11)
+(18, 10)
+(18, 11)
+(16, 12)
+(17, 12)
+(16, 13)
+(17, 13)
+(18, 12)
+(18, 13)
+(16, 14)
+(17, 14)
+(16, 15)
+(17, 15)
+(18, 14)
+(18, 15)
+(0, 16)
+(1, 16)
+(2, 16)
+(3, 16)
+(4, 16)
+(5, 16)
+(6, 16)
+(7, 16)
+(8, 16)
+(9, 16)
+(10, 16)
+(11, 16)
+(12, 16)
+(13, 16)
+(14, 16)
+(15, 16)
+(16, 16)
+(17, 16)
+(18, 16)
+(2, 2)
+(3, 2)
+(4, 2)
+(2, 2)
+(2, 3)
+(2, 4)
+(4, 0)
+(4, 1)
+(4, 2)