OSDN Git Service

バージョンを1.9b33に更新
[kcd/KCD.git] / KCD / SakutekiCalculator.swift
1 //
2 //  SakutekiCalculator.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/06/18.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Foundation
10
11 protocol SakutekiCalculator {
12     
13     func calculate(_ ships: [Ship]) -> Double
14 }
15
16 final class SimpleCalculator: SakutekiCalculator {
17     
18     func calculate(_ ships: [Ship]) -> Double {
19         
20         return Double(ships.reduce(0) { $0 + $1.sakuteki_0 })
21     }
22 }
23
24 final class Formula33: SakutekiCalculator {
25     
26     let condition: Int
27     
28     init(_ condition: Int = 1) {
29         
30         self.condition = condition
31     }
32     
33     private func printShipData(_ ship: Ship) {
34         
35         let shipData = "\(ship.name)\t\(normalSakuteki(ship))"
36         let itemNames = ship
37             .equippedItem
38             .array
39             .flatMap { $0 as? SlotItem }
40             .reduce("") {
41                 
42                 let saku = $1.master_slotItem.saku ?? 0
43                 let ratio = typeRatio($1)
44                 let bounus = levelBounus($1)
45                 let culcSaku = ratio * (Double(truncating: saku) + bounus)
46                 
47                 return $0 + "\n\t\($1.name)\tLv.\($1.level)\t\t\(saku)\t\(ratio)\t\(bounus)\t\(culcSaku)"
48         }
49         
50         print("\(shipData)\(itemNames)\n")
51         
52     }
53     
54     func calculate(_ ships: [Ship]) -> Double {
55         
56         Debug.excute(level: .full) {
57             ships.forEach(printShipData)
58         }
59         
60         let aliveShips = ships.filter(alive)
61         
62         let saku1 = aliveShips
63             .map(normalSakuteki)
64             .map(sqrt)
65             .reduce(0, +)
66         
67         let saku2 = aliveShips
68             .map(equipsSakuteki)
69             .reduce(0, +)
70         
71         let saku3 = shireiSakuteki()
72         
73         let saku4 = 2 * (6 - ships.count)
74         
75         return saku1 + saku2 - saku3 + Double(saku4)
76     }
77     
78     private func alive(_ ship: Ship) -> Bool {
79         
80         if let _ = TemporaryDataStore.default.ensuredGuardEscaped(byShipId: ship.id) {
81             
82             return false
83         }
84         
85         return true
86     }
87     
88     private func normalSakuteki(_ ship: Ship) -> Double {
89         
90         let eqSakuteki = ship
91             .equippedItem
92             .array
93             .flatMap { $0 as? SlotItem }
94             .flatMap { $0.master_slotItem.saku as? Double }
95             .reduce(0, +)
96         
97         return Double(ship.sakuteki_0) - eqSakuteki
98     }
99     
100     private func equipsSakuteki(_ ship: Ship) -> Double {
101         
102         let saku = ship
103             .equippedItem
104             .array
105             .flatMap { $0 as? SlotItem }
106             .map(equipSakuteki)
107             .reduce(0, +)
108         
109         return Double(condition) * saku
110     }
111     
112     private func equipSakuteki(_ item: SlotItem) -> Double {
113         
114         guard let saku = item.master_slotItem.saku as? Double else { return 0 }
115         
116         let lvBounus = levelBounus(item)
117         
118         let ratio = typeRatio(item)
119         
120         return Double(condition) * ratio * (saku + lvBounus)
121     }
122     
123     private func typeRatio(_ item: SlotItem) -> Double {
124         
125         let type2 = item.master_slotItem.type_2
126         
127         guard let eqType = EquipmentType(rawValue: type2) else { return 1 }
128         
129         switch eqType {
130         case .fighter: return 0.6
131         case .bomber: return 0.6
132         case .attacker: return 0.8
133         case .searcher: return 1
134         case .airplaneSearcher: return 1.2
135         case .airplaneBomber: return 1.1
136         case .smallRadar: return 0.6
137         case .largeRadar: return 0.6
138         case .antiSunmrinerSercher: return 0.6
139         case .searchlight: return 0.6
140         case .headquaters: return 0.6
141         case .pilot: return 0.6
142         case .shipPersonnel: return 0.6
143         case .largeSonar: return 0.6
144         case .largeAirplane: return 0.6
145         case .largeSearchlight: return 0.6
146         case .airplaneFighter: return 0.6
147         case .searcherII: return 1
148         case .jetBomber: return 0.6
149         default: return 0
150         }
151     }
152     
153     private func levelBounus(_ item: SlotItem) -> Double {
154         
155         let level = item.level
156         
157         let ratio = levelRatio(item)
158         
159         return ratio * sqrt(Double(level))
160     }
161     
162     private func levelRatio(_ item: SlotItem) -> Double {
163         
164         let type2 = item.master_slotItem.type_2
165         
166         guard let eqType = EquipmentType(rawValue: type2) else { return 1 }
167         
168         switch eqType {
169         case .smallRadar: return 1.25
170         case .largeRadar: return 1.4
171         case .airplaneSearcher, .searcher: return 1.2
172         default: return 0
173         }
174     }
175     
176     private func shireiSakuteki() -> Double {
177         
178         guard let basic = ServerDataStore.default.basic() else { return 0 }
179         
180         return ceil(0.4 * Double(basic.level))
181     }
182     
183 }