Решения по отчёту от 01.11: потери сильной стороны до 2% при 10:1, 5 временных мест госпиталя, лечение 1/1/2/3 золота

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander
2026-11-04 14:42:07 +01:00
co-authored by Claude Opus 5.5
parent af57a13f0f
commit f50591d5fe
10 changed files with 28 additions and 22 deletions
+3 -3
View File
@@ -12,7 +12,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 7264ce138a844adc81fa69b77a27c8a6, type: 3}
m_Name: BattleConfig
m_EditorClassIdentifier:
version: 6
version: 7
counterPercent: 25
wallsPercent: 20
siegeVsWallsPercent: 50
@@ -30,8 +30,8 @@ MonoBehaviour:
- 450
- 160
- 110
- 110
- 110
- 74
- 20
weakLossPermille:
- 450
- 740
+2 -2
View File
@@ -13,10 +13,10 @@ MonoBehaviour:
m_Name: HospitalConfig
m_EditorClassIdentifier:
bedsByLevel: 140000001e00000028000000320000003c000000
temporaryBeds: 0
temporaryBeds: 5
requiredTownHallLevel: 1
buildWood: 250
buildStone: 150
healGameHours: 04000000040000000600000008000000
healFoodPerSoldier: 00000000000000000000000000000000
healGoldPerSoldier: 00000000000000000000000000000000
healGoldPerSoldier: 01000000010000000200000003000000
+1 -1
View File
@@ -30,7 +30,7 @@ public class BattleConfig : ScriptableObject
[Tooltip("Опорные точки соотношения сил (сильная / слабая) в десятых долях процента: 1000 = 1:1, 3000 = 3:1. Первая -- обязательно 1000, дальше по возрастанию")]
public int[] lossRatioPermille = { 1000, 3000, 5000, 7000, 10000 };
[Tooltip("Доля выбывших у сильной стороны в каждой точке, десятые доли процента: 450 = 45%")]
public int[] strongLossPermille = { 450, 160, 110, 110, 110 };
public int[] strongLossPermille = { 450, 160, 110, 74, 20 };
[Tooltip("Доля выбывших у слабой стороны в каждой точке, десятые доли процента: 740 = 74%")]
public int[] weakLossPermille = { 450, 740, 880, 920, 950 };
[Tooltip("Разгром дальше последней точки: слабая сторона плавно стремится к этому пределу, десятые доли процента. Решения 31.10, п. 5: 990 = 99%")]
+4 -4
View File
@@ -14,8 +14,8 @@ public class HospitalConfig : ScriptableObject
[Header("Здание «Госпиталь» (ТЕСТ)")]
[Tooltip("Мест для лечения по уровням госпиталя I..V. Регламент 31.10: 20..60. Число строк -- число уровней")]
public int[] bedsByLevel = { 20, 30, 40, 50, 60 };
[Tooltip("Мест, пока в городе нет госпиталя. 0 -- раненые ждут, пока госпиталь не построят")]
public int temporaryBeds = 0;
[Tooltip("Мест, пока в городе нет госпиталя. Решения 01.11, п. 3: 5. После постройки заменяются штатными, не складываются")]
public int temporaryBeds = 5;
[Tooltip("С какого уровня Ратуши можно строить")]
public int requiredTownHallLevel = 1;
[Tooltip("Цена постройки: дерево")]
@@ -27,11 +27,11 @@ public class HospitalConfig : ScriptableObject
[Tooltip("Пехота, лучники, кавалерия, осадные. Регламент 31.10: 4 / 4 / 6 / 8")]
public int[] healGameHours = { 4, 4, 6, 8 };
[Header("Цена лечения одного воина -- НЕ УТВЕРЖДЕНА (0 -- без цены)")]
[Header("Цена лечения одного воина (решения 01.11, п. 3: золото 1 / 1 / 2 / 3)")]
[Tooltip("Еды за воина: пехота, лучники, кавалерия, осадные")]
public int[] healFoodPerSoldier = { 0, 0, 0, 0 };
[Tooltip("Золота за воина: пехота, лучники, кавалерия, осадные")]
public int[] healGoldPerSoldier = { 0, 0, 0, 0 };
public int[] healGoldPerSoldier = { 1, 1, 2, 3 };
static HospitalConfig cached;
+2 -2
View File
@@ -14,10 +14,10 @@ using System.Text;
// Числа госпиталя (регламент 31.10, ТЕСТ). В игре -- из таблицы HospitalConfig.
public sealed class HospitalRules
{
public int TemporaryBeds = 20; // мест, пока здания госпиталя нет (как у госпиталя I уровня)
public int TemporaryBeds = 5; // мест, пока здания госпиталя нет (решения 01.11, п. 3); после постройки -- штатные, не вместе
public int[] HealGameHours = { 4, 4, 6, 8 }; // лечение одного воина: пехота и лучники 4, кавалерия 6, осадные 8 ИГРОВЫХ часов
public long GameHourMs = 5 * 60 * 1000; // 1 игровой час = 5 реальных минут
// Цена лечения одного воина по типам -- НЕ УТВЕРЖДЕНА: пока пусто, лечение без цены
// Цена лечения одного воина по типам (решения 01.11, п. 3: 1 / 1 / 2 / 3 золота -- в таблице HospitalConfig); пусто -- без цены
public ResourceAmount[][] HealCostPerSoldier = null;
public static HospitalRules Default => new HospitalRules();
+5 -4
View File
@@ -6,8 +6,9 @@
// итог боя запоминает версию, по которой посчитан.
public sealed class BattleRules
{
public int Version = 6; // 2 -- голод и усталость; 3 -- сила без округления, потери шансом (№12, №13); 4 -- кривая потерь (№14);
// 5 -- разгром дальше 5:1 (решения по 8 вопросам Саши, 31.10, п. 5); 6 -- раненые (п. 7)
public int Version = 7; // 2 -- голод и усталость; 3 -- сила без округления, потери шансом (№12, №13); 4 -- кривая потерь (№14);
// 5 -- разгром дальше 5:1 (решения по 8 вопросам Саши, 31.10, п. 5); 6 -- раненые (п. 7);
// 7 -- сильная сторона 5:1 -> 10:1 с 11% до 2% (решения по отчёту Саши, 01.11, п. 1)
// Сила одного воина каждого типа. В игре -- из GameData.Troops (там же цена и время обучения).
public int[] UnitPower = { 4, 5, 9, 16 };
@@ -23,9 +24,9 @@ public sealed class BattleRules
// (линейно), без порогов-переключателей.
// Разгром (решения 31.10, п. 5): 7:1 -- 92%, 10:1 -- 95%, дальше слабая сторона плавно стремится к WeakLossMaxPermille (99%):
// v = max - (max - v_last) * R_last / R -- при 20:1 97%, при 100:1 98,6%; 100% не достигается.
// Сильная сторона за последней точкой -- значение последней точки (документ числа для неё не задаёт).
// Сильная сторона (решения по отчёту Саши, 01.11, п. 1): 5:1 -- 11%, плавно до 2% при 10:1, дальше 2%.
public int[] LossRatioPermille = { 1000, 3000, 5000, 7000, 10000 }; // 1:1, 3:1, 5:1, 7:1, 10:1
public int[] StrongLossPermille = { 450, 160, 110, 110, 110 }; // сильная сторона: 45%, 16%, 11%, 11%, 11%
public int[] StrongLossPermille = { 450, 160, 110, 74, 20 }; // сильная сторона: 45%, 16%, 11%, 7,4%, 2%
public int[] WeakLossPermille = { 450, 740, 880, 920, 950 }; // слабая сторона: 45%, 74%, 88%, 92%, 95%
public int WeakLossMaxPermille = 990; // верхний предел ожидаемых потерь слабой стороны: 99%
+3 -1
View File
@@ -562,7 +562,9 @@ public class ModuleTests
Assert.AreEqual(950, Fight(10000, 1000).DefenderLosses, "10:1 -- 95%");
Assert.AreEqual(970, Fight(20000, 1000).DefenderLosses, "20:1 -- 99 - 4 x 10/20 = 97%");
Assert.AreEqual(986, Fight(100000, 1000).DefenderLosses, "100:1 -- 98,6%");
Assert.AreEqual(1100, Fight(10000, 1000).AttackerLosses, "сильная сторона дальше 5:1 -- 11%");
Assert.AreEqual(518, Fight(7000, 1000).AttackerLosses, "сильная 7:1 -- 7,4% от 7000 (решения 01.11, п. 1)");
Assert.AreEqual(200, Fight(10000, 1000).AttackerLosses, "сильная 10:1 -- 2%");
Assert.AreEqual(400, Fight(20000, 1000).AttackerLosses, "сильная дальше 10:1 -- 2%");
// Симметрия: тот же перевес у защитника -- те же доли (одинаково для PvE, PvP и Круга)
BattleOutcome threeDef = Fight(1000, 3000);