using System.Diagnostics; using SoulstormReplayReader.Core.Extensions; using SoulstormReplayReader.Core.Domain.Player; namespace SoulstormReplayReader.Core.Utils; // TODO: Посмотреть что происходит с наблюдателями internal sealed class PlayersRandomizer { private readonly NativeDowRandom _rand = new(); public uint Seed { get => _rand.Seed; set => _rand.SetSeed(value); } public PlayersRandomizer(uint seed = 0) { Seed = seed; Debug.WriteLine($"The seed is: {Seed}"); } public List Randomize(List players, int mapPlayersCount) { var isFfa = GetIsFfa(players); Debug.WriteLine(isFfa ? "FFA" : "SET TEAMS"); Debug.WriteLine("RANDOMIZING TEAMS"); var newPlayers = RandomizeTeams(players, isFfa); Debug.WriteLine("RANDOMIZING HOLES"); RandomizeHoles(newPlayers, mapPlayersCount); if (!isFfa) { Debug.WriteLine("RANDOMIZING PLAYERS IN TEAMS"); RandomizePlayersInTeams(newPlayers); } return newPlayers; } private static bool GetIsFfa(List players) { var lastTeam = 0; foreach (var player in players.OrderBy(static p => p.Team)) { if (player.Team - lastTeam > 1) return true; lastTeam = player.Team; } return false; } private List RandomizeTeams(List players, bool isFfa) { if (isFfa) { var nPlayers = players.ToList(); var activePlayersCount = players.Count(static p => p.IsActive); for (var i = 1; i < 8 && activePlayersCount > 1; i++) { if (nPlayers[i].IsActive) activePlayersCount--; nPlayers.Swap(i, _rand.GetMax(i + 1)); } return nPlayers.Where(static p => p.IsActive).ToList(); } var teams = players .Where(static p => p.IsActive) .OrderBy(static p => p.Team) .GroupBy(static pl => pl.Team) .Select(static team => team.ToList()).ToList(); for (var i = 1; i < teams.Count; i++) teams.Swap(i, _rand.GetMax(i + 1)); return teams.SelectMany(static p => p).ToList(); } private void RandomizeHoles(List players, int mapPlayersCount) { var holesCount = mapPlayersCount - players.Count; for (var i = 1; i < players.Count && holesCount != 0; i++) { var playerHolesCount = _rand.GetMax(holesCount + 1); if (playerHolesCount == 0) continue; holesCount -= playerHolesCount; for (var j = 0; j < playerHolesCount; j++) { players.Insert(i, PlayerModel.Empty); i++; } } if (holesCount == 0) return; Debug.WriteLine($"{holesCount + 1} {holesCount}"); while (holesCount-- != 0) players.Add(PlayerModel.Empty); } private void RandomizePlayersInTeams(List players) { var indexTeams = players .Select(static (p, i) => new KeyValuePair(p.Team, i)) .Where(static kv => kv.Key != 0) .GroupBy(static kv => kv.Key) .Select(static teamIndexes => teamIndexes.ToList()) .ToList(); foreach (var indexTeam in indexTeams) for (var i = 1; i < indexTeam.Count; i++) { var n = _rand.GetMax(i + 1); indexTeam.Swap(i, n); players.Swap(indexTeam[i].Value, indexTeam[n].Value); } } }