Compare commits

..

3 Commits

Author SHA1 Message Date
vargadavidlajos
6c2c9aeb10 added points 7-15 to rendszerterv.md 2025-11-15 20:19:35 +01:00
Bence
0dae3f9773 Rendszerterv első része az órán közösen megbeszéltek alapján 2025-11-12 11:20:54 +01:00
8f9a48fa96 rendszerterv v1 2025-11-11 12:40:29 +01:00
13 changed files with 519 additions and 384 deletions

View File

@@ -26,13 +26,13 @@ jobs:
SERVER=false
UI=false
if [[ "$BRANCH" == *"Engine"* ]] ; then
if [[ "$BRANCH" == *"Engine"* ]]; then
ENGINE=true
fi
if [[ "$BRANCH" == *"Server"* ]] ; then
if [[ "$BRANCH" == *"Server"* ]]; then
SERVER=true
fi
if [[ "$BRANCH" == *"UI"* ]] ; then
if [[ "$BRANCH" == *"UI"* ]]; then
UI=true
fi

View File

@@ -1,6 +1,7 @@
name: Engine Tests
on:
pull_request:
workflow_dispatch:
workflow_call:

View File

@@ -1,6 +1,7 @@
name: Release build
on:
pull_request:
workflow_dispatch:
workflow_call:

View File

@@ -1,6 +1,7 @@
name: Server Tests
on:
pull_request:
workflow_dispatch:
workflow_call:

View File

@@ -1,6 +1,7 @@
name: UI Tests
on:
pull_request:
workflow_dispatch:
workflow_call:

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

View File

