simples wfc, funktioniert noch nicht immer
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
import time
|
import time
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
|
|
||||||
|
from src.algorithms.wfc import WFCSolver
|
||||||
from src.algorithms.bruteforce import BruteForceSolver
|
from src.algorithms.bruteforce import BruteForceSolver
|
||||||
from src.net import NetGame
|
from src.net import NetGame
|
||||||
|
|
||||||
|
|
||||||
def test_run() -> float:
|
def test_run(i: int) -> float:
|
||||||
game = NetGame(3, 3)
|
game = NetGame(5, 5, i)
|
||||||
solver = BruteForceSolver(game)
|
solver = WFCSolver(game)
|
||||||
a = time.perf_counter()
|
a = time.perf_counter()
|
||||||
for _ in solver.solve():
|
for _ in solver.solve():
|
||||||
pass
|
pass
|
||||||
@@ -18,7 +19,7 @@ def test_run() -> float:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
total = 0
|
total = 0
|
||||||
with Pool() as p:
|
with Pool() as p:
|
||||||
processes = [p.apply_async(test_run) for _ in range(100)]
|
processes = [p.apply_async(test_run, (i,)) for i in range(1000)]
|
||||||
for proc in processes:
|
for proc in processes:
|
||||||
total += proc.get()
|
total += proc.get()
|
||||||
print(total)
|
print(total / 1000)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from netTypes import Direction, PieceType
|
from collections.abc import Generator
|
||||||
|
from src.netTypes import Direction, PieceType
|
||||||
from src.net import NetGame
|
from src.net import NetGame
|
||||||
|
|
||||||
|
|
||||||
@@ -36,13 +37,13 @@ class WFCSolver:
|
|||||||
return dirs
|
return dirs
|
||||||
elif ptype == PieceType.CORNER:
|
elif ptype == PieceType.CORNER:
|
||||||
possible: set[Direction] = set()
|
possible: set[Direction] = set()
|
||||||
if dirs.union({Direction.UP, Direction.RIGHT}):
|
if dirs.issuperset({Direction.UP, Direction.RIGHT}):
|
||||||
possible.add(Direction.UP)
|
possible.add(Direction.UP)
|
||||||
if dirs.union({Direction.RIGHT, Direction.DOWN}):
|
if dirs.issuperset({Direction.RIGHT, Direction.DOWN}):
|
||||||
possible.add(Direction.RIGHT)
|
possible.add(Direction.RIGHT)
|
||||||
if dirs.union({Direction.DOWN, Direction.LEFT}):
|
if dirs.issuperset({Direction.DOWN, Direction.LEFT}):
|
||||||
possible.add(Direction.DOWN)
|
possible.add(Direction.DOWN)
|
||||||
if dirs.union({Direction.LEFT, Direction.UP}):
|
if dirs.issuperset({Direction.LEFT, Direction.UP}):
|
||||||
possible.add(Direction.LEFT)
|
possible.add(Direction.LEFT)
|
||||||
return possible
|
return possible
|
||||||
elif ptype == PieceType.STRAIGHT:
|
elif ptype == PieceType.STRAIGHT:
|
||||||
@@ -67,56 +68,33 @@ class WFCSolver:
|
|||||||
else:
|
else:
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
def get_possible_direction_count(self, x: int, y: int) -> int:
|
def solve(self) -> Generator[None]:
|
||||||
ptype = self.game.get_piece(x, y).type
|
|
||||||
connectable = self.possible_connections[x][y]
|
|
||||||
camount = len(connectable)
|
|
||||||
if camount == 4:
|
|
||||||
return 4
|
|
||||||
if ptype == PieceType.NODE:
|
|
||||||
return camount
|
|
||||||
elif ptype == PieceType.CORNER:
|
|
||||||
if camount == 3:
|
|
||||||
return 2
|
|
||||||
elif (
|
|
||||||
camount == 2
|
|
||||||
and connectable != {Direction.UP, Direction.DOWN}
|
|
||||||
and connectable != {Direction.LEFT, Direction.RIGHT}
|
|
||||||
): # 2 nicht-gegenüberliegende seiten
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
elif ptype == PieceType.STRAIGHT:
|
|
||||||
if camount == 4:
|
|
||||||
return 4
|
|
||||||
elif (
|
|
||||||
camount == 3
|
|
||||||
or connectable == {Direction.UP, Direction.DOWN}
|
|
||||||
or connectable == {Direction.LEFT, Direction.RIGHT}
|
|
||||||
):
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
else: # T-JUNCTION
|
|
||||||
if camount == 4:
|
|
||||||
return 4
|
|
||||||
elif camount == 3:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def solve(self) -> None:
|
|
||||||
coordinates = list(
|
coordinates = list(
|
||||||
((i, j) for i in range(self.game.width) for j in range(self.game.height))
|
((i, j) for i in range(self.game.width) for j in range(self.game.height))
|
||||||
)
|
)
|
||||||
while not self.game.solved():
|
while not self.game.solved():
|
||||||
|
yield
|
||||||
(x, y) = min(
|
(x, y) = min(
|
||||||
coordinates, key=lambda t: self.get_possible_direction_count(*t)
|
coordinates, key=lambda t: len(self.get_possible_directions(*t))
|
||||||
)
|
)
|
||||||
if self.get_possible_direction_count(x, y) == 0:
|
if len(self.get_possible_directions(x, y)) == 0:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Irgendwo eine falsche Richtung gewählt, muss diese Logik noch schreiben"
|
"Irgendwo eine falsche Richtung gewählt, muss diese Logik noch schreiben"
|
||||||
)
|
)
|
||||||
direction = self.get_possible_directions(x, y).pop()
|
direction = self.get_possible_directions(x, y).pop()
|
||||||
self.game.set_direction(x, y, direction)
|
self.game.set_direction(x, y, direction)
|
||||||
# TODO: Nachbaren updaten
|
self.game.lock(x, y)
|
||||||
|
coordinates.remove((x, y))
|
||||||
|
for nx, ny in self.game.neighbors(x, y):
|
||||||
|
dx = nx - x
|
||||||
|
dy = ny - y
|
||||||
|
ndir = Direction.from_offset(dx, dy)
|
||||||
|
if ndir not in self.game.get_piece(x, y).connected_directions():
|
||||||
|
try:
|
||||||
|
self.possible_connections[nx][ny].remove(
|
||||||
|
Direction((ndir + 2) % 4)
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
elif self.game.get_piece(nx, ny).type == PieceType.NODE:
|
||||||
|
self.possible_connections[nx][ny] = {Direction((ndir + 2) % 4)}
|
||||||
|
|||||||
14
src/net.py
14
src/net.py
@@ -13,14 +13,17 @@ class Grid:
|
|||||||
width: int
|
width: int
|
||||||
height: int
|
height: int
|
||||||
|
|
||||||
def __init__(self, width: int, height: int) -> None:
|
def __init__(self, width: int, height: int, specific: int | None = None) -> None:
|
||||||
self.height = height
|
self.height = height
|
||||||
self.width = width
|
self.width = width
|
||||||
if width != height or width not in [3, 5, 7, 9, 11, 13]:
|
if width != height or width not in [3, 5, 7, 9, 11, 13]:
|
||||||
raise ValueError("Feldgrösse nicht erlaubt")
|
raise ValueError("Feldgrösse nicht erlaubt")
|
||||||
with open(f"descriptions/{width}x{height}.txt") as f:
|
with open(f"descriptions/{width}x{height}.txt") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
selected = choice(lines).strip()
|
if specific:
|
||||||
|
selected = lines[specific].strip()
|
||||||
|
else:
|
||||||
|
selected = choice(lines).strip()
|
||||||
self.pieces = parse_description(selected)
|
self.pieces = parse_description(selected)
|
||||||
|
|
||||||
def neighbors(self, x: int, y: int) -> list[Coordinate]:
|
def neighbors(self, x: int, y: int) -> list[Coordinate]:
|
||||||
@@ -71,8 +74,8 @@ class NetGame:
|
|||||||
width: int
|
width: int
|
||||||
height: int
|
height: int
|
||||||
|
|
||||||
def __init__(self, width: int, height: int) -> None:
|
def __init__(self, width: int, height: int, specific: int | None = None) -> None:
|
||||||
self._grid = Grid(width, height)
|
self._grid = Grid(width, height, specific)
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
||||||
@@ -94,5 +97,8 @@ class NetGame:
|
|||||||
def set_direction(self, x: int, y: int, dir: Direction) -> None:
|
def set_direction(self, x: int, y: int, dir: Direction) -> None:
|
||||||
self._grid.pieces[x][y].direction = dir
|
self._grid.pieces[x][y].direction = dir
|
||||||
|
|
||||||
|
def neighbors(self, x: int, y: int) -> list[Coordinate]:
|
||||||
|
return self._grid.neighbors(x, y)
|
||||||
|
|
||||||
def solved(self):
|
def solved(self):
|
||||||
return self._grid.solved()
|
return self._grid.solved()
|
||||||
|
|||||||
Reference in New Issue
Block a user