+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+// http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using static System.Math;\r
+\r
+namespace KancolleSniffer\r
+{\r
+ public struct ChargeStatus\r
+ {\r
+ public int Fuel { get; set; }\r
+ public int Bull { get; set; }\r
+\r
+ public ChargeStatus(ShipStatus status) : this()\r
+ {\r
+ Fuel = CalcChargeState(status.Fuel, status.Spec.FuelMax);\r
+ Bull = CalcChargeState(status.Bull, status.Spec.BullMax);\r
+ }\r
+\r
+ public ChargeStatus(int fuel, int bull) : this()\r
+ {\r
+ Fuel = fuel;\r
+ Bull = bull;\r
+ }\r
+\r
+ private int CalcChargeState(int now, int full)\r
+ {\r
+ if (full == 0 || now == full)\r
+ return 0;\r
+ var ratio = (double)now / full;\r
+ if (ratio >= 7.0 / 9)\r
+ return 1;\r
+ if (ratio >= 3.0 / 9)\r
+ return 2;\r
+ if (ratio > 0)\r
+ return 3;\r
+ return 4;\r
+ }\r
+ }\r
+\r
+ public enum FleetState\r
+ {\r
+ Port,\r
+ Mission,\r
+ Sortie,\r
+ Practice\r
+ }\r
+\r
+ public class Fleet\r
+ {\r
+ private readonly ShipInfo _shipInfo;\r
+ public FleetState State { get; set; }\r
+ public int[] Deck { get; set; } = Enumerable.Repeat(-1, ShipInfo.MemberCount).ToArray();\r
+ public ShipStatus[] Ships => Deck.Where(id => id != -1).Select(_shipInfo.GetStatus).ToArray();\r
+\r
+ public Fleet(ShipInfo shipInfo)\r
+ {\r
+ _shipInfo = shipInfo;\r
+ }\r
+\r
+ public ChargeStatus ChargeStatus\r
+ {\r
+ get\r
+ {\r
+ var fs = new ChargeStatus(_shipInfo.GetStatus(Deck[0]));\r
+ var others = (from id in Deck.Skip(1) select new ChargeStatus(_shipInfo.GetStatus(id))).Aggregate(\r
+ (result, next) => new ChargeStatus(Max(result.Fuel, next.Fuel), Max(result.Bull, next.Bull)));\r
+ return new ChargeStatus(fs.Fuel != 0 ? fs.Fuel : others.Fuel + 5, fs.Bull != 0 ? fs.Bull : others.Bull + 5);\r
+ }\r
+ }\r
+\r
+ public int[] FighterPower\r
+ => Ships.Where(ship => !ship.Escaped).SelectMany(ship =>\r
+ ship.Slot.Zip(ship.OnSlot, (slot, onslot) => slot.CalcFighterPower(onslot)))\r
+ .Aggregate(new[] {0, 0}, (prev, cur) => new[] {prev[0] + cur[0], prev[1] + cur[1]});\r
+\r
+ public double ContactTriggerRate\r
+ => Ships.Where(ship => !ship.Escaped).SelectMany(ship =>\r
+ ship.Slot.Zip(ship.OnSlot, (slot, onslot) =>\r
+ slot.Spec.ContactTriggerRate * slot.Spec.LoS * Sqrt(onslot))).Sum();\r
+\r
+ public double GetLineOfSights(int factor)\r
+ {\r
+ var result = 0.0;\r
+ var emptyBonus = 6;\r
+ foreach (var s in Ships.Where(s => !s.Escaped))\r
+ {\r
+ emptyBonus--;\r
+ var itemLoS = 0;\r
+ foreach (var item in s.Slot)\r
+ {\r
+ var spec = item.Spec;\r
+ itemLoS += spec.LoS;\r
+ result += (spec.LoS + item.LoSLevelBonus) * spec.LoSScaleFactor * factor;\r
+ }\r
+ result += Sqrt(s.LoS - itemLoS);\r
+ }\r
+ return result > 0 ? result - Ceiling(_shipInfo.HqLevel * 0.4) + emptyBonus * 2 : 0.0;\r
+ }\r
+\r
+ public double DaihatsuBonus\r
+ {\r
+ get\r
+ {\r
+ var tokudaiBonus = new[,]\r
+ {\r
+ {0.00, 0.00, 0.00, 0.00, 0.00},\r
+ {0.02, 0.02, 0.02, 0.02, 0.02},\r
+ {0.04, 0.04, 0.04, 0.04, 0.04},\r
+ {0.05, 0.05, 0.052, 0.054, 0.054},\r
+ {0.054, 0.056, 0.058, 0.059, 0.06}\r
+ };\r
+ var daihatsu = 0;\r
+ var tokudai = 0;\r
+ var bonus = 0.0;\r
+ var level = 0;\r
+ var sum = 0;\r
+ foreach (var ship in Ships)\r
+ {\r
+ if (ship.Name == "鬼怒改二")\r
+ bonus += 0.05;\r
+ foreach (var item in ship.Slot)\r
+ {\r
+ switch (item.Spec.Name)\r
+ {\r
+ case "大発動艇":\r
+ level += item.Level;\r
+ sum++;\r
+ daihatsu++;\r
+ bonus += 0.05;\r
+ break;\r
+ case "特大発動艇":\r
+ level += item.Level;\r
+ sum++;\r
+ tokudai++;\r
+ bonus += 0.05;\r
+ break;\r
+ case "大発動艇(八九式中戦車&陸戦隊)":\r
+ level += item.Level;\r
+ sum++;\r
+ bonus += 0.02;\r
+ break;\r
+ case "特二式内火艇":\r
+ level += item.Level;\r
+ sum++;\r
+ bonus += 0.01;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ var levelAverage = sum == 0 ? 0.0 : (double)level / sum;\r
+ bonus = Min(bonus, 0.2);\r
+ return bonus + 0.01 * bonus * levelAverage + tokudaiBonus[Min(tokudai, 4), Min(daihatsu, 4)];\r
+ }\r
+ }\r
+\r
+ public double TransportPoint => Ships.Where(ship => !ship.Escaped).Sum(ship => ship.TransportPoint);\r
+ }\r
+}
\ No newline at end of file