feat: 1vs BOT

This commit is contained in:
shahdlala66
2026-04-19 01:06:13 +02:00
parent 5497997455
commit bc644c16e3
5 changed files with 201 additions and 4 deletions
+67 -1
View File
@@ -1,7 +1,7 @@
import { DestroyRef, Injectable, OnDestroy, inject } from '@angular/core';
import { Router } from '@angular/router';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval, startWith, Subscription, switchMap } from 'rxjs';
import { interval, startWith, Subscription, switchMap, delay } from 'rxjs';
import { getPieceAtSquare, isPieceColor } from '../../core/chess/fen.utils';
import { getErrorMessage } from '../../core/http/error-message.util';
import { GameFull, GameState, GameStreamEvent, LegalMove } from '../../models/game.models';
@@ -25,16 +25,37 @@ export class GameFacade implements OnDestroy {
private readonly destroyRef = inject(DestroyRef);
private streamSubscription: Subscription | null = null;
private pollSubscription: Subscription | null = null;
private botMoveSubscription: Subscription | null = null;
ngOnDestroy(): void {
this.streamSubscription?.unsubscribe();
this.pollSubscription?.unsubscribe();
this.botMoveSubscription?.unsubscribe();
}
get state(): GameState | null {
return this.game?.state ?? null;
}
private isBotPlayer(playerId: string): boolean {
return playerId.startsWith('bot-');
}
private isPlayingAgainstBot(): boolean {
if (!this.game) {
return false;
}
return this.isBotPlayer(this.game.white.id) || this.isBotPlayer(this.game.black.id);
}
private isCurrentPlayerBot(): boolean {
if (!this.game || !this.state) {
return false;
}
const currentPlayer = this.state.turn === 'white' ? this.game.white : this.game.black;
return this.isBotPlayer(currentPlayer.id);
}
setGameId(gameId: string): void {
this.gameId = gameId;
this.loadGame();
@@ -94,6 +115,7 @@ export class GameFacade implements OnDestroy {
}
this.moveInput = '';
this.clearSelection();
this.tryMakeBotMove();
},
error: (error) => {
this.errorMessage = getErrorMessage(error, 'Move rejected.');
@@ -153,6 +175,7 @@ export class GameFacade implements OnDestroy {
this.clearSelection();
this.streamSubscription?.unsubscribe();
this.pollSubscription?.unsubscribe();
this.botMoveSubscription?.unsubscribe();
this.pollSubscription = null;
this.gameApi
@@ -163,6 +186,7 @@ export class GameFacade implements OnDestroy {
this.game = game;
this.loading = false;
this.startStream();
this.tryMakeBotMove();
},
error: (error) => {
this.errorMessage = getErrorMessage(error, `Could not load game ${this.gameId}.`);
@@ -205,6 +229,7 @@ export class GameFacade implements OnDestroy {
this.game = game;
if (previousMoves !== game.state.moves.join(',')) {
this.clearSelection();
this.tryMakeBotMove();
}
}
});
@@ -214,6 +239,7 @@ export class GameFacade implements OnDestroy {
if (event.type === 'gameFull') {
this.game = event.game;
this.clearSelection();
this.tryMakeBotMove();
return;
}
@@ -222,6 +248,7 @@ export class GameFacade implements OnDestroy {
this.game = { ...this.game, state: event.state };
if (event.state.moves.length !== moveCountBefore) {
this.clearSelection();
this.tryMakeBotMove();
}
return;
}
@@ -231,6 +258,45 @@ export class GameFacade implements OnDestroy {
}
}
private tryMakeBotMove(): void {
if (!this.isPlayingAgainstBot() || !this.isCurrentPlayerBot() || !this.state) {
return;
}
this.botMoveSubscription?.unsubscribe();
this.botMoveSubscription = this.gameApi
.getLegalMoves(this.gameId)
.pipe(
delay(1000),
takeUntilDestroyed(this.destroyRef)
)
.subscribe({
next: (response) => {
if (response.moves.length === 0) {
return;
}
const botMove = response.moves[Math.floor(Math.random() * response.moves.length)];
this.gameApi
.makeMove(this.gameId, botMove.uci)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: (state) => {
if (this.game) {
this.game = { ...this.game, state };
}
this.clearSelection();
},
error: (error) => {
this.errorMessage = getErrorMessage(error, 'Bot move failed.');
}
});
},
error: () => {
this.errorMessage = 'Could not get legal moves for bot move.';
}
});
}
private clearSelection(): void {
this.selectedSquare = null;
this.selectedSquareMoves = [];