コミットメタ情報

リビジョンa92a57c92d73ff6a586ef7cc7a83d1acb1b1a022 (tree)
日時2018-08-04 13:44:35
作者Kazuhiro Fujieda <fujieda@user...>
コミッターKazuhiro Fujieda

ログメッセージ

Fleetクラスで艦隊編成を行いShipStatusのリストを構築する

変更サマリ

差分

--- a/KancolleSniffer.Test/BattleTest.cs
+++ b/KancolleSniffer.Test/BattleTest.cs
@@ -62,8 +62,8 @@ namespace KancolleSniffer.Test
6262 var id = _shipInventry.MaxId + 1;
6363 var ships = nowhps.Zip(maxhps,
6464 (now, max) => new ShipStatus {Id = id++, NowHp = now, MaxHp = max}).ToArray();
65- _shipInfo.Fleets[deck].Deck = (from ship in ships select ship.Id).ToArray();
6665 _shipInventry.Add(ships);
66+ _shipInfo.Fleets[deck].Deck = (from ship in ships select ship.Id).ToArray();
6767 foreach (var entry in ships.Zip(slots, (ship, slot) => new {ship, slot}))
6868 {
6969 entry.ship.Slot = _itemInfo.InjectItems(entry.slot.Take(5));
--- a/KancolleSniffer.Test/SnifferTest.cs
+++ b/KancolleSniffer.Test/SnifferTest.cs
@@ -420,7 +420,7 @@ namespace KancolleSniffer.Test
420420 {
421421 var sniffer = new Sniffer();
422422 SniffLogFile(sniffer, "nightbattlepower_001");
423- var ships = sniffer.Fleets[0].Ships;
423+ var ships = sniffer.Fleets[0].ActualShips;
424424 PAssert.That(() =>
425425 ships.Select(ship => (int)(ship.NightBattlePower * 100))
426426 .SequenceEqual(new[] {11202, 14985, 20092, 17354}));
--- a/KancolleSniffer/Logger.cs
+++ b/KancolleSniffer/Logger.cs
@@ -245,56 +245,53 @@ namespace KancolleSniffer
245245 int deckId = BattleInfo.DeckId(_battle);
246246 if (_battle.api_f_nowhps_combined())
247247 {
248- var main = _shipInfo.Fleets[0].Deck;
249- var guard = _shipInfo.Fleets[1].Deck;
250- return main.Zip(guard, (m, g) =>
248+ var mainShips = _shipInfo.Fleets[0].Ships;
249+ var guardShips = _shipInfo.Fleets[1].Ships;
250+ return mainShips.Zip(guardShips, (main, guard) =>
251251 {
252- if (m == -1 && g == -1)
252+ if (main.Empty && guard.Empty)
253253 return ",";
254254 var name = "";
255255 var hp = "";
256- if (m != -1)
256+ if (!main.Empty)
257257 {
258- var sm = _shipInfo.GetStatus(m);
259- name = $"{sm.Name}(Lv{sm.Level})";
260- hp = $"{sm.NowHp}/{sm.MaxHp}";
258+ name = $"{main.Name}(Lv{main.Level})";
259+ hp = $"{main.NowHp}/{main.MaxHp}";
261260 }
262261 name += "・";
263262 hp += "・";
264- if (g != -1)
263+ if (!guard.Empty)
265264 {
266- var sg = _shipInfo.GetStatus(g);
267- name += $"{sg.Name}(Lv{sg.Level})";
268- hp += $"{sg.NowHp}/{sg.MaxHp}";
265+ name += $"{guard.Name}(Lv{guard.Level})";
266+ hp += $"{guard.NowHp}/{guard.MaxHp}";
269267 }
270268 return name + "," + hp;
271269 }).ToList();
272270 }
273- var deck = _shipInfo.Fleets[deckId].Deck;
274- if (deck.Length > 6)
271+ var ships = _shipInfo.Fleets[deckId].Ships;
272+ if (ships.Count > 6)
275273 {
276274 var result = new List<string>();
277- for (var i = 0; i < 12 - deck.Length; i++)
275+ for (var i = 0; i < 12 - ships.Count; i++)
278276 {
279- var s = _shipInfo.GetStatus(deck[i]);
280- result.Add($"{s.Name}(Lv{s.Level}),{s.NowHp}/{s.MaxHp}");
277+ var ship = ships[i];
278+ result.Add($"{ship.Name}(Lv{ship.Level}),{ship.NowHp}/{ship.MaxHp}");
281279 }
282- for (var i = 0; i < deck.Length - 6; i++)
280+ for (var i = 0; i < ships.Count - 6; i++)
283281 {
284- var s1 = _shipInfo.GetStatus(deck[12 - deck.Length + i]);
285- var s2 = _shipInfo.GetStatus(deck[6 + i]);
282+ var s1 = ships[12 - ships.Count + i];
283+ var s2 = ships[6 + i];
286284 result.Add(
287285 $"{s1.Name}(Lv{s1.Level})・{s2.Name}(Lv{s2.Level})," +
288286 $"{s1.NowHp}/{s1.MaxHp}・{s2.NowHp}/{s2.MaxHp}");
289287 }
290288 return result;
291289 }
292- return deck.Select(id =>
290+ return ships.Select(ship =>
293291 {
294- if (id == -1)
292+ if (ship.Empty)
295293 return ",";
296- var s = _shipInfo.GetStatus(id);
297- return $"{s.Name}(Lv{s.Level}),{s.NowHp}/{s.MaxHp}";
294+ return $"{ship.Name}(Lv{ship.Level}),{ship.NowHp}/{ship.MaxHp}";
298295 }).ToList();
299296 }
300297
@@ -305,25 +302,25 @@ namespace KancolleSniffer
305302 {
306303 return result.Select(s => s.Empty ? "," : $"{s.Name},{s.NowHp}/{s.MaxHp}").ToList();
307304 }
308- var main = result;
309- var guard = _battleInfo.Result.Enemy.Guard.Concat(Enumerable.Repeat(new ShipStatus(), 6)).Take(6);
310- return main.Zip(guard, (m, g) =>
305+ var mainShips = result;
306+ var guardShips = _battleInfo.Result.Enemy.Guard.Concat(Enumerable.Repeat(new ShipStatus(), 6)).Take(6);
307+ return mainShips.Zip(guardShips, (main, guard) =>
311308 {
312- if (m.Empty && g.Empty)
309+ if (main.Empty && guard.Empty)
313310 return ",";
314311 var name = "";
315312 var hp = "";
316- if (!m.Empty)
313+ if (!main.Empty)
317314 {
318- name = $"{m.Name}";
319- hp = $"{m.NowHp}/{m.MaxHp}";
315+ name = $"{main.Name}";
316+ hp = $"{main.NowHp}/{main.MaxHp}";
320317 }
321318 name += "・";
322319 hp += "・";
323- if (!g.Empty)
320+ if (!guard.Empty)
324321 {
325- name += $"{g.Name}";
326- hp += $"{g.NowHp}/{g.MaxHp}";
322+ name += $"{guard.Name}";
323+ hp += $"{guard.NowHp}/{guard.MaxHp}";
327324 }
328325 return name + "," + hp;
329326 }).ToList();
@@ -553,7 +550,7 @@ namespace KancolleSniffer
553550 var ship1 = Secretary();
554551 var ship2 = "";
555552 var ships = _shipInfo.Fleets[0].Ships;
556- if (ships.Length >= 2)
553+ if (!ships[1].Empty)
557554 ship2 = ships[1].Name + "(" + ships[1].Level + ")";
558555 _writer("改修報告書",
559556 FormatDateTime(now) + "," +
--- a/KancolleSniffer/MainForm.cs
+++ b/KancolleSniffer/MainForm.cs
@@ -524,8 +524,8 @@ namespace KancolleSniffer
524524 if (!_listForm.Visible)
525525 return;
526526 var idx = (int)((Control)sender).Tag;
527- var ships = _sniffer.Fleets[_currentFleet].Ships;
528- if (ships.Length <= idx)
527+ var ships = _sniffer.Fleets[_currentFleet].ActualShips;
528+ if (ships.Count <= idx)
529529 return;
530530 _listForm.ShowShip(ships[idx].Id);
531531 }
@@ -642,15 +642,15 @@ namespace KancolleSniffer
642642 private void UpdatePanelShipInfo()
643643 {
644644 var fleets = _sniffer.Fleets;
645- var ships = fleets[_currentFleet].Ships;
646- panel7Ships.Visible = ships.Length == 7;
645+ var ships = fleets[_currentFleet].ActualShips;
646+ panel7Ships.Visible = ships.Count == 7;
647647 _mainLabels.SetShipLabels(ships);
648648 if (!_sniffer.IsCombinedFleet)
649649 _combinedFleet = false;
650650 labelFleet1.Text = _combinedFleet ? "連合" : "第一";
651651 panelCombinedFleet.Visible = _combinedFleet;
652652 if (_combinedFleet)
653- _mainLabels.SetCombinedShipLabels(fleets[0].Ships, fleets[1].Ships);
653+ _mainLabels.SetCombinedShipLabels(fleets[0].ActualShips, fleets[1].ActualShips);
654654 for (var i = 0; i < _labelCheckFleets.Length; i++)
655655 _labelCheckFleets[i].Visible = _currentFleet == i;
656656 UpdateAkashiTimer();
@@ -924,7 +924,7 @@ namespace KancolleSniffer
924924 {
925925 if (_config.UsePresetAkashi)
926926 UpdatePresetAkashiTimer();
927- _mainLabels.SetAkashiTimer(_sniffer.Fleets[_currentFleet].Ships,
927+ _mainLabels.SetAkashiTimer(_sniffer.Fleets[_currentFleet].ActualShips,
928928 _sniffer.AkashiTimer.GetTimers(_currentFleet));
929929 }
930930
--- a/KancolleSniffer/Model/AkashiTimer.cs
+++ b/KancolleSniffer/Model/AkashiTimer.cs
@@ -41,8 +41,8 @@ namespace KancolleSniffer.Model
4141
4242 private class RepairStatus
4343 {
44- private ShipStatus[] _target = new ShipStatus[0];
45- private int[] _deck = new int[0];
44+ private IReadOnlyList<ShipStatus> _target = new ShipStatus[0];
45+ private IReadOnlyList<int> _deck = new int[0];
4646 private TimeSpan FirstRepairTime => TimeSpan.FromMinutes(20);
4747
4848 private bool PassedFirstRepairTime(DateTime start, DateTime prev, DateTime now) =>
@@ -52,7 +52,7 @@ namespace KancolleSniffer.Model
5252 TimeSpan.FromMinutes(Math.Ceiling(ship.RepairTime.TotalMinutes / (ship.MaxHp - ship.NowHp) * damage));
5353
5454
55- public int[] Deck
55+ public IReadOnlyList<int> Deck
5656 {
5757 set => _deck = value;
5858 }
@@ -183,11 +183,11 @@ namespace KancolleSniffer.Model
183183
184184 private void CheckFleet(Fleet fleet)
185185 {
186- var deck = fleet.Deck.ToArray();
186+ var deck = fleet.Deck;
187+ var ships = fleet.Ships;
187188 var repair = _repairStatuses[fleet.Number];
188- var fs = _shipInfo.GetStatus(deck[0]);
189189 repair.State = State.Continue;
190- if (!fs.Spec.IsRepairShip)
190+ if (!ships[0].Spec.IsRepairShip)
191191 {
192192 repair.UpdateTarget(new ShipStatus[0]);
193193 repair.Deck = deck;
@@ -198,15 +198,15 @@ namespace KancolleSniffer.Model
198198 repair.State = State.Reset;
199199 repair.Deck = deck;
200200 }
201- var target = RepairTarget(deck);
201+ var target = RepairTarget(ships);
202202 if (repair.IsRepaired(target))
203203 repair.State = State.Reset;
204204 repair.UpdateTarget(target);
205205 }
206206
207- private ShipStatus[] RepairTarget(int[] deck)
207+ private ShipStatus[] RepairTarget(IReadOnlyList<ShipStatus> ships)
208208 {
209- var fs = _shipInfo.GetStatus(deck[0]);
209+ var fs = ships[0];
210210 if (!fs.Spec.IsRepairShip || _dockInfo.InNDock(fs.Id) || fs.DamageLevel >= ShipStatus.Damage.Half)
211211 return new ShipStatus[0];
212212 var cap = fs.Slot.Count(item => item.Spec.IsRepairFacility) + 2;
@@ -215,11 +215,11 @@ namespace KancolleSniffer.Model
215215 * - 入渠中の艦娘は終わったときに回復扱いされないようNowHp=MaxHpに
216216 * - 中破以上でNowHp=MaxHpにすると回復扱いされるのでNowHp=MaxHp=0に
217217 */
218- return (from id in deck.Take(cap)
219- let s = (ShipStatus)_shipInfo.GetStatus(id).Clone()
218+ return (from ship in ships.Take(cap)
219+ let s = (ShipStatus)ship.Clone()
220220 let full = new ShipStatus {NowHp = s.MaxHp, MaxHp = s.MaxHp}
221221 let zero = new ShipStatus()
222- select _dockInfo.InNDock(id) ? full : s.DamageLevel >= ShipStatus.Damage.Half ? zero : s).ToArray();
222+ select _dockInfo.InNDock(s.Id) ? full : s.DamageLevel >= ShipStatus.Damage.Half ? zero : s).ToArray();
223223 }
224224
225225 public RepairSpan[] GetTimers(int fleet)
@@ -242,7 +242,7 @@ namespace KancolleSniffer.Model
242242
243243 public bool CheckPresetRepairing()
244244 => _presetDeck.Decks.Where(deck => deck != null)
245- .Any(deck => RepairTarget(deck).Any(s => s.NowHp < s.MaxHp));
245+ .Any(deck => RepairTarget(deck.Select(id => _shipInfo.GetShip(id)).ToArray()).Any(s => s.NowHp < s.MaxHp));
246246
247247 public Notice[] GetNotice(DateTime prev, DateTime now)
248248 {
--- a/KancolleSniffer/Model/BattleInfo.cs
+++ b/KancolleSniffer/Model/BattleInfo.cs
@@ -131,10 +131,10 @@ namespace KancolleSniffer.Model
131131 _shipInfo.SaveBattleStartStatus();
132132 var fleets = _shipInfo.Fleets;
133133 _fleet = fleets[DeckId(json)];
134- FlagshipRecovery(request, _fleet.Ships[0]);
135- _friend = Record.Setup(_fleet.Ships, practice);
134+ FlagshipRecovery(request, _fleet.ActualShips[0]);
135+ _friend = Record.Setup(_fleet.ActualShips, practice);
136136 _guard = json.api_f_nowhps_combined()
137- ? Record.Setup(fleets[1].Ships, practice)
137+ ? Record.Setup(fleets[1].ActualShips, practice)
138138 : new Record[0];
139139 _enemy = Record.Setup((int[])json.api_e_nowhps,
140140 ((int[])json.api_ship_ke).Select(_shipInfo.GetSpec).ToArray(),
@@ -165,7 +165,7 @@ namespace KancolleSniffer.Model
165165 };
166166 }
167167
168- private void FlagshipRecovery(string request, ShipStatus flagship)
168+ private void FlagshipRecovery(string request, ShipStatus flagship)
169169 {
170170 var type = int.Parse(HttpUtility.ParseQueryString(request)["api_recovery_type"] ?? "0");
171171 switch (type)
@@ -477,6 +477,8 @@ namespace KancolleSniffer.Model
477477 public void InspectBattleResult(dynamic json)
478478 {
479479 BattleState = BattleState.Result;
480+ if (_friend == null)
481+ return;
480482 ShowResult(!_lastCell);
481483 _shipInfo.SaveBattleResult();
482484 _shipInfo.DropShipId = json.api_get_ship() ? (int)json.api_get_ship.api_ship_id : -1;
@@ -485,23 +487,11 @@ namespace KancolleSniffer.Model
485487 SetEscapeShips(json);
486488 }
487489
488- private void VerifyResultRank(dynamic json)
489- {
490- if (_friend == null)
491- return;
492- if (!json.api_win_rank())
493- return;
494- var assumed = "PSABCDE"[(int)ResultRank];
495- if (assumed == 'P')
496- assumed = 'S';
497- var actual = ((string)json.api_win_rank)[0];
498- DisplayedResultRank.Assumed = assumed;
499- DisplayedResultRank.Actual = actual;
500- }
501-
502490 public void InspectPracticeResult(dynamic json)
503491 {
504492 BattleState = BattleState.Result;
493+ if (_friend == null)
494+ return;
505495 ShowResult(false);
506496 VerifyResultRank(json);
507497 CleanupResult();
@@ -513,8 +503,8 @@ namespace KancolleSniffer.Model
513503 return;
514504 var fleets = _shipInfo.Fleets;
515505 var ships = _guard.Length > 0
516- ? fleets[0].Ships.Concat(fleets[1].Ships)
517- : _fleet.Ships;
506+ ? fleets[0].ActualShips.Concat(fleets[1].ActualShips)
507+ : _fleet.ActualShips;
518508 foreach (var entry in ships.Zip(_friend.Concat(_guard), (ship, now) => new {ship, now}))
519509 entry.now.UpdateShipStatus(entry.ship);
520510 if (warnDamagedShip)
@@ -523,6 +513,18 @@ namespace KancolleSniffer.Model
523513 _shipInfo.ClearBadlyDamagedShips();
524514 }
525515
516+ private void VerifyResultRank(dynamic json)
517+ {
518+ if (!json.api_win_rank())
519+ return;
520+ var assumed = "PSABCDE"[(int)ResultRank];
521+ if (assumed == 'P')
522+ assumed = 'S';
523+ var actual = ((string)json.api_win_rank)[0];
524+ DisplayedResultRank.Assumed = assumed;
525+ DisplayedResultRank.Actual = actual;
526+ }
527+
526528 public void SetEscapeShips(dynamic json)
527529 {
528530 _escapingShips.Clear();
@@ -558,11 +560,11 @@ namespace KancolleSniffer.Model
558560 public string Name => _status.Name;
559561 public int StartHp { get; private set; }
560562
561- public static Record[] Setup(ShipStatus[] ships, bool practice) =>
563+ public static Record[] Setup(IEnumerable<ShipStatus> ships, bool practice) =>
562564 (from s in ships
563565 select new Record {_status = (ShipStatus)s.Clone(), _practice = practice, StartHp = s.NowHp}).ToArray();
564566
565- public static Record[] Setup(int[] nowhps, ShipSpec[] ships, ItemSpec[][] slots, bool practice)
567+ public static Record[] Setup(int[] nowhps, ShipSpec[] specs, ItemSpec[][] slots, bool practice)
566568 {
567569 return Enumerable.Range(0, nowhps.Length).Select(i =>
568570 new Record
@@ -570,10 +572,10 @@ namespace KancolleSniffer.Model
570572 StartHp = nowhps[i],
571573 _status = new ShipStatus
572574 {
573- Id = ships[i].Id,
575+ Id = specs[i].Id,
574576 NowHp = nowhps[i],
575577 MaxHp = nowhps[i],
576- Spec = ships[i],
578+ Spec = specs[i],
577579 Slot = slots[i].Select(spec => new ItemStatus {Id = spec.Id, Spec = spec}).ToArray(),
578580 SlotEx = new ItemStatus(0)
579581 },
--- a/KancolleSniffer/Model/Fleet.cs
+++ b/KancolleSniffer/Model/Fleet.cs
@@ -12,6 +12,8 @@
1212 // See the License for the specific language governing permissions and
1313 // limitations under the License.
1414
15+using System;
16+using System.Collections.Generic;
1517 using System.Linq;
1618 using static System.Math;
1719
@@ -67,25 +69,87 @@ namespace KancolleSniffer.Model
6769
6870 public class Fleet
6971 {
70- private readonly ShipInfo _shipInfo;
72+ private readonly ShipInventry _shipInventry;
73+ private readonly Func<int> _getHqLevel;
74+ private int[] _deck = Enumerable.Repeat(-1, ShipInfo.MemberCount).ToArray();
7175 public int Number { get; }
7276 public FleetState State { get; set; }
7377 public CombinedType CombinedType { get; set; }
74- public int[] Deck { get; set; } = Enumerable.Repeat(-1, ShipInfo.MemberCount).ToArray();
75- public ShipStatus[] Ships => Deck.Where(id => id != -1).Select(_shipInfo.GetStatus).ToArray();
78+ public IReadOnlyList<ShipStatus> Ships { get; private set; }
79+ public IReadOnlyList<ShipStatus> ActualShips { get; private set; }
7680
77- public Fleet(ShipInfo shipInfo, int number)
81+ public Fleet(ShipInventry shipInventry, int number, Func<int> getHqLevel)
7882 {
79- _shipInfo = shipInfo;
83+ _shipInventry = shipInventry;
8084 Number = number;
85+ _getHqLevel = getHqLevel;
86+ Ships = _deck.Select(id => new ShipStatus()).ToArray();
87+ ActualShips = new ShipStatus[0];
88+ }
89+
90+ public IReadOnlyList<int> Deck
91+ {
92+ get => _deck;
93+ set
94+ {
95+ _deck = value.ToArray();
96+ SetDeck();
97+ }
98+ }
99+
100+ public void SetDeck()
101+ {
102+ foreach (var ship in Ships)
103+ {
104+ ship.Fleet = null;
105+ ship.DeckIndex = -1;
106+ }
107+ Ships = _deck.Select((id, idx) =>
108+ {
109+ var ship = _shipInventry[id];
110+ if (ship.Empty)
111+ return ship;
112+ ship.DeckIndex = id;
113+ ship.Fleet = this;
114+ return ship;
115+ }).ToArray();
116+ ActualShips = Ships.Where(ship => !ship.Empty).ToArray();
117+ }
118+
119+ public int SetShip(int index, int shipId)
120+ {
121+ var prev = _deck[index];
122+ _deck[index] = shipId;
123+ SetDeck();
124+ return prev;
125+ }
126+
127+ public void WithdrowShip(int index)
128+ {
129+ if (index == -1) // 旗艦以外解除
130+ {
131+ for (var i = 1; i < _deck.Length; i++)
132+ _deck[i] = -1;
133+ SetDeck();
134+ return;
135+ }
136+ var dst = index;
137+ for (var src = index + 1; src < _deck.Length; src++)
138+ {
139+ if (_deck[src] != -1)
140+ _deck[dst++] = _deck[src];
141+ }
142+ for (; dst < _deck.Length; dst++)
143+ _deck[dst] = -1;
144+ SetDeck();
81145 }
82146
83147 public ChargeStatus ChargeStatus
84148 {
85149 get
86150 {
87- var fs = new ChargeStatus(_shipInfo.GetStatus(Deck[0]));
88- var others = (from id in Deck.Skip(1) select new ChargeStatus(_shipInfo.GetStatus(id))).Aggregate(
151+ var fs = new ChargeStatus(Ships[0]);
152+ var others = (from ship in Ships.Skip(1) select new ChargeStatus(ship)).Aggregate(
89153 (result, next) => new ChargeStatus(Max(result.Fuel, next.Fuel), Max(result.Bull, next.Bull)));
90154 return new ChargeStatus(fs.Fuel != 0 ? fs.Fuel : others.Fuel + 5,
91155 fs.Bull != 0 ? fs.Bull : others.Bull + 5);
@@ -93,12 +157,12 @@ namespace KancolleSniffer.Model
93157 }
94158
95159 public int[] FighterPower
96- => Ships.Where(ship => !ship.Escaped).SelectMany(ship =>
160+ => ActualShips.Where(ship => !ship.Escaped).SelectMany(ship =>
97161 ship.Slot.Zip(ship.OnSlot, (slot, onslot) => slot.CalcFighterPower(onslot)))
98162 .Aggregate(new[] {0, 0}, (prev, cur) => new[] {prev[0] + cur[0], prev[1] + cur[1]});
99163
100164 public double ContactTriggerRate
101- => Ships.Where(ship => !ship.Escaped).SelectMany(ship =>
165+ => ActualShips.Where(ship => !ship.Escaped).SelectMany(ship =>
102166 ship.Slot.Zip(ship.OnSlot, (slot, onslot) =>
103167 slot.Spec.ContactTriggerRate * slot.Spec.LoS * Sqrt(onslot))).Sum();
104168
@@ -106,7 +170,7 @@ namespace KancolleSniffer.Model
106170 {
107171 var result = 0.0;
108172 var emptyBonus = 6;
109- foreach (var s in Ships.Where(s => !s.Escaped))
173+ foreach (var s in ActualShips.Where(s => !s.Escaped))
110174 {
111175 emptyBonus--;
112176 var itemLoS = 0;
@@ -118,7 +182,7 @@ namespace KancolleSniffer.Model
118182 }
119183 result += Sqrt(s.LoS - itemLoS);
120184 }
121- return result > 0 ? result - Ceiling(_shipInfo.HqLevel * 0.4) + emptyBonus * 2 : 0.0;
185+ return result > 0 ? result - Ceiling(_getHqLevel() * 0.4) + emptyBonus * 2 : 0.0;
122186 }
123187
124188 public double DaihatsuBonus
--- a/KancolleSniffer/Model/ShipInfo.cs
+++ b/KancolleSniffer/Model/ShipInfo.cs
@@ -12,7 +12,6 @@
1212 // See the License for the specific language governing permissions and
1313 // limitations under the License.
1414
15-using System;
1615 using System.Collections.Generic;
1716 using System.Linq;
1817 using KancolleSniffer.Util;
@@ -24,15 +23,15 @@ namespace KancolleSniffer.Model
2423 public const int FleetCount = 4;
2524 public const int MemberCount = 6;
2625
27- private readonly Fleet[] _fleets;
26+ private readonly IReadOnlyList<Fleet> _fleets;
2827 private readonly ShipMaster _shipMaster;
2928 private readonly ShipInventry _shipInventry;
3029 private readonly ItemInventry _itemInventry;
3130 private readonly List<int> _escapedShips = new List<int>();
3231 private ShipStatus[] _battleResult = new ShipStatus[0];
3332 private readonly NumEquipsChecker _numEquipsChecker = new NumEquipsChecker();
33+ private int _hqLevel;
3434 public AlarmCounter Counter { get; }
35- public int HqLevel { get; private set; }
3635 public ShipStatusPair[] BattleResultDiff { get; private set; } = new ShipStatusPair[0];
3736 public bool IsBattleResultError => BattleResultDiff.Length > 0;
3837 public ShipStatus[] BattleStartStatus { get; private set; } = new ShipStatus[0];
@@ -67,7 +66,7 @@ namespace KancolleSniffer.Model
6766 {
6867 _shipMaster = shipMaster;
6968 _shipInventry = shipInventry;
70- _fleets = Enumerable.Range(0, FleetCount).Select((x, i) => new Fleet(this, i)).ToArray();
69+ _fleets = Enumerable.Range(0, FleetCount).Select((x, i) => new Fleet(_shipInventry, i, () => _hqLevel)).ToArray();
7170 _itemInventry = itemInventry;
7271 Counter = new AlarmCounter(() => _shipInventry.Count){Margin = 4};
7372 }
@@ -86,8 +85,7 @@ namespace KancolleSniffer.Model
8685 _escapedShips.Clear();
8786 for (var i = 0; i < FleetCount; i++)
8887 _fleets[i].State = FleetState.Port;
89- InspectDeck(json.api_deck_port);
90- InspectShipData(json.api_ship);
88+ InspectShipDataAndDeck(json.api_ship, json.api_deck_port);
9189 InspectBasic(json.api_basic);
9290 if (json.api_combined_flag())
9391 _fleets[0].CombinedType = _fleets[1].CombinedType = (CombinedType)(int)json.api_combined_flag;
@@ -95,13 +93,11 @@ namespace KancolleSniffer.Model
9593 }
9694 else if (json.api_data()) // ship2
9795 {
98- InspectDeck(json.api_data_deck);
99- InspectShipData(json.api_data);
96+ InspectShipDataAndDeck(json.api_data, json.api_data_deck);
10097 }
10198 else if (json.api_ship_data()) // ship3とship_deck
10299 {
103- InspectDeck(json.api_deck_data);
104- InspectShipData(json.api_ship_data);
100+ InspectShipDataAndDeck(json.api_ship_data, json.api_deck_data);
105101 VerifyBattleResult();
106102 // ship_deckでドロップ艦を反映する
107103 if (DropShipId != -1)
@@ -112,7 +108,7 @@ namespace KancolleSniffer.Model
112108 _itemInventry.InflateCount(num);
113109 }
114110 }
115- else if (json.api_ship()) // getshipとpowerup
111+ else if (json.api_ship()) // getship
116112 {
117113 InspectShipData(new[] {json.api_ship});
118114 }
@@ -122,14 +118,14 @@ namespace KancolleSniffer.Model
122118 public void SaveBattleResult()
123119 {
124120 _battleResult = _fleets.Where(fleet =>
125- fleet.State >= FleetState.Sortie && !GetStatus(fleet.Deck[0]).Spec.IsRepairShip)
126- .SelectMany(fleet => fleet.Deck.Select(GetStatus)).ToArray();
121+ fleet.State >= FleetState.Sortie && !fleet.Ships[0].Spec.IsRepairShip)
122+ .SelectMany(fleet => fleet.Ships).ToArray();
127123 }
128124
129125 private void VerifyBattleResult()
130126 {
131127 BattleResultDiff = (from assumed in _battleResult
132- let actual = GetStatus(assumed.Id)
128+ let actual = GetShip(assumed.Id)
133129 where !assumed.Escaped && assumed.NowHp != actual.NowHp
134130 select new ShipStatusPair(assumed, actual)).ToArray();
135131 _battleResult = new ShipStatus[0];
@@ -138,7 +134,13 @@ namespace KancolleSniffer.Model
138134 public void SaveBattleStartStatus()
139135 {
140136 BattleStartStatus = _fleets.Where(fleet => fleet.State >= FleetState.Sortie)
141- .SelectMany(fleet => fleet.Deck.Select(id => (ShipStatus)GetStatus(id).Clone())).ToArray();
137+ .SelectMany(fleet => fleet.Ships.Select(ship => (ShipStatus)ship.Clone())).ToArray();
138+ }
139+
140+ private void InspectShipDataAndDeck(dynamic ship, dynamic deck)
141+ {
142+ InspectShipData(ship);
143+ InspectDeck(deck); // FleetのDeckを設定した時点でShipStatusを取得するので必ずdeckが後
142144 }
143145
144146 public void InspectDeck(dynamic json)
@@ -191,7 +193,7 @@ namespace KancolleSniffer.Model
191193
192194 private void InspectBasic(dynamic json)
193195 {
194- HqLevel = (int)json.api_level;
196+ _hqLevel = (int)json.api_level;
195197 Counter.Max = (int)json.api_max_chara;
196198 }
197199
@@ -209,37 +211,30 @@ namespace KancolleSniffer.Model
209211 public void InspectChange(string request)
210212 {
211213 var values = HttpUtility.ParseQueryString(request);
212- var fleet = _fleets[int.Parse(values["api_id"]) - 1];
213- var idx = int.Parse(values["api_ship_idx"]);
214- var ship = int.Parse(values["api_ship_id"]);
214+ var dstFleet = _fleets[int.Parse(values["api_id"]) - 1];
215+ var dstIdx = int.Parse(values["api_ship_idx"]);
216+ var shipId = int.Parse(values["api_ship_id"]);
215217
216- if (idx == -1)
217- {
218- var deck = fleet.Deck;
219- for (var i = 1; i < deck.Length; i++)
220- deck[i] = -1;
221- return;
222- }
223- if (ship == -1)
218+ if (dstIdx == -1 || shipId == -1) // 解除
224219 {
225- WithdrowShip(fleet, idx);
220+ dstFleet.WithdrowShip(dstIdx);
226221 return;
227222 }
228- var of = FindFleet(ship, out var oi);
229- var orig = fleet.Deck[idx];
230- fleet.Deck[idx] = ship;
231- if (of == null)
223+ var srcFleet = FindFleet(shipId, out var srcIdx);
224+ var prevShipId = dstFleet.SetShip(dstIdx, shipId);
225+ if (srcFleet == null)
232226 return;
233227 // 入れ替えの場合
234- if ((of.Deck[oi] = orig) == -1)
235- WithdrowShip(of, oi);
228+ srcFleet.SetShip(srcIdx, prevShipId);
229+ if (prevShipId == -1)
230+ srcFleet.WithdrowShip(srcIdx);
236231 }
237232
238233 private Fleet FindFleet(int ship, out int idx)
239234 {
240235 foreach (var fleet in _fleets)
241236 {
242- idx = Array.FindIndex(fleet.Deck, id => id == ship);
237+ idx = fleet.Deck.ToList().IndexOf(ship);
243238 if (idx < 0)
244239 continue;
245240 return fleet;
@@ -248,19 +243,6 @@ namespace KancolleSniffer.Model
248243 return null;
249244 }
250245
251- private void WithdrowShip(Fleet fleet, int idx)
252- {
253- var deck = fleet.Deck;
254- var j = idx;
255- for (var i = idx + 1; i < deck.Length; i++)
256- {
257- if (deck[i] != -1)
258- deck[j++] = deck[i];
259- }
260- for (; j < deck.Length; j++)
261- deck[j] = -1;
262- }
263-
264246 public void InspectPowerup(string request, dynamic json)
265247 {
266248 var values = HttpUtility.ParseQueryString(request);
@@ -269,8 +251,7 @@ namespace KancolleSniffer.Model
269251 return;
270252 _itemInventry.Remove(ships.SelectMany(id => _shipInventry[id].Slot));
271253 _shipInventry.Remove(ships);
272- InspectDeck(json.api_deck);
273- InspectShip(json);
254+ InspectShipDataAndDeck(new[]{json.api_ship}, json.api_deck);
274255 }
275256
276257 public void InspectSlotExchange(string request, dynamic json)
@@ -283,20 +264,21 @@ namespace KancolleSniffer.Model
283264 public void InspectSlotDeprive(dynamic json)
284265 {
285266 InspectShipData(new[] {json.api_ship_data.api_set_ship, json.api_ship_data.api_unset_ship});
267+ foreach (var fleet in _fleets)
268+ fleet.SetDeck(); // ShipStatusの差し替え
286269 }
287270
288271 public void InspectDestroyShip(string request, dynamic json)
289272 {
290273 var values = HttpUtility.ParseQueryString(request);
291274 var delitem = int.Parse(values["api_slot_dest_flag"] ?? "0") == 1;
292- foreach (var id in values["api_ship_id"].Split(',').Select(int.Parse))
275+ foreach (var shipId in values["api_ship_id"].Split(',').Select(int.Parse))
293276 {
294277 if (delitem)
295- _itemInventry.Remove(_shipInventry[id].AllSlot);
296- var of = FindFleet(id, out var oi);
297- if (of != null)
298- WithdrowShip(of, oi);
299- _shipInventry.Remove(id);
278+ _itemInventry.Remove(_shipInventry[shipId].AllSlot);
279+ var srcFleet = FindFleet(shipId, out var srcIdx);
280+ srcFleet?.WithdrowShip(srcIdx);
281+ _shipInventry.Remove(shipId);
300282 }
301283 }
302284
@@ -328,18 +310,9 @@ namespace KancolleSniffer.Model
328310 _fleets[fleet].State = FleetState.Practice;
329311 }
330312
331- public Fleet[] Fleets => _fleets;
313+ public IReadOnlyList<Fleet> Fleets => _fleets;
332314
333- public ShipStatus GetStatus(int id) => FillUp(_shipInventry[id]);
334-
335- private ShipStatus FillUp(ShipStatus ship)
336- {
337- if (ship.Empty)
338- return ship;
339- ship.Fleet = FindFleet(ship.Id, out var idx);
340- ship.DeckIndex = idx;
341- return ship;
342- }
315+ public ShipStatus GetShip(int id) => _shipInventry[id];
343316
344317 public void SetItemHolder()
345318 {
@@ -353,7 +326,7 @@ namespace KancolleSniffer.Model
353326
354327 public ShipSpec GetSpec(int id) => _shipMaster.GetSpec(id);
355328
356- public ShipStatus[] ShipList => _shipInventry.AllShips.Select(FillUp).ToArray();
329+ public ShipStatus[] ShipList => _shipInventry.AllShips.ToArray();
357330
358331 public ShipStatus[] GetRepairList(DockInfo dockInfo)
359332 => (from s in ShipList
@@ -367,7 +340,7 @@ namespace KancolleSniffer.Model
367340 {
368341 BadlyDamagedShips =
369342 (from s in _fleets.Where(fleet => fleet.State == FleetState.Sortie)
370- .SelectMany(fleet => fleet.Deck.Where(id => id != -1).Select(GetStatus))
343+ .SelectMany(fleet => fleet.ActualShips)
371344 where !s.Escaped && s.DamageLevel == ShipStatus.Damage.Badly &&
372345 !(s.Fleet.CombinedType != 0 && s.Fleet.Number == 1 && s.DeckIndex == 0) // 第二艦隊の旗艦を除く
373346 select s.Name).ToArray();
--- a/KancolleSniffer/Model/ShipStatus.cs
+++ b/KancolleSniffer/Model/ShipStatus.cs
@@ -56,8 +56,8 @@ namespace KancolleSniffer.Model
5656
5757 public IReadOnlyList<ItemStatus> Slot
5858 {
59- get => _slot.Select(item => GetItem(item)).ToList();
60- set => _slot = value.ToList();
59+ get => _slot.Select(item => GetItem(item)).ToArray();
60+ set => _slot = value.ToArray();
6161 }
6262
6363 public ItemStatus SlotEx
--- a/KancolleSniffer/Sniffer.cs
+++ b/KancolleSniffer/Sniffer.cs
@@ -600,7 +600,7 @@ namespace KancolleSniffer
600600
601601 public AlarmCounter ShipCounter => _shipInfo.Counter;
602602
603- public Fleet[] Fleets => _shipInfo.Fleets;
603+ public IReadOnlyList<Fleet> Fleets => _shipInfo.Fleets;
604604
605605 public ShipInfo.ShipStatusPair[] BattleResultStatusDiff => _shipInfo.BattleResultDiff;
606606
--- a/KancolleSniffer/TextGenerator.cs
+++ b/KancolleSniffer/TextGenerator.cs
@@ -77,7 +77,7 @@ namespace KancolleSniffer
7777 var sb = new StringBuilder();
7878 var fn = new[] {"第一艦隊", "第二艦隊", "第三艦隊", "第四艦隊"};
7979 sb.Append(fn[fleet] + "\r\n");
80- sb.Append(string.Concat(from s in target.Ships
80+ sb.Append(string.Concat(from s in target.ActualShips
8181 select ($"{s.Name} Lv{s.Level} " +
8282 string.Join(",",
8383 from item in s.AllSlot
@@ -146,8 +146,8 @@ namespace KancolleSniffer
146146 if (fleet.Number != 0)
147147 sb.Append(",");
148148 sb.Append($"\"f{fleet.Number + 1}\":{{");
149- var ships = fleet.Ships;
150- for (var s = 0; s < ships.Length; s++)
149+ var ships = fleet.ActualShips;
150+ for (var s = 0; s < ships.Count; s++)
151151 {
152152 if (s != 0)
153153 sb.Append(",");
--- a/KancolleSniffer/View/AntiAirPanel.cs
+++ b/KancolleSniffer/View/AntiAirPanel.cs
@@ -56,7 +56,7 @@ namespace KancolleSniffer.View
5656 var fn = new[] {"第一艦隊", "第二艦隊", "第三艦隊", "第四艦隊"};
5757 foreach (var fleet in sniffer.Fleets)
5858 {
59- var ships = fleet.Ships;
59+ var ships = fleet.ActualShips;
6060 var rawForFleet = ships.Sum(ship => ship.EffectiveAntiAirForFleet);
6161 var forFleet = new[] {1.0, 1.2, 1.6}.Select(r => (int)(rawForFleet * r) * 2 / 1.3).ToArray();
6262 _table.Add(new Record
--- a/KancolleSniffer/View/FleetPanel.cs
+++ b/KancolleSniffer/View/FleetPanel.cs
@@ -94,15 +94,15 @@ namespace KancolleSniffer.View
9494 foreach (var fleet in sniffer.Fleets)
9595 {
9696 var total = new Total();
97- var ships = new List<Record>();
98- foreach (var s in fleet.Ships)
97+ var shipRecords = new List<Record>();
98+ foreach (var ship in fleet.ActualShips)
9999 {
100100 var equips = new List<Record>();
101- for (var i = 0; i < s.Slot.Count; i++)
101+ for (var i = 0; i < ship.Slot.Count; i++)
102102 {
103- var item = s.Slot[i];
104- var onslot = s.OnSlot[i];
105- var max = s.Spec.MaxEq[i];
103+ var item = ship.Slot[i];
104+ var onslot = ship.OnSlot[i];
105+ var max = ship.Spec.MaxEq[i];
106106 if (item.Empty)
107107 continue;
108108 var airspec = "";
@@ -124,32 +124,32 @@ namespace KancolleSniffer.View
124124 Color = item.Spec.Color
125125 });
126126 }
127- if (s.SlotEx.Id > 0)
127+ if (ship.SlotEx.Id > 0)
128128 {
129- var item = s.SlotEx;
129+ var item = ship.SlotEx;
130130 equips.Add(new Record {Equip = GenEquipString(item), Color = item.Spec.Color});
131131 }
132- total.Add(s);
133- var fire = s.EffectiveFirepower;
134- var subm = s.EffectiveAntiSubmarine;
135- var torp = s.EffectiveTorpedo;
136- var night = s.NightBattlePower;
137- var oasa = s.CanOpeningAntiSubmarineAttack ? "*" : "";
138- var ship = new Record
132+ total.Add(ship);
133+ var fire = ship.EffectiveFirepower;
134+ var subm = ship.EffectiveAntiSubmarine;
135+ var torp = ship.EffectiveTorpedo;
136+ var night = ship.NightBattlePower;
137+ var oasa = ship.CanOpeningAntiSubmarineAttack ? "*" : "";
138+ var record = new Record
139139 {
140- Ship = (s.Escaped ? "[避]" : "") + s.Name + " Lv" + s.Level,
141- Ship2 = $"燃{s.EffectiveFuelMax} 弾{s.EffectiveBullMax}",
142- Id = s.Id,
140+ Ship = (ship.Escaped ? "[避]" : "") + ship.Name + " Lv" + ship.Level,
141+ Ship2 = $"燃{ship.EffectiveFuelMax} 弾{ship.EffectiveBullMax}",
142+ Id = ship.Id,
143143 Spec = HideIfZero("砲", fire) + HideIfZero(" 潜", subm) + oasa,
144144 Spec2 = (HideIfZero("雷", torp) + HideIfZero(" 夜", night)).TrimStart(' ')
145145 };
146- if (ship.Spec == "")
146+ if (record.Spec == "")
147147 {
148- ship.Spec = ship.Spec2;
149- ship.Spec2 = "";
148+ record.Spec = record.Spec2;
149+ record.Spec2 = "";
150150 }
151- ships.Add(ship);
152- ships.AddRange(equips);
151+ shipRecords.Add(record);
152+ shipRecords.AddRange(equips);
153153 }
154154 var daihatsu = fleet.DaihatsuBonus;
155155 var tp = fleet.TransportPoint;
@@ -170,7 +170,7 @@ namespace KancolleSniffer.View
170170 ? ""
171171 : $"\r\nTP:S{(int)tp} A{(int)(tp * 0.7)}")
172172 });
173- list.AddRange(ships);
173+ list.AddRange(shipRecords);
174174 }
175175 if (sniffer.BaseAirCorps != null)
176176 {
--- a/KancolleSniffer/View/MainFormLabels.cs
+++ b/KancolleSniffer/View/MainFormLabels.cs
@@ -144,22 +144,22 @@ namespace KancolleSniffer.View
144144 label.ToggleHpPercent();
145145 }
146146
147- public void SetShipLabels(ShipStatus[] statuses)
147+ public void SetShipLabels(IReadOnlyList<ShipStatus> ships)
148148 {
149- SetShipLabels(statuses, statuses.Length == 7 ? _shipLabels7 : _shiplabels);
149+ SetShipLabels(ships, ships.Count == 7 ? _shipLabels7 : _shiplabels);
150150 }
151151
152- public void SetShipLabels(ShipStatus[] statuses, ShipLabel[][] shipLabels)
152+ public void SetShipLabels(IReadOnlyList<ShipStatus> ships, ShipLabel[][] shipLabels)
153153 {
154154 for (var i = 0; i < shipLabels.Length; i++)
155155 {
156156 var labels = shipLabels[i];
157- var s = i < statuses.Length ? statuses[i] : null;
158- labels[0].SetHp(s);
159- labels[1].SetCond(s);
160- labels[2].SetLevel(s);
161- labels[3].SetExpToNext(s);
162- labels[4].SetName(s, ShipNameWidth.MainPanel);
157+ var ship = i < ships.Count ? ships[i] : null;
158+ labels[0].SetHp(ship);
159+ labels[1].SetCond(ship);
160+ labels[2].SetLevel(ship);
161+ labels[3].SetExpToNext(ship);
162+ labels[4].SetName(ship, ShipNameWidth.MainPanel);
163163 }
164164 }
165165
@@ -223,14 +223,14 @@ namespace KancolleSniffer.View
223223 parent.ResumeLayout();
224224 }
225225
226- public void SetCombinedShipLabels(ShipStatus[] first, ShipStatus[] second)
226+ public void SetCombinedShipLabels(IReadOnlyList<ShipStatus> first, IReadOnlyList<ShipStatus> second)
227227 {
228228 for (var i = 0; i < _combinedLabels.Length; i++)
229229 {
230230 var idx = i % ShipInfo.MemberCount;
231- var statuses = i < ShipInfo.MemberCount ? first : second;
231+ var ships = i < ShipInfo.MemberCount ? first : second;
232232 var labels = _combinedLabels[i];
233- var s = idx < statuses.Length ? statuses[idx] : null;
233+ var s = idx < ships.Count ? ships[idx] : null;
234234 labels[0].SetHp(s);
235235 labels[1].SetCond(s);
236236 labels[2].SetName(s, ShipNameWidth.Combined);
@@ -290,19 +290,19 @@ namespace KancolleSniffer.View
290290 }
291291 }
292292
293- public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers)
293+ public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers)
294294 {
295- if (statuses.Length == 7)
295+ if (ships.Count == 7)
296296 {
297- SetAkashiTimer(statuses, timers, _akashiTimers7, _shipLabels7);
297+ SetAkashiTimer(ships, timers, _akashiTimers7, _shipLabels7);
298298 }
299299 else
300300 {
301- SetAkashiTimer(statuses, timers, _akashiTimers, _shiplabels);
301+ SetAkashiTimer(ships, timers, _akashiTimers, _shiplabels);
302302 }
303303 }
304304
305- public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers, ShipLabel[] timerLabels,
305+ public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers, ShipLabel[] timerLabels,
306306 ShipLabel[][] shipLabels)
307307 {
308308 var shortest = -1;
@@ -325,7 +325,7 @@ namespace KancolleSniffer.View
325325 continue;
326326 }
327327 var timer = timers[i];
328- var stat = statuses[i];
328+ var stat = ships[i];
329329 label.Visible = true;
330330 label.Text = timer.Span.ToString(@"mm\:ss");
331331 label.ForeColor = Control.DefaultForeColor;
--- a/KancolleSniffer/View/MiscTextInfo.cs
+++ b/KancolleSniffer/View/MiscTextInfo.cs
@@ -114,11 +114,11 @@ namespace KancolleSniffer.View
114114 var raw = _expTable[Min(s1, _expTable.Length) - 1] / 100.0 +
115115 _expTable[Min(s2, _expTable.Length) - 1] / 300.0;
116116 var exp = raw >= 500 ? 500 + (int)Sqrt(raw - 500) : (int)raw;
117- var bonus = 1 + TrainingCruiserBonus(_shipInfo.Fleets[0].Ships);
117+ var bonus = 1 + TrainingCruiserBonus(_shipInfo.Fleets[0].ActualShips);
118118 Text += $"獲得経験値 : {(int)(exp * bonus)}\r\nS勝利 : {(int)((int)(exp * 1.2) * bonus)}";
119119 }
120120
121- private double TrainingCruiserBonus(ShipStatus[] fleet)
121+ private double TrainingCruiserBonus(IReadOnlyList<ShipStatus> fleet)
122122 {
123123 if (fleet[0].Spec.IsTrainingCruiser)
124124 {
旧リポジトリブラウザで表示