Guest User

updated monster killing

a guest
Jun 2nd, 2017
276
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.00 KB | None | 0 0
  1. // DavidL1450 - solves PvE instances in Cosmos Quest
  2.  
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <vector>
  6. #include <string>
  7. #include <map>
  8. #include <algorithm>
  9. #include <ctime>
  10. using namespace std;
  11.  
  12. class monster;
  13.  
  14. class fight_result{
  15. public:
  16.  
  17. vector<monster> * source = nullptr;
  18. fight_result(bool winner, int lost, int damage, int followers):winner(winner), lost(lost),damage(damage),followers(followers){};
  19. bool winner;//false -> left win, true -> right win.
  20. int lost;
  21. int damage;
  22. int followers; // left side's followers
  23. bool operator<= (fight_result & f){ // if this left side did non-strictly worse than the other left side
  24. if(winner == false && f.winner == true){ // this left won, that left didn't
  25. return false;
  26. }
  27. if(winner == true && f.winner == false){ // this left lost, that left won
  28. return true;
  29. }
  30. if(winner == false && f.winner == false){ // both lefts won
  31. return true; // non-strict comparison
  32. } // the right won here. "lost" is right losses
  33. if(lost < f.lost){ // this left killed strictly less
  34. return true;
  35. }
  36. if(lost > f.lost){ // this left killed strictly more
  37. return false;
  38. }
  39. if(lost == f.lost){
  40. return damage <= f.damage; // left dealt less damage -> left won
  41. }
  42. };
  43. };
  44. int fights_simulated = 0;
  45. class monster{
  46. public:
  47. int hp;
  48. int damage;
  49. int cost;
  50. string name;
  51. string element;
  52. monster(int hp, int damage, int cost, string name, string element):hp(hp),damage(damage),cost(cost),name(name),element(element){};
  53. int fight(string enemy_element){ // target's element
  54. if(element == "e" && enemy_element == "a"){
  55. return damage*1.5;
  56. }if(element == "a" && enemy_element == "w"){
  57. return damage*1.5;
  58. }if(element == "w" && enemy_element == "f"){
  59. return damage*1.5;
  60. }if(element == "f" && enemy_element == "e"){
  61. return damage*1.5;
  62. }
  63. return damage;
  64. };
  65. };
  66.  
  67. vector<monster> monster_list {
  68. monster(20, 8, 1000, "a1", "a"),
  69. monster(48, 6, 3900, "a2", "a"),
  70. monster(36, 12, 8000, "a3", "a"),
  71. monster(24, 26, 15000, "a4", "a"),
  72. monster(60, 20, 41000, "a5", "a"),
  73. monster(62, 34, 96000, "a6", "a"),
  74. monster(106, 26, 144000, "a7", "a"),
  75. monster(78, 52, 257000, "a8", "a"),
  76. monster(116, 54, 495000, "a9", "a"),
  77. monster(142, 60, 785000, "a10", "a"),
  78.  
  79. monster(30, 6, 1400, "w1", "w"),
  80. monster(24, 12, 3900, "w2", "w"),
  81. monster(18, 24, 8000, "w3", "w"),
  82. monster(36, 20, 18000, "w4", "w"),
  83. monster(78, 18, 52000, "w5", "w"),
  84. monster(44, 44, 84000, "w6", "w"),
  85. monster(92, 32, 159000, "w7", "w"),
  86. monster(108, 36, 241000, "w8", "w"),
  87. monster(80, 70, 418000, "w9", "w"),
  88. monster(110, 70, 675000, "w10", "w"),
  89.  
  90. monster(44, 4, 1300, "e1", "e"),
  91. monster(30, 8, 2700, "e2", "e"),
  92. monster(26, 16, 7500, "e3", "e"),
  93. monster(72, 10, 18000, "e4", "e"),
  94. monster(36, 40, 54000, "e5", "e"),
  95. monster(72, 24, 71000, "e6", "e"),
  96. monster(66, 36, 115000, "e7", "e"),
  97. monster(60, 60, 215000, "e8", "e"),
  98. monster(120, 48, 436000, "e9", "e"),
  99. monster(122, 64, 689000, "e10", "e"),
  100.  
  101. monster(16, 10, 1000, "f1", "f"),
  102. monster(18, 16, 3900, "f2", "f"),
  103. monster(54, 8, 8000, "f3", "f"),
  104. monster(52, 16, 23000, "f4", "f"),
  105. monster(42, 24, 31000, "f5", "f"),
  106. monster(104, 20, 94000, "f6", "f"),
  107. monster(54, 44, 115000, "f7", "f"),
  108. monster(94, 50, 321000, "f8", "f"),
  109. monster(102, 58, 454000, "f9", "f"),
  110. monster(104, 82, 787000, "f10", "f")
  111.  
  112. };
  113. map<string,monster>monster_map{
  114. {"a1", monster(20, 8, 1000, "a1", "a")},
  115. {"a2", monster(48, 6, 3900, "a2", "a")},
  116. {"a3", monster(36, 12, 8000, "a3", "a")},
  117. {"a4", monster(24, 26, 15000, "a4", "a")},
  118. {"a5", monster(60, 20, 41000, "a5", "a")},
  119. {"a6", monster(62, 34, 96000, "a6", "a")},
  120. {"a7", monster(106, 26, 144000, "a7", "a")},
  121. {"a8", monster(78, 52, 257000, "a8", "a")},
  122. {"a9", monster(116, 54, 495000, "a9", "a")},
  123. {"a10", monster(142, 60, 785000, "a10", "a")},
  124.  
  125. {"w1", monster(30, 6, 1400, "w1", "w")},
  126. {"w2", monster(24, 12, 3900, "w2", "w")},
  127. {"w3", monster(18, 24, 8000, "w3", "w")},
  128. {"w4", monster(36, 20, 18000, "w4", "w")},
  129. {"w5", monster(78, 18, 52000, "w5", "w")},
  130. {"w6", monster(44, 44, 84000, "w6", "w")},
  131. {"w7", monster(92, 32, 159000, "w7", "w")},
  132. {"w8", monster(108, 36, 241000, "w8", "w")},
  133. {"w9", monster(80, 70, 418000, "w9", "w")},
  134. {"w10", monster(110, 70, 675000, "w10", "w")},
  135.  
  136. {"e1", monster(44, 4, 1300, "e1", "e")},
  137. {"e2", monster(30, 8, 2700, "e2", "e")},
  138. {"e3", monster(26, 16, 7500, "e3", "e")},
  139. {"e4", monster(72, 10, 18000, "e4", "e")},
  140. {"e5", monster(36, 40, 54000, "e5", "e")},
  141. {"e6", monster(72, 24, 71000, "e6", "e")},
  142. {"e7", monster(66, 36, 115000, "e7", "e")},
  143. {"e8", monster(60, 60, 215000, "e8", "e")},
  144. {"e9", monster(120, 48, 436000, "e9", "e")},
  145. {"e10", monster(122, 64, 689000, "e10", "e")},
  146.  
  147. {"f1", monster(16, 10, 1000, "f1", "f")},
  148. {"f2", monster(18, 16, 3900, "f2", "f")},
  149. {"f3", monster(54, 8, 8000, "f3", "f")},
  150. {"f4", monster(52, 16, 23000, "f4", "f")},
  151. {"f5", monster(42, 24, 31000, "f5", "f")},
  152. {"f6", monster(104, 20, 94000, "f6", "f")},
  153. {"f7", monster(54, 44, 115000, "f7", "f")},
  154. {"f8", monster(94, 50, 321000, "f8", "f")},
  155. {"f9", monster(102, 58, 454000, "f9", "f")},
  156. {"f10", monster(104, 82, 787000, "f10", "f")}
  157.  
  158. };
  159.  
  160. map<string, string> countered_by{
  161. {"a1", "e1"},
  162. {"a2", "e2"},
  163. {"a3", "e3"},
  164. {"a4", "e4"},
  165. {"a5", "e5"},
  166. {"a6", "e6"},
  167. {"a7", "e7"},
  168. {"a8", "e8"},
  169. {"a9", "e9"},
  170. {"a10", "e10"},
  171.  
  172. {"w1", "a1"},
  173. {"w2", "a2"},
  174. {"w3", "a3"},
  175. {"w4", "a4"},
  176. {"w5", "a5"},
  177. {"w6", "a6"},
  178. {"w7", "a7"},
  179. {"w8", "a8"},
  180. {"w9", "a9"},
  181. {"w10", "a10"},
  182.  
  183. {"e1", "f1"},
  184. {"e2", "f2"},
  185. {"e3", "f3"},
  186. {"e4", "f4"},
  187. {"e5", "f5"},
  188. {"e6", "f6"},
  189. {"e7", "f7"},
  190. {"e8", "f8"},
  191. {"e9", "f9"},
  192. {"e10", "f10"},
  193.  
  194. {"f1", "w1"},
  195. {"f2", "w2"},
  196. {"f3", "w3"},
  197. {"f4", "w4"},
  198. {"f5", "w5"},
  199. {"f6", "w6"},
  200. {"f7", "w7"},
  201. {"f8", "w8"},
  202. {"f9", "w9"},
  203. {"f10", "w10"}
  204.  
  205. };
  206. // initialize
  207. int cost(vector<monster> & army);
  208. fight_result simulate_fight(vector<monster> & left, vector<monster> & right){
  209. //fights left to right, so left[0] and right[0] are the first to fight
  210. fights_simulated++;
  211. int left_lost = 0;
  212. int left_damage_taken = 0;
  213. int right_lost = 0;
  214. int right_damage_taken = 0;
  215. while(left_lost < left.size() && right_lost < right.size()){
  216. //attack once
  217. right_damage_taken += left.at(left_lost).fight(right.at(right_lost).element);
  218. left_damage_taken += right.at(right_lost).fight(left.at(left_lost).element);
  219. //check for deaths
  220. if(left_damage_taken >= left.at(left_lost).hp){
  221. left_damage_taken = 0;
  222. left_lost++;
  223. }
  224. if(right_damage_taken >= right.at(right_lost).hp){
  225. right_damage_taken = 0;
  226. right_lost++;
  227. }
  228. }
  229. //draws count as right wins.
  230. if(left_lost == left.size()){
  231. return fight_result(true, right_lost, right_damage_taken, cost(left));
  232. }
  233. return fight_result(false, left_lost, left_damage_taken,cost(left));
  234. }
  235.  
  236. int cost(vector<monster> & m){
  237. int result = 0;
  238. for(int i=0;i<m.size();i++){
  239. result = result + m.at(i).cost;
  240. }
  241. return result;
  242. }
  243. bool function_compare(fight_result & a, fight_result & b){
  244. return (a.followers < b.followers);
  245. }
  246. int main(int argc, char** argv) {
  247. bool time_it=(argc ==3); // if set to true, it will show how much time each step takes
  248. vector<monster> target {};//somehow get stuff here
  249. string target_string;
  250. cout << "enter the enemy sequence left to right ";
  251. getline(cin, target_string);
  252. string parsing = "";
  253. for(int i=0; i < target_string.length();i++){
  254. if(target_string.at(i) != ' '){
  255. parsing = parsing + target_string.at(i);
  256. }
  257. else {
  258. target.push_back(monster_map.at(parsing));
  259. parsing = "";
  260. }
  261. }
  262. target.push_back(monster_map.at(parsing));
  263. int limit = 0; // somehow get stuff here.
  264. cout << "enter the maximum number of monsters ";
  265. cin >> limit;
  266. vector<vector<monster> >optimal = {}; // initialize with all single monsters
  267. for(int i=0; i<monster_list.size();i++){
  268. optimal.push_back(vector<monster>{monster_list.at(i)});
  269. }
  270. //get a good upper bound
  271.  
  272. int upper_bound = 99999999;
  273. vector<monster> trial {};
  274. vector<monster> best {};
  275. for(int i=0; i < target.size() && i < limit;i++){
  276. trial.push_back(monster_map.at(countered_by.at(target.at(i).name) ));
  277. }
  278. fight_result this_result = simulate_fight(trial, target);
  279. if(this_result.winner == false){
  280. upper_bound = cost(trial);
  281. best = trial;
  282. }
  283. //check if optimizable - if no single monster can defeat the last two monsters, then we can optimize
  284. bool optimizable = (target.size() >= 3);
  285. if(target.size() >= 3){
  286. vector<monster> last2 = {target.at(target.size()-2), target.at(target.size()-1) };
  287. for(int i=0; i < monster_list.size(); i++){
  288. if(monster_list.at(i).cost > upper_bound){
  289. continue;
  290. }
  291. vector<monster> fighting { monster_list.at(i)};
  292. fight_result s = simulate_fight( fighting, last2);
  293. if(s.winner == false){
  294. //single monster can defeat last 2 -> cannot optimize
  295. optimizable = false;
  296. }
  297. }
  298. }
  299.  
  300. //best so far
  301. for(int c=1; c <= limit; c++){
  302. if(time_it == true){
  303. cout << "TIME : starting loop " << time(NULL) << "\n";
  304. }
  305. vector<fight_result> result {};
  306. // for each optimal result (that is, not known to be dominated), fight against the target and record values
  307. for(int i=0; i<optimal.size();i++){
  308. fight_result this_result = simulate_fight(optimal.at(i), target);
  309. this_result.source = &optimal.at(i);
  310. if(this_result.winner == false && cost(optimal.at(i)) < upper_bound ){ // left (our side) wins:
  311. upper_bound = this_result.followers;
  312. best = optimal.at(i);
  313. }
  314. result.push_back(this_result);
  315.  
  316. }
  317. if(time_it == true){
  318. cout << "TIME : finished fight, starting sort " << time(NULL) << "\n";
  319. }
  320. if(c != limit){ // do not do the last expansion
  321. //sort for O(n) searching
  322. // //faster lookup
  323. sort(result.begin(), result.end(), function_compare);
  324. // do not use optimal.at(i) anymore, replace with (*(result.at(i).source))
  325.  
  326. if(time_it == true){
  327. cout << "TIME : finished sort, starting check dominance " << time(NULL) << "\n";
  328. }
  329. for(int i=0; i<optimal.size();i++){
  330. // it is also dominated if c+1 = limit (one monster left) and the last 2 monsters are still alive
  331. if(c+1 == limit && optimizable == true){
  332. if(result.at(i).winner== true && result.at(i).lost < target.size()-2)
  333. /*
  334. cout << "OPTIMIZED OUT"; //debug
  335. for (monster m : *(result.at(i).source)){
  336. cout << m.name << " ";
  337. } // end debug
  338. */
  339. (*(result.at(i).source)).at(0).name = "dominated";
  340. }
  341. if((*(result.at(i).source)).at(0).name != "dominated"){
  342. for(int j=i+1; j<optimal.size();j++){
  343. // if i costs more followers and got less far than j, then i is dominated
  344. // set optimal[i][0]'s name to dominated
  345. if(result.at(i).followers >= result.at(j).followers && result.at(i) <= result.at(j)){
  346. (*(result.at(i).source)).at(0).name = "dominated";
  347. }
  348. if(result.at(i).followers < result.at(j).followers){
  349. break; // since the list is sorted
  350. }
  351. }
  352. }
  353. }
  354. // now we expand to add the next monster to all non-dominated armies
  355. if(time_it == true){
  356. cout << "TIME : finished check dominance, starting expanding " << time(NULL) << "\n";
  357. }
  358. vector<vector<monster> > next_optimal {};
  359. for(int i=0;i<optimal.size();i++){
  360. for(int m=0; m < monster_list.size();m++){
  361. monster x = monster_list.at(m);
  362. if((*(result.at(i).source)).at(0).name != "dominated" && (result.at(i).followers + x.cost) < upper_bound){
  363. // expand: next_optimal.append( x + optimal.at(i)), for every monster x that keeps followers count strictly less than the upper bound.;
  364. next_optimal.push_back((*(result.at(i).source)));
  365. next_optimal.at(next_optimal.size()-1).push_back(x);
  366. }
  367. }
  368. }
  369. if(time_it == true){
  370. cout << "TIME : finished expanding (move)" << time(NULL) << "\n";
  371. }
  372. optimal = move(next_optimal);
  373. }
  374. }
  375. // print out the winning combination!
  376. cout << "The minimum number of followers is : " << upper_bound;
  377. cout << "\nand the winning combination is:\n";
  378. for(int i=0; i<best.size();i++){
  379. cout << best.at(best.size()-1-i).name << " "; // backwards
  380. }
  381. cout << "\n" << "(right-most fights first)\n" << fights_simulated << " fights simulated\n";
  382. return 0;
  383. }
Advertisement
Add Comment
Please, Sign In to add comment