-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cc
231 lines (197 loc) · 8.91 KB
/
main.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include <string>
#include <vector>
#include <random>
#include <memory>
#include <utility>
#include "skill.h"
#include "resources.h"
#include "node.h"
#include "explore.h"
// Example (a simplified BM rotation): 3 skills called Lunar Slash,
// Dragon Tongue, and Flicker, with their effects as follows:
// - Lunar Slash: Has 400 millisecond cast time, does 100 damage
// non-crit and 180 damage crit, with 40% chance of critting.
// Has 18 sec cooldown measured from the end of its cast. Triggers
// conflagration for 3 secs measured from the end of its cast.
// - Dragon Tongue: Has 400 millisecond cast time, does 120 damage
// non-crit and 200 damage crit when conflagration is down, with
// 40% chance of critting, and does 180 damage non-crit and 320
// damage crit when conflagration is up, with 60% chance of critting.
// Has 6 sec cooldown measured from the end of its cast only if
// conflagration is down. Reduces the cooldown of Lunar Slash by
// 1 sec on every cast.
// - Flicker: has 250 millisecond cast time, does 40 damage non-crit
// and 60 damage crit, with 40% chance of critting. Has no cooldown.
// Reduces the cooldown of Dragon Tongue by 2 secs on every cast.
// In addition, there is a resource called Focus, starting at 10
// units. One unit is regenerated every second when it is not at
// its maximum. Every cast of Lunar Slash triggers regeneration of
// 3 units of Focus immediately after cast, in addition to 3 units
// every second for 6 seconds. Every Dragon Tongue costs 2 units
// when conflagration is down and 1 unit when conflagration is up.
// Every Flicker costs 1 unit.
class LunarSlash;
class DragonTongue;
class Flicker;
struct BMResources : public Resources {
int focus = 10;
bool conflagrationUp() const {return conflagration;}
int timeUntilNextUpdate() const override {
// return the minimum of the conflagration time left, the
// natural focus regen time left, and the lunar slash
// focus regen time left
int conflagrationLeft = conflagrationTimeLeft > 0 ? conflagrationTimeLeft : 3600000;
int naturalRegenTimeLeft = focus == 10 ? 3600000 : 1000 - focusRegenOffset;
int lsRegenTimeLeft = timeSinceLastLS < 6000 ? 1000 - (timeSinceLastLS % 1000) : 3600000;
return conflagrationLeft < naturalRegenTimeLeft ?
(conflagrationLeft < lsRegenTimeLeft ? conflagrationLeft : lsRegenTimeLeft) :
(naturalRegenTimeLeft < lsRegenTimeLeft ? naturalRegenTimeLeft : lsRegenTimeLeft);
}
void wait(int time) override {
// conflagration
if (conflagration) {
conflagrationTimeLeft -= time;
if (conflagrationTimeLeft <= 0) {
conflagrationTimeLeft = 0;
conflagration = false;
}
}
// natural regen of focus
if (focus < 10) {
focusRegenOffset += time;
if (focusRegenOffset >= 1000) {
focus += 1;
focusRegenOffset -= 1000;
if (focus == 10) {
focusRegenOffset = 0;
}
}
}
// focus regen from lunar slash
int prevTime = timeSinceLastLS;
timeSinceLastLS += time;
if (timeSinceLastLS <= 6000) {
if (prevTime < 0 || (prevTime / 1000 != timeSinceLastLS / 1000)) {
focus += 3;
if (focus >= 10) {
focus = 10;
focusRegenOffset = 0;
}
}
}
}
Resources* copy() const override {
BMResources* newResources = new BMResources();
newResources->focus = focus;
newResources->focusRegenOffset = focusRegenOffset;
newResources->conflagration = conflagration;
newResources->conflagrationTimeLeft = conflagrationTimeLeft;
newResources->timeSinceLastLS = timeSinceLastLS;
return newResources;
}
void notify(LunarSlash* ls);
void notify(DragonTongue* dt) {focus -= (conflagration ? 1 : 2);}
void notify(Flicker* fl) {focus -= 1;}
private:
int focusRegenOffset = 0;
bool conflagration = false;
int conflagrationTimeLeft = 0;
int timeSinceLastLS = 3600000;
};
class LunarSlash : public Skill {
static std::mt19937 mt;
static std::uniform_int_distribution<int> dist;
int cd = 0;
void notify(Skill* from) override;
void notifyResources() override {static_cast<BMResources*>(resources)->notify(this);}
void useSkill() override {cd = 18000;}
Skill* copy() const override {LunarSlash* ls = new LunarSlash{}; ls->cd = cd; return ls;}
public:
bool isReady() const override {return cd == 0;}
int timeUntilReady() const override {return cd;}
void wait(int time) override {cd = cd < time ? 0 : cd - time;}
int getDamage() const override {return (dist(mt) >= 4) ? 180 : 100;}
int getCastTime() const override {return 400;}
std::string toString() const override {return "L";}
};
class DragonTongue : public Skill {
static std::mt19937 mt;
static std::uniform_int_distribution<int> dist;
int cd = 0;
void notify(Skill* from) override;
void notifyResources() override {static_cast<BMResources*>(resources)->notify(this);}
void useSkill() override {if (!static_cast<BMResources*>(resources)->conflagrationUp()) cd = 6000;}
Skill* copy() const override {DragonTongue* dt = new DragonTongue{}; dt->cd = cd; return dt;}
public:
bool isReady() const override {
if (static_cast<BMResources*>(resources)->conflagrationUp()) return static_cast<BMResources*>(resources)->focus >= 1;
else return cd == 0 && static_cast<BMResources*>(resources)->focus >= 2;
}
int timeUntilReady() const override {
BMResources* r = static_cast<BMResources*>(resources);
if (r->conflagrationUp()) return r->focus >= 1 ? 0 : 3600000;
else return r->focus >= 2 ? cd : 3600000;
}
void wait(int time) override {cd = cd < time ? 0 : cd - time;}
int getDamage() const override {
if (static_cast<BMResources*>(resources)->conflagrationUp()) return (dist(mt) >= 3) ? 320 : 180;
else return (dist(mt) >= 4) ? 200 : 120;
}
int getCastTime() const override {return 400;}
std::string toString() const override {return "D";}
};
class Flicker : public Skill {
static std::mt19937 mt;
static std::uniform_int_distribution<int> dist;
void notify(Skill* from) override {}
void notifyResources() override {static_cast<BMResources*>(resources)->notify(this);}
void useSkill() override {}
Skill* copy() const override {return new Flicker{};}
public:
bool isReady() const override {return static_cast<BMResources*>(resources)->focus >= 1;}
int timeUntilReady() const override {return static_cast<BMResources*>(resources)->focus >= 1 ? 0 : 3600000;}
void wait(int time) override {}
int getDamage() const override {return (dist(mt) >= 4) ? 60 : 40;}
int getCastTime() const override {return 250;}
std::string toString() const override {return "F";}
};
void BMResources::notify(LunarSlash* ls) {
conflagration = true;
conflagrationTimeLeft = 3000;
timeSinceLastLS = -1 * ls->getCastTime();
}
void LunarSlash::notify(Skill* from) {if (dynamic_cast<DragonTongue*>(from)) cd = cd < 1000 ? 0 : cd - 1000;}
void DragonTongue::notify(Skill* from) {
if (dynamic_cast<Flicker*>(from)) cd = cd < 2000 ? 0 : cd - 2000;
else if (dynamic_cast<LunarSlash*>(from)) cd = 0;
}
std::random_device rd;
std::mt19937 LunarSlash::mt = std::mt19937{rd()};
std::uniform_int_distribution<int> LunarSlash::dist = std::uniform_int_distribution<int>{1, 5};
std::mt19937 DragonTongue::mt = std::mt19937{rd()};
std::uniform_int_distribution<int> DragonTongue::dist = std::uniform_int_distribution<int>{1, 5};
std::mt19937 Flicker::mt = std::mt19937{rd()};
std::uniform_int_distribution<int> Flicker::dist = std::uniform_int_distribution<int>{1, 5};
int main(int argc, char* argv[]) {
double cPUCT = 1;
if (argc > 1) cPUCT = std::stod(std::string(argv[1]));
long numPlayouts = 10000000;
if (argc > 2) numPlayouts = std::stol(std::string(argv[2]));
std::vector<std::unique_ptr<Skill>> skills;
std::unique_ptr<Resources> resources = std::make_unique<BMResources>();
skills.emplace_back(std::make_unique<LunarSlash>());
skills.emplace_back(std::make_unique<DragonTongue>());
skills.emplace_back(std::make_unique<Flicker>());
skills[0]->addObserver(skills[1].get());
skills[1]->addObserver(skills[0].get());
skills[2]->addObserver(skills[1].get());
skills[0]->setResources(resources.get());
skills[1]->setResources(resources.get());
skills[2]->setResources(resources.get());
std::unique_ptr<State> state = std::make_unique<State>();
state->setSkills(std::move(skills));
state->setResources(std::move(resources));
Node root;
root.setState(std::move(state));
Explore::explore(&root, cPUCT, numPlayouts);
}