Skip to content

Commit bc18905

Browse files
Merge pull request #24 from devninja-sudo/pushes
Pushes, closes #17, closes #18, closes #23
2 parents 5d24a91 + a8ba75a commit bc18905

6 files changed

Lines changed: 70 additions & 71 deletions

File tree

.github/workflows/exebuilder.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ jobs:
6565
# BUILD
6666
# -------------------------
6767
- name: Build EXE
68+
shell: bash
6869
run: |
69-
python -m PyInstaller --onefile --windowed --name Schach Brett.py
70+
EXE_NAME="Schach_v${{ steps.version.outputs.new_version }}"
71+
python -m PyInstaller --onefile --windowed --add-data "assets;assets" --name "$EXE_NAME" Brett.py
7072
7173
# -------------------------
7274
# TAG ERSTELLEN
@@ -86,6 +88,6 @@ jobs:
8688
with:
8789
tag_name: v${{ steps.version.outputs.new_version }}
8890
name: Schachspiel v${{ steps.version.outputs.new_version }}
89-
files: dist/Schach.exe
91+
files: dist/Schach_v${{ steps.version.outputs.new_version }}.exe
9092
env:
9193
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ share/python-wheels/
2525
.installed.cfg
2626
*.egg
2727
MANIFEST
28+
*.exe
2829

2930
# PyInstaller
3031
# Usually these files are written by a python script from a template

Brett.py

Lines changed: 26 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from Koenig import Koenig
1212
from Dialog import Dialog, TextInputDialog
1313
from time import time
14+
from resource_path import resource_path
1415

