Алгоритм расчета боя будет посложнее, чем прорезка корпуса и хак. И пытаться просчитать ВЕСЬ бой, пожалуй, будет слишком. Имеет смысл посчитать вероятности для боя на палубах и перед рубкой.
Начнем, пожалуй, с того, что нам понадобится посчитать вероятности того, что один из параметров (атака или защита) не только больше другого, но и больше на 40, на 150, на 400 и на 550. С этими вероятностями будут увеличиваться/уменьшаться количества потерь на палубах.
Исходя из класса, расы, наличия внутренних лазеров, суммарного навыка вражеского десанта и места боя (N-я палуба), считаем DefenceLevel.
| статья писал(а):Для ксенонов:
| DefenceLevel = BaseDefenceLevel × 2 + 85 × MaxMarines - 80 × <количество пройденных палуб> |
| |
- Наличие на корабле внутренних сторожевых лазеров и вражеского десанта не учитывается.
Для землян и АОГ:
| DefenceLevel = BaseDefenceLevel × 4 + <суммарный боевой уровень вражеских десантников> |
| |
- При наличии на корабле внутренних сторожевых лазеров DefenceLevel увеличивается на 200.
Для всех остальных:
| DefenceLevel = BaseDefenceLevel + <суммарный боевой уровень вражеских десантников> |
| |
- При наличии на корабле внутренних сторожевых лазеров DefenceLevel увеличивается на 200.
|
| |
Для боя перед рубкой формула у ксенонов и некоторые другие нюансы отличаются, но там и потери не считаются. Поэтому его считать нужно вообще отдельно. Сейчас займемся чисто палубным боем.
Теперь считаем AttackLevel - суммарный боевой навык атакующих десантников.
Высчитываем пределы изменений обоих параметров.
DefenceLevelmax = DefenceLevel + [0,1 * DefenceLevel] - 1 DefenceLevelmin = DefenceLevel - [0,1 * DefenceLevel]
AttackLevelmax = AttackLevel + [0.1 * AttackLevel] - 1 AttackLevelmin = AttackLevel - [0.1 * AttackLevel]
Но вот дальше идет загвоздка: раньше у нас была только линия "AttackLevel = DefenceLevel", а теперь линии другие и теперь их больше. Они идут под углом 45 градусов из нескольких точек на осях и обозначают результаты "AttackLevel = DefenceLevel + 40", "AttackLevel = DefenceLevel + 150", "AttackLevel = DefenceLevel - 40", "AttackLevel = DefenceLevel - 150" и т.д.
Мало того, отсекаться теперь может не только "равносторонний цифровой треугольник", а вполне себе возможны вот такие результаты:


Ну, а вдобавок, наш прямоугольник может запросто пересекаться не одной, а несколькими линиями.
И на этот раз я не вижу смысла в проверках, что и по какому алгоритму считать. Нужно делать универсальную формулу, через которую потом прогнать значения на предмет вероятностей разных разностей (неужели это я ТАКОЕ написал :lol:).
Итак, нас интересуют вероятности выпадения результатов, когда Защита превышает Атаку на:
более 550 от 401 до 550 от 151 до 400 от 41 до 150 от -40 до 40 от -150 до -41 от -400 до -151 от -550 до -401 менее -550
Назовем этот параметр Х. Соответственно, теперь нам нужен набор формул, последовательно подставляя в которые нужные нам значения Х, мы сможем высчитать вероятности таких превышений Защиты над Атакой.
Как быть?
Выход довольно прост. Будем перебирать последовательно все значения Х и перед подсчетом - проверять, проходит ли соответствующая линия по нашему прямоугольнику. Это довольно просто. Если (DefenceLevelmin - AttackLevelmax) =< Х < (DefenceLevelmax - AttackLevelmin), то линия наш прямоугольник пересекает. Если одно из этих условий не соблюдено - линия нас не интересует.
Хорошо. А как мы будем считать потом?