@@ -0,0 +1,287 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:144.0) Gecko/20100101 Firefox/144.0" version="28.2.9">
<diagram name="Page-1" id="9d-IwT1pk2NoWoP7MTJv">
<mxGraphModel dx="1534" dy="751" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="9999" pageHeight="9999" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-1" target="IaA3IaIvg4qVMEhu7ya9-36" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-1" value="App megnyitása" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="50" width="140" height="40" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-9" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="540" y="120" />
<mxPoint x="370" y="120" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-12" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-13" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-15" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-18" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="670" y="180" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-6" target="IaA3IaIvg4qVMEhu7ya9-20" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-6" value="&lt;div&gt;főmenü&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="480" y="40" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-9" target="IaA3IaIvg4qVMEhu7ya9-23" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-9" value="Lokális játék hosztolása" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="310" y="210" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-32" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-11" target="IaA3IaIvg4qVMEhu7ya9-31" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-11" value="&lt;div&gt;Lokális játékba csatlakozni&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="460" y="220" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-13" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-18" target="4rzJeeoM2DMZDjvMm2AJ-12" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-18" value="Online jatek&lt;br&gt;(sorba allas)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="695" y="200" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="IaA3IaIvg4qVMEhu7ya9-6" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-28" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="IaA3IaIvg4qVMEhu7ya9-27" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="IaA3IaIvg4qVMEhu7ya9-27">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="iJwoCWMJ6fIoSaqHo3aH-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-6" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="iJwoCWMJ6fIoSaqHo3aH-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="iJwoCWMJ6fIoSaqHo3aH-7">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="770" y="80" />
<mxPoint x="1000" y="80" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-20" target="iJwoCWMJ6fIoSaqHo3aH-9">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-20" value="&lt;div&gt;Beallitasok&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="650" y="40" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-23" target="4rzJeeoM2DMZDjvMm2AJ-4" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-23" value="&lt;div&gt;Szerver peldany elinditasa&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="130" y="150" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-31" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-25" target="IaA3IaIvg4qVMEhu7ya9-29" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-16" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="IaA3IaIvg4qVMEhu7ya9-25" target="iJwoCWMJ6fIoSaqHo3aH-15">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-25" value="varakozas az ellenfelre" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="130" y="390" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-27" value="lokalis jatekhoz port megvaltoztatasa" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="830" y="10" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-33" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-29" target="4rzJeeoM2DMZDjvMm2AJ-32" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-29" value="&lt;div&gt;jatek elkezdése&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="400" y="850" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-34" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-31" target="IaA3IaIvg4qVMEhu7ya9-33" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-31" value="&lt;div&gt;lokalis halozaton szerver ip:port megadasa&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="460" y="360" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-33" target="IaA3IaIvg4qVMEhu7ya9-29" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-33" value="csatlakozás" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="290" y="360" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="IaA3IaIvg4qVMEhu7ya9-36" target="IaA3IaIvg4qVMEhu7ya9-6" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="IaA3IaIvg4qVMEhu7ya9-36" value="user struct letrehozasa a app-ban" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="340" y="40" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-4" target="4rzJeeoM2DMZDjvMm2AJ-7" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-4" value="hostolo kapcsolodik a szerverehez" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="130" y="230" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-7" target="IaA3IaIvg4qVMEhu7ya9-25" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-7" value="eszköz ip cím lekérése a csatlakozáshoz" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="130" y="310" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-12" target="4rzJeeoM2DMZDjvMm2AJ-20" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-12" value="&lt;div&gt;csatlakozás a központi szerverhez&lt;/div&gt;(tudjuk az ip cimet)" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="690" y="300" width="130" height="70" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-16" target="4rzJeeoM2DMZDjvMm2AJ-23" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-27" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-16" target="4rzJeeoM2DMZDjvMm2AJ-26" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-16" value="sorban állás szabad játékra várva" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="695" y="480" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-20" target="4rzJeeoM2DMZDjvMm2AJ-16" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-20" value="a szerver eltárolja az uj jatekost mint aktiv felhasznalo a listaban" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="700" y="390" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-23" value="a szerveren bekerultunk a varolistaba" style="ellipse;whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="850" y="465" width="155" height="90" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-26" target="4rzJeeoM2DMZDjvMm2AJ-28" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-26" value="&lt;div&gt;megjelent meg egy jatekos a varolistan&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="695" y="570" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-28" target="IaA3IaIvg4qVMEhu7ya9-29" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-28" value="ket jatekos ossze vonasa egy meccsbe. Kivesszuk oket a varolistabol es egy Match structba osszevonjuk oket" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="682.5" y="660" width="145" height="120" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-35" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-32" target="4rzJeeoM2DMZDjvMm2AJ-34" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-32" value="&lt;div&gt;fehér és fekete oldal eldöntése&lt;/div&gt;&lt;div&gt;(szerver által, érme dobással)&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="390" y="950" width="140" height="80" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-37" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-34" target="4rzJeeoM2DMZDjvMm2AJ-36" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-34" value="játék ui megjelenítése" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="400" y="1060" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-39" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-36" target="4rzJeeoM2DMZDjvMm2AJ-38" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-36" value="lehetséges lépések lekérése a tábla állapot alapján a szerver / engine-től" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="390" y="1160" width="140" height="90" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-41" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-38" target="4rzJeeoM2DMZDjvMm2AJ-40" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-38" value="a ui lokalisan eltarolja ezt az adot a következő körig" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="400" y="1280" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-40" target="iJwoCWMJ6fIoSaqHo3aH-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="4rzJeeoM2DMZDjvMm2AJ-40" target="iJwoCWMJ6fIoSaqHo3aH-18">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="4rzJeeoM2DMZDjvMm2AJ-40" value="a jatekos lep a egy babual. Ekkor ellenorizzuk hogy szabad e volt ezt a léppést megtennie" style="whiteSpace=wrap;html=1;rounded=0;" parent="1" vertex="1">
<mxGeometry x="390" y="1370" width="140" height="90" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-12" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-1" target="iJwoCWMJ6fIoSaqHo3aH-11">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-14" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-1" target="iJwoCWMJ6fIoSaqHo3aH-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-1" value="ha szabad volt elküldjük a lépést a szervernek" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="400" y="1490" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-4" value="felbontás megváltoztatása" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="830" y="90" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-7" value="teljes képernyő" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1000" y="50" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-9" value="ai api kulcs megadása" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1000" y="140" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-11" target="iJwoCWMJ6fIoSaqHo3aH-20">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-11" value="&lt;div&gt;ellenfél ui frissítése&lt;/div&gt;" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="400" y="1580" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-13" value="&lt;div&gt;{&lt;/div&gt;&lt;div&gt;from:str,&lt;/div&gt;&lt;div&gt;to: str&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;" style="rhombus;whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="560" y="1455" width="140" height="130" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-15" value="Ip cím megjelenítése a könnyebb csatlakozás érdekében" style="ellipse;whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="20" y="490" width="120" height="150" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-18" value="a ui végig megy az adatokon, amit visszakapott a szervertől a kör elején" style="ellipse;whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="590" y="1290" width="170" height="110" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-23" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-20" target="iJwoCWMJ6fIoSaqHo3aH-22">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-20" target="iJwoCWMJ6fIoSaqHo3aH-24">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-20">
<mxGeometry relative="1" as="geometry">
<mxPoint x="640" y="1860" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-20" value="ellenőrizzük, hogy nyert-e a játékos vagy döntetlen lett-e" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="395" y="1670" width="130" height="70" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-22" value="a szerver megkapja a tábla állást és elküldi az enginnek ami ad egy választ" style="ellipse;whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="560" y="1647.5" width="200" height="115" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-24" target="4rzJeeoM2DMZDjvMm2AJ-36">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="360" y="1820" />
<mxPoint x="360" y="1205" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-24" value="kör átadása az ellenfélnek" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="400" y="1790" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-30" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="iJwoCWMJ6fIoSaqHo3aH-28" target="iJwoCWMJ6fIoSaqHo3aH-29">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-28" value="játék befejezése, nyertes megjelnítése,&amp;nbsp;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="1860" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="iJwoCWMJ6fIoSaqHo3aH-29" value="a játékosokat vissza küldjük a menübe, a szerver oldalon töröljük a meccset a listából, és töröljük&amp;nbsp; a játékosokat a meccs közben lévő listából" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
<mxGeometry x="560" y="1940" width="160" height="120" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -1,125 +0,0 @@
# Követelmény-specifikáció
## 1. Áttekintés
A jelen dokumentum célja, hogy bemutassa a CastlingCreations megrendelésére készülő Knightly nevű alkalmazás alapvető céljait, funkcionális és nem funkcionális követelményeinek áttekintését, valamint a fejlesztés kontextusát.
A Knightly egy modern, digitális sakkalkalmazás, amely kezdetben helyi hálózaton (LAN) keresztül teszi lehetővé két játékos számára, hogy valós időben mérkőzzenek meg egymással. A rendszer egy grafikus felhasználói felületen keresztül biztosítja a játék indítását, a szerver futtatását és a másik félhez történő csatlakozást.
A projekt hosszú távú célja, hogy a Knightly egy online platformmá fejlődjön, amely hasonló módon működik, mint a népszerű sakkportálok (pl. chess.com): a felhasználók fiókot hozhatnak létre, bejelentkezhetnek, és egy központi szerveren keresztül kereshetnek, illetve indíthatnak mérkőzéseket.
A fejlesztés első szakasza azonban a LAN-alapú verzió megvalósítására koncentrál, amely a sakkjátszma logikai alapjainak, a játékállapot kezelésének és a hálózati kommunikáció modelljének megvalósítását célozza. A későbbi online verzió ezekre az alapokra építkezve bővíthető tovább.
## 2. Vágyálom rendszer
A vágyálom rendszer célja egy teljes körű, modern online sakkplatform létrehozása, amely nemcsak a klasszikus sakkjáték digitális megvalósítását kínálja, hanem egy közösségi, versenyképes és kényelmes felhasználói élményt is biztosít. A hosszú távú cél, hogy a rendszer működése és felépítése a nagyobb nemzetközi sakkoldalakhoz (például a chess.com-hoz vagy a lichess.org-hoz) hasonló legyen, de saját, könnyen kezelhető és letisztult felülettel.
A felhasználók a rendszerben saját profilt hozhatnak létre, amellyel be tudnak jelentkezni, és részt vehetnek online mérkőzéseken más játékosok ellen. A rendszer automatikusan párosítaná őket ellenfelekkel, de lehetőséget adna arra is, hogy barátokat hívjanak meg privát meccsekre. A lejátszott mérkőzések mentésre kerülnének, így a játékosok bármikor visszanézhetnék vagy elemezhetnék azokat.
A játék mellett a felhasználók statisztikákat is láthatnának magukról, például nyerési arányt, aktuális értékszámot (rating), leggyakoribb megnyitásokat, illetve fejlődési tendenciát az idő során. A rendszer ezen felül egy egyszerű chat funkciót is tartalmazna, hogy a játékosok kommunikálhassanak egymással a játszmák közben vagy akár azokon kívül is.
A vágyálom rendszer alapját egy központi szerver képezné, amely kezeli a felhasználói fiókokat, a bejelentkezéseket, a matchmaking folyamatot, valamint a játékok futását és szinkronizálását. A szerver a kliensalkalmazásokkal valós idejű adatkapcsolatot tartana fenn, így a játék során minden lépés azonnal megjelenne a másik játékosnál is.
A platform célja a megbízható és folyamatos működés, akár nagyobb terhelés mellett is. A rendszer fejlesztése során kiemelt szempont lenne a biztonság (adatvédelem, csalás elleni védelem), a stabil hálózati kommunikáció, valamint a bővíthetőség például ranglisták, versenyek vagy mobilalkalmazás későbbi integrálásának lehetősége.
Összességében a vágyálom rendszer egy minden szempontból teljes értékű, közösségorientált sakkalkalmazás lenne, amely a mostani, helyi hálózaton működő változatból fejlődne tovább egy interneten keresztül bárhonnan elérhető platformmá.
## 4. Rendszer követelmények
A rendszer célja egy kétjátékos sakkalkalmazás megvalósítása, amely alapvetően hálózati kapcsolat (LAN vagy internet) segítségével biztosítja a valós idejű játékot. A rendszer kliensszerver architektúrán alapul, ahol az egyes komponensek jól elkülönülten, meghatározott feladatokat látnak el.
### 4.1 Kötelező funkcionális követelmények
A rendszernek az alábbi alapvető funkciókat mindenképpen biztosítania kell:
- Két játékos közötti sakkjátszma lebonyolítása, a hivatalos sakk szabályai alapján.
- A játékosok felváltva tehetnek lépéseket, a lépések érvényességét a kliens oldali logika ellenőrzi.
- A rendszer valós időben szinkronizálja a két kliens állapotát (mindkét fél ugyanazt a táblát látja).
- A játék vége (sakkmatt, patt, idő lejárta) automatikusan felismerésre kerül.
- A szerver egyidejűleg több játékot is képes kezelni (külön szobákban vagy sessionökben).
- A játékosok elindíthatnak új meccset, illetve befejezett játék után visszatérhetnek a főmenübe.
- A rendszer minden játékban egyedi azonosítót (Game ID) használ a játékállapot nyomon követéséhez.
- A kliens értesítéseket kap az ellenfél lépéseiről és a játék állapotváltozásairól.
### 4.2 Kliens oldali követelmények
A kliens felelős a játékos felhasználói élményéért, a grafikus megjelenítésért és a játéklogika helyi működéséért.
A kliensnek tudnia kell:
- A sakk tábla és a figurák megjelenítése, lépések kezelése (egérkattintás vagy billentyűparancsok).
- Lépések érvényesítése és elküldése a szervernek.
- A szervertől érkező események (ellenfél lépése, állapotváltozás) feldolgozása és megjelenítése.
- Hibák és megszakadt kapcsolat kezelése (újracsatlakozási lehetőség).
- Saját IP vagy szerver cím megadása LAN esetén.
- Alapvető menürendszer (csatlakozás, szerverindítás, új játék, kilépés).
- A hálózati kommunikáció egységes formátumban történjen (pl. JSON alapú üzenetek).
### 4.3 Szerver oldali követelmények
A szerver feladata a kliensek közti kommunikáció kezelése, az állapotok szinkronizálása és a játék logikai integritásának megőrzése.
A szervernek tudnia kell:
- Kapcsolatok fogadása és kezelése több kliens esetén is.
- Új játék (session) létrehozása és azonosító kiosztása.
- Üzenetek továbbítása a kliensek között (pl. lépés, visszajelzés, játék vége).
- A játékállapot naprakészen tartása és küldése mindkét félnek.
- Kapcsolat megszakadása esetén az érintett játék szüneteltetése vagy lezárása.
- Üzenetformátumok ellenőrzése és hibás adatok elutasítása.
- Kliensazonosítás és egyszerű hitelesítés (pl. játékosnév alapján).
- A kommunikáció biztonságos kezelése (üzenetduplikáció, szinkronizációs hibák elkerülése).
### 4.4 A komponensek közti kommunikáció (szerződések)
A rendszer komponensei egy meghatározott üzenetprotokollon keresztül kommunikálnak egymással.
A kommunikáció kétirányú, valós idejű, és az alábbi szerződések szerint zajlik:
A kliens minden lépést csak akkor hajt végre a felhasználói felületen, ha a szervertől visszaigazolást kapott az érvényességéről.
A szerver az üzeneteket sorosítva, FIFO-elv szerint dolgozza fel, és broadcastolja a változásokat az adott játékhoz tartozó összes kliensnek.
### 4.5 Nem funkcionális követelmények
- Megbízhatóság: a rendszernek stabilan kell működnie hálózati késleltetés és csomagvesztés esetén is.
- Teljesítmény: a szerver legalább 10 párhuzamos játékot képes kezelni érezhető lassulás nélkül.
- Biztonság: a kliens csak a szerver által engedélyezett parancsokat hajthatja végre.
- Bővíthetőség: a rendszer felépítése moduláris legyen, hogy később könnyen kiterjeszthető legyen (pl. online matchmaking).
- Platformfüggetlenség: a kliens és a szerver futtatható legyen Windows, Linux és esetleg webes környezetben.
- Karbantarthatóság: kódmodulok (logika, hálózat, UI) elkülönítése, jól dokumentált interfészekkel.
### 4.6 Minimális technikai elvárások
- Programozási nyelv: Rust, C#, Python vagy más, hálózati alkalmazásokra alkalmas nyelv.
- Kommunikációs protokoll: TCP vagy WebSocket alapú kapcsolat.
- Adatcsere formátum: JSON.
- Grafikus felület: desktop GUI (pl. egérvezérlés, drag & drop lépés).
- Követelmény kliensoldalon: legalább 4 GB RAM, modern operációs rendszer.
- Követelmény szerveroldalon: 1 CPU mag, 512 MB RAM, állandó hálózati kapcsolat.
## 5. Követelménylista
### Szerver
| Név | Verzió | Leírás |
| --- | ------ | ------ |
| **WebSocket** | 1.0 | A szerver és a kliens között folyamatos kétirányú kommunikációt biztosít. A kapcsolat létrejötte után a szerver valós időben képes fogadni és továbbítani az eseményeket (pl. lépés végrehajtása, állapotfrissítés). Hiba esetén a kapcsolat automatikusan újraépül. |
| **Kapcsolatok csoportosítása** | 1.0 | A szerver figyeli az elérhető, szabad klienseket, majd két szabad kapcsolatot automatikusan összerendel egy meccsbe. A csoportosítás után a játékosok azonos „room”-ba kerülnek, és a szerver biztosítja az egymás közötti adatkommunikációt. |
| **Kommunikáció az engine-nel** | 1.0 | A szerver a játékosoktól érkező lépéseket és játékinformációkat továbbítja az engine-nek feldolgozásra. Az engine válasza után a szerver visszaküldi az eredményt a klienseknek (pl. érvényes lépés, matt, patt). A kommunikáció aszinkron módon zajlik, válaszidő-ellenőrzéssel. |
| **Kommunikáció a UI-al** | 1.0 | A szerver WebSocket-en keresztül adatokat továbbít a felhasználói felület és az engine között. A UI által kért műveletek (pl. új meccs létrehozása, állapotlekérés) feldolgozását a szerver közvetíti.|
### Engine
| Név | Verzió | Leírás |
| --- | ------ | ------ |
| **Bitboard** | 1.0 | A játék táblaállapotát bitműveletekkel reprezentálja a hatékonyság érdekében. Minden bábu típus és szín külön bitmask-on kerül tárolásra, lehetővé téve a gyors lekérdezéseket és lépésellenőrzéseket. |
| **Lépésgenerálás LUT** | 1.0 | Előre kiszámított lookup táblák segítségével gyorsítja a lépésgenerálást és szabályellenőrzést. Ez csökkenti a számítási időt, és optimalizálja az engine teljesítményét. |
| **Lépésgenerálás** | 1.0 | A különböző bábutípusok (gyalog, bástya, futó, stb.) lépési logikáját valósítja meg. A függvények ellenőrzik a lépés érvényességét, figyelembe véve az aktuális állást, sakkhelyzetet és speciális szabályokat (pl. sáncolás, en passant). |
| **Util függvények** | 1.0 | Segédfüggvények az engine belső működéséhez, például raycast műveletek, bitműveleti maszkok kezelése, valamint logikai ellenőrzések a lépések és ütések számításához. |
### UI
| Név | Verzió | Leírás |
| --- | ------ | ------ |
| **Belépés** | 1.0 | A felhasználó a kezdőképernyőn keresztül adhatja meg a nevét lokális játékhoz, vagy hitelesítheti magát online játékmód esetén. Hibás adatok esetén a rendszer figyelmeztetést küld. |
| **Főmenü** | 1.0 | Az alkalmazás központi navigációs felülete, ahol a felhasználó meccset kereshet, új játékot indíthat lokálisan, vagy beállításokat módosíthat. A menü megjeleníti az aktuális státuszt (online/offline). |
| **Játék** | 1.0 | A játékfelület megjeleníti a táblát, bábukat, lépéseket, és az aktuális játékállást. Támogatja mind az online, mind a lokális módot. A felület kezeli az interakciókat (lépéskattintás, visszavonás, végeredmény kijelzés). |
| **Kommunikáció a szerverrel** | 1.0 | A kliens a szerveren keresztül kommunikál az engine-nel. A UI felel az üzenetek küldéséért (lépés, új játék, visszajelzés), valamint a szervertől kapott események vizuális megjelenítéséért. |
### GitHub Actions (CI/CD)
| Név | Leírás |
| --- | ------ |
| Folyamatos tesztelés | A projekt minden commit után automatikusan tesztelődik. A pipeline lefuttatja a teszteket, és értesítést küld hibás build esetén. |
| Folyamatos integráció | Az új funkciók beolvadásakor a rendszer automatikusan integrálja a változtatásokat, új buildet hoz létre, és frissíti a fejlesztői környezetet. |
| Tesztadatok | A tesztadatok legyenek elérhetőek egy táblázatban, dátummal ellátva. (Google Sheets) |

