128 lines
3.7 KiB
C#
128 lines
3.7 KiB
C#
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<PlayerModel> Randomize(List<PlayerModel> 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<PlayerModel> 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<PlayerModel> RandomizeTeams(List<PlayerModel> 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<PlayerModel> 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<PlayerModel> players)
|
||
{
|
||
var indexTeams = players
|
||
.Select(static (p, i) => new KeyValuePair<int, int>(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);
|
||
}
|
||
}
|
||
} |