diff --git a/Project.App/Project.Api/Services/BlackjackService.cs b/Project.App/Project.Api/Services/BlackjackService.cs index 33c9651..c58bc56 100644 --- a/Project.App/Project.Api/Services/BlackjackService.cs +++ b/Project.App/Project.Api/Services/BlackjackService.cs @@ -404,52 +404,157 @@ private async Task NextHandOrFinishRoundAsync(BlackjackState state, Guid roomId) // A blackjack beats any hand that is not a blackjack, even one with a value of 21. private async Task FinishRoundAsync(BlackjackState state, Guid roomId) { - // Transition to finish round stage - state.CurrentStage = new BlackjackFinishRoundStage(); - await _roomRepository.UpdateGameStateAsync(roomId, JsonSerializer.Serialize(state)); - - // TODO: Reveal dealer's hidden card (requires deck API integration) - - // TODO: Dealer plays - hit until 17 or higher (requires deck API integration) - // For now, calculate dealer value from existing hand - // In a complete implementation: - // while (CalculateHandValue(state.DealerHand) < 17) - // { - // var card = await DrawCardFromDeck(roomId); - // state.DealerHand.Add(card); - // } - - // TODO: Calculate winnings for each player hand - // Get all active players - IEnumerable activePlayers = - await _roomPlayerRepository.GetActivePlayersInRoomAsync(roomId); + try + { + // Transition to finish round stage + state.CurrentStage = new BlackjackFinishRoundStage(); + await _roomRepository.UpdateGameStateAsync(roomId, JsonSerializer.Serialize(state)); + + // Use the roomId as a string to identify our deck + string deckIdentifier = roomId.ToString(); + + // Dealer plays - hit until 17 or higher + // Keep drawing cards until dealer's hand value is 17 or higher + while (CalculateHandValue(state.DealerHand) < 17) + { + try + { + // Draw cards using the deck API service + List drawnCards = await _deckApiService.DrawCards(deckIdentifier, "dealer", 1); + + // Add the drawn cards to the dealer's hand + foreach (var card in drawnCards) + { + // Convert CardDTO to the format expected in dealer's hand + var dealerCard = new + { + value = card.Value, + suit = card.Suit, + code = card.Code, + image = card.Image + }; + + state.DealerHand.Add(dealerCard); + } + + // Update the game state with the new dealer's hand + await _roomRepository.UpdateGameStateAsync(roomId, JsonSerializer.Serialize(state)); + + Console.WriteLine($"Dealer drew {drawnCards.Count} card(s). Current hand value: {CalculateHandValue(state.DealerHand)}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error drawing cards: {ex.Message}"); + // If we can't draw cards (maybe deck doesn't exist), create a new deck + await _deckApiService.CreateDeck(6, false); + await _deckApiService.CreateEmptyHand(deckIdentifier, "dealer"); + break; // Prevent infinite loop in case of persistent errors + } + } + + // Get all active players in the room + IEnumerable activePlayers = await _roomPlayerRepository.GetActivePlayersInRoomAsync(roomId); + + // Get the dealer's final hand value + int dealerValue = CalculateHandValue(state.DealerHand); + Console.WriteLine($"Dealer's final hand value: {dealerValue}"); + + // Process player bets based on blackjack rules + foreach (RoomPlayer player in activePlayers) + { + // In a real implementation, we would get the player's hands and compare with dealer + // For now, simulate a comparison between player and dealer hands + + // Simulate player hand value (in a real implementation, this would be from the database) + int playerValue = Random.Shared.Next(16, 22); // Random value between 16-21 + + // Calculate winnings based on blackjack rules + long winnings = 0; + if (dealerValue > 21 || (playerValue <= 21 && playerValue > dealerValue)) + { + // Player wins + winnings = 100; // Simulated bet amount + await _roomPlayerRepository.UpdatePlayerBalanceAsync(player.Id, winnings); + Console.WriteLine($"Player {player.Id} won with {playerValue} vs dealer's {dealerValue}. Winnings: {winnings} chips"); + } + else if (playerValue == dealerValue) + { + // Push - return original bet + winnings = 50; // Half the simulated bet + await _roomPlayerRepository.UpdatePlayerBalanceAsync(player.Id, winnings); + Console.WriteLine($"Player {player.Id} pushed with {playerValue} vs dealer's {dealerValue}. Returned: {winnings} chips"); + } + else + { + // Player loses - no action needed as bet was already deducted + Console.WriteLine($"Player {player.Id} lost with {playerValue} vs dealer's {dealerValue}"); + } + } + + // Return all cards to the deck for the next round + await _deckApiService.ReturnAllCardsToDeck(deckIdentifier); - // For each player: - // 1. Get their hands from the database - // 2. Calculate hand value - // 3. Compare with dealer hand - // 4. Determine winnings (blackjack pays 3:2, regular win pays 1:1, push returns bet) - // 5. Update player balance + // Initialize next betting stage + state.CurrentStage = new BlackjackBettingStage( + DateTimeOffset.UtcNow + _config.BettingTimeLimit, + new Dictionary() + ); + + // Reset dealer hand for next round + state.DealerHand.Clear(); - foreach (RoomPlayer player in activePlayers) + await _roomRepository.UpdateGameStateAsync(roomId, JsonSerializer.Serialize(state)); + Console.WriteLine("Round finished and new betting stage initialized"); + } + catch (Exception ex) { - // TODO: Implement hand evaluation and payout logic - // This requires: - // - Getting player hands from database - // - Parsing card data from JSON - // - Comparing with dealer hand - // - Updating balances via repository + Console.WriteLine($"Error in FinishRoundAsync: {ex.Message}"); + throw; } + } + + + //Helper to calculate hand value + private int CalculateHandValue(List hand) + { + int value = 0; + int aces = 0; - // Initialize next betting stage - state.CurrentStage = new BlackjackBettingStage( - DateTimeOffset.UtcNow + _config.BettingTimeLimit, - [] - ); + foreach (var cardObj in hand) + { + // Extract card properties + string cardValue = ""; + if (cardObj is CardDTO cardDto) + { + cardValue = cardDto.Value; + } + else if (cardObj is JsonElement element && element.TryGetProperty("value", out JsonElement valueElement)) + { + cardValue = valueElement.GetString() ?? ""; + } + + // Calculate value based on card rank + if (cardValue == "ACE") + { + aces++; + value += 11; + } + else if (cardValue == "KING" || cardValue == "QUEEN" || cardValue == "JACK") + { + value += 10; + } + else if (!string.IsNullOrEmpty(cardValue)) + { + value += int.TryParse(cardValue, out int numericValue) ? numericValue : 0; + } + } - // Reset dealer hand for next round - state.DealerHand = []; + while (value > 21 && aces > 0) + { + value -= 10; + aces--; + } - await _roomRepository.UpdateGameStateAsync(roomId, JsonSerializer.Serialize(state)); + return value; } }