Game.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #include <GL/glew.h>
  2. #include <GLFW/glfw3.h>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <chrono>
  6. #include <fstream>
  7. #include <cmath>
  8. #include "Game.h"
  9. #include "utils/Random.h"
  10. constexpr float EPS = 0.00000001f;
  11. bool compare(float a, float b) {
  12. return std::abs(a - b) < EPS;
  13. }
  14. bool Point::operator<(const Point& other) const {
  15. if(x == other.x) {
  16. return y < other.y;
  17. }
  18. return x < other.x;
  19. }
  20. float Point::distance(const Point& other) const {
  21. return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y);
  22. }
  23. Game::Game(Keys& keys, const char* file, bool steps) : keys(keys), keyNext(keys.add(GLFW_KEY_N)), active(0),
  24. state(SPLIT) {
  25. if(file == nullptr) {
  26. Random r;
  27. int amount = steps ? 50 : 100000;
  28. for(int i = 0; i < amount; i++) {
  29. data.push_back({r.nextFloat(), r.nextFloat()});
  30. }
  31. } else {
  32. std::ifstream in;
  33. in.open(file);
  34. if(!in.good()) {
  35. std::cout << "cannot read '" << file << "'\n";
  36. return;
  37. }
  38. int count;
  39. in >> count;
  40. while(in.get() != '\n');
  41. for(int i = 0; i < count; i++) {
  42. float x;
  43. float y;
  44. in >> x;
  45. in.get();
  46. in >> y;
  47. while(!in.eof() && in.get() != '\n');
  48. data.push_back({x, y});
  49. }
  50. }
  51. if(data.size() > 0) {
  52. minX = data[0].x;
  53. maxX = data[0].x;
  54. minY = data[0].y;
  55. maxY = data[0].y;
  56. for(const Point& p : data) {
  57. if(p.x < minX) {
  58. minX = p.x;
  59. }
  60. if(p.x > maxX) {
  61. maxX = p.x;
  62. }
  63. if(p.y < minY) {
  64. minY = p.y;
  65. }
  66. if(p.y > maxY) {
  67. maxY = p.y;
  68. }
  69. }
  70. }
  71. if(!steps) {
  72. skip();
  73. }
  74. }
  75. bool Game::merge() {
  76. auto start = groups[active].begin();
  77. auto end = groups[active].end();
  78. if(start == end) {
  79. if(groups[1 - active].begin() == groups[1 - active].end() ||
  80. groups[1 - active].begin() + 1 == groups[1 - active].end()) {
  81. return false;
  82. }
  83. active = 1 - active;
  84. } else if(start + 1 == end) {
  85. std::vector<Point> group = groups[active].front();
  86. groups[active].pop_front();
  87. groups[1 - active].push_back(group);
  88. return merge();
  89. }
  90. hullA = groups[active].front();
  91. groups[active].pop_front();
  92. hullB = groups[active].front();
  93. groups[active].pop_front();
  94. lowerIndexA = findMaxX(hullA);
  95. lowerIndexB = findMinX(hullB);
  96. upperIndexA = lowerIndexA;
  97. upperIndexB = lowerIndexB;
  98. return true;
  99. }
  100. void Game::finalizeMerge() {
  101. std::vector<Point> mergedHull;
  102. mergedHull.reserve(hullA.size() + hullB.size());
  103. while(lowerIndexA != upperIndexA) {
  104. mergedHull.push_back(hullA[lowerIndexA]);
  105. lowerIndexA = (lowerIndexA + 1) % hullA.size();
  106. }
  107. mergedHull.push_back(hullA[upperIndexA]);
  108. while(upperIndexB != lowerIndexB) {
  109. mergedHull.push_back(hullB[upperIndexB]);
  110. upperIndexB = (upperIndexB + 1) % hullB.size();
  111. }
  112. mergedHull.push_back(hullB[lowerIndexB]);
  113. groups[1 - active].push_back(mergedHull);
  114. }
  115. void Game::split() {
  116. std::sort(data.begin(), data.end());
  117. int index = 0;
  118. while(index + 2 < static_cast<int> (data.size())) {
  119. groups[active].push_back(std::vector<Point>());
  120. std::vector<Point>& v = groups[active].back();
  121. Point& a = data[index];
  122. Point& b = data[index + 1];
  123. Point& c = data[index + 2];
  124. float f = det(a, b, c);
  125. if(compare(f, 0.0f)) {
  126. v.push_back({std::min(a.x, std::min(b.x, c.x)), std::min(a.y, std::min(b.y, c.y))});
  127. v.push_back({std::max(a.x, std::max(b.x, c.x)), std::max(a.y, std::max(b.y, c.y))});
  128. } else if(f > 0.0f) {
  129. v.push_back(a);
  130. v.push_back(c);
  131. v.push_back(b);
  132. } else {
  133. v.push_back(a);
  134. v.push_back(b);
  135. v.push_back(c);
  136. }
  137. index += 3;
  138. }
  139. int diff = data.size() - index;
  140. if(diff > 0) {
  141. groups[active].push_back(std::vector<Point>());
  142. std::vector<Point>& v = groups[active].back();
  143. while(index < static_cast<int> (data.size())) {
  144. v.push_back(data[index++]);
  145. }
  146. }
  147. }
  148. bool Game::isLowerTangent(const std::vector<Point>& hull) const {
  149. for(const Point& p : hull) {
  150. float f = det(hullA[lowerIndexA], hullB[lowerIndexB], p);
  151. if(f < -EPS) {
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. bool Game::isUpperTangent(const std::vector<Point>& hull) const {
  158. for(const Point& p : hull) {
  159. float f = det(hullA[upperIndexA], hullB[upperIndexB], p);
  160. if(f > EPS) {
  161. return false;
  162. }
  163. }
  164. return true;
  165. }
  166. bool Game::findLowerTangent() {
  167. if(!isLowerTangent(hullA)) {
  168. lowerIndexA = (lowerIndexA + 1) % hullA.size();
  169. } else if(!isLowerTangent(hullB)) {
  170. lowerIndexB = (lowerIndexB == 0) ? hullB.size() - 1 : lowerIndexB - 1;
  171. }
  172. if(!isLowerTangent(hullA) || !isLowerTangent(hullB)) {
  173. return true;
  174. }
  175. for(int i = 0; i < static_cast<int> (hullA.size()); i++) {
  176. if(i != lowerIndexA && compare(det(hullA[lowerIndexA], hullB[lowerIndexB], hullA[i]), 0.0f)) {
  177. if(hullB[lowerIndexB].distance(hullA[i]) > hullB[lowerIndexB].distance(hullA[lowerIndexA])) {
  178. lowerIndexA = i;
  179. }
  180. }
  181. }
  182. for(int i = 0; i < static_cast<int> (hullB.size()); i++) {
  183. if(i != lowerIndexB && compare(det(hullA[lowerIndexA], hullB[lowerIndexB], hullB[i]), 0.0f)) {
  184. if(hullA[lowerIndexA].distance(hullB[i]) > hullA[lowerIndexA].distance(hullB[lowerIndexB])) {
  185. lowerIndexB = i;
  186. }
  187. }
  188. }
  189. return false;
  190. }
  191. bool Game::findUpperTangent() {
  192. if(!isUpperTangent(hullA)) {
  193. upperIndexA = (upperIndexA == 0) ? hullA.size() - 1 : upperIndexA - 1;
  194. } else if(!isUpperTangent(hullB)) {
  195. upperIndexB = (upperIndexB + 1) % hullB.size();
  196. }
  197. if(!isUpperTangent(hullA) || !isUpperTangent(hullB)) {
  198. return true;
  199. }
  200. for(int i = 0; i < static_cast<int> (hullA.size()); i++) {
  201. if(i != upperIndexA && compare(det(hullA[upperIndexA], hullB[upperIndexB], hullA[i]), 0.0f)) {
  202. if(hullB[upperIndexB].distance(hullA[i]) > hullB[upperIndexB].distance(hullA[upperIndexA])) {
  203. upperIndexA = i;
  204. }
  205. }
  206. }
  207. for(int i = 0; i < static_cast<int> (hullB.size()); i++) {
  208. if(i != upperIndexB && compare(det(hullA[upperIndexA], hullB[upperIndexB], hullB[i]), 0.0f)) {
  209. if(hullA[upperIndexA].distance(hullB[i]) > hullA[upperIndexA].distance(hullB[upperIndexB])) {
  210. upperIndexB = i;
  211. }
  212. }
  213. }
  214. return false;
  215. }
  216. int Game::findMaxX(const std::vector<Point>& hull) const {
  217. if(hull.size() == 0) {
  218. return -1;
  219. }
  220. int index = 0;
  221. for(int i = 1; i < static_cast<int> (hull.size()); i++) {
  222. if(hull[i].x > hull[index].x) {
  223. index = i;
  224. }
  225. }
  226. return index;
  227. }
  228. int Game::findMinX(const std::vector<Point>& hull) const {
  229. if(hull.size() == 0) {
  230. return -1;
  231. }
  232. int index = 0;
  233. for(int i = 1; i < static_cast<int> (hull.size()); i++) {
  234. if(hull[i].x < hull[index].x) {
  235. index = i;
  236. }
  237. }
  238. return index;
  239. }
  240. void Game::tick() {
  241. if(keys.getDownTime(keyNext) == 1) {
  242. next();
  243. }
  244. if(keys.getDownTime(keyNext) >= 60) {
  245. for(int i = 0; i < 100; i++) {
  246. next();
  247. }
  248. }
  249. }
  250. void Game::next() {
  251. switch(state) {
  252. case SPLIT:
  253. split();
  254. state = MERGE;
  255. break;
  256. case MERGE:
  257. if(merge()) {
  258. state = FIND_LOWER_TANGENT;
  259. } else {
  260. state = END;
  261. hullA.clear();
  262. hullB.clear();
  263. }
  264. break;
  265. case FIND_LOWER_TANGENT:
  266. if(!findLowerTangent()) {
  267. state = FIND_UPPER_TANGENT;
  268. }
  269. break;
  270. case FIND_UPPER_TANGENT:
  271. if(!findUpperTangent()) {
  272. state = FINALIZE_MERGE;
  273. }
  274. break;
  275. case FINALIZE_MERGE:
  276. finalizeMerge();
  277. state = MERGE;
  278. break;
  279. default:
  280. break;
  281. }
  282. }
  283. void Game::render(float lag, Renderer& renderer) const {
  284. (void) lag;
  285. renderer.setPointSize(7);
  286. for(const Point& p : data) {
  287. renderer.drawPoint(normalizeX(p.x), normalizeY(p.y), 0x707070);
  288. }
  289. for(int k = 0; k < 2; k++) {
  290. for(const std::vector<Point> group : groups[k]) {
  291. renderGroup(renderer, group, 0xFFFFFF);
  292. }
  293. }
  294. renderGroup(renderer, hullA, 0xFF00FF);
  295. renderGroup(renderer, hullB, 0xFFFF00);
  296. if(state == FIND_LOWER_TANGENT || state == FIND_UPPER_TANGENT || state == FINALIZE_MERGE) {
  297. renderer.drawLine(
  298. normalizeX(hullA[lowerIndexA].x), normalizeY(hullA[lowerIndexA].y),
  299. normalizeX(hullB[lowerIndexB].x), normalizeY(hullB[lowerIndexB].y),
  300. 0x00FFFF);
  301. renderer.drawLine(
  302. normalizeX(hullA[upperIndexA].x), normalizeY(hullA[upperIndexA].y),
  303. normalizeX(hullB[upperIndexB].x), normalizeY(hullB[upperIndexB].y),
  304. 0x00FFFF);
  305. }
  306. }
  307. bool Game::isRunning() const {
  308. return true;
  309. }
  310. float Game::det(const Point& a, const Point& b, const Point& c) const {
  311. return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);
  312. }
  313. void Game::renderGroup(Renderer& renderer, const std::vector<Point>& group, uint color) const {
  314. static unsigned int colorMap[] = {
  315. 0xFF0000, 0x00FF00, 0x0000FF
  316. };
  317. for(int i = 0; i < static_cast<int> (group.size()); i++) {
  318. int next = (i + 1) % group.size();
  319. renderer.drawLine(
  320. normalizeX(group[i].x),
  321. normalizeY(group[i].y),
  322. normalizeX(group[next].x),
  323. normalizeY(group[next].y),
  324. color);
  325. }
  326. for(int i = 0; i < static_cast<int> (group.size()); i++) {
  327. renderer.drawPoint(normalizeX(group[i].x), normalizeY(group[i].y), colorMap[i % 3]);
  328. }
  329. }
  330. void Game::skip() {
  331. long time = std::chrono::high_resolution_clock::now().time_since_epoch().count();
  332. split();
  333. while(merge()) {
  334. while(findLowerTangent());
  335. while(findUpperTangent());
  336. finalizeMerge();
  337. }
  338. time = std::chrono::high_resolution_clock::now().time_since_epoch().count() - time;
  339. std::cout << "Took " << (time / 1000000.0) << "ms\n";
  340. state = END;
  341. hullA.clear();
  342. hullB.clear();
  343. }
  344. float Game::normalizeX(float f) const {
  345. if(compare(maxX, minX)) {
  346. return 0.0f;
  347. }
  348. f = (f - minX) / (maxX - minX);
  349. return f * 1.90f - 0.95f;
  350. }
  351. float Game::normalizeY(float f) const {
  352. if(compare(maxY, minY)) {
  353. return 0.0f;
  354. }
  355. f = (f - minY) / (maxY - minY);
  356. return f * 1.90f - 0.95f;
  357. }