1516
class Brett(pygame.sprite.Sprite):
1617
'''
@@ -80,7 +81,6 @@ def __setupNetzwerkVars(self):
8081
self.__netzVerbundenEvent = threading.Event()
8182
self.__netzEmpfangThread:threading.Thread|None = None
8283
self.__netzListenerThread:threading.Thread|None = None
83-
self.__netzSucheThread:threading.Thread|None = None
8484
self.__spielerName:str = ""
8585
self.__meinTeam:int = 0
8686
self.__wendeRemoteZugAn:bool = False
@@ -120,7 +120,7 @@ def __zeigeNameDialog(self):
120120
Vor.: Die Startdialoggruppe ist initialisiert.
121121
Eff.: Der Dialog zur Namenseingabe ist erstellt und aktiv gesetzt.
122122
Inform einer weißen Box, welche sich ueber das Schachbrett streckt und die Ueberschrift "Name eingeben" traegt.
123-
Mit den Unterueberschriften "Weiter", welche Interaktionsmoeglichkeiten darstellen im Bezug zur Ueberschrift.
123+
Mit den Unterueberschriften "Zurück" und "Weiter", welche Interaktionsmoeglichkeiten darstellen im Bezug zur Ueberschrift.
124124
Texteingaben sind in einem Eingabeberreich dargestellt.
125125
Erg.: -
126126
'''
@@ -135,7 +135,9 @@ def __zeigeNameDialog(self):
135135
onVoidClick=self.__generateImage,
136136
posOffset=self.rect.topleft,
137137
onSurfaceChange=self.__generateImage,
138-
maxInputLength=24
138+
maxInputLength=24,
139+
zweiterKnopfText="Zurück",
140+
wennZweiterButton=self.__setupStartDialogs
139141
)
140142
self.__startDialogGruppe.empty()
141143
self.__startDialogGruppe.add(self.__nameDialog)
@@ -144,16 +146,17 @@ def __zeigeNameDialog(self):
144146
def __zeigeNetzStatusDialog(self, headline:str):
145147
'''
146148
Vor.: -headline- ist ein String und beschreibt die anzuzeigende Ueberschrift.
147-
Eff.: Der Dialog zur Netzwerkinit und Suche ist erstellt und angezeigt.
149+
Eff.: Der Dialog zur Netzwerkinit ist erstellt und angezeigt.
148150
Inform einer weißen Box, welche sich ueber das Schachbrett streckt und die Ueberschrift -headline- mittig traegt.
149-
Mit den Unterueberschriften "Erneut suchen", welche eine Interaktionsmoeglichkeit darstellen im Bezug zur Ueberschrift.
151+
Mit den Unterueberschriften zur Anzeige der eigenen IP und zum manuellen Verbinden per IP.
150152
Erg.: -
151153
'''
154+
lokaleIp = self.__holeLokaleIp()
152155
self.__netzStatusDialog = Dialog(
153156
self.rect.width, self.rect.height,
154157
(self.rect.width//2, self.rect.height//2),
155158
headline, self.rect.height//14,
156-
[["Erneut suchen", self.__starteNetzSuche], ["IP eingeben", self.__zeigeIpDialog]],
159+
[["Eigene IP: " + lokaleIp, None], ["IP eingeben", self.__zeigeIpDialog], ["Zurück", self.__zeigeNameDialog]],
157160
self.rect.height//10, 0.7, False,
158161
onVoidClick=self.__generateImage,
159162
posOffset=self.rect.topleft,
@@ -175,7 +178,9 @@ def __zeigeIpDialog(self):
175178
onVoidClick=self.__generateImage,
176179
posOffset=self.rect.topleft,
177180
onSurfaceChange=self.__generateImage,
178-
maxInputLength=15
181+
maxInputLength=15,
182+
zweiterKnopfText="Zurück",
183+
wennZweiterButton=lambda: self.__zeigeNetzStatusDialog("Warte auf Verbindung")
179184
)
180185
self.__startDialogGruppe.empty()
181186
self.__startDialogGruppe.add(self.__ipDialog)
@@ -257,29 +262,16 @@ def __uebernehmeSpielerName(self, playerName:str):
257262
def __starteMultiplayer(self):
258263
'''
259264
Vor.: Ein gueltiger Spielername ist gesetzt.
260-
Eff.: Multiplayer ist aktiviert, Listener gestartet und Suche wird gestartet.
261-
Mittels einen bereits in der optik Beschriebenden Dialogfensters ist der Suchstatus mittels der Ueberschrift "Suche im Netzwerk nach Spiel" abzulesen.
265+
Eff.: Multiplayer ist aktiviert, Listener gestartet und die eigene IP wird zur manuellen Verbindungsaufnahme angezeigt.
266+
Mittels einen bereits in der optik Beschriebenden Dialogfensters ist der Status mittels der Ueberschrift "Warte auf Verbindung" abzulesen.
262267
Erg.: -
263268
'''
264269
self.__netzAktiv = True
265270
print("Netzwerkstart auf Host:", socket.gethostname(), "IP:", self.__holeLokaleIp())
266-
self.__zeigeNetzStatusDialog("Suche im Netzwerk nach Spiel")
271+
self.__zeigeNetzStatusDialog("Warte auf Verbindung")
267272
if self.__netzListenerThread == None or not(self.__netzListenerThread.is_alive()):
268273
self.__netzListenerThread = threading.Thread(target=self.__listenerWorker, daemon=True)
269274
self.__netzListenerThread.start()
270-
self.__starteNetzSuche()
271-
272-
def __starteNetzSuche(self):
273-
'''
274-
Vor.: -
275-
Eff.: Ein Suchthread ist gestartet, falls dieser nicht bereits läuft.
276-
Erg.: -
277-
'''
278-
if self.__netzVerbundenEvent.is_set():
279-
return
280-
self.__zeigeNetzStatusDialog("Suche im Netzwerk nach Spiel")
281-
self.__netzSucheThread = threading.Thread(target=self.__discoveryWorker, daemon=True)
282-
self.__netzSucheThread.start()
283275

284276
def __holeLokaleIp(self)->str:
285277
'''
@@ -328,47 +320,6 @@ def __listenerWorker(self):
328320
self.__setzeNetzSocket(conn, 1)
329321
return
330322

331-
def __discoveryWorker(self):
332-
'''
333-
Vor.: Netzwerkmodus ist aktiv.
334-
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.
335-
Erg.: -
336-
'''
337-
localIp = self.__holeLokaleIp()
338-
chunks = localIp.split(".")
339-
if len(chunks) != 4:
340-
self.__zeigeNetzStatusDialog("LAN-Suche fehlgeschlagen")
341-
return
342-
prefix = f"{chunks[0]}.{chunks[1]}.{chunks[2]}"
343-
own = int(chunks[3])
344-
print("Starte Suche in", prefix + ".1-254", "eigene IP-Endung:", own)
345-
for host in range(1, 255):
346-
if not(self.__netzAktiv) or self.__netzVerbundenEvent.is_set():
347-
return
348-
if host == own:
349-
continue
350-
target = f"{prefix}.{host}"
351-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
352-
if sock.connect_ex((target, self.__netzPort)) != 0:
353-
sock.close()
354-
continue
355-
print("Port offen auf", target)
356-
sock.sendall(("ASK;" + self.__spielerName + "\n").encode("utf-8"))
357-
print("Gesendet an", target, ": ASK;" + self.__spielerName)
358-
raw = sock.recv(2048)
359-
if len(raw) == 0:
360-
sock.close()
361-
continue
362-
responseText = raw.decode("utf-8").strip()
363-
print("Antwort von", target, ":", responseText)
364-
if responseText.startswith("OK;"):
365-
self.__setzeNetzSocket(sock, 0)
366-
return
367-
sock.close()
368-
if not(self.__netzVerbundenEvent.is_set()):
369-
print("Suche fertig, kein Spiel gefunden")
370-
self.__zeigeNetzStatusDialog("Kein Spiel gefunden, warte auf Anfrage")
371-
372323
def __setzeNetzSocket(self, sock:socket.socket, localTeam:int):
373324
'''
374325
Vor.: -sock- ist ein offener Socket, -localTeam- ist eine Team-ID.
@@ -548,14 +499,23 @@ def setupDialogGroup(self):
548499
self.rect.width, self.rect.height,
549500
(self.rect.width//2, self.rect.height//2),
550501
"Was möchtest du tun?", self.rect.height//8,
551-
[["Neues Spiel!", self.restartGame]],
502+
[["Neues Spiel!", self.restartGame], ["Zurück", self.__resignDialogAusblenden]],
552503
self.rect.height//5, 0.4, True,
553504
onVoidClick=self.__generateImage,
554505
posOffset=self.rect.topleft,
555506
onSurfaceChange=self.__generateImage
556507
)
557508
self.__DialogGroup.add(self.__resignDialog)
558509

510+
def __resignDialogAusblenden(self):
511+
'''
512+
Vor.: Der Aufgabedialog ist initialisiert.
513+
Eff.: Der Aufgabedialog ist ausgeblendet und das Brettbild aktualisiert.
514+
Erg.: -
515+
'''
516+
self.__resignDialog.hideSurface()
517+
self.__generateImage()
518+
559519
def __reset_game_state(self):
560520
'''
561521
Vor.: -
@@ -1725,7 +1685,7 @@ def getFieldByCords(self, pos:tuple[int, int])->Feld|None:
17251685

17261686
if __name__ == "__main__":
17271687
pygame.init()
1728-
icon = pygame.image.load("assets/graphics/icon.png")
1688+
icon = pygame.image.load(resource_path("assets/graphics/icon.png"))
17291689
width = 800
17301690
height = width
17311691
screen = pygame.display.set_mode((width, height))

Dialog.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def handleLeftClick(self, pos:tuple[int, int]):
165165
self.hideSurface()
166166

167167
class TextInputDialog(pygame.sprite.Sprite):
168-
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):
168+
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):
169169
super().__init__()
170170
self.__initPhase = True
171171
self.__width:int = DialogWidth
@@ -182,6 +182,8 @@ def __init__(self, DialogWidth:int, DialogHeight:int, centerPosition:tuple[int],
182182
self.__posOffset = posOffset
183183
self.__onSurfaceChange = onSurfaceChange
184184
self.__maxInputLength:int = maxInputLength
185+
self.__secondaryButtonText:str|None = zweiterKnopfText
186+
self.__wennZweiterButton:Callable|None = wennZweiterButton
185187
self.__isShown = True
186188
self.__eingabeWert:str = ""
187189
self.__cursorSichtbar:bool = True
@@ -240,9 +242,19 @@ def makeSurface(self):
240242

241243
buttonFont = pygame.font.Font(None, self.__buttonSize)
242244
self.__buttonSurface = buttonFont.render(self.__buttonText, False, "black").convert()
243-
self.__buttonRect = self.__buttonSurface.get_rect(center=(self.__width//2, int(self.__height*0.78)))
245+
buttonCenterY = int(self.__height*0.78)
246+
if self.__secondaryButtonText == None:
247+
self.__buttonRect = self.__buttonSurface.get_rect(center=(self.__width//2, buttonCenterY))
248+
else:
249+
self.__buttonRect = self.__buttonSurface.get_rect(center=(int(self.__width*0.68), buttonCenterY))
244250
self.image.blit(self.__buttonSurface, self.__buttonRect)
245251

252+
self.__secondaryButtonRect = None
253+
if self.__secondaryButtonText != None:
254+
self.__secondaryButtonSurface = buttonFont.render(self.__secondaryButtonText, False, "black").convert()
255+
self.__secondaryButtonRect = self.__secondaryButtonSurface.get_rect(center=(int(self.__width*0.32), buttonCenterY))
256+
self.image.blit(self.__secondaryButtonSurface, self.__secondaryButtonRect)
257+
246258
if not(self.__initPhase):
247259
self.__CallOnSurfaceChange()
248260

@@ -260,6 +272,10 @@ def handleLeftClick(self, pos:tuple[int, int]):
260272
return
261273
localPos = (pos[0] - self.rect.x - self.__posOffset[0], pos[1] - self.rect.y - self.__posOffset[1])
262274
didNoAction = True
275+
if self.__secondaryButtonRect != None and self.__secondaryButtonRect.collidepoint(localPos):
276+
if self.__wennZweiterButton != None:
277+
self.__wennZweiterButton()
278+
didNoAction = False
263279
if self.__buttonRect.collidepoint(localPos):
264280
if self.__onSubmit != None:
265281
self.__onSubmit(self.__eingabeWert)
@@ -273,6 +289,10 @@ def handleLeftClick(self, pos:tuple[int, int]):
273289
def handleKeyDown(self, event:pygame.event.Event):
274290
if not(self.__isShown):
275291
return
292+
if event.key == pygame.K_ESCAPE:
293+
if self.__wennZweiterButton != None:
294+
self.__wennZweiterButton()
295+
return
276296
if event.key == pygame.K_RETURN:
277297
if self.__onSubmit != None:
278298
self.__onSubmit(self.__eingabeWert)

FigurBuilder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pygame
22
from sys import exit
33
from typing import Callable
4+
from resource_path import resource_path
45

56
class FigurBuilder(pygame.sprite.Sprite):
67
'''
@@ -28,7 +29,7 @@ def __init__(self, image:str, size:int, field_length:int, field_count:int, field
2829
self.__field_count:int = field_count
2930
self.__fieldLabelStartLetter:str = fieldLabelStartLetter
3031

31-
self.image:pygame.surface.Surface = pygame.image.load(self.__imagePath).convert_alpha()
32+
self.image:pygame.surface.Surface = pygame.image.load(resource_path(self.__imagePath)).convert_alpha()
3233
self.image:pygame.surface.Surface = pygame.transform.scale(self.image, (size, size))
3334

3435
self.rect:pygame.rect.Rect = self.image.get_rect(center = self.__centerPos)

resource_path.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import os
2+
import sys
3+
4+
5+
def resource_path(relative_path:str)->str:
6+
'''
7+
Vor.: -relative_path- ist ein relativer Pfad innerhalb des Projekts.
8+
Eff.: -
9+
Erg.: Der zur Laufzeit gueltige absolute Pfad ist geliefert, sowohl im Projektordner als auch in einer PyInstaller-Exe.
10+
'''
11+
if hasattr(sys, "_MEIPASS"):
12+
base_path = sys._MEIPASS
13+
else:
14+
base_path = os.path.dirname(os.path.abspath(__file__))
15+
return os.path.join(base_path, relative_path)

0 commit comments

Comments
 (0)