komplexeres wfc, funktioniert jetzt immer

This commit is contained in:
Alfred Baumann
2026-06-11 16:01:44 +02:00
parent 8139af00d5
commit f4ef3c7555
3 changed files with 56 additions and 12 deletions

View File

@@ -7,7 +7,7 @@ from src.net import NetGame
def test_run(i: int) -> float: def test_run(i: int) -> float:
game = NetGame(5, 5, i) game = NetGame(11, 11, i)
solver = WFCSolver(game) solver = WFCSolver(game)
a = time.perf_counter() a = time.perf_counter()
for _ in solver.solve(): for _ in solver.solve():

View File

@@ -1,9 +1,21 @@
from collections.abc import Generator from collections.abc import Generator
from copy import deepcopy
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, auto from enum import Enum, auto
from src.netTypes import Direction, PieceType from src.netTypes import Direction, PieceType
from src.net import NetGame from src.net import NetGame
type RollbackType = list[
tuple[
list[tuple[int, int]],
list[list[Direction]],
set[Direction],
int,
int,
list[list[PieceConnectionState]],
]
]
class ConnectionState(Enum): class ConnectionState(Enum):
DISCONNECTED = auto() DISCONNECTED = auto()
@@ -73,9 +85,16 @@ class WFCSolver:
def get_possible_corner_directions(self, x: int, y: int) -> set[Direction]: def get_possible_corner_directions(self, x: int, y: int) -> set[Direction]:
cstates = self.connection_states[x][y] cstates = self.connection_states[x][y]
connected = cstates.connected_or_unknown() connected = cstates.directions_with_state(ConnectionState.CONNECTED)
possible = connected.copy() if connected:
possible.update(map(lambda d: Direction((d - 1) % 4), connected)) possible = {Direction.UP, Direction.DOWN, Direction.LEFT, Direction.RIGHT}
for direction in connected:
possible.intersection_update(
{direction, Direction((direction - 1) % 4)}
)
else:
possible = cstates.directions_with_state(ConnectionState.UNKNOWN)
possible.update(map(lambda d: Direction((d - 1) % 4), possible.copy()))
disconnected = cstates.directions_with_state(ConnectionState.DISCONNECTED) disconnected = cstates.directions_with_state(ConnectionState.DISCONNECTED)
possible.difference_update(disconnected) possible.difference_update(disconnected)
possible.difference_update(map(lambda d: Direction((d - 1) % 4), disconnected)) possible.difference_update(map(lambda d: Direction((d - 1) % 4), disconnected))
@@ -117,20 +136,44 @@ class WFCSolver:
) )
return possible return possible
def get_field_rotations(self) -> list[list[Direction]]:
return [[p.direction for p in col] for col in self.game.get_field()]
def set_field_rotations(self, rotations: list[list[Direction]]):
for x, col in enumerate(rotations):
for y, d in enumerate(col):
self.game.set_direction(x, y, d)
def solve(self) -> Generator[None]: def solve(self) -> Generator[None]:
unfixed = list( unfixed = 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))
) )
rollback: RollbackType = []
while not self.game.solved(): while not self.game.solved():
yield yield
(x, y) = min(unfixed, key=lambda t: len(self.get_possible_directions(*t))) if len(unfixed) == 0:
if len(self.get_possible_directions(x, y)) == 0: unfixed, rotations, dirs, x, y, self.connection_states = rollback.pop()
raise NotImplementedError( self.set_field_rotations(rotations)
"Irgendwo eine falsche Richtung gewählt, muss diese Logik noch schreiben" else:
(x, y) = min(
unfixed, key=lambda t: len(self.get_possible_directions(*t))
)
dirs = self.get_possible_directions(x, y)
if len(dirs) == 0:
unfixed, rotations, dirs, x, y, self.connection_states = rollback.pop()
self.set_field_rotations(rotations)
direction = dirs.pop()
if len(dirs) > 0:
rollback.append(
(
unfixed.copy(),
self.get_field_rotations(),
dirs,
x,
y,
deepcopy(self.connection_states),
)
) )
if len(self.get_possible_directions(x, y)) > 1:
print("AAAAAAAA")
direction = self.get_possible_directions(x, y).pop()
self.game.set_direction(x, y, direction) self.game.set_direction(x, y, direction)
self.game.lock(x, y) self.game.lock(x, y)
unfixed.remove((x, y)) unfixed.remove((x, y))

View File

@@ -20,10 +20,11 @@ class Grid:
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()
if specific: if specific is not None:
selected = lines[specific].strip() selected = lines[specific].strip()
else: else:
selected = choice(lines).strip() selected = choice(lines).strip()
print(f"Seed: {lines.index(selected + "\n")}")
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]: