using System; using System.Collections.Generic; // МОДУЛЬ АРМИИ: войска и их распределение. Документ: Docs/Modules/Army.md // Без Unity: правила деления войск одинаковы на клиенте и на сервере. public static class ArmyMath { // Сколько воинов каждого типа взять, чтобы набрать count, пропорционально составу армии. // Остаток округления раздаётся типам с наибольшей дробной частью. null -- столько воинов нет. public static int[] TakeProportional(int[] troops, int count) { int total = 0; foreach (var t in troops) total += t; if (count <= 0 || count > total) return null; var taken = new int[troops.Length]; int given = 0; var remainders = new List>(); for (int i = 0; i < troops.Length; i++) { double exact = (double)count * troops[i] / total; taken[i] = Math.Min(troops[i], (int)Math.Floor(exact)); given += taken[i]; remainders.Add(new KeyValuePair(i, exact - taken[i])); } remainders.Sort((a, b) => b.Value.CompareTo(a.Value)); for (int k = 0; given < count && k < remainders.Count * 2; k++) { int i = remainders[k % remainders.Count].Key; if (taken[i] < troops[i]) { taken[i]++; given++; } } return taken; } // Как разложить survivors выживших по типам, если в поход ушли sentUnits. // Остаток округления -- в самый многочисленный тип похода. public static int[] SplitSurvivors(int[] sentUnits, int survivors) { var back = new int[sentUnits.Length]; survivors = Math.Max(0, survivors); int sent = 0; foreach (var u in sentUnits) sent += u; int given = 0; for (int i = 0; i < sentUnits.Length; i++) { back[i] = sent > 0 ? (int)Math.Floor((double)survivors * sentUnits[i] / sent) : 0; given += back[i]; } int best = 0; for (int i = 1; i < sentUnits.Length; i++) if (sentUnits[i] > sentUnits[best]) best = i; if (back.Length > 0) back[best] += survivors - given; return back; } }