OSDN Git Service

staticプロパティをインスタンスプロパティに変更
[kcd/KCD.git] / KCD / SeikuCalclator.swift
1 //
2 //  SeikuCalclator.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/08/20.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Foundation
10
11 private let seikuEffectiveTypes = [6, 7, 8, 11, 45, 56, 57, 58]
12
13 private let fighterTypes =              [ 6]
14 private let bomberTypes =               [ 7]
15 private let attackerTypes =             [ 8]
16 private let floatplaneBomberTypes =     [11]
17 private let floatplaneFighterTypes =    [45]
18 private let jetFighter =                [56]
19 private let jetBomberTypes =            [57]
20 private let jetAttackerTypes =          [58]
21
22 // swiftlint:disable comma
23 private let fighterBonus: [Double] =            [0, 0, 2, 5, 9, 14, 14, 22]
24 private let bomberBonus: [Double] =             [0, 0, 0, 0, 0,  0,  0,  0]
25 private let attackerBonus: [Double] =           [0, 0, 0, 0, 0,  0,  0,  0]
26 private let floatplaneBomberBonus: [Double] =   [0, 0, 1, 1, 1,  3,  3,  6]
27 private let floatplaneFighterBonus: [Double] =  [0, 0, 2, 5, 9, 14, 14, 22]
28 private let jetBomberBonus: [Double] =          [0, 0, 0, 0, 0,  0,  0,  0]
29 // swiftlint:enable comma
30
31 //                             sqrt 0, 1,     2.5,   4,     5.5,   7,     8.5,   10
32 private let skillBonus: [Double] = [0, 1.000, 1.581, 2.000, 2.345, 2.645, 2.915, 3.162]
33
34
35 final class SeikuCalclator {
36     
37     let ship: Ship
38     
39     init(ship: Ship) {
40         
41         self.ship = ship
42     }
43     
44     var seiku: Int {
45         
46         let guardEscaped = TemporaryDataStore.default.ensuredGuardEscaped(byShipId: ship.id)
47         guard guardEscaped == nil else {
48             
49             return 0
50         }
51         
52         return (0...4).map(slotSeiku).map { Int($0) }.reduce(0, +)
53     }
54     
55     var totalSeiku: Int {
56         
57         let guardEscaped = TemporaryDataStore.default.ensuredGuardEscaped(byShipId: ship.id)
58         guard guardEscaped == nil else {
59             
60             return 0
61         }
62         
63         return (0...4).map(seiku).reduce(0, +)
64     }
65     
66     private func slotItem(at index: Int) -> SlotItem? {
67         
68         return ServerDataStore.default.slotItem(by: ship.slotItemId(index))
69     }
70     
71     private func typeBonus(_ type: Int) -> [Double]? {
72         
73         switch type {
74             
75         case let t where fighterTypes.contains(t): return fighterBonus
76             
77         case let t where bomberTypes.contains(t): return bomberBonus
78             
79         case let t where attackerTypes.contains(t): return attackerBonus
80             
81         case let t where floatplaneBomberTypes.contains(t): return floatplaneBomberBonus
82             
83         case let t where floatplaneFighterTypes.contains(t): return floatplaneFighterBonus
84             
85         case let t where jetBomberTypes.contains(t): return jetBomberBonus
86             
87         default: return nil
88             
89         }
90     }
91     
92     private enum SlotState {
93         
94         case valid(SlotItem, Int, Int)
95         
96         case invalid
97     }
98     
99     private func slotState(at index: Int) -> SlotState {
100         
101         let itemCount = ship.slotItemCount(index)
102         if itemCount == 0 {
103             
104             return .invalid
105         }
106         guard let item = slotItem(at: index) else {
107             
108             return .invalid
109         }
110         
111         return .valid(item, itemCount, item.master_slotItem.type_2)
112     }
113     
114     private func slotSeiku(at index: Int) -> Double {
115         
116         guard case let .valid(item, itemCount, type2) = slotState(at: index),
117             seikuEffectiveTypes.contains(type2) else {
118                 
119                 return 0
120         }
121         
122         let taiku = Double(item.master_slotItem.tyku)
123         let lv = Double(item.level)
124         let rate = bomberTypes.contains(type2) ? 0.25 : 0.2
125         
126         return (taiku + lv * rate) * sqrt(Double(itemCount))
127     }
128     
129     private func skilledSlotSeiku(at index: Int) -> Double {
130         
131         guard case let .valid(item, _, type2) = slotState(at: index),
132             let typeBonus = typeBonus(type2) else {
133                 
134                 return 0
135         }
136         
137         let airLevel = item.alv
138         
139         return typeBonus[airLevel] + skillBonus[airLevel]
140     }
141     
142     private func seiku(at index: Int) -> Int {
143         
144         return Int(slotSeiku(at: index) + skilledSlotSeiku(at: index))
145     }
146     
147 }