using API.Controllers; using API.Models.DataClasses; using API.Models.Game; using API.Repository.GameRepo; using Microsoft.AspNetCore.SignalR; using System.Text.RegularExpressions; namespace API.Services.GameManager; public class GameManager(IGameRepository gameRepository, IHubContext hubContext) : IGameManager { public (string, int) CreateGame(Coordinates gFs, Player player) { var game = gameRepository.Create(gFs); game.AddPlayer(player); return (game.Id, game.GameCode); } public async Task JoinGame(Player player, int gameCode) { var game = gameRepository.GetOne(new SixDigitInt(gameCode)); var success = game != null && game.State == GameState.Lobby && game.AddPlayer(player); if (!success) { await hubContext.Clients.Client(player.ConnectionId).SendAsync("Error", "Spiel Existiert nicht!"); return null; } await hubContext.Groups.AddToGroupAsync(player.ConnectionId, game.Id); if (game.Players.Count == 2) { game.StartGame(); var gameInfoDto = new GameInformationDto { Players = game?.Players, CurrentField = ConvertField(game?.Field.CurrentField), State = game?.State, CurrentTurn = game?.CurrentTurn ?? 0 }; await hubContext.Clients.Group(game.Id).SendAsync("GameStarted", gameInfoDto); } return game.Id; } public async Task RequestGameInformation(string gameId, string playerConnectionId) { var game = gameRepository.GetOne(gameId); if (game == null) return; var gameInfoDto = new GameInformationDto { Players = game?.Players, CurrentField = ConvertField(game?.Field.CurrentField), State = game?.State, CurrentTurn = game?.CurrentTurn ?? 0 }; await hubContext.Clients.Client(playerConnectionId).SendAsync("GameInformation", gameInfoDto); } public async Task Drop(string gameCode, int column, string playerConnectionId) { var game = gameRepository.GetOne(gameCode); var player = game?.GetPlayerByConnectionId(playerConnectionId); if (player == null) return; if(game.CurrentTurn != player.PlayerTag || game.State != GameState.Running) return; if(game.State != GameState.Running) return; var result = game.Field.Drop(column, player.PlayerTag); if (result != DropResult.Placed) { await hubContext.Clients.Client(playerConnectionId).SendAsync("Error", "Ungültiger Zug."); return; } game.CurrentTurn = game.CurrentTurn == 1 ? 2 : 1; var gameInfoDto = new GameInformationDto { Players = game?.Players, CurrentField = ConvertField(game?.Field.CurrentField), State = game?.State, CurrentTurn = game?.CurrentTurn ?? 0 }; await hubContext.Clients.Group(game.Id).SendAsync("FieldUpdated", gameInfoDto); var winResult = game.Field.CheckForWin(); if (winResult != 0) { var newGame = gameRepository.Create(game.Field.GFs); var winPlayer = game.GetPlayerByTag(winResult); game.EndGame(); await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new { Method = "Win", Player = winPlayer, ReplayGameCode = newGame.GameCode }); ScheduleGameDeletion(newGame.Id, TimeSpan.FromSeconds(20)); ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(10)); } if (game.Field.IsFull()) { var newGame = gameRepository.Create(game.Field.GFs); game.EndGame(); await hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new { Method = "Draw", ReplayGameCode = newGame.GameCode }); ScheduleGameDeletion(newGame.Id, TimeSpan.FromSeconds(15)); ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(10)); } } public Task DisconnectedPlayer(string playerConnectionId) { var game = gameRepository.GetOneByConnectionId(playerConnectionId); if (game == null || game.State == GameState.Ended) return Task.CompletedTask; var player = game.GetPlayerByConnectionId(playerConnectionId); if (player == null) return Task.CompletedTask; game.RemovePlayer(playerConnectionId); game.EndGame(); hubContext.Clients.Group(game.Id).SendAsync("GameEnded", new { Method = "PlayerDisconnected", Player = player }); ScheduleGameDeletion(game.Id, TimeSpan.FromSeconds(0)); return Task.CompletedTask; } private static int[][] ConvertField(int[,]? field) { if (field == null) return Array.Empty(); var rows = field.GetLength(0); var cols = field.GetLength(1); var convertedField = new int[rows][]; for (var y = 0; y < rows; y++) { convertedField[y] = new int[cols]; for (var x = 0; x < cols; x++) { convertedField[y][x] = field[y, x]; } } return convertedField; } private void ScheduleGameDeletion(string gameId, TimeSpan delay) { _ = Task.Run(async () => { await Task.Delay(delay); var g = gameRepository.GetOne(gameId); if (g != null && g.State != GameState.Running) { gameRepository.Destroy(gameId); await hubContext.Clients.Group(gameId).SendAsync("GameDestroyed"); } }); } }