Descriptions benutzen und andere Feldgrössen als 5x5 erlauben
This commit is contained in:
@@ -7,3 +7,8 @@ requires-python = ">=3.13"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"pygame>=2.6.1",
|
"pygame>=2.6.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"basedpyright>=1.39.6",
|
||||||
|
]
|
||||||
|
|||||||
32
src/GUI.py
32
src/GUI.py
@@ -1,12 +1,15 @@
|
|||||||
import os
|
import os
|
||||||
from typing import override
|
from typing import override
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from src.net import NetGame
|
from src.net import NetGame
|
||||||
|
|
||||||
# pyright: reportUnusedCallResult=false, reportAny=false
|
# pyright: reportUnusedCallResult=false, reportAny=false
|
||||||
|
|
||||||
LEFT_TURN = pygame.USEREVENT + 1
|
LEFT_TURN = pygame.USEREVENT + 1
|
||||||
RIGHT_TURN = pygame.USEREVENT + 2
|
RIGHT_TURN = pygame.USEREVENT + 2
|
||||||
|
LOCK = pygame.USEREVENT + 3
|
||||||
|
|
||||||
|
|
||||||
class PieceSprite(pygame.sprite.Sprite):
|
class PieceSprite(pygame.sprite.Sprite):
|
||||||
@@ -28,7 +31,12 @@ class PieceSprite(pygame.sprite.Sprite):
|
|||||||
def update(self, game: NetGame, events: list[pygame.event.Event]):
|
def update(self, game: NetGame, events: list[pygame.event.Event]):
|
||||||
piece = game.get_piece(self.x, self.y)
|
piece = game.get_piece(self.x, self.y)
|
||||||
image = pygame.image.load(os.path.join("assets", f"{piece.type}.bmp")).convert()
|
image = pygame.image.load(os.path.join("assets", f"{piece.type}.bmp")).convert()
|
||||||
image = pygame.transform.rotate(image, -90 * piece.direction)
|
image.set_colorkey("#ffffff")
|
||||||
|
image = pygame.transform.rotate(image, -90 * int(piece.direction))
|
||||||
|
if piece.locked:
|
||||||
|
self.image.fill("#a0a0a0")
|
||||||
|
else:
|
||||||
|
self.image.fill("#ffffff")
|
||||||
self.image.blit(image, (0, 0))
|
self.image.blit(image, (0, 0))
|
||||||
for event in events:
|
for event in events:
|
||||||
if event.type == pygame.MOUSEBUTTONUP:
|
if event.type == pygame.MOUSEBUTTONUP:
|
||||||
@@ -38,6 +46,10 @@ class PieceSprite(pygame.sprite.Sprite):
|
|||||||
pygame.event.post(
|
pygame.event.post(
|
||||||
pygame.event.Event(LEFT_TURN, {"x": self.x, "y": self.y})
|
pygame.event.Event(LEFT_TURN, {"x": self.x, "y": self.y})
|
||||||
)
|
)
|
||||||
|
elif event.button == 2:
|
||||||
|
pygame.event.post(
|
||||||
|
pygame.event.Event(LOCK, {"x": self.x, "y": self.y})
|
||||||
|
)
|
||||||
elif event.button == 3:
|
elif event.button == 3:
|
||||||
pygame.event.post(
|
pygame.event.post(
|
||||||
pygame.event.Event(RIGHT_TURN, {"x": self.x, "y": self.y})
|
pygame.event.Event(RIGHT_TURN, {"x": self.x, "y": self.y})
|
||||||
@@ -47,18 +59,18 @@ class PieceSprite(pygame.sprite.Sprite):
|
|||||||
class NetGUI:
|
class NetGUI:
|
||||||
game: NetGame
|
game: NetGame
|
||||||
window: pygame.Surface
|
window: pygame.Surface
|
||||||
pieceSprites: pygame.sprite.Group[PieceSprite]
|
pieceSprites: pygame.sprite.Group[PieceSprite] # pyright: ignore[reportInvalidTypeArguments]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, width: int, height: int):
|
||||||
self.game = NetGame(5, 5)
|
self.game = NetGame(width, height)
|
||||||
pygame.init()
|
pygame.init()
|
||||||
self.window = pygame.display.set_mode((5 * 30, 5 * 30))
|
self.window = pygame.display.set_mode((width * 30, height * 30))
|
||||||
self.window.fill("#ffffff")
|
self.window.fill("#ffffff")
|
||||||
pygame.display.set_caption("Net")
|
pygame.display.set_caption("Net")
|
||||||
|
|
||||||
self.pieceSprites = pygame.sprite.Group()
|
self.pieceSprites = pygame.sprite.Group()
|
||||||
for x in range(5):
|
for x in range(width):
|
||||||
for y in range(5):
|
for y in range(height):
|
||||||
self.pieceSprites.add(PieceSprite(x, y))
|
self.pieceSprites.add(PieceSprite(x, y))
|
||||||
|
|
||||||
def run_game(self):
|
def run_game(self):
|
||||||
@@ -71,11 +83,13 @@ class NetGUI:
|
|||||||
elif event.type == LEFT_TURN:
|
elif event.type == LEFT_TURN:
|
||||||
self.game.turn_ccw(event.x, event.y)
|
self.game.turn_ccw(event.x, event.y)
|
||||||
if self.game.solved():
|
if self.game.solved():
|
||||||
raise SystemExit
|
raise SystemExit # TODO: Richtiger Spiel schluss, nicht einfach schliessen
|
||||||
elif event.type == RIGHT_TURN:
|
elif event.type == RIGHT_TURN:
|
||||||
self.game.turn_cw(event.x, event.y)
|
self.game.turn_cw(event.x, event.y)
|
||||||
if self.game.solved():
|
if self.game.solved():
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
elif event.type == LOCK:
|
||||||
|
self.game.lock(event.x, event.y)
|
||||||
|
|
||||||
self.pieceSprites.update(self.game, events)
|
self.pieceSprites.update(self.game, events)
|
||||||
for sprite in self.pieceSprites:
|
for sprite in self.pieceSprites:
|
||||||
@@ -84,4 +98,4 @@ class NetGUI:
|
|||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
|
|
||||||
NetGUI().run_game()
|
NetGUI(13, 13).run_game()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from src.types import Piece, Direction, PieceType
|
from src.netTypes import Piece, Direction, PieceType
|
||||||
|
|
||||||
|
|
||||||
# Tatham's board description format:
|
# Tatham's board description format:
|
||||||
|
|||||||
61
src/net.py
61
src/net.py
@@ -2,47 +2,10 @@
|
|||||||
Kernlogik des Spiels
|
Kernlogik des Spiels
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from src.types import Piece, Direction
|
from random import choice
|
||||||
|
|
||||||
from src.interface import parse_description
|
from src.interface import parse_description
|
||||||
|
from src.netTypes import Piece, Direction, Coordinate
|
||||||
|
|
||||||
# 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),
|
|
||||||
# ],
|
|
||||||
# ]
|
|
||||||
|
|
||||||
DEMO_FIELD = parse_description("5x5:c7634887c213e5b8db3e69282")
|
DEMO_FIELD = parse_description("5x5:c7634887c213e5b8db3e69282")
|
||||||
|
|
||||||
@@ -55,9 +18,12 @@ class Grid:
|
|||||||
def __init__(self, width: int, height: int) -> None:
|
def __init__(self, width: int, height: int) -> None:
|
||||||
self.height = height
|
self.height = height
|
||||||
self.width = width
|
self.width = width
|
||||||
self.pieces = (
|
if width != height or width not in [5, 7, 9, 11, 13]:
|
||||||
DEMO_FIELD # TODO: Field generation or import from Tatham's version
|
raise ValueError("Feldgrösse nicht erlaubt")
|
||||||
)
|
with open(f"descriptions/{width}x{height}.txt") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
selected = choice(lines).strip()
|
||||||
|
self.pieces = parse_description(selected)
|
||||||
|
|
||||||
def neighbors(self, x: int, y: int) -> list[Coordinate]:
|
def neighbors(self, x: int, y: int) -> list[Coordinate]:
|
||||||
neighbors: list[Coordinate] = []
|
neighbors: list[Coordinate] = []
|
||||||
@@ -82,7 +48,7 @@ class Grid:
|
|||||||
) -> list[list[bool]]:
|
) -> list[list[bool]]:
|
||||||
connected[x][y] = True
|
connected[x][y] = True
|
||||||
|
|
||||||
connectedNeighbors: list[Coordinate] = []
|
connected_neighbors: list[Coordinate] = []
|
||||||
for nx, ny in self.neighbors(x, y):
|
for nx, ny in self.neighbors(x, y):
|
||||||
dx = x - nx
|
dx = x - nx
|
||||||
dy = y - ny
|
dy = y - ny
|
||||||
@@ -92,9 +58,9 @@ class Grid:
|
|||||||
and Direction.from_offset(-dx, -dy)
|
and Direction.from_offset(-dx, -dy)
|
||||||
in self.pieces[x][y].connected_directions()
|
in self.pieces[x][y].connected_directions()
|
||||||
):
|
):
|
||||||
connectedNeighbors.append((nx, ny))
|
connected_neighbors.append((nx, ny))
|
||||||
|
|
||||||
for nx, ny in connectedNeighbors:
|
for nx, ny in connected_neighbors:
|
||||||
if connected[nx][ny]:
|
if connected[nx][ny]:
|
||||||
continue
|
continue
|
||||||
connected = self._solve_floodfill(nx, ny, connected)
|
connected = self._solve_floodfill(nx, ny, connected)
|
||||||
@@ -119,6 +85,9 @@ class NetGame:
|
|||||||
|
|
||||||
def turn_ccw(self, x: int, y: int) -> None:
|
def turn_ccw(self, x: int, y: int) -> None:
|
||||||
self._grid.pieces[x][y].turn_ccw()
|
self._grid.pieces[x][y].turn_ccw()
|
||||||
|
|
||||||
|
def lock(self, x: int, y: int) -> None:
|
||||||
|
self._grid.pieces[x][y].locked = not self._grid.pieces[x][y].locked
|
||||||
|
|
||||||
def solved(self):
|
def solved(self):
|
||||||
return self._grid.solved()
|
return self._grid.solved()
|
||||||
|
|||||||
@@ -51,7 +51,11 @@ class Piece:
|
|||||||
]
|
]
|
||||||
|
|
||||||
def turn_cw(self) -> None:
|
def turn_cw(self) -> None:
|
||||||
|
if self.locked:
|
||||||
|
return
|
||||||
self.direction = Direction((self.direction + 1) % 4)
|
self.direction = Direction((self.direction + 1) % 4)
|
||||||
|
|
||||||
def turn_ccw(self) -> None:
|
def turn_ccw(self) -> None:
|
||||||
|
if self.locked:
|
||||||
|
return
|
||||||
self.direction = Direction((self.direction - 1) % 4)
|
self.direction = Direction((self.direction - 1) % 4)
|
||||||
36
uv.lock
generated
36
uv.lock
generated
@@ -2,6 +2,18 @@ version = 1
|
|||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "basedpyright"
|
||||||
|
version = "1.39.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "nodejs-wheel-binaries" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/7a/1a/48296b4479ccc9051eb9617a6507a69a68f5b68693fb6a118cfe08199270/basedpyright-1.39.6.tar.gz", hash = "sha256:d00ec5f8ba4e1a67dfc2fa3a9474229c89f61f207d14c02d320db78f57aa16ef", size = 25504244, upload-time = "2026-05-24T07:44:41.864Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/07/6d1b3192715d42e8c9887876684a941eff28ec5d79c23a0f3758377e2182/basedpyright-1.39.6-py3-none-any.whl", hash = "sha256:5e0b9befbae6b26d0fbcc6645ac26923725e749d1224539e24f05ab07f9365ad", size = 13182122, upload-time = "2026-05-24T07:44:47.086Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maturaarbeit"
|
name = "maturaarbeit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -10,9 +22,33 @@ dependencies = [
|
|||||||
{ name = "pygame" },
|
{ name = "pygame" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "basedpyright" },
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "pygame", specifier = ">=2.6.1" }]
|
requires-dist = [{ name = "pygame", specifier = ">=2.6.1" }]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [{ name = "basedpyright", specifier = ">=1.39.6" }]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodejs-wheel-binaries"
|
||||||
|
version = "24.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a3/22/2a5beb4e21417c73233d9f65cf6f3e96e891b80d2f550a8f630ebc6b88c6/nodejs_wheel_binaries-24.16.0.tar.gz", hash = "sha256:c973cb69dc5fd16e6f6dc6e579e2c3d5534e2a1f57619dddf5ba070efa7dde37", size = 8056, upload-time = "2026-05-30T16:52:09.807Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/83/d1/68b43b53cd0fa83ae6fd406705023ca988d9e0ca41c724d82e66fbeb2ef6/nodejs_wheel_binaries-24.16.0-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:d9f8f677dcf30e37ac244f07869726abe043f01eb0f45722b1df31cc2af7093c", size = 55666374, upload-time = "2026-05-30T16:51:39.588Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e9/b2/40a989159599080da485de966c4c2d207e852ac7aa7864702626d96c8bf5/nodejs_wheel_binaries-24.16.0-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:3d0370fe7120ce9697a4f60d40480d2bd8808d9f30131458d5afc0040d4e5a51", size = 55838487, upload-time = "2026-05-30T16:51:43.383Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/a7/cd42174fb5ff6faff7fa8d326a18914d8f232098ab5de055b57c16fa13ca/nodejs_wheel_binaries-24.16.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:85dc92bbb79c851569c5925dcc2a4c915a034efab375f99e4e7e6bbe9cca8342", size = 60179540, upload-time = "2026-05-30T16:51:47.036Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/95/c8a1f9ae140aa28df8744d984d01d4b3af7cdd6555af12127f40ceb45a7d/nodejs_wheel_binaries-24.16.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:2f3036292811514ba847b3708492644764f88a833ac425c5f55007014308ddfd", size = 60716262, upload-time = "2026-05-30T16:51:50.711Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/c9/7c35b3737f59e36d0249c265397b7bff570519b95301d6e16ea361e904ad/nodejs_wheel_binaries-24.16.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:db8a8a76ebd2b28ecbfc9ad464baa3707241b9e050a30e2efdf6f60c0f886502", size = 62230592, upload-time = "2026-05-30T16:51:55Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/96/d931255cf9d11a84d6b54d882dba7434646467d568ccf070ea3418638df3/nodejs_wheel_binaries-24.16.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f1a3d8f7b4491cbbd023ba3fc4e901fcca2d9fb80d57f24ba3890de8b1dbac03", size = 62841759, upload-time = "2026-05-30T16:51:59.407Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/7b/8b7a3f41bc255411be30b6d7d288aab8ffd9ea2055db8555ced3548007b9/nodejs_wheel_binaries-24.16.0-py2.py3-none-win_amd64.whl", hash = "sha256:bb136be9944f0662dcf1120f45193a6b75b13fac378971a95cc42c9f879a81aa", size = 42027734, upload-time = "2026-05-30T16:52:03.348Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/66/1ed71f1f529b8ca727d42c7ceb9db0bef145ce4a13dfc86fb50aa44f3be6/nodejs_wheel_binaries-24.16.0-py2.py3-none-win_arm64.whl", hash = "sha256:8308940b5edd0a50dc5267ea36ba21c9f668e83fe0d9f293937174d3a7e31c36", size = 39714528, upload-time = "2026-05-30T16:52:06.421Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pygame"
|
name = "pygame"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user