| 
					
				 | 
			
			
				@@ -6,60 +6,92 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "Game.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "utils/Random.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-bool Game::Point::operator<(const Point& other) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if(std::abs(x - other.x) < 0.0001f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+constexpr float EPS = 0.00000001f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool compare(float a, float b) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return std::abs(a - b) < EPS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Point::operator<(const Point& other) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(x == other.x) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return y < other.y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return x < other.x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-Game::Game(Keys& keys) : keys(keys), keyNext(keys.add(GLFW_KEY_N)), active(0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::cout << "register on " << keys.add(GLFW_KEY_W) << "\n"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+float Point::distance(const Point& other) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    Random r(6476); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for(int i = 0; i < 25; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        data.push_back({r.nextFloat() * 1.9f - 0.95f, r.nextFloat() * 1.9f - 0.95f}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        //float f = r.nextFloat() * 1.9f - 0.95f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        //data.push_back({f * 0.8f, f}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        //data.push_back({r.nextFloat() * 1.9f - 0.95f, 0}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        //data.push_back({0, r.nextFloat() * 1.9f - 0.95f}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Game::Game(Keys& keys, const char* file, bool steps) : keys(keys), keyNext(keys.add(GLFW_KEY_N)), active(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+state(SPLIT) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(file == nullptr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Random r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int amount = steps ? 50 : 1000000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for(int i = 0; i < amount; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data.push_back({r.nextFloat(), r.nextFloat()}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::cout << data.size() << "\n"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(data.size() > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        minX = data[0].x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        maxX = data[0].x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        minY = data[0].y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        maxY = data[0].y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for(const Point& p : data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(p.x < minX) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                minX = p.x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(p.x > maxX) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                maxX = p.x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(p.y < minY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                minY = p.y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(p.y > maxY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                maxY = p.y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    split(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(!steps) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        skip(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-void Game::merge() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Game::merge() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     auto start = groups[active].begin(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     auto end = groups[active].end(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if(start == end) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(groups[1 - active].begin() + 1 == groups[1 - active].end()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(groups[1 - active].begin() == groups[1 - active].end() || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                groups[1 - active].begin() + 1 == groups[1 - active].end()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         active = 1 - active; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } else if(start + 1 == end) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         std::vector<Point> group = groups[active].front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         groups[active].pop_front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         groups[1 - active].push_back(group); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return merge(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::vector<Point> hullA = groups[active].front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hullA = groups[active].front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     groups[active].pop_front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::vector<Point> hullB = groups[active].front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hullB = groups[active].front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     groups[active].pop_front(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    std::vector<Point> mergedHull; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    mergedHull.reserve(hullA.size() + hullB.size()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lowerIndexA = findMaxX(hullA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lowerIndexB = findMinX(hullB); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    int lowerIndexA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    int lowerIndexB; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    findLowerTangent(hullA, hullB, lowerIndexA, lowerIndexB); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    upperIndexA = lowerIndexA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    upperIndexB = lowerIndexB; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    int upperIndexA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    int upperIndexB; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    findUpperTangent(hullA, hullB, upperIndexA, upperIndexB); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Game::finalizeMerge() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::vector<Point> mergedHull; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mergedHull.reserve(hullA.size() + hullB.size()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     while(lowerIndexA != upperIndexA) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mergedHull.push_back(hullA[lowerIndexA]); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -83,23 +115,23 @@ void Game::split() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     while(index + 2 < static_cast<int> (data.size())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         groups[active].push_back(std::vector<Point>()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         std::vector<Point>& v = groups[active].back(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        v.push_back(data[index++]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        v.push_back(data[index++]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        v.push_back(data[index++]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        float f = det(groups[active].back()[0], groups[active].back()[1], groups[active].back()[2]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(std::abs(f) < 0.0001f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(std::abs(v[0].y - v[1].y) > 0.0001f || std::abs(v[1].y - v[2].y) > 0.0001f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v[0].x = (std::abs(v[0].x) < 0.0001f) ? 0.001f : v[0].x * 1.001f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v[0].y = (std::abs(v[0].y) < 0.0001f) ? 0.001f : v[0].y * 1.001f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            f = det(groups[active].back()[0], groups[active].back()[1], groups[active].back()[2]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(f > 0.0f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                std::swap(groups[active].back()[1], groups[active].back()[2]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Point& a = data[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Point& b = data[index + 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Point& c = data[index + 2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        float f = det(a, b, c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(compare(f, 0.0f)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back({std::min(a.x, std::min(b.x, c.x)), std::min(a.y, std::min(b.y, c.y))}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back({std::max(a.x, std::max(b.x, c.x)), std::max(a.y, std::max(b.y, c.y))}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } else if(f > 0.0f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            std::swap(groups[active].back()[1], groups[active].back()[2]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(b); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(b); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            v.push_back(c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        index += 3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int diff = data.size() - index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if(diff > 0) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -111,51 +143,76 @@ void Game::split() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-bool Game::isLowerTangent(const Point& a, const Point& b, const std::vector<Point>& hull) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Game::isLowerTangent(const std::vector<Point>& hull) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for(const Point& p : hull) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        float det = (a.x - p.x) * (b.y - p.y) - (b.x - p.x) * (a.y - p.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(det < -0.00001f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        float f = det(hullA[lowerIndexA], hullB[lowerIndexB], p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(f < -EPS) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-bool Game::isUpperTangent(const Point& a, const Point& b, const std::vector<Point>& hull) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Game::isUpperTangent(const std::vector<Point>& hull) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for(const Point& p : hull) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        float det = (a.x - p.x) * (b.y - p.y) - (b.x - p.x) * (a.y - p.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if(det > 0.00001f) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        float f = det(hullA[upperIndexA], hullB[upperIndexB], p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(f > EPS) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-void Game::findLowerTangent(const std::vector<Point>& hullA, const std::vector<Point>& hullB, int& a, int& b) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    a = findMaxX(hullA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    b = findMinX(hullB); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while(!isLowerTangent(hullA[a], hullB[b], hullA) || !isLowerTangent(hullA[a], hullB[b], hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        while(!isLowerTangent(hullA[a], hullB[b], hullA)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            a = (a + 1) % hullA.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Game::findLowerTangent() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(!isLowerTangent(hullA)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        lowerIndexA = (lowerIndexA + 1) % hullA.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if(!isLowerTangent(hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        lowerIndexB = (lowerIndexB == 0) ? hullB.size() - 1 : lowerIndexB - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(!isLowerTangent(hullA) || !isLowerTangent(hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (hullA.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(i != lowerIndexA && compare(det(hullA[lowerIndexA], hullB[lowerIndexB], hullA[i]), 0.0f)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(hullB[lowerIndexB].distance(hullA[i]) > hullB[lowerIndexB].distance(hullA[lowerIndexA])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lowerIndexA = i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        while(!isLowerTangent(hullA[a], hullB[b], hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            b = (b == 0) ? hullB.size() - 1 : b - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (hullB.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(i != lowerIndexB && compare(det(hullA[lowerIndexA], hullB[lowerIndexB], hullB[i]), 0.0f)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(hullA[lowerIndexA].distance(hullB[i]) > hullA[lowerIndexA].distance(hullB[lowerIndexB])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lowerIndexB = i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-void Game::findUpperTangent(const std::vector<Point>& hullA, const std::vector<Point>& hullB, int& a, int& b) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    a = findMaxX(hullA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    b = findMinX(hullB); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while(!isUpperTangent(hullA[a], hullB[b], hullA) || !isUpperTangent(hullA[a], hullB[b], hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        while(!isUpperTangent(hullA[a], hullB[b], hullA)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            a = (a == 0) ? hullA.size() - 1 : a - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bool Game::findUpperTangent() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(!isUpperTangent(hullA)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        upperIndexA = (upperIndexA == 0) ? hullA.size() - 1 : upperIndexA - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if(!isUpperTangent(hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        upperIndexB = (upperIndexB + 1) % hullB.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(!isUpperTangent(hullA) || !isUpperTangent(hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (hullA.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(i != upperIndexA && compare(det(hullA[upperIndexA], hullB[upperIndexB], hullA[i]), 0.0f)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(hullB[upperIndexB].distance(hullA[i]) > hullB[upperIndexB].distance(hullA[upperIndexA])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                upperIndexA = i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        while(!isUpperTangent(hullA[a], hullB[b], hullB)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            b = (b + 1) % hullB.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (hullB.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(i != upperIndexB && compare(det(hullA[upperIndexA], hullB[upperIndexB], hullB[i]), 0.0f)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(hullA[upperIndexA].distance(hullB[i]) > hullA[upperIndexA].distance(hullB[upperIndexB])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                upperIndexB = i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 int Game::findMaxX(const std::vector<Point>& hull) const { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -186,10 +243,46 @@ int Game::findMinX(const std::vector<Point>& hull) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void Game::tick() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if(keys.getDownTime(keyNext) == 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        merge(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        next(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if(keys.getDownTime(keyNext) >= 40) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        merge(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(keys.getDownTime(keyNext) >= 60) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for(int i = 0; i < 100; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            next(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Game::next() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    switch(state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case SPLIT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            split(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            state = MERGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case MERGE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(merge()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                state = FIND_LOWER_TANGENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                state = END; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hullA.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hullB.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case FIND_LOWER_TANGENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!findLowerTangent()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                state = FIND_UPPER_TANGENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case FIND_UPPER_TANGENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(!findUpperTangent()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                state = FINALIZE_MERGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case FINALIZE_MERGE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            finalizeMerge(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            state = MERGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -197,28 +290,28 @@ void Game::render(float lag, Renderer& renderer) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     (void) lag; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     renderer.setPointSize(7); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for(const Point& p : data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        renderer.drawPoint(p.x, p.y, 0x707070); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        renderer.drawPoint(normalizeX(p.x), normalizeY(p.y), 0x707070); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    static unsigned int color[] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        0xFF0000, 0x00FF00, 0x0000FF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for(int k = 0; k < 2; k++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for(const std::vector<Point> group : groups[k]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for(int i = 0; i < static_cast<int> (group.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                int next = (i + 1) % group.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                renderer.drawLine( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        group[i].x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        group[i].y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        group[next].x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        group[next].y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        0xFFFFFF); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for(int i = 0; i < static_cast<int> (group.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                renderer.drawPoint(group[i].x, group[i].y, color[i % 3]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            renderGroup(renderer, group, 0xFFFFFF); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    renderGroup(renderer, hullA, 0xFF00FF); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    renderGroup(renderer, hullB, 0xFFFF00); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(state == FIND_LOWER_TANGENT || state == FIND_UPPER_TANGENT || state == FINALIZE_MERGE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        renderer.drawLine( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(hullA[lowerIndexA].x), normalizeY(hullA[lowerIndexA].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(hullB[lowerIndexB].x), normalizeY(hullB[lowerIndexB].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                0x00FFFF); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        renderer.drawLine( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(hullA[upperIndexA].x), normalizeY(hullA[upperIndexA].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(hullB[upperIndexB].x), normalizeY(hullB[upperIndexB].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                0x00FFFF); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 bool Game::isRunning() const { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -227,4 +320,50 @@ bool Game::isRunning() const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 float Game::det(const Point& a, const Point& b, const Point& c) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Game::renderGroup(Renderer& renderer, const std::vector<Point>& group, uint color) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    static unsigned int colorMap[] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        0xFF0000, 0x00FF00, 0x0000FF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (group.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int next = (i + 1) % group.size(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        renderer.drawLine( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(group[i].x), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeY(group[i].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeX(group[next].x), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                normalizeY(group[next].y), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                color); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for(int i = 0; i < static_cast<int> (group.size()); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        renderer.drawPoint(normalizeX(group[i].x), normalizeY(group[i].y), colorMap[i % 3]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void Game::skip() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    split(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while(merge()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while(findLowerTangent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while(findUpperTangent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        finalizeMerge(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    state = END; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hullA.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hullB.clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+float Game::normalizeX(float f) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(compare(maxX, minX)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    f = (f - minX) / (maxX - minX); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return f * 1.90f - 0.95f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+float Game::normalizeY(float f) const { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if(compare(maxY, minY)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 0.0f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    f = (f - minY) / (maxY - minY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return f * 1.90f - 0.95f; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |