public void ExecuteDuel(MatchmakingEntry match, int maxNumberOfRounds) { Assert.NotNull(match, nameof(match)); Assert.NotNull(match.Adversary, "match.Adversary"); Assert.NotNull(match.AdversaryRequestedDeck, "match.AdversaryRequestedDeck"); Assert.NotNull(match.Self, "match.Self"); Assert.NotNull(match.SelfRequestedDeck, "match.SelfRequestedDeck"); using (NpgsqlConnection connection = database.CreateAndOpenConnection()) using (NpgsqlTransaction transaction = connection.BeginTransaction()) { User winner = null; List <InsertBattleLogEntryModel> battleLogEntries = new List <InsertBattleLogEntryModel>(); Deck deck1 = deckRepository.GetDeck(match.Self, match.SelfRequestedDeck, transaction); Deck deck2 = deckRepository.GetDeck(match.Adversary, match.AdversaryRequestedDeck, transaction); Assert.That(deck1.Cards.Count > 0, $"deck1 CardCount must be larger than 0."); Assert.That(deck2.Cards.Count > 0, $"deck2 CardCount must be larger than 0."); Assert.That(deck1.Cards.Count == deck2.Cards.Count, $"deck1 CardCount must be equal to deck2 CardCount."); int currentRound; for (currentRound = 0; currentRound < maxNumberOfRounds; currentRound++) { if (deck1.Cards.Count == 0) { winner = deck2.Player; break; } else if (deck2.Cards.Count == 0) { winner = deck1.Player; break; } int cardNumber_Deck1 = randomNumberGenerator.Next() % deck1.Cards.Count; int cardNumber_Deck2 = randomNumberGenerator.Next() % deck2.Cards.Count; Card card1 = deck1.Cards[cardNumber_Deck1]; Card card2 = deck2.Cards[cardNumber_Deck2]; int effectiveAttackPointsCard1 = GetEffectiveAttackPoints(card1, card2); int effectiveAttackPointsCard2 = GetEffectiveAttackPoints(card2, card1); InsertBattleLogEntryModel logEntry = new InsertBattleLogEntryModel() { Card1 = card1, Card2 = card2, Order = currentRound }; StringBuilder roundDescriptionBuilder = new StringBuilder(); roundDescriptionBuilder.Append(BuildPlayerCardSummary(deck1.Player, card1, effectiveAttackPointsCard1)); roundDescriptionBuilder.Append(" vs. "); roundDescriptionBuilder.AppendLine(BuildPlayerCardSummary(deck2.Player, card2, effectiveAttackPointsCard2)); roundDescriptionBuilder.Append("Result: "); if (effectiveAttackPointsCard1 == effectiveAttackPointsCard2) { roundDescriptionBuilder.Append("Tie."); } else if (effectiveAttackPointsCard1 > effectiveAttackPointsCard2) { roundDescriptionBuilder.Append(BuildWinnerSummary(deck1.Player, currentRound)); deck1.Cards.Add(card2); deck2.Cards.Remove(card2); } else { roundDescriptionBuilder.Append(BuildWinnerSummary(deck2.Player, currentRound)); deck2.Cards.Add(card1); deck1.Cards.Remove(card1); } logEntry.DeckState1 = deck1.GenerateDeckStateString(); logEntry.DeckState2 = deck2.GenerateDeckStateString(); logEntry.RoundDescription = roundDescriptionBuilder.ToString(); battleLogEntries.Add(logEntry); } InsertBattleLogModel battleLog = new InsertBattleLogModel() { Match_ID = match.MatchID, Winner = winner, BattleResult = GetBattleResult(winner, deck1.Player, deck2.Player), Deck1 = deck1, Deck2 = deck2, CreationDate = DateTime.Now, Turns = currentRound }; int battleLogID = battleLogRepository.InsertBattleLog(battleLog, transaction); foreach (InsertBattleLogEntryModel logEntryModel in battleLogEntries) { battleLogRepository.InsertBattleLogEntry(battleLogID, logEntryModel, transaction); } transaction.Commit(); } }
public MatchmakingEntry FindMatch(RequestContext requestContext, string requestedDeck) { using (NpgsqlConnection connection = database.CreateAndOpenConnection()) using (NpgsqlTransaction transaction = connection.BeginTransaction()) { UserSession session = CookieAuthenticationModule.GetUserSessionFromRequest(requestContext, transaction); User user = userRepository.GetUser(session.UserID, transaction); Assert.NotNull(user, nameof(user)); Validate.Condition(deckRepository.Exists(requestedDeck, user.UserID, transaction), $"Requested Deck: {requestedDeck} could not be found for User: {user.UserName}"); MatchmakingEntry self = new MatchmakingEntry(user, requestedDeck); lock (duelQueue) { if (duelQueue.Any(mme => mme.Self.UserID == user.UserID || mme.Adversary?.UserID == user.UserID)) { throw new InvalidOperationException( $"Gegnersuche fehlgeschlagen. Der Benutzer: {user.UserName} " + "ist dem Matchmaking bereits beigetreten."); } duelQueue.Add(self); } const int maxAttemptCount = 60; int currentAttempt = 0; MatchmakingEntry adversary = null; do { ++currentAttempt; Thread.Sleep(2000); lock (duelQueue) { if (self.IsMatched) { return(self); } adversary = duelQueue .FirstOrDefault(mmEntry => mmEntry != self); if (adversary != null) { Guid matchID = Guid.NewGuid(); adversary.Adversary = user; adversary.AdversaryRequestedDeck = requestedDeck; adversary.IsMatched = true; adversary.MatchID = matchID; duelQueue.Remove(adversary); self.Adversary = adversary.Self; self.AdversaryRequestedDeck = adversary.SelfRequestedDeck; self.IsMatched = true; self.ShouldInitiate = true; self.MatchID = matchID; duelQueue.Remove(self); return(self); } } } while (currentAttempt <= maxAttemptCount); // no Match could be found -> deregister. lock (duelQueue) { duelQueue.Remove(self); } return(self); } }