Compare commits

..

2 Commits

Author SHA1 Message Date
Alfred Baumann
f3a6257cd4 anfang des wave function collapse algorithmus 2026-06-09 16:16:44 +02:00
Alfred Baumann
52142da3f3 einfaches timen vom brute-force 2026-06-09 11:16:31 +02:00
3 changed files with 146 additions and 8 deletions

View File

@@ -15,16 +15,8 @@ class BruteForceSolver:
self.game.set_direction(x, y, Direction.UP) self.game.set_direction(x, y, Direction.UP)
def solve(self) -> Generator[None]: def solve(self) -> Generator[None]:
attempts = 0
required = 4 ** (self.game.width * self.game.height)
while not self.game.solved(): while not self.game.solved():
yield yield
attempts += 1
print(
f"{attempts:0>{len(str(required))}}/{required} ({attempts / required * 100}%) ",
end="\r",
)
self.game.turn_cw(0, 0) self.game.turn_cw(0, 0)
for prev, curr in pairwise( for prev, curr in pairwise(
chain( chain(

24
src/algorithms/profile.py Normal file
View File

@@ -0,0 +1,24 @@
import time
from multiprocessing import Pool
from src.algorithms.bruteforce import BruteForceSolver
from src.net import NetGame
def test_run() -> float:
game = NetGame(3, 3)
solver = BruteForceSolver(game)
a = time.perf_counter()
for _ in solver.solve():
pass
b = time.perf_counter()
return b - a
if __name__ == "__main__":
total = 0
with Pool() as p:
processes = [p.apply_async(test_run) for _ in range(100)]
for proc in processes:
total += proc.get()
print(total)

122
src/algorithms/wfc.py Normal file
View File

@@ -0,0 +1,122 @@
from netTypes import Direction, PieceType
from src.net import NetGame
class WFCSolver:
game: NetGame
observed: list[list[bool]]
possible_connections: list[list[set[Direction]]]
def __init__(self, game: NetGame) -> None:
self.game = game
self.observed = [[False] * self.game.width for _ in range(self.game.height)]
self.possible_connections = [
[
{Direction.UP, Direction.RIGHT, Direction.DOWN, Direction.LEFT}
for _ in range(self.game.width)
]
for _ in range(self.game.width)
]
# Es kann nicht mit dem Rand des Feldes eine Verbindung bestehen
for column in self.possible_connections:
column[0].remove(Direction.UP)
column[-1].remove(Direction.DOWN)
for i in range(len(self.possible_connections[0])):
self.possible_connections[0][i].remove(Direction.LEFT)
for i in range(len(self.possible_connections[-1])):
self.possible_connections[-1][i].remove(Direction.RIGHT)
def get_possible_directions(self, x: int, y: int) -> set[Direction]:
ptype = self.game.get_piece(x, y).type
dirs = self.possible_connections[x][y]
if ptype == PieceType.NODE:
return dirs
elif ptype == PieceType.CORNER:
possible: set[Direction] = set()
if dirs.union({Direction.UP, Direction.RIGHT}):
possible.add(Direction.UP)
if dirs.union({Direction.RIGHT, Direction.DOWN}):
possible.add(Direction.RIGHT)
if dirs.union({Direction.DOWN, Direction.LEFT}):
possible.add(Direction.DOWN)
if dirs.union({Direction.LEFT, Direction.UP}):
possible.add(Direction.LEFT)
return possible
elif ptype == PieceType.STRAIGHT:
if len(dirs) == 4:
return dirs
elif {Direction.UP, Direction.DOWN}.issubset(dirs):
return {Direction.UP}
elif {Direction.LEFT, Direction.RIGHT}.issubset(dirs):
return {Direction.RIGHT}
else:
return set()
else:
if len(dirs) == 4:
return dirs
elif len(dirs) == 3:
not_connected = (
{Direction.UP, Direction.DOWN, Direction.LEFT, Direction.RIGHT}
.difference(dirs)
.pop()
)
return {Direction((not_connected + 2) % 4)}
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:
coordinates = list(
((i, j) for i in range(self.game.width) for j in range(self.game.height))
)
while not self.game.solved():
(x, y) = min(
coordinates, key=lambda t: self.get_possible_direction_count(*t)
)
if self.get_possible_direction_count(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