fix: resolve all 3 open Gitea issues

Issue #1 - Bot vs Bot Turnierspiele:
- triggerBotMove ruft sich rekursiv selbst auf wenn der nächste Spieler
  auch ein Bot ist (bot vs bot läuft jetzt vollautomatisch durch)
- startNextRoundGames erstellt aktive Spiele für die nächste Runde wenn
  eine Runde endet; bot vs bot Spiele starten sofort ohne Spectator
- updateRoundResult gibt jetzt die nächste Runden-Daten zurück statt void
- Alle Handler (sendMove, claimAbandoned, claimTimeout, triggerBotMove)
  starten die nächste Runde automatisch

Issue #2 - Bot-Schwierigkeit zu hoch:
- randomChance zu StockfishLevel hinzugefügt: Level 1=80%, 2=50%,
  3=15%, 4=3%, 5-6=0% zufällige Züge statt Stockfish-Best-Move
- Gilt sowohl für Socket-Bot-Züge als auch /v1/ai/move REST-Endpoint

Issue #3 - Turnier beenden + Zurück-Button:
- POST /:code/cancel Endpoint (nur Host), setzt status='finished'
- Turnier-Seite: 'Turnier beenden' Button für Host (rot, outline)
- tournamentCode Feld im Game-Typ; wird beim Erstellen von Turnierspielen
  gesetzt (inkl. Folgerunden)
- GamePage zeigt '← Zur Turnierübersicht' Link wenn tournamentCode gesetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Michess
2026-04-15 07:46:40 +02:00
parent 536160bba6
commit 86fbdd39ed
10 changed files with 159 additions and 44 deletions

View File

@@ -7,15 +7,16 @@ export interface StockfishLevel {
skillLevel: number;
depth: number;
moveTime: number;
randomChance: number; // 01 probability of playing a random legal move instead of Stockfish's best
}
export const AI_LEVELS: StockfishLevel[] = [
{ level: 1, name: "Anfänger", skillLevel: 0, depth: 1, moveTime: 100 },
{ level: 2, name: "Leicht", skillLevel: 3, depth: 3, moveTime: 200 },
{ level: 3, name: "Mittel", skillLevel: 8, depth: 5, moveTime: 500 },
{ level: 4, name: "Fortgeschritten", skillLevel: 14, depth: 10, moveTime: 1000 },
{ level: 5, name: "Experte", skillLevel: 18, depth: 15, moveTime: 2000 },
{ level: 6, name: "Meister", skillLevel: 20, depth: 20, moveTime: 3000 },
{ level: 1, name: "Anfänger", skillLevel: 0, depth: 1, moveTime: 50, randomChance: 0.80 },
{ level: 2, name: "Leicht", skillLevel: 2, depth: 2, moveTime: 100, randomChance: 0.50 },
{ level: 3, name: "Mittel", skillLevel: 7, depth: 4, moveTime: 300, randomChance: 0.15 },
{ level: 4, name: "Fortgeschritten", skillLevel: 13, depth: 8, moveTime: 800, randomChance: 0.03 },
{ level: 5, name: "Experte", skillLevel: 18, depth: 14, moveTime: 1500, randomChance: 0 },
{ level: 6, name: "Meister", skillLevel: 20, depth: 20, moveTime: 3000, randomChance: 0 },
];
export class StockfishEngine {

View File

@@ -71,7 +71,8 @@ export const startTournament = async (req: Request, res: Response) => {
startedAt: Date.now(),
timeControl: tc || undefined,
whiteTimeMs: tc ? tc * 60 * 1000 : undefined,
blackTimeMs: tc ? tc * 60 * 1000 : undefined
blackTimeMs: tc ? tc * 60 * 1000 : undefined,
tournamentCode: req.params.code
};
activeGames.push(game);
await TournamentModel.setRoundGameCode(row.id, code);
@@ -82,6 +83,19 @@ export const startTournament = async (req: Request, res: Response) => {
} catch (e) { console.error(e); res.status(500).end(); }
};
export const cancelTournament = async (req: Request, res: Response) => {
if (!req.session.user?.id || typeof req.session.user.id === "string") { res.status(401).end(); return; }
try {
const tournament = await TournamentModel.findByCode(req.params.code);
if (!tournament) { res.status(404).end(); return; }
if (tournament.hostId !== req.session.user.id) { res.status(403).end(); return; }
if (tournament.status === "finished") { res.status(400).json({ message: "Turnier bereits beendet." }); return; }
await db.query(`UPDATE "tournament" SET status='finished' WHERE code=$1`, [req.params.code]);
const updated = await TournamentModel.findByCode(req.params.code);
res.status(200).json(updated);
} catch (e) { console.error(e); res.status(500).end(); }
};
export const addBot = async (req: Request, res: Response) => {
if (!req.session.user?.id || typeof req.session.user.id === "string") { res.status(401).end(); return; }
const { botName } = req.body;