225
Docs/rendszerterv.md Normal file
View File

@@ -0,0 +1,225 @@
# Knightly — Rendszerterv (végleges architektúra)
Ez a dokumentum a *Knightly* sakkprojekt végleges rendszertervét írja le. A terv a korábban megosztott draw.io diagramon alapul, és fejlesztésre kész, technikai + működési leírást egyaránt tartalmaz.
---
## Tartalom
1. Összefoglaló célok
2. Fő komponensek és szerepek
3. Kommunikációs modell (WebSocket)
4. Üzenetsémák (JSON) — szabványosított formátumok
5. Matchmaking és meccskezelés
6. Játékfolyamat (lifecycle)
7. Engine integráció és validáció
8. UIServerEngine adatáramlás
9. Hálózat, üzemeltetés és deployment
10. Biztonság és jogosultságok
11. Naplózás, hibakezelés és monitoring
12. Tesztelés és CI/CD integráció
13. Üzemeltetési kézikönyv (runbook)
14. Fejlesztési roadmap és ajánlott következő lépések
15. Mellékletek — fontos konfigurációk, environment változók
---
## 1. Összefoglaló célok
- Kisméretű, LAN-on vagy interneten keresztül futtatható sakk-szerver tervezése.
- Stabil WebSocket alapú kommunikáció a UI (Rust) és a Server (Rust) között.
- Egyszerű, megbízható matchmaking (sorbaállás) és 1v1 meccskezelés.
- A szerver felel a meccsek létrehozásáért, a játék állapotáért és az engine-nek továbbított validálásért.
- A rendszer skálázható alapokra épül, később központi (cloud) hosztolásra bővíthető.
---
## 2. Fő komponensek és szerepek
### 2.1 UI (Client)
- Nyelv: Rust (egységes platform). Desktop UI (pl. egui/Tauri/SDL stb.).
- Feladatai: felhasználói interakció, önálló render, locale input, kliens-oldali lépésellenőrzés előzetes vizsgálata, WebSocket kapcsolat kezelése.
- Kommunikáció: WebSocket (ws:// vagy wss://) a szerverrel.
### 2.2 Server
- Nyelv: Rust, aszinkron (`tokio`), WebSocket támogatás (`tokio-tungstenite` vagy `axum`+`tokio-tungstenite`).
- Feladatai: kapcsolatok kezelése, matchmaking, meccsek életciklusa, üzenetek továbbítása, engine-hez való kommunikáció a lépések ellenőrzésére és szerepeltetésére.
- Állapot: memória alapú strukturák (`players`, `waiting_queue`, `matches`), opcionális perzisztencia (logok, ranglista) később.
### 2.3 Engine
- Feladat: sakk-szabályok végrehajtása, lépések validálása, legális lépések listázása, opció: AI játékos.
- Integrációs lehetőségek:
- könyvtárként (Rust crate) közvetlenül a szerveren belül, vagy
- külön folyamatként (stdin/stdout) vagy helyi RPC (Unix socket), illetve
- távoli szolgáltatás (gRPC/HTTP) később.
---
## 3. Kommunikációs modell (WebSocket)
- Egy porton fut a WS szerver (pl. `0.0.0.0:8080`). Nem szükséges több port.
- Minden kliens egyedi WebSocket kapcsolatot nyit. A szerver minden kapcsolatot azonosít (UUID vagy generált client id).
- A szerver tartja a `tx` (küldő) csatornát minden csatlakozott játékoshoz, így onnan tud üzenetet küldeni.
- Az üzenetek JSON formátumban érkeznek és mennek (text frames). Binary nem szükséges a kezdetekkor.
**Kapcsolódási lépések:**
1. UI csatlakozik → `Join` üzenet (felhasználónév).
2. Szerver visszaad `Welcome` (player id) vagy `Error`.
3. Keresés vagy hosting esetén a UI küld `FindMatch` vagy `HostLocal` parancsot.
4. Szerver párosít és `MatchFound` üzenetet küld mindkét félnek, tartalmazza az ellenfél metaadatait és ki kezd.
---
## 4. Üzenetsémák (JSON)
Az alábbiak a tervezett, szabványosított JSON üzenettípusok. Nem pszeudokód — egyszerű, pontos séma.
### 4.1 **Client -> Server**
- `Join`
```json
{ "type": "join", "username": "Alice" }
```
- `FindMatch` (sorbaállás)
```json
{ "type": "find_match", "mode": "1v1" }
```
- `HostLocal` (ha a kliens hostolni akarja a lokális meccset)
```json
{ "type": "host_local", "port": 9001 }
```
- `Move` (lépés beküldése)
```json
{ "type": "move", "from": "e2", "to": "e4", "promotion": null }
```
- `RequestLegalMoves`
```json
{ "type": "legal_moves", "fen": "..." }
```
- `Resign` / `OfferDraw` / `Chat` — hasonló egyszerű objektumok.
### 4.2 **Server -> Client**
- `Welcome`
```json
{ "type": "welcome", "player_id": "<uuid>" }
```
- `MatchFound`
```json
{ "type": "match_found", "match_id": "<uuid>", "opponent": {"id":"...","name":"Bob"}, "color": "white" }
```
- `OpponentMove`
```json
{ "type": "opponent_move", "from": "e2", "to": "e4", "promotion": null }
```
- `MoveResult` (valid/invalid, updated FEN, clocks)
```json
{ "type": "move_result", "valid": true, "fen": "...", "turn": "black" }
```
- `LegalMovesResponse`
```json
{ "type": "legal_moves", "moves": ["e2e4","d2d4"] }
```
- `Error` / `Info` / `GameEnd`
---
## 5. Matchmaking és meccskezelés
- **Várólista (FIFO):** a `waiting_queue` (`VecDeque<Uuid>`) tartja a *FindMatch*-előket.
- **Automatikus párosítás:** ha legalább két játékos van a várólistában, a szerver párba állítja őket és létrehoz egy `Match` struct-ot.
- **Match struct tartalma:** `match_id`, `white_id`, `black_id`, `fen` (kezdőállás), `move_history`, `clocks`.
- **Szereposztás:** véletlenszerű (érme dobás szerű) döntés vagy rang alapján.
- **Állapotkezelés:** a szerver az egyetlen egységes állapotgazda; minden új lépés a szerveren kerül ellenőrzésre és csak ha valid, akkor broadcastolásra.
**Különleges esetek:**
- Ha egyik fél kilép a meccs közben → szerver értesíti az ellenfelet, meccs státusza `aborted` vagy `win_by_disconnect`.
- Reconnect: ha a kliens újracsatlakozik, a szerver match-id alapján visszaállíthatja a játékot (ha ezt implementáljuk).
---
## 6. Játékfolyamat (lifecycle)
1. **Csatlakozás:** client küld `join`, szerver visszaad `welcome`.
2. **Keresés vagy hostolás:** client küld `find_match` vagy `host_local`.
3. **Párosítás:** szerver párosít, küld `match_found` mindkét félnek.
4. **Kezdés:** szerver küld kezdő FEN-t és azt, ki a fehér.
5. **Lépés küldése:** player A küld `move` üzenetet.
6. **Validálás:** szerver lekéri a félellenőrzést az engine-től (vagy saját szabályellenőrzés), ha valid → update `fen`, append `move_history`, küld `move_result` és `opponent_move` a másik félnek.
7. **Végállapot:** ha matt/döntetlen/timeout → szerver `game_end` és törli match-t, kerül a statisztikákba.
8. **Utak a menübe:** a játékosokat visszairányítjuk a főmenübe, match eltávolítva.
---
## 7. Engine integráció és validáció
- **Ajánlott integráció:** a chess engine legyen Rust crate, amelyet a szerver hív pontos függvényekkel — így egyszerű és gyors. Ha nem lehetséges, használjunk helyi folyamatot (`stdin/stdout`), vagy IPC (Unix domain socket).
- **Funkciók az engine-ben:** validálás (`is_move_legal`), lépések generálása (`generate_moves`), FEN kezelése, játék vége ellenőrzése.
- **SLA/Timeout:** minden engine kéréshez legyen timeout (pl. 2s). Ha az engine nem válaszol → szerver fallback: elutasítja a lépést vagy elfogadja lokálisan, attól függően.
---
## 8. UIServerEngine adatáramlás
- **Kliens → Szerver:** JSON üzenetek (lásd 4. rész).
- **Szerver → Engine:** függvényhívás vagy IPC hívás a board állás kapcsán.
- **Engine → Szerver:** válasz: legális/illegális, lehetséges lépések, új FEN.
- **Szerver → Kliens(ek):** a véglegesített, validált lépést, valamint állapot- és hibainformációkat.
---
## 9. Hálózat, üzemeltetés és deployment
- **Port:** alap WebSocket port (például `9001` vagy `8080`).
- **Bind cím:** `0.0.0.0` (LAN- és DDNS-elérést is lehetővé téve), dev környezetben `127.0.0.1` is használható.
- **Domain/DDNS:** a szerver elérhetővá tehető DDNS-en keresztül (pl. `mychess.ddns.net:9001`).
- **TLS:** ha publikus elérés szükséges, használj `wss://` TLS-t — pl. reverse proxy (nginx) terminálja a TLS-t és belsőleg csatlakozik `ws://`-on.
- **Self-hosted runner & CI:** a fejlesztői runner lehet persistens; minden workflow végén takarítás javasolt. Artefaktok feltöltése (logok) az Action-ökben.
---
## 10. Biztonság és jogosultságok
- **Input validáció:** a szerver soha ne bízzon a kliensben — minden lépést validálni kell az engine-nel.
- **Rate limiting:** egyszerű védelem (per IP/játékos) botok ellen.
- **TLS:** javasolt publikus hosztingnál.
- **Auth:** kezdetben opcionális, később token/username+password vagy OAuth implementálása.
---
## 11. Naplózás, hibakezelés és monitoring
- **Naplózási szint:** `info` alap, `debug` fejlesztéshez.
- **Naplófájlok:** per-meccs és per-játékos események — eseményeket timeframe-ekkel rögzíteni.
- **Error handling:** minden külső hívás (engine, disk, network) timeout-tal és visszapattanó logikával kezelve legyen.
- **Monitoring:** egyszerű health endpoint (HTTP) és process monitoring (systemd, Prometheus exporter később).
---
## 12. Tesztelés és CI/CD integráció
- **Unit tesztek:** rule engine, move validation, matchmaker logic.
- **Integration tesztek:** szerverkliens kommunikáció; mock engine használata.
- **CI:** GitHub Actions — teszt workflow-ok per-projekt (Engine/Server/UI). Rendszertervben előírt log exportálás a Google Sheets-be lehetőség.
---
## 13. Üzemeltetési kézikönyv (runbook)
- **Indítás:** `cargo run --release` vagy systemd service. Ajánlott: service fájl, ami a runner felhasználó alatt fut.
- **Stop:** graceful shutdown jelzés a futó meccsek befejezésére (vagy mentés után stop).
- **Frissítés:** stop → pull → `cargo build --release` → restart.
- **Hiba esetén:** ellenőrizd a naplókat, engine elérhetőségét, hálózati port forwardokat.
---
## 14. Fejlesztési roadmap és ajánlott következő lépések
1. Alap WebSocket server implementáció és egyszerű client teszt (lokálisan).
2. Shared message schema (JSON) és basic `Join/FindMatch/Move` támogatás.
3. Matchmaker + in-memory match tárolás.
4. Engine integráció (egy egyszerű lib vagy local process).
5. Reconnect és állapot-szinkronizáció (sync_state).
6. TLS és reverse proxy beállítása (ha publikus).
7. Perzisztencia (match history, eredmények).
8. Skálázás (ha szükséges: több match host, load balancing, stateless match managers).
---
## 15. Mellékletek — fontos konfigurációk
- **Environment változók**
- `SERVER_BIND=0.0.0.0:9001`
- `LOG_LEVEL=info`
- `ENGINE_PATH=/opt/knightly/engine` (ha külön process)
- **Ajánlott crate-ek**: `tokio`, `tokio-tungstenite`, `serde`, `serde_json`, `uuid`, `tracing`.
---
## Záró megjegyzés
Ez a dokumentum a diagram és a megbeszélések alapján készült. A terv elég részletes ahhoz, hogy a szerver fejlesztését megkezdjétek: tartalmazza az üzenetsémákat, a matchmaking logikát, az engine integrációs lehetőségeket és az üzemeltetési követelményeket.
Ha szeretnéd, legközelebb tudok készíteni belőle egy rövidebb fejlesztői checklistát (sprint backlog), vagy generálhatok egy külön implementációs tervet (fájlok/funkciók szerinti bontás).

View File

@@ -4,4 +4,3 @@ version = "0.1.0"
edition = "2024"
[dependencies]
once_cell = "1.19"

View File

@@ -1 +0,0 @@
mod attackmaps;

View File

@@ -1,252 +0,0 @@
use once_cell::sync::Lazy;
const A_FILE: u64 = 0x0101_0101_0101_0101;
const H_FILE: u64 = 0x8080_8080_8080_8080;
const AB_FILE: u64 = 0x0303_0303_0303_0303;
const GH_FILE: u64 = 0xC0C0_C0C0_C0C0_C0C0;
/*
EXPLANATIONS:
> square_index: 8 * rank number + file number (a-h = 0-7)
> side: white = 0, black = 1
> direction_index: 0..8 = [E, NE, N, NW, W, SW, S, SE]
*/
// KING_ATTACK_MAP[<square_index>]
pub static KING_ATTACK_MAP: Lazy<[u64; 64]> = Lazy::new(|| {
let mut table: [u64; 64] = [0u64; 64];
for sq in 0..64 {
let king: u64 = 1 << sq;
let left_attacks: u64 = king << 7 | king >> 1 | king >> 9;
let right_attacks: u64 = king << 1 | king << 9 | king >> 7;
table[sq] = (left_attacks & !H_FILE) | (right_attacks & !A_FILE) | king << 8 | king >> 8;
}
return table;
});
// PAWN_ATTACK_MAP[<square_index>][<side>]
pub static PAWN_ATTACK_MAP: Lazy<[[u64; 2]; 64]> = Lazy::new(|| {
let mut table: [[u64; 2]; 64] = [[0u64; 2]; 64];
for sq in 0..64 {
let pawn: u64 = 1 << sq;
table[sq][0] |= (pawn << 9) & !A_FILE;
table[sq][0] |= (pawn << 7) & !H_FILE;
}
for sq in 0..64 {
let pawn: u64 = 1 << sq;
table[sq][1] |= (pawn >> 9) & !H_FILE;
table[sq][1] |= (pawn >> 7) & !A_FILE;
}
return table;
});
// KNIGHT_ATTACK_MAP[<square_index>]
pub static KNIGHT_ATTACK_MAP: Lazy<[u64; 64]> = Lazy::new(|| {
let mut table: [u64; 64] = [0u64; 64];
for sq in 0..64 {
let knight: u64 = 1 << sq;
let far_left_attacks: u64 = knight << 6 | knight >> 10;
let near_left_attacks: u64 = knight << 15 | knight >> 17;
let far_right_attacks: u64 = knight << 10 | knight >> 6;
let near_right_attacks: u64 = knight << 17 | knight >> 15;
table[sq] = (far_left_attacks & !GH_FILE) | (far_right_attacks & !AB_FILE) | (near_left_attacks & !H_FILE) | (near_right_attacks & !A_FILE);
}
return table;
});
// RAY_TABLE[<square_index>][<direction_index>]
pub static RAY_TABLE: Lazy<[[u64; 8]; 64]> = Lazy::new(|| {
let mut table: [[u64; 8]; 64] = [[0u64; 8]; 64];
let dirs: [i8; 8] = [1, 9, 8, 7, -1, -9, -8, -7];
for sq in 0..64 {
for d in 0..8 {
let mut ray: u64 = 0u64;
let origin: u64 = 1 << sq;
let mut new_target: u64 = if dirs[d] > 0 {origin << dirs[d]} else {origin >> -dirs[d]};
if [0, 1, 7].contains(&d) {
new_target &= !A_FILE;
}
else if [3, 4, 5].contains(&d) {
new_target &= !H_FILE;
}
while new_target != 0 {
ray |= new_target;
new_target = if dirs[d] > 0 {new_target << dirs[d]} else {new_target >> -dirs[d]};
if [0, 1, 7].contains(&d) {
new_target &= !A_FILE;
}
else if [3, 4, 5].contains(&d) {
new_target &= !H_FILE;
}
}
table[sq][d] = ray;
}
}
return table;
});
// <----- TESTS ----->
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_king_attack_map() {
// test setup for corners [SW, SE, NW, NE]
let corner_indexes: [usize; 4] = [0, 7, 56, 63];
let corner_attack_maps: [u64; 4] = [
(1u64 << 1) | (1u64 << 8) | (1u64 << 9),
(1u64 << 6) | (1u64 << 14) | (1u64 << 15),
(1u64 << 48) | (1u64 << 49) | (1u64 << 57),
(1u64 << 54) | (1u64 << 55) | (1u64 << 62)
];
// tests for corners
for index in 0..4 {
assert_eq!(KING_ATTACK_MAP[corner_indexes[index]], corner_attack_maps[index]);
}
// test setup for sides [S, E, W, N]
let side_indexes: [usize; 4] = [3, 31, 32, 60];
let side_attack_maps: [u64; 4] = [
(1 << 2) | (1 << 4) | (1 << 10) | (1 << 11) | (1 << 12),
(1 << 22) | (1 << 23) | (1 << 30) | (1 << 38) | (1 << 39),
(1 << 24) | (1 << 25) | (1 << 33) | (1 << 40) | (1 << 41),
(1 << 51) | (1 << 52) | (1 << 53) | (1 << 59) | (1 << 61)
];
// tests for sides
for index in 0..4 {
assert_eq!(KING_ATTACK_MAP[side_indexes[index]], side_attack_maps[index]);
}
// test setup for center
let center_index: usize = 27;
let center_attack_map: u64 = (1 << 18) | (1 << 19) | (1 << 20) | (1 << 26) | (1 << 28) | (1 << 34) | (1 << 35) | (1 << 36);
// test for center
assert_eq!(KING_ATTACK_MAP[center_index], center_attack_map);
}
#[test]
fn test_pawn_attack_map() {
// test setup for white sides
let white_side_indexes: [usize; 2] = [24, 31];
let white_side_attack_maps: [u64; 2] = [
(1 << 33),
(1 << 38)
];
// tests for white sides
for index in 0..2 {
assert_eq!(PAWN_ATTACK_MAP[white_side_indexes[index]][0], white_side_attack_maps[index])
}
// test setup for black sides
let black_side_indexes: [usize; 2] = [32, 39];
let black_side_attack_maps: [u64; 2] = [
(1 << 25),
(1 << 30)
];
// tests for black sides
for index in 0..2 {
assert_eq!(PAWN_ATTACK_MAP[black_side_indexes[index]][1], black_side_attack_maps[index])
}
// test setup for white center
let white_center_indexes: [usize; 2] = [11, 12];
let white_center_attack_maps: [u64; 2] = [
(1 << 18) | (1 << 20),
(1 << 19) | (1 << 21)
];
// tests for white center
for index in 0..2 {
assert_eq!(PAWN_ATTACK_MAP[white_center_indexes[index]][0], white_center_attack_maps[index])
}
// test setup for black center
let black_center_indexes: [usize; 2] = [51, 52];
let black_center_attack_maps: [u64; 2] = [
(1 << 42) | (1 << 44),
(1 << 43) | (1 << 45)
];
// tests for black center
for index in 0..2 {
assert_eq!(PAWN_ATTACK_MAP[black_center_indexes[index]][1], black_center_attack_maps[index])
}
}
#[test]
fn test_knight_attack_map() {
// test setup for corners [SW, SE, NW, NE]
let corner_indexes: [usize; 4] = [0, 7, 56, 63];
let corner_attack_maps: [u64; 4] = [
(1 << 17) | (1 << 10),
(1 << 13) | (1 << 22),
(1 << 41) | (1 << 50),
(1 << 46) | (1 << 53)
];
// tests for corners
for index in 0..4 {
assert_eq!(KNIGHT_ATTACK_MAP[corner_indexes[index]], corner_attack_maps[index]);
}
// test setup for sides [S, E, W, N]
let side_indexes: [usize; 4] = [3, 31, 32, 60];
let side_attack_maps: [u64; 4] = [
(1 << 9) | (1 << 13) | (1 << 18) | (1 << 20),
(1 << 14) | (1 << 21) | (1 << 37) | (1 << 46),
(1 << 17) | (1 << 26) | (1 << 42) | (1 << 49),
(1 << 43) | (1 << 45) | (1 << 50) | (1 << 54)
];
// tests for sides
for index in 0..4 {
assert_eq!(KNIGHT_ATTACK_MAP[side_indexes[index]], side_attack_maps[index]);
}
// test setup for center
let center_index: usize = 27;
let center_attack_map: u64 = (1 << 10) | (1 << 12) | (1 << 17) | (1 << 21) | (1 << 33) | (1 << 37) | (1 << 42) | (1 << 44);
// test for center
assert_eq!(KNIGHT_ATTACK_MAP[center_index], center_attack_map);
}
#[test]
fn test_ray_table() {
// test setup for all directions from center
let starting_square_index: usize = 27;
let ray_masks: [u64; 8] = [
(1 << 28) | (1 << 29) | (1 << 30) | (1 << 31),
(1 << 36) | (1 << 45) | (1 << 54) | (1 << 63),
(1 << 35) | (1 << 43) | (1 << 51) | (1 << 59),
(1 << 34) | (1 << 41) | (1 << 48),
(1 << 26) | (1 << 25) | (1 << 24),
(1 << 18) | (1 << 9) | (1 << 0),
(1 << 19) | (1 << 11) | (1 << 3),
(1 << 20) | (1 << 13) | (1 << 6)
];
// tests for all directions from starting_square
for direction in 0..8 {
assert_eq!(RAY_TABLE[starting_square_index][direction], ray_masks[direction]);
}
}
}

View File

@@ -1,5 +1,3 @@
mod bitboard;
fn main() {
println!("Hello, world!");
}