simples wfc, funktioniert noch nicht immer

This commit is contained in:
Alfred Baumann
2026-06-10 14:41:34 +02:00
parent 62864b7c00
commit d39e6ecc25
3 changed files with 41 additions and 56 deletions

View File

@@ -1,13 +1,14 @@
import time
from multiprocessing import Pool
from src.algorithms.wfc import WFCSolver
from src.algorithms.bruteforce import BruteForceSolver
from src.net import NetGame
def test_run() -> float:
game = NetGame(3, 3)
solver = BruteForceSolver(game)
def test_run(i: int) -> float:
game = NetGame(5, 5, i)
solver = WFCSolver(game)
a = time.perf_counter()
for _ in solver.solve():
pass
@@ -18,7 +19,7 @@ def test_run() -> float:
if __name__ == "__main__":
total = 0
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:
total += proc.get()
print(total)
print(total / 1000)

View File

@@ -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
@@ -36,13 +37,13 @@ class WFCSolver:
return dirs
elif ptype == PieceType.CORNER:
possible: set[Direction] = set()
if dirs.union({Direction.UP, Direction.RIGHT}):
if dirs.issuperset({Direction.UP, Direction.RIGHT}):
possible.add(Direction.UP)
if dirs.union({Direction.RIGHT, Direction.DOWN}):
if dirs.issuperset({Direction.RIGHT, Direction.DOWN}):
possible.add(Direction.RIGHT)
if dirs.union({Direction.DOWN, Direction.LEFT}):
if dirs.issuperset({Direction.DOWN, Direction.LEFT}):
possible.add(Direction.DOWN)
if dirs.union({Direction.LEFT, Direction.UP}):
if dirs.issuperset({Direction.LEFT, Direction.UP}):
possible.add(Direction.LEFT)
return possible
elif ptype == PieceType.STRAIGHT:
@@ -67,56 +68,33 @@ class WFCSolver:
else:
return set()
def get_possible_direction_count(self, x: int, y: int) -> int:
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:
def solve(self) -> Generator[None]:
coordinates = list(
((i, j) for i in range(self.game.width) for j in range(self.game.height))
)
while not self.game.solved():
yield
(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(
"Irgendwo eine falsche Richtung gewählt, muss diese Logik noch schreiben"
)
direction = self.get_possible_directions(x, y).pop()
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)}

View File

@@ -13,13 +13,16 @@ class Grid:
width: 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.width = width
if width != height or width not in [3, 5, 7, 9, 11, 13]:
raise ValueError("Feldgrösse nicht erlaubt")
with open(f"descriptions/{width}x{height}.txt") as f:
lines = f.readlines()
if specific:
selected = lines[specific].strip()
else:
selected = choice(lines).strip()
self.pieces = parse_description(selected)
@@ -71,8 +74,8 @@ class NetGame:
width: int
height: int
def __init__(self, width: int, height: int) -> None:
self._grid = Grid(width, height)
def __init__(self, width: int, height: int, specific: int | None = None) -> None:
self._grid = Grid(width, height, specific)
self.width = width
self.height = height
@@ -94,5 +97,8 @@ class NetGame:
def set_direction(self, x: int, y: int, dir: Direction) -> None:
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):
return self._grid.solved()