OSDN Git Service

海戦・ドロップ報告書に連合艦隊の護衛艦隊を出力する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / BattleInfo.cs
index 2926568..604e691 100644 (file)
@@ -29,6 +29,14 @@ namespace KancolleSniffer
         E,\r
     }\r
 \r
+    public enum BattleState\r
+    {\r
+        None,\r
+        Day,\r
+        Night,\r
+        Result\r
+    }\r
+\r
     public class BattleInfo\r
     {\r
         private readonly ShipInfo _shipInfo;\r
@@ -43,12 +51,14 @@ namespace KancolleSniffer
         private readonly List<int> _escapingShips = new List<int>();\r
         private int _flagshipRecoveryType;\r
 \r
-        public bool InBattle { get; set; }\r
+        public BattleState BattleState { get; set; }\r
         public string Formation { get; private set; }\r
         public string EnemyFighterPower { get; private set; }\r
         public int AirControlLevel { get; private set; }\r
         public BattleResultRank ResultRank { get; private set; }\r
         public ShipStatus[] EnemyResultStatus { get; private set; }\r
+        public List<AirBattleResult> AirBattleResults { get; } = new List<AirBattleResult>();\r
+\r
 \r
         public BattleInfo(ShipInfo shipInfo, ItemInfo itemInfo)\r
         {\r
@@ -58,7 +68,6 @@ namespace KancolleSniffer
 \r
         public void InspectBattle(dynamic json, string url)\r
         {\r
-            InBattle = true;\r
             Formation = FormationName(json);\r
             EnemyFighterPower = CalcEnemyFighterPower(json);\r
             AirControlLevel = CheckAirControlLevel(json);\r
@@ -66,18 +75,26 @@ namespace KancolleSniffer
             SetupResult(json);\r
             if (IsNightBattle(json))\r
             {\r
+                BattleState = BattleState.Night;\r
                 CalcHougekiDamage(json.api_hougeki,\r
                     _guard.Length > 0 ? _guard : _friend,\r
                     json.api_active_deck() && json.api_active_deck[1] != 1 ? _enemyGuardHp : _enemyHp);\r
             }\r
             else\r
             {\r
+                BattleState = BattleState.Day;\r
                 CalcDamage(json, url.EndsWith("battle_water"));\r
             }\r
-            ClearOverKill(_enemyHp);\r
+            ClearEnemyOverKill();\r
             ResultRank = url.EndsWith("ld_airbattle") ? CalcLdAirBattleRank() : CalcResultRank();\r
         }\r
 \r
+        private void ClearEnemyOverKill()\r
+        {\r
+            _enemyHp = _enemyHp.Select(hp => hp < 0 ? 0 : hp).ToArray();\r
+            _enemyGuardHp = _enemyGuardHp.Select(hp => hp < 0 ? 0 : hp).ToArray();\r
+        }\r
+\r
         public void InspectMapNext(string request)\r
         {\r
             var type = HttpUtility.ParseQueryString(request)["api_recovery_type"];\r
@@ -88,11 +105,11 @@ namespace KancolleSniffer
 \r
         private bool IsNightBattle(dynamic json) => json.api_hougeki();\r
 \r
-        private int DeckId(dynamic json)\r
+        public static int DeckId(dynamic json)\r
         {\r
             if (json.api_dock_id()) // 昼戦はtypoしている\r
                 return (int)json.api_dock_id - 1;\r
-            if (json.api_deck_id is string) // 通常の夜戦では文字列\r
+            if (json.api_deck_id is string) // é\80\9a常ã\81®å¤\9cæ\88¦ã\81¨é\80£å\90\88è\89¦é\9a\8a\91³æ\96¹ã\81®ã\81¿)ã\81§ã\81¯æ\96\87å­\97å\88\97\r
                 return int.Parse(json.api_deck_id) - 1;\r
             return (int)json.api_deck_id - 1;\r
         }\r
@@ -124,11 +141,13 @@ namespace KancolleSniffer
             var fstats = _shipInfo.GetShipStatuses(_fleet);\r
             FlagshipRecovery(fstats[0]);\r
             _friend = Record.Setup(fstats);\r
-            _enemyHp = nowhps.Skip(7).TakeWhile(hp => hp != -1).ToArray();\r
+            _enemyHp = nowhps.Skip(7).ToArray();\r
             _enemyStartHp = (int[])_enemyHp.Clone();\r
             EnemyResultStatus =\r
-            (from id in (int[])json.api_ship_ke\r
-                where id != -1\r
+            (from id in\r
+                json.api_ship_ke_combined()\r
+                    ? ((int[])json.api_ship_ke).Skip(1).Concat(((int[])json.api_ship_ke_combined).Skip(1))\r
+                    : ((int[])json.api_ship_ke).Skip(1)\r
                 select new ShipStatus {Id = id, Spec = _shipInfo.GetSpec(id)}).ToArray();\r
             _guard = new Record[0];\r
             _enemyGuardHp = new int[0];\r
@@ -142,7 +161,7 @@ namespace KancolleSniffer
             {\r
                 _enemyGuardHp =\r
                     ((int[])json.api_nowhps_combined).\r
-                        Skip(7).TakeWhile(hp => hp != -1).ToArray();\r
+                        Skip(7).ToArray();\r
                 _enemyGuardStartHp = (int[])_enemyGuardHp.Clone();\r
             }\r
         }\r
@@ -221,20 +240,31 @@ namespace KancolleSniffer
 \r
         private void CalcDamage(dynamic json, bool surfaceFleet = false)\r
         {\r
+            AirBattleResults.Clear();\r
             var fc = _guard.Length > 0;\r
             var ec = _enemyGuardHp.Length > 0;\r
+            var both = fc && ec;\r
+            if (json.api_air_base_injection())\r
+            {\r
+                AddAirBattleResult(json.api_air_base_injection, "AB噴式");\r
+                CalcKoukuDamage(json.api_air_base_injection);\r
+            }\r
+            if (json.api_injection_kouku())\r
+            {\r
+                AddAirBattleResult(json.api_injection_kouku, "噴式");\r
+                CalcKoukuDamage(json.api_injection_kouku);\r
+            }\r
             if (json.api_air_base_attack())\r
                 CalcAirBaseAttackDamage(json.api_air_base_attack);\r
-            if (json.api_kouku.api_stage3 != null)\r
-                CalcSimpleDamage(json.api_kouku.api_stage3, _friend, _enemyHp);\r
-            if (json.api_kouku.api_stage3_combined() && json.api_kouku.api_stage3_combined != null)\r
-                CalcSimpleDamage(json.api_kouku.api_stage3_combined, _guard, _enemyGuardHp);\r
+            if (json.api_kouku())\r
+            {\r
+                AddAirBattleResult(json.api_kouku, "航空戦");\r
+                CalcKoukuDamage(json.api_kouku);\r
+            }\r
             if (json.api_kouku2()) // 航空戦2回目\r
             {\r
-                if (json.api_kouku2.api_stage3 != null)\r
-                    CalcSimpleDamage(json.api_kouku2.api_stage3, _friend, _enemyHp);\r
-                if (json.api_kouku2.api_stage3_combined() && json.api_kouku2.api_stage3_combined != null)\r
-                    CalcSimpleDamage(json.api_kouku2.api_stage3_combined, _guard, _enemyGuardHp);\r
+                AddAirBattleResult(json.api_kouku2, "航空戦2");\r
+                CalcKoukuDamage(json.api_kouku2);\r
             }\r
             if (!json.api_opening_atack()) // 航空戦のみ\r
                 return;\r
@@ -242,26 +272,53 @@ namespace KancolleSniffer
                 CalcSupportDamage(json.api_support_info);\r
             if (json.api_opening_taisen() && json.api_opening_taisen != null)\r
             {\r
-                var friend = fc ? _guard : _friend; // 先制対潜攻撃の対象は護衛(たぶん)\r
-                CalcHougekiDamage(json.api_opening_taisen, friend, _enemyHp);\r
+                if (json.api_opening_taisen.api_at_eflag())\r
+                {\r
+                    CalcCombinedHougekiDamage(json.api_opening_taisen, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+                }\r
+                else\r
+                {\r
+                    CalcHougekiDamage(json.api_opening_taisen,\r
+                        fc ? _guard : _friend, // 先制対潜攻撃の対象は護衛\r
+                        _enemyHp);\r
+                }\r
             }\r
             if (json.api_opening_atack != null)\r
             {\r
-                var friend = fc ? _guard : _friend; // 雷撃の対象は護衛\r
-                CalcSimpleDamage(json.api_opening_atack, friend, _enemyHp, _enemyGuardHp);\r
+                if (both)\r
+                {\r
+                    CalcSimpleDamage(json.api_opening_atack, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+                }\r
+                else\r
+                {\r
+                    CalcSimpleDamage(json.api_opening_atack,\r
+                        fc ? _guard : _friend, // 雷撃の対象は護衛\r
+                        _enemyHp, _enemyGuardHp);\r
+                }\r
             }\r
             if (json.api_hougeki1() && json.api_hougeki1 != null)\r
             {\r
-                CalcHougekiDamage(json.api_hougeki1,\r
-                    fc && !surfaceFleet ? _guard : _friend, // 空母機動部隊は一巡目が護衛\r
-                    ec ? _enemyGuardHp : _enemyHp); // 敵連合艦隊は一巡目が護衛\r
+                if (json.api_hougeki1.api_at_eflag())\r
+                {\r
+                    CalcCombinedHougekiDamage(json.api_hougeki1, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+                }\r
+                else\r
+                {\r
+                    CalcHougekiDamage(json.api_hougeki1,\r
+                        fc && !surfaceFleet ? _guard : _friend, // 空母機動部隊は一巡目が護衛\r
+                        ec ? _enemyGuardHp : _enemyHp); // 敵連合艦隊は一巡目が護衛\r
+                }\r
             }\r
             if (json.api_hougeki2() && json.api_hougeki2 != null)\r
             {\r
                 if (json.api_hougeki2.api_at_eflag())\r
+                {\r
                     CalcCombinedHougekiDamage(json.api_hougeki2, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+                }\r
                 else\r
+                {\r
                     CalcHougekiDamage(json.api_hougeki2, _friend, _enemyHp);\r
+                }\r
             }\r
             if (json.api_hougeki3() && json.api_hougeki3 != null)\r
             {\r
@@ -271,41 +328,91 @@ namespace KancolleSniffer
                 }\r
                 else\r
                 {\r
-                    var friend = fc && surfaceFleet ? _guard : _friend; // 水上打撃部隊は三順目が護衛\r
-                    CalcHougekiDamage(json.api_hougeki3, friend, _enemyHp);\r
+                    CalcHougekiDamage(json.api_hougeki3,\r
+                        fc && surfaceFleet ? _guard : _friend, // 水上打撃部隊は三順目が護衛\r
+                        _enemyHp);\r
                 }\r
             }\r
             if (json.api_raigeki() && json.api_raigeki != null)\r
             {\r
-                var friend = fc ? _guard : _friend;\r
-                CalcSimpleDamage(json.api_raigeki, friend, _enemyHp, _enemyGuardHp);\r
+                if (both)\r
+                {\r
+                    CalcSimpleDamage(json.api_raigeki, _friend, _guard, _enemyHp, _enemyGuardHp);\r
+                }\r
+                else\r
+                {\r
+                    CalcSimpleDamage(json.api_raigeki,\r
+                        fc ? _guard : _friend, // 雷撃の対象は護衛\r
+                        _enemyHp, _enemyGuardHp);\r
+                }\r
             }\r
         }\r
 \r
         private void CalcSupportDamage(dynamic json)\r
         {\r
             if (json.api_support_hourai != null)\r
-                CalcSimpleDamage(json.api_support_hourai.api_damage, _enemyHp);\r
+            {\r
+                CalcSimpleDamage(json.api_support_hourai.api_damage, _enemyHp, _enemyGuardHp);\r
+            }\r
             else if (json.api_support_airatack != null)\r
             {\r
-                var stage3 = json.api_support_airatack.api_stage3;\r
-                if (stage3 != null)\r
-                    CalcSimpleDamage(stage3.api_edam, _enemyHp);\r
+                CalcSimpleDamage(json.api_support_airatack.api_stage3.api_edam, _enemyHp, _enemyGuardHp);\r
             }\r
         }\r
 \r
         private void CalcAirBaseAttackDamage(dynamic json)\r
         {\r
+            var i = 1;\r
             foreach (var entry in json)\r
             {\r
-                if (!entry.api_stage3() || entry.api_stage3 == null)\r
-                    continue;\r
-                CalcSimpleDamage(entry.api_stage3.api_edam, _enemyHp);\r
-                if (entry.api_stage3_combined())\r
-                    CalcSimpleDamage(entry.api_stage3_combined.api_edam, _enemyGuardHp);\r
+                AddAirBattleResult(entry, "基地" + i++);\r
+                CalcKoukuDamage(entry);\r
             }\r
         }\r
 \r
+        private void AddAirBattleResult(dynamic json, string phaseName)\r
+        {\r
+            var stage1 = json.api_stage1;\r
+            if (stage1 == null || (stage1.api_f_count == 0 && stage1.api_e_count == 0))\r
+                return;\r
+            AirBattleResults.Add(new AirBattleResult\r
+            {\r
+                PhaseName = phaseName,\r
+                AirControlLevel = json.api_stage1.api_disp_seiku() ? (int)json.api_stage1.api_disp_seiku : 0,\r
+                Stage1 = new AirBattleResult.StageResult\r
+                {\r
+                    FriendCount = (int)json.api_stage1.api_f_count,\r
+                    FriendLost = (int)json.api_stage1.api_f_lostcount,\r
+                    EnemyCount = (int)json.api_stage1.api_e_count,\r
+                    EnemyLost = (int)json.api_stage1.api_e_lostcount\r
+                },\r
+                Stage2 = json.api_stage2 == null\r
+                    ? new AirBattleResult.StageResult\r
+                    {\r
+                        FriendCount = 0,\r
+                        FriendLost = 0,\r
+                        EnemyCount = 0,\r
+                        EnemyLost = 0\r
+                    }\r
+                    : new AirBattleResult.StageResult\r
+                    {\r
+                        FriendCount = (int)json.api_stage2.api_f_count,\r
+                        FriendLost = (int)json.api_stage2.api_f_lostcount,\r
+                        EnemyCount = (int)json.api_stage2.api_e_count,\r
+                        EnemyLost = (int)json.api_stage2.api_e_lostcount\r
+                    }\r
+            });\r
+        }\r
+\r
+        private void CalcKoukuDamage(dynamic json)\r
+        {\r
+            if (!json.api_stage3() || json.api_stage3 == null)\r
+                return;\r
+            CalcSimpleDamage(json.api_stage3, _friend, _enemyHp);\r
+            if (json.api_stage3_combined())\r
+                CalcSimpleDamage(json.api_stage3_combined, _guard, _enemyGuardHp);\r
+        }\r
+\r
         private void CalcSimpleDamage(dynamic json, Record[] friend, int[] enemy)\r
         {\r
             if (json.api_fdam())\r
@@ -317,18 +424,38 @@ namespace KancolleSniffer
         private void CalcSimpleDamage(dynamic json, Record[] friend, int[] enemy, int[] enemyGuard)\r
         {\r
             CalcSimpleDamage(json.api_fdam, friend);\r
-            var damage = (int[])json.api_edam;\r
-            for (var i = 0; i < enemy.Length; i++)\r
-                enemy[i] -= damage[i + 1];\r
-            for (var i = 0; i < enemyGuard.Length; i++)\r
-                enemyGuard[i] -= damage[i + 6 + 1];\r
+            CalcSimpleDamage(json.api_edam, enemy, enemyGuard);\r
         }\r
 \r
-        private void CalcSimpleDamage(dynamic rawDamage, Record[] result)\r
+        private void CalcSimpleDamage(dynamic json, Record[] friend, Record[] guard, int[] enemy, int[] enemyGuard)\r
+        {\r
+            CalcSimpleDamage(json.api_fdam, friend, guard);\r
+            CalcSimpleDamage(json.api_edam, enemy, enemyGuard);\r
+        }\r
+\r
+        private void CalcSimpleDamage(dynamic rawDamage, Record[] friend, Record[] guard)\r
         {\r
             var damage = (int[])rawDamage;\r
-            for (var i = 0; i < result.Length; i++)\r
-                result[i].ApplyDamage(damage[i + 1]);\r
+            for (var i = 0; i < friend.Length; i++)\r
+                friend[i].ApplyDamage(damage[i + 1]);\r
+            for (var i = 0; i < guard.Length; i++)\r
+                guard[i].ApplyDamage(damage[i + 6 + 1]);\r
+        }\r
+\r
+        private void CalcSimpleDamage(dynamic rawDamage, Record[] friend)\r
+        {\r
+            var damage = (int[])rawDamage;\r
+            for (var i = 0; i < friend.Length; i++)\r
+                friend[i].ApplyDamage(damage[i + 1]);\r
+        }\r
+\r
+        private void CalcSimpleDamage(dynamic rawDamage, int[] enemy, int[] enemyGuard)\r
+        {\r
+            var damage = (int[])rawDamage;\r
+            for (var i = 0; i < enemy.Length; i++)\r
+                enemy[i] -= damage[i + 1];\r
+            for (var i = 0; i < enemyGuard.Length; i++)\r
+                enemyGuard[i] -= damage[i + 6 + 1];\r
         }\r
 \r
         private void CalcSimpleDamage(dynamic rawDamage, int[] result)\r
@@ -370,7 +497,7 @@ namespace KancolleSniffer
                         if (hit.t <= 6)\r
                             friend[hit.t - 1].ApplyDamage(hit.d);\r
                         else\r
-                            guard[hit.t - 1].ApplyDamage(hit.d);\r
+                            guard[(hit.t - 1) % 6].ApplyDamage(hit.d);\r
                     }\r
                     else\r
                     {\r
@@ -383,15 +510,9 @@ namespace KancolleSniffer
             }\r
         }\r
 \r
-        private void ClearOverKill(int[] result)\r
-        {\r
-            for (var i = 0; i < result.Length; i++)\r
-                if (result[i] < 0)\r
-                    result[i] = 0;\r
-        }\r
-\r
         public void InspectBattleResult(dynamic json)\r
         {\r
+            BattleState = BattleState.Result;\r
             ShowResult();\r
             CleanupResult();\r
             SetEscapeShips(json);\r
@@ -399,6 +520,7 @@ namespace KancolleSniffer
 \r
         public void InspectPracticeResult(dynamic json)\r
         {\r
+            BattleState = BattleState.Result;\r
             ShowResult(false);\r
             CleanupResult();\r
         }\r
@@ -421,11 +543,16 @@ namespace KancolleSniffer
 \r
         private void SetEnemyResultStatus()\r
         {\r
-            for (var i = 0; i < EnemyResultStatus.Length; i++)\r
+            for (var i = 0; i < 6; i++)\r
             {\r
                 EnemyResultStatus[i].MaxHp = _enemyStartHp[i];\r
                 EnemyResultStatus[i].NowHp = _enemyHp[i];\r
             }\r
+            for (var i = 6; i < EnemyResultStatus.Length; i++)\r
+            {\r
+                EnemyResultStatus[i].MaxHp = _enemyGuardStartHp[i - 6];\r
+                EnemyResultStatus[i].NowHp = _enemyGuardHp[i - 6];\r
+            }\r
         }\r
 \r
         public void SetEscapeShips(dynamic json)\r
@@ -450,6 +577,7 @@ namespace KancolleSniffer
             private ShipStatus _status;\r
             public int NowHp => _status.NowHp;\r
             public bool Escaped => _status.Escaped;\r
+            public ShipStatus.Damage DamageLevel => _status.DamageLevel;\r
             public int StartHp;\r
 \r
             public static Record[] Setup(ShipStatus[] ships) =>\r
@@ -513,87 +641,50 @@ namespace KancolleSniffer
             return BattleResultRank.E;\r
         }\r
 \r
-        // 以下のコードは航海日誌拡張版の以下のファイルのcalcResultRankを移植したもの\r
-        // https://github.com/nekopanda/logbook/blob/94ceca4be6d4ce79a8759d1ee747fb9827c08edc/main/logbook/dto/BattleExDto.java\r
-        //\r
-        // The MIT License (MIT)\r
-        //\r
-        // Copyright (c) 2014-2015 航海日誌拡張版開発者\r
-        //\r
-        // Permission is hereby granted, free of charge, to any person obtaining a copy\r
-        // of this software and associated documentation files (the "Software"), to deal\r
-        // in the Software without restriction, including without limitation the rights\r
-        // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-        // copies of the Software, and to permit persons to whom the Software is\r
-        // furnished to do so, subject to the following conditions:\r
-        //\r
-        // The above copyright notice and this permission notice shall be included in\r
-        // all copies or substantial portions of the Software.\r
-        //\r
-        // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-        // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-        // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-        // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-        // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-        // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-        // THE SOFTWARE.\r
-        //\r
         private BattleResultRank CalcResultRank()\r
         {\r
             var friend = _friend.Concat(_guard).ToArray();\r
             var enemyHp = _enemyHp.Concat(_enemyGuardHp).ToArray();\r
             var enemyStartHp = _enemyStartHp.Concat(_enemyGuardStartHp).ToArray();\r
-            // 戦闘後に残っている艦数\r
-            var friendNowShips = friend.Count(r => r.NowHp > 0);\r
-            var enemyNowShips = enemyHp.Count(hp => hp > 0);\r
-            // 総ダメージ\r
-            var friendGauge = Max(friend.Sum(r => r.StartHp - r.NowHp), 0); // ダメコン・女神発動で負になりうる\r
-            var enemyGauge = enemyStartHp.Sum() - enemyHp.Sum();\r
-            // 轟沈・撃沈数\r
-            var friendSunk = friend.Count(r => r.NowHp == 0);\r
-            var enemySunk = enemyHp.Count(hp => hp == 0);\r
-\r
-            var friendGaugeRate = Floor((double)friendGauge / friend.Where(r => !r.Escaped).Sum(r => r.StartHp) * 100);\r
-            var enemyGaugeRate = Floor((double)enemyGauge / enemyStartHp.Sum() * 100);\r
-            var equalOrMore = enemyGaugeRate > 0.9 * friendGaugeRate;\r
-            var superior = enemyGaugeRate > 0 && enemyGaugeRate > 2.5 * friendGaugeRate;\r
 \r
-            if (friendSunk == 0)\r
+            var friendCount = friend.Length;\r
+            var friendStartHpTotal = 0;\r
+            var friendNowHpTotal = 0;\r
+            var friendSunk = 0;\r
+            foreach (var ship in friend)\r
             {\r
-                if (enemyNowShips == 0)\r
-                {\r
-                    if (friendGauge == 0)\r
-                        return BattleResultRank.P;\r
-                    return BattleResultRank.S;\r
-                }\r
-                if (enemyHp.Length == 6)\r
-                {\r
-                    if (enemySunk >= 4)\r
-                        return BattleResultRank.A;\r
-                }\r
-                else if (enemySunk * 2 >= _enemyHp.Length)\r
-                {\r
-                    return BattleResultRank.A;\r
-                }\r
-                if (_enemyHp[0] == 0)\r
-                    return BattleResultRank.B;\r
-                if (superior)\r
-                    return BattleResultRank.B;\r
+                if (ship.Escaped)\r
+                    continue;\r
+                friendStartHpTotal += ship.StartHp;\r
+                friendNowHpTotal += ship.NowHp;\r
+                if (ship.NowHp == 0)\r
+                    friendSunk++;\r
             }\r
-            else\r
+            var friendGaugeRate = (int)((double)(friendStartHpTotal - friendNowHpTotal) / friendStartHpTotal * 100);\r
+\r
+            var enemyCount = enemyHp.Length;\r
+            var enemyStartHpTotal = enemyStartHp.Sum();\r
+            var enemyNowHpTotal = enemyHp.Sum();\r
+            var enemySunk = enemyHp.Count(hp => hp == 0);\r
+            var enemyGaugeRate = (int)((double)(enemyStartHpTotal - enemyNowHpTotal) / enemyStartHpTotal * 100);\r
+\r
+            if (friendSunk == 0 && enemySunk == enemyCount)\r
             {\r
-                if (enemyNowShips == 0)\r
-                    return BattleResultRank.B;\r
-                if (_enemyHp[0] == 0 && friendSunk < enemySunk)\r
-                    return BattleResultRank.B;\r
-                if (superior)\r
-                    return BattleResultRank.B;\r
-                if (_enemyHp[0] == 0)\r
-                    return BattleResultRank.C;\r
+                if (friendNowHpTotal >= friendStartHpTotal)\r
+                    return BattleResultRank.P;\r
+                return BattleResultRank.S;\r
             }\r
-            if (enemyGauge > 0 && equalOrMore)\r
+            if (friendSunk == 0 && enemySunk >= (int)(enemyCount * 0.7) && enemyCount > 1)\r
+                return BattleResultRank.A;\r
+            if (friendSunk < enemySunk && enemyHp[0] == 0)\r
+                return BattleResultRank.B;\r
+            if (friendCount == 1 && friend[0].DamageLevel == ShipStatus.Damage.Badly)\r
+                return BattleResultRank.D;\r
+            if (enemyGaugeRate > friendGaugeRate * 2.5)\r
+                return BattleResultRank.B;\r
+            if (enemyGaugeRate > friendGaugeRate * 0.9)\r
                 return BattleResultRank.C;\r
-            if (friendSunk > 0 && friendNowShips == 1)\r
+            if (friendCount > 1 && friendCount - 1 == friendSunk)\r
                 return BattleResultRank.E;\r
             return BattleResultRank.D;\r
         }\r