А почему нам сначала не посчитать большой треугольник, а потом вычесть из него два красных? И дело в шляпе. А если линий, пересекающихся с нашим прямоугольником не одна, а больше? Да, тоже довольно просто. Из каждого результата, кроме первого, надо вычитать предыдущий. Если предыдущая линия не пересекалась с прямоугольником - так и отнимем ноль. А если пересекалась - останется результат для участка МЕЖДУ линиями, что нам и нужно. Считать треугольники мы умеем. Надо только вычислить сторону (А) для каждого из них.
Сторона большого треугольника:
А1 = DefenceLevelmax - AttackLevelmin - X + 1
Стороны малых (красных) треугольников:
А2 = DefenceLevelmin - AttackLevelmin - X
А3 = DefenceLevelmax - AttackLevelmax - X
Обратите внимание на отсутствие приращения единицы при расчете сторон малых треугольников. На этот раз равенство показателей означает, что треугольников нет вообще.
Если сделать формулу правильно, то если красных треугольников физически нет, то они будут получаться нулевыми. Как это сделать? Тоже несложно. Нужно просто все отрицательные значения, полученные в результате вычисления сторон, сделать нулевыми. Делается это до одури легко: А = (А + |А|) / 2.
Ну, вот мы и готовы уже к созданию окончательного алгоритма. Будем считать, что мы уже посчитали показатели Атаки и Защиты и пределы их изменений:
DefenceLevelmax = DefenceLevel + [0,1 * DefenceLevel] - 1 DefenceLevelmin = DefenceLevel - [0,1 * DefenceLevel]
AttackLevelmax = AttackLevel + [0.1 * AttackLevel] - 1 AttackLevelmin = AttackLevel - [0.1 * AttackLevel]
И у нас есть значения Х(N)
N | X | 1 | 550 | 2 | 400 | 3 | 150 | 4 | 40 | 5 | -40 | 6 | -150 | 7 | -400 | 8 | -550 | 9 | - ∞ * |
|
* Не волнуйтесь. "Минус бесконечность" - это всего лишь то, что останется после отсечения по "минус пицод писят".
Тогда ! 
// В данном случае мы от защиты отнимаем атаку, а не наоборот, как я делал в предыдущих алгоритмах. Это несколько сбивает с толку, поскольку интересующие нас значения "больше Х" лежат уже правее/ниже разделительной линии. Поэтому лучше всего представить, что в этот раз на вертикальной числовой оси лежат значения защиты, а на горизонтальной - атаки.
| DefenceLevel | | | | | | |_____________________ AttackLevel
И еще мы будем использовать два значения: Расчет - это все результаты выше текущей линии, Результат - все результаты, лежащие выше текущей, но не выше предыдущей линии.
1. А1 = DefenceLevelmax - AttackLevelmin + 1 // в пп. 1- 6 мы задаем нужные нам переменные, которые будем потом использовать
2. А2 = DefenceLevelmin - AttackLevelmin
3. А3 = DefenceLevelmax - AttackLevelmax
4. MAX = DefenceLevelmax - AttackLevelmin
5. MIN = DefenceLevelmin - AttackLevelmax
6. S = (DefenceLevelmax - DefenceLevelmin + 1) * (AttackLevelmax - AttackLevelmin + 1)
7. N = 1 // начинаем цикл, задав значение счетчика
8. Если MIN > 550, то РасчетN = РезультатN = S, goto 28 // При этом условии весь прямоугольник лежит выше линии 550. Можно ничего не считать, а присвоить Расчету и Результату значения, равные площади. Данный кусок проходится только для первой линии, поэтому предыдущей быть не может. Идем считать Шанс.
9. Если MIN =< 550 < MAX, то goto 20 // В этом случае наш прямоугольник пересекается линией 550. Идем считать треугольники.
10. Если MAX =< 550, то РасчетN = РезультатN = 0, goto 28 // В принципе, условие можно было вообще выкинуть. Это просто все остальные случаи. Прямоугольник не высовывается за линию 550 и нам нечего считать. И Результат и Расчет равны нулю, отправляемся считать Шанс.
11. Если N < 9, то goto 16 // Если это не самый последний проход, идем смотреть, как проходит текущая линия по нашему прямоугольнику.
12. Если MAX < -550, то РасчетN = РезультатN = S, goto 15 // Если при последнем проходе весь прямоугольник лежит ниже линии -550 (у нас ведь нет X9), то последний Расчет и последний Результат равны площади всего прямоугольника. Идем считать последний Шанс и завершать работу.
13. Если MIN >= -550, то РасчетN = РезультатN = 0, goto 15 // Если при последнем проходе весь прямоугольник лежит не ниже линии -550, то Расчет и Результат оба нулевые. Идем считать последний Шанс и завершать алгоритм.
14. РасчетN = РезультатN = S - РасчетN - 1 // В остальных случаях последнего прохода ниже линии -550 лежит только часть прямоугольника. И последние Расчет с Результатом равны площади за вычетом предыдущего Результата.
15. ШансN = РезультатN / S, goto 30 // Считаем последний Шанс из последнего Результата и завершаем работу.
16. Если Х(N) >= MAX, то РасчетN = РезультатN = 0, goto 28 // Если весь прямоугольник не выше текущей линии, Расчет и Результат - нулевые. Идем считать Шанс и начинать следующий цикл.
17. Если MIN =< Х(N) < MAX, то goto 20 // Если текущая линия пересекает прямоугольник - идем считать треугольники.
18. Если Х(N-1) >= MAX, то РасчетN = РезультатN = S, goto 28 // В остальных случаях линия лежит ниже прямоугольника. Но вот если при этом он еще и не выступает за предыдущую линию, то текущий Результат - это вся площадь прямоугольника и мы идем считать Шанс и начинать следующий цикл...
19. Если Х(N-1) > MIN, то РасчетN = РезультатN = S - РасчетN-1, иначе РасчетN = РезультатN = 0 // ...а раз уж все-таки выступает, то Расчет и Результат равны площади прямоугольника за вычетом предыдущего результата, если только весь прямоугольник не остался выше предыдущей линии (тогда Расчет и Результат - нулевые).
19,5. goto 28 Идем считать Шанс и продолжать.
20. A1N = A1 - XN
21. A2N = (A2 - XN + |A2 - XN|) / 2
22. A3N = (A3 - XN + |A3 - XN|) / 2
23. Тр1N = (А1N2 - A1N) / 2
24. Тр2N = (А2N2 - A2N) / 2
25. Тр3N = (А3N2 - A3N) / 2
26. РасчетN = Тр1N - Тр2N - Тр3N
27. Если N > 1, то РезультатN = РасчетN - РасчетN-1, иначе РезультатN = РасчетN // Здесь мы занимались тем, что считали наши треугольники, получая значение Расчет. А потом считали результат, вычитая из текущего значения Расчета предыдущее значение каждый раз, кроме самого первого.
28. ШансN = РезультатN / S // Считаем Шанс из Результата.
29. N = N + 1, goto 11 Приращиваем N и отправляемся обсчитывать следующую линию.
30. Конец.
По окончании этой процедуры у нас будет девять значений ШансN для N от 1 до 9. И соответствовать они будут шансам из Табл. 7 статьи toor'а:
| | | | | AttackCasualties | DefenceCasualties | Шанс такого варианта | 550 | < | DefenceLevel - AttackLevel | | | AC × 3 | 0 | Шанс1 | 400 | < | DefenceLevel - AttackLevel | ≤ | 550 | AC × 3 | DC - 3 | Шанс2 | 150 | < | DefenceLevel - AttackLevel | ≤ | 400 | AC + (AC + 1) / 2 | DC - (DC + 1) / 2 | Шанс3 | 40 | < | DefenceLevel - AttackLevel | ≤ | 150 | AC + 1 | DC - 1 | Шанс4 | -40 | ≤ | DefenceLevel - AttackLevel | ≤ | 40 | AC | DC | Шанс5 | -150 | ≤ | DefenceLevel - AttackLevel | < | -40 | AC - 1 | DC + 1 | Шанс6 | -400 | ≤ | DefenceLevel - AttackLevel | < | -150 | AC - (AC + 1) / 2 | DC + (DC + 1) / 2 | Шанс7 | -550 | ≤ | DefenceLevel - AttackLevel | < | -400 | AC - 3 | DC × 2 | Шанс8 | | | DefenceLevel - AttackLevel | < | -550 | 0 | DC × 3 | Шанс9 |
|
Теперь вспомним о том, что еще до расчета вышеприведенных линеечек было еще такое: если (DefenceLevel - AttackLevel) ≤ 40, то с вероятностью 2% AttackCasualties будет увеличена на 1, а DefenceCasualties уменьшается на 1.
И вот в связи с этим табличку следует слегка модифицировать, учитывая данную вероятность. И вот теперь мы получаем уже окончательную таблицу вероятности модификации палубных потерь:
AttackCasualties | DefenceCasualties | Шанс такого варианта | AC × 3 | 0 | Шанс1 | AC × 3 | DC - 3 | Шанс2 | AC + (AC + 1) / 2 | DC - (DC + 1) / 2 | Шанс3 | AC + 1 | DC - 1 | Шанс4 + 0,02 * (Шанс5 + Шанс6 + Шанс7 + Шанс8 + Шанс9) | AC | DC | 0,98 * Шанс5 | AC - 1 | DC + 1 | 0,98 * Шанс6 | AC - (AC + 1) / 2 | DC + (DC + 1) / 2 | 0,98 * Шанс7 | AC - 3 | DC × 2 | 0,98 * Шанс8 | 0 | DC × 3 | 0,98 * Шанс9 |
|
Продолжение следует. |