Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/exebuilder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ jobs:
# BUILD
# -------------------------
- name: Build EXE
shell: bash
run: |
python -m PyInstaller --onefile --windowed --name Schach Brett.py
EXE_NAME="Schach_v${{ steps.version.outputs.new_version }}"
python -m PyInstaller --onefile --windowed --add-data "assets;assets" --name "$EXE_NAME" Brett.py

# -------------------------
# TAG ERSTELLEN
Expand All @@ -86,6 +88,6 @@ jobs:
with:
tag_name: v${{ steps.version.outputs.new_version }}
name: Schachspiel v${{ steps.version.outputs.new_version }}
files: dist/Schach.exe
files: dist/Schach_v${{ steps.version.outputs.new_version }}.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
*.exe

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
99 changes: 32 additions & 67 deletions Brett.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from Koenig import Koenig
from Dialog import Dialog, TextInputDialog
from time import time
from resource_path import resource_path

class Brett(pygame.sprite.Sprite):
'''
Expand Down Expand Up @@ -80,7 +81,6 @@ def __setupNetzwerkVars(self):
self.__netzVerbundenEvent = threading.Event()
self.__netzEmpfangThread:threading.Thread|None = None
self.__netzListenerThread:threading.Thread|None = None
self.__netzSucheThread:threading.Thread|None = None
self.__spielerName:str = ""
self.__meinTeam:int = 0
self.__wendeRemoteZugAn:bool = False
Expand Down Expand Up @@ -120,7 +120,7 @@ def __zeigeNameDialog(self):
Vor.: Die Startdialoggruppe ist initialisiert.
Eff.: Der Dialog zur Namenseingabe ist erstellt und aktiv gesetzt.
Inform einer weißen Box, welche sich ueber das Schachbrett streckt und die Ueberschrift "Name eingeben" traegt.
Mit den Unterueberschriften "Weiter", welche Interaktionsmoeglichkeiten darstellen im Bezug zur Ueberschrift.
Mit den Unterueberschriften "Zurück" und "Weiter", welche Interaktionsmoeglichkeiten darstellen im Bezug zur Ueberschrift.
Texteingaben sind in einem Eingabeberreich dargestellt.
Erg.: -
'''
Expand All @@ -135,7 +135,9 @@ def __zeigeNameDialog(self):
onVoidClick=self.__generateImage,
posOffset=self.rect.topleft,
onSurfaceChange=self.__generateImage,
maxInputLength=24
maxInputLength=24,
zweiterKnopfText="Zurück",
wennZweiterButton=self.__setupStartDialogs
)
self.__startDialogGruppe.empty()
self.__startDialogGruppe.add(self.__nameDialog)
Expand All @@ -144,16 +146,17 @@ def __zeigeNameDialog(self):
def __zeigeNetzStatusDialog(self, headline:str):
'''
Vor.: -headline- ist ein String und beschreibt die anzuzeigende Ueberschrift.
Eff.: Der Dialog zur Netzwerkinit und Suche ist erstellt und angezeigt.
Eff.: Der Dialog zur Netzwerkinit ist erstellt und angezeigt.
Inform einer weißen Box, welche sich ueber das Schachbrett streckt und die Ueberschrift -headline- mittig traegt.
Mit den Unterueberschriften "Erneut suchen", welche eine Interaktionsmoeglichkeit darstellen im Bezug zur Ueberschrift.
Mit den Unterueberschriften zur Anzeige der eigenen IP und zum manuellen Verbinden per IP.
Erg.: -
'''
lokaleIp = self.__holeLokaleIp()
self.__netzStatusDialog = Dialog(
self.rect.width, self.rect.height,
(self.rect.width//2, self.rect.height//2),
headline, self.rect.height//14,
[["Erneut suchen", self.__starteNetzSuche], ["IP eingeben", self.__zeigeIpDialog]],
[["Eigene IP: " + lokaleIp, None], ["IP eingeben", self.__zeigeIpDialog], ["Zurück", self.__zeigeNameDialog]],
self.rect.height//10, 0.7, False,
onVoidClick=self.__generateImage,
posOffset=self.rect.topleft,
Expand All @@ -175,7 +178,9 @@ def __zeigeIpDialog(self):
onVoidClick=self.__generateImage,
posOffset=self.rect.topleft,
onSurfaceChange=self.__generateImage,
maxInputLength=15
maxInputLength=15,
zweiterKnopfText="Zurück",
wennZweiterButton=lambda: self.__zeigeNetzStatusDialog("Warte auf Verbindung")
)
self.__startDialogGruppe.empty()
self.__startDialogGruppe.add(self.__ipDialog)
Expand Down Expand Up @@ -257,29 +262,16 @@ def __uebernehmeSpielerName(self, playerName:str):
def __starteMultiplayer(self):
'''
Vor.: Ein gueltiger Spielername ist gesetzt.
Eff.: Multiplayer ist aktiviert, Listener gestartet und Suche wird gestartet.
Mittels einen bereits in der optik Beschriebenden Dialogfensters ist der Suchstatus mittels der Ueberschrift "Suche im Netzwerk nach Spiel" abzulesen.
Eff.: Multiplayer ist aktiviert, Listener gestartet und die eigene IP wird zur manuellen Verbindungsaufnahme angezeigt.
Mittels einen bereits in der optik Beschriebenden Dialogfensters ist der Status mittels der Ueberschrift "Warte auf Verbindung" abzulesen.
Erg.: -
'''
self.__netzAktiv = True
print("Netzwerkstart auf Host:", socket.gethostname(), "IP:", self.__holeLokaleIp())
self.__zeigeNetzStatusDialog("Suche im Netzwerk nach Spiel")
self.__zeigeNetzStatusDialog("Warte auf Verbindung")
if self.__netzListenerThread == None or not(self.__netzListenerThread.is_alive()):
self.__netzListenerThread = threading.Thread(target=self.__listenerWorker, daemon=True)
self.__netzListenerThread.start()
self.__starteNetzSuche()

def __starteNetzSuche(self):
'''
Vor.: -
Eff.: Ein Suchthread ist gestartet, falls dieser nicht bereits läuft.
Erg.: -
'''
if self.__netzVerbundenEvent.is_set():
return
self.__zeigeNetzStatusDialog("Suche im Netzwerk nach Spiel")
self.__netzSucheThread = threading.Thread(target=self.__discoveryWorker, daemon=True)
self.__netzSucheThread.start()

def __holeLokaleIp(self)->str:
'''
Expand Down Expand Up @@ -328,47 +320,6 @@ def __listenerWorker(self):
self.__setzeNetzSocket(conn, 1)
return

def __discoveryWorker(self):
'''
Vor.: Netzwerkmodus ist aktiv.
Eff.: Sucht im lokalen Netz nach Gegenstellen und fuehrt ggf. Handshake aus. Bei Fehlern ist der Fehler im Dialogfenster "LAN-Suche fehlgeschlagen" oder "Kein Spiel gefunden, warte auf Anfrage" ablesbar.
Erg.: -
'''
localIp = self.__holeLokaleIp()
chunks = localIp.split(".")
if len(chunks) != 4:
self.__zeigeNetzStatusDialog("LAN-Suche fehlgeschlagen")
return
prefix = f"{chunks[0]}.{chunks[1]}.{chunks[2]}"
own = int(chunks[3])
print("Starte Suche in", prefix + ".1-254", "eigene IP-Endung:", own)
for host in range(1, 255):
if not(self.__netzAktiv) or self.__netzVerbundenEvent.is_set():
return
if host == own:
continue
target = f"{prefix}.{host}"
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if sock.connect_ex((target, self.__netzPort)) != 0:
sock.close()
continue
print("Port offen auf", target)
sock.sendall(("ASK;" + self.__spielerName + "\n").encode("utf-8"))
print("Gesendet an", target, ": ASK;" + self.__spielerName)
raw = sock.recv(2048)
if len(raw) == 0:
sock.close()
continue
responseText = raw.decode("utf-8").strip()
print("Antwort von", target, ":", responseText)
if responseText.startswith("OK;"):
self.__setzeNetzSocket(sock, 0)
return
sock.close()
if not(self.__netzVerbundenEvent.is_set()):
print("Suche fertig, kein Spiel gefunden")
self.__zeigeNetzStatusDialog("Kein Spiel gefunden, warte auf Anfrage")

def __setzeNetzSocket(self, sock:socket.socket, localTeam:int):
'''
Vor.: -sock- ist ein offener Socket, -localTeam- ist eine Team-ID.
Expand All @@ -381,6 +332,10 @@ def __setzeNetzSocket(self, sock:socket.socket, localTeam:int):
return
self.__netzSock = sock
self.__meinTeam = localTeam
if self.__meinTeam == 0:
self.setRotation(180)
else:
self.setRotation(0)
self.__netzVerbundenEvent.set()
print("Verbindung hergestellt. Eigenes Team:", localTeam)
if self.__modusDialog != None:
Expand Down Expand Up @@ -548,14 +503,23 @@ def setupDialogGroup(self):
self.rect.width, self.rect.height,
(self.rect.width//2, self.rect.height//2),
"Was möchtest du tun?", self.rect.height//8,
[["Neues Spiel!", self.restartGame]],
[["Neues Spiel!", self.restartGame], ["Zurück", self.__resignDialogAusblenden]],
self.rect.height//5, 0.4, True,
onVoidClick=self.__generateImage,
posOffset=self.rect.topleft,
onSurfaceChange=self.__generateImage
)
self.__DialogGroup.add(self.__resignDialog)

def __resignDialogAusblenden(self):
'''
Vor.: Der Aufgabedialog ist initialisiert.
Eff.: Der Aufgabedialog ist ausgeblendet und das Brettbild aktualisiert.
Erg.: -
'''
self.__resignDialog.hideSurface()
self.__generateImage()

def __reset_game_state(self):
'''
Vor.: -
Expand Down Expand Up @@ -1725,7 +1689,7 @@ def getFieldByCords(self, pos:tuple[int, int])->Feld|None:

if __name__ == "__main__":
pygame.init()
icon = pygame.image.load("assets/graphics/icon.png")
icon = pygame.image.load(resource_path("assets/graphics/icon.png"))
width = 800
height = width
screen = pygame.display.set_mode((width, height))
Expand Down Expand Up @@ -1764,4 +1728,5 @@ def getFieldByCords(self, pos:tuple[int, int])->Feld|None:
TestBrettGroup.draw(screen)
TestBrettGroup.update()
pygame.display.update()
clock.tick(60)

clock.tick(60)
24 changes: 22 additions & 2 deletions Dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def handleLeftClick(self, pos:tuple[int, int]):
self.hideSurface()

class TextInputDialog(pygame.sprite.Sprite):
def __init__(self, DialogWidth:int, DialogHeight:int, centerPosition:tuple[int], headline:str, headlineSize:int, inputSize:int, buttonText:str, buttonSize:int, closeable:bool, onSubmit:Callable|None=None, onVoidClick:Callable|None=None, posOffset:tuple[int, int]=(0,0), onSurfaceChange:Callable=None, maxInputLength:int=24):
def __init__(self, DialogWidth:int, DialogHeight:int, centerPosition:tuple[int], headline:str, headlineSize:int, inputSize:int, buttonText:str, buttonSize:int, closeable:bool, onSubmit:Callable|None=None, onVoidClick:Callable|None=None, posOffset:tuple[int, int]=(0,0), onSurfaceChange:Callable=None, maxInputLength:int=24, zweiterKnopfText:str|None=None, wennZweiterButton:Callable|None=None):
super().__init__()
self.__initPhase = True
self.__width:int = DialogWidth
Expand All @@ -182,6 +182,8 @@ def __init__(self, DialogWidth:int, DialogHeight:int, centerPosition:tuple[int],
self.__posOffset = posOffset
self.__onSurfaceChange = onSurfaceChange
self.__maxInputLength:int = maxInputLength
self.__secondaryButtonText:str|None = zweiterKnopfText
self.__wennZweiterButton:Callable|None = wennZweiterButton
self.__isShown = True
self.__eingabeWert:str = ""
self.__cursorSichtbar:bool = True
Expand Down Expand Up @@ -240,9 +242,19 @@ def makeSurface(self):

buttonFont = pygame.font.Font(None, self.__buttonSize)
self.__buttonSurface = buttonFont.render(self.__buttonText, False, "black").convert()
self.__buttonRect = self.__buttonSurface.get_rect(center=(self.__width//2, int(self.__height*0.78)))
buttonCenterY = int(self.__height*0.78)
if self.__secondaryButtonText == None:
self.__buttonRect = self.__buttonSurface.get_rect(center=(self.__width//2, buttonCenterY))
else:
self.__buttonRect = self.__buttonSurface.get_rect(center=(int(self.__width*0.68), buttonCenterY))
self.image.blit(self.__buttonSurface, self.__buttonRect)

self.__secondaryButtonRect = None
if self.__secondaryButtonText != None:
self.__secondaryButtonSurface = buttonFont.render(self.__secondaryButtonText, False, "black").convert()
self.__secondaryButtonRect = self.__secondaryButtonSurface.get_rect(center=(int(self.__width*0.32), buttonCenterY))
self.image.blit(self.__secondaryButtonSurface, self.__secondaryButtonRect)

if not(self.__initPhase):
self.__CallOnSurfaceChange()

Expand All @@ -260,6 +272,10 @@ def handleLeftClick(self, pos:tuple[int, int]):
return
localPos = (pos[0] - self.rect.x - self.__posOffset[0], pos[1] - self.rect.y - self.__posOffset[1])
didNoAction = True
if self.__secondaryButtonRect != None and self.__secondaryButtonRect.collidepoint(localPos):
if self.__wennZweiterButton != None:
self.__wennZweiterButton()
didNoAction = False
if self.__buttonRect.collidepoint(localPos):
if self.__onSubmit != None:
self.__onSubmit(self.__eingabeWert)
Expand All @@ -273,6 +289,10 @@ def handleLeftClick(self, pos:tuple[int, int]):
def handleKeyDown(self, event:pygame.event.Event):
if not(self.__isShown):
return
if event.key == pygame.K_ESCAPE:
if self.__wennZweiterButton != None:
self.__wennZweiterButton()
return
if event.key == pygame.K_RETURN:
if self.__onSubmit != None:
self.__onSubmit(self.__eingabeWert)
Expand Down
3 changes: 2 additions & 1 deletion FigurBuilder.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pygame
from sys import exit
from typing import Callable
from resource_path import resource_path

class FigurBuilder(pygame.sprite.Sprite):
'''
Expand Down Expand Up @@ -28,7 +29,7 @@ def __init__(self, image:str, size:int, field_length:int, field_count:int, field
self.__field_count:int = field_count
self.__fieldLabelStartLetter:str = fieldLabelStartLetter

self.image:pygame.surface.Surface = pygame.image.load(self.__imagePath).convert_alpha()
self.image:pygame.surface.Surface = pygame.image.load(resource_path(self.__imagePath)).convert_alpha()
self.image:pygame.surface.Surface = pygame.transform.scale(self.image, (size, size))

self.rect:pygame.rect.Rect = self.image.get_rect(center = self.__centerPos)
Expand Down
Loading
Loading