79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
import { Injectable, DestroyRef, inject } from '@angular/core';
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
import { delay, Subscription } from 'rxjs';
|
|
import { GameApiService } from './game-api.service';
|
|
import { getErrorMessage } from '../core/http/error-message.util';
|
|
import { GameFull, GameState } from '../models/game.models';
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class BotMoveService {
|
|
private readonly gameApi = inject(GameApiService);
|
|
private readonly destroyRef = inject(DestroyRef);
|
|
private botMoveSubscription: Subscription | null = null;
|
|
|
|
private isBotPlayer(playerId: string): boolean {
|
|
return playerId.startsWith('bot-');
|
|
}
|
|
|
|
isPlayingAgainstBot(game: GameFull | null): boolean {
|
|
if (!game) {
|
|
return false;
|
|
}
|
|
return this.isBotPlayer(game.white.id) || this.isBotPlayer(game.black.id);
|
|
}
|
|
|
|
isCurrentPlayerBot(game: GameFull | null, state: GameState | null): boolean {
|
|
if (!game || !state) {
|
|
return false;
|
|
}
|
|
const currentPlayer = state.turn === 'white' ? game.white : game.black;
|
|
return this.isBotPlayer(currentPlayer.id);
|
|
}
|
|
|
|
tryMakeBotMove(
|
|
gameId: string,
|
|
game: GameFull | null,
|
|
state: GameState | null,
|
|
onSuccess: (updatedState: GameState) => void,
|
|
onError: (error: string) => void
|
|
): void {
|
|
if (!this.isPlayingAgainstBot(game) || !this.isCurrentPlayerBot(game, state) || !state) {
|
|
return;
|
|
}
|
|
|
|
this.botMoveSubscription?.unsubscribe();
|
|
this.botMoveSubscription = this.gameApi
|
|
.getLegalMoves(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(gameId, botMove.uci)
|
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
.subscribe({
|
|
next: (updatedState) => {
|
|
onSuccess(updatedState);
|
|
},
|
|
error: (error) => {
|
|
onError(getErrorMessage(error, 'Bot move failed.'));
|
|
}
|
|
});
|
|
},
|
|
error: () => {
|
|
onError('Could not get legal moves for bot move.');
|
|
}
|
|
});
|
|
}
|
|
|
|
cleanup(): void {
|
|
this.botMoveSubscription?.unsubscribe();
|
|
}
|
|
}
|