parser für die Descriptions, die Tatham's version generiert
This commit is contained in:
64
src/interface.py
Normal file
64
src/interface.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from src.types import Piece, Direction, PieceType
|
||||||
|
|
||||||
|
|
||||||
|
# Tatham's board description format:
|
||||||
|
# {width}x{height}:{board}
|
||||||
|
# the board is a string of single-digit hex numbers
|
||||||
|
# where each number is a bitfield of which sides the piece is connected to
|
||||||
|
RIGHT = 0x1
|
||||||
|
UP = 0x2
|
||||||
|
LEFT = 0x4
|
||||||
|
DOWN = 0x8
|
||||||
|
|
||||||
|
|
||||||
|
def flip_direction(d: int) -> int:
|
||||||
|
return (d >> 2) | ((d << 2) & 0xC)
|
||||||
|
|
||||||
|
|
||||||
|
def direction_from_tatham(d: int) -> Direction:
|
||||||
|
if d == RIGHT:
|
||||||
|
return Direction.RIGHT
|
||||||
|
elif d == UP:
|
||||||
|
return Direction.UP
|
||||||
|
elif d == LEFT:
|
||||||
|
return Direction.LEFT
|
||||||
|
else:
|
||||||
|
return Direction.DOWN
|
||||||
|
|
||||||
|
|
||||||
|
def corner_direction_from_sides(sides: int) -> Direction:
|
||||||
|
if sides == 0x3:
|
||||||
|
return Direction.UP
|
||||||
|
elif sides == 0x6:
|
||||||
|
return Direction.LEFT
|
||||||
|
elif sides == 0xC:
|
||||||
|
return Direction.DOWN
|
||||||
|
else:
|
||||||
|
return Direction.RIGHT
|
||||||
|
|
||||||
|
|
||||||
|
def parse_description(desc: str) -> list[list[Piece]]:
|
||||||
|
dimensions, field = desc.split(":")
|
||||||
|
width, height = map(int, dimensions.split("x"))
|
||||||
|
parsed: list[list[Piece]] = []
|
||||||
|
for y in range(height):
|
||||||
|
line: list[Piece] = []
|
||||||
|
for x in range(width):
|
||||||
|
value = int(field[x * width + y], 16)
|
||||||
|
connected_sides = value.bit_count()
|
||||||
|
if connected_sides == 1:
|
||||||
|
ptype = PieceType.NODE
|
||||||
|
direction = direction_from_tatham(value)
|
||||||
|
elif connected_sides == 2:
|
||||||
|
if value == 0x5 or value >> 1 == 0x5:
|
||||||
|
ptype = PieceType.STRAIGHT
|
||||||
|
direction = direction_from_tatham(value & 0x3)
|
||||||
|
else:
|
||||||
|
ptype = PieceType.CORNER
|
||||||
|
direction = corner_direction_from_sides(value)
|
||||||
|
else:
|
||||||
|
ptype = PieceType.T_JUNCTION
|
||||||
|
direction = direction_from_tatham(flip_direction(~value & 0xF))
|
||||||
|
line.append(Piece(ptype, direction))
|
||||||
|
parsed.append(line)
|
||||||
|
return parsed
|
||||||
132
src/net.py
132
src/net.py
@@ -2,101 +2,49 @@
|
|||||||
Kernlogik des Spiels
|
Kernlogik des Spiels
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from enum import IntEnum, auto
|
from src.types import Piece, Direction
|
||||||
|
from src.interface import parse_description
|
||||||
type Coordinate = tuple[int, int]
|
|
||||||
|
|
||||||
|
|
||||||
class PieceType(IntEnum):
|
# DEMO_FIELD = [
|
||||||
T_JUNCTION = auto() # Direction is the piece at the "stem" of the T
|
# [
|
||||||
STRAIGHT = auto()
|
# Piece(PieceType.NODE),
|
||||||
CORNER = auto() # Direction is the more counter-clockwise connection
|
# Piece(PieceType.NODE),
|
||||||
NODE = auto()
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# Piece(PieceType.STRAIGHT),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.STRAIGHT),
|
||||||
|
# Piece(PieceType.CORNER),
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# Piece(PieceType.STRAIGHT),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.T_JUNCTION),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# ],
|
||||||
|
# [
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# Piece(PieceType.NODE),
|
||||||
|
# Piece(PieceType.CORNER),
|
||||||
|
# Piece(PieceType.CORNER),
|
||||||
|
# Piece(PieceType.CORNER),
|
||||||
|
# ],
|
||||||
|
# ]
|
||||||
|
|
||||||
|
DEMO_FIELD = parse_description("5x5:c7634887c213e5b8db3e69282")
|
||||||
class Direction(IntEnum):
|
|
||||||
UP = 0
|
|
||||||
RIGHT = auto()
|
|
||||||
DOWN = auto()
|
|
||||||
LEFT = auto()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_offset(dx: int, dy: int) -> Direction:
|
|
||||||
if (dx != 0 and dy != 0) or abs(dx + dy) != 1:
|
|
||||||
raise ValueError(f"({dx}, {dy}) is not a valid direction offset")
|
|
||||||
if dx != 0:
|
|
||||||
return Direction(dx % 4)
|
|
||||||
else:
|
|
||||||
return Direction(dy + 1)
|
|
||||||
|
|
||||||
|
|
||||||
class Piece:
|
|
||||||
type: PieceType
|
|
||||||
direction: Direction = Direction.UP
|
|
||||||
locked: bool = False
|
|
||||||
|
|
||||||
def __init__(self, type: PieceType) -> None:
|
|
||||||
self.type = type
|
|
||||||
|
|
||||||
def connected_directions(self) -> list[Direction]:
|
|
||||||
match self.type:
|
|
||||||
case PieceType.NODE:
|
|
||||||
return [self.direction]
|
|
||||||
case PieceType.CORNER:
|
|
||||||
return [self.direction, Direction((self.direction + 1) % 4)]
|
|
||||||
case PieceType.STRAIGHT:
|
|
||||||
return [self.direction, Direction((self.direction + 2) % 4)]
|
|
||||||
case PieceType.T_JUNCTION:
|
|
||||||
return [
|
|
||||||
self.direction,
|
|
||||||
Direction((self.direction + 1) % 4),
|
|
||||||
Direction((self.direction - 1) % 4),
|
|
||||||
]
|
|
||||||
|
|
||||||
def turn_cw(self) -> None:
|
|
||||||
self.direction = Direction((self.direction + 1) % 4)
|
|
||||||
|
|
||||||
def turn_ccw(self) -> None:
|
|
||||||
self.direction = Direction((self.direction - 1) % 4)
|
|
||||||
|
|
||||||
|
|
||||||
DEMO_FIELD = [
|
|
||||||
[
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Piece(PieceType.STRAIGHT),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.STRAIGHT),
|
|
||||||
Piece(PieceType.CORNER),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Piece(PieceType.STRAIGHT),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.T_JUNCTION),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.NODE),
|
|
||||||
Piece(PieceType.CORNER),
|
|
||||||
Piece(PieceType.CORNER),
|
|
||||||
Piece(PieceType.CORNER),
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class Grid:
|
class Grid:
|
||||||
|
|||||||
57
src/types.py
Normal file
57
src/types.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
from enum import IntEnum, auto
|
||||||
|
|
||||||
|
type Coordinate = tuple[int, int]
|
||||||
|
|
||||||
|
|
||||||
|
class PieceType(IntEnum):
|
||||||
|
T_JUNCTION = auto() # Direction is the piece at the "stem" of the T
|
||||||
|
STRAIGHT = auto()
|
||||||
|
CORNER = auto() # Direction is the more counter-clockwise connection
|
||||||
|
NODE = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Direction(IntEnum):
|
||||||
|
UP = 0
|
||||||
|
RIGHT = auto()
|
||||||
|
DOWN = auto()
|
||||||
|
LEFT = auto()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_offset(dx: int, dy: int) -> Direction:
|
||||||
|
if (dx != 0 and dy != 0) or abs(dx + dy) != 1:
|
||||||
|
raise ValueError(f"({dx}, {dy}) is not a valid direction offset")
|
||||||
|
if dx != 0:
|
||||||
|
return Direction(dx % 4)
|
||||||
|
else:
|
||||||
|
return Direction(dy + 1)
|
||||||
|
|
||||||
|
|
||||||
|
class Piece:
|
||||||
|
type: PieceType
|
||||||
|
direction: Direction
|
||||||
|
locked: bool = False
|
||||||
|
|
||||||
|
def __init__(self, type: PieceType, direction: Direction = Direction.UP) -> None:
|
||||||
|
self.type = type
|
||||||
|
self.direction = direction
|
||||||
|
|
||||||
|
def connected_directions(self) -> list[Direction]:
|
||||||
|
match self.type:
|
||||||
|
case PieceType.NODE:
|
||||||
|
return [self.direction]
|
||||||
|
case PieceType.CORNER:
|
||||||
|
return [self.direction, Direction((self.direction + 1) % 4)]
|
||||||
|
case PieceType.STRAIGHT:
|
||||||
|
return [self.direction, Direction((self.direction + 2) % 4)]
|
||||||
|
case PieceType.T_JUNCTION:
|
||||||
|
return [
|
||||||
|
self.direction,
|
||||||
|
Direction((self.direction + 1) % 4),
|
||||||
|
Direction((self.direction - 1) % 4),
|
||||||
|
]
|
||||||
|
|
||||||
|
def turn_cw(self) -> None:
|
||||||
|
self.direction = Direction((self.direction + 1) % 4)
|
||||||
|
|
||||||
|
def turn_ccw(self) -> None:
|
||||||
|
self.direction = Direction((self.direction - 1) % 4)
|
||||||
Reference in New Issue
Block a user