From dea1dc1f690aa9764e4af2e1bd9fe2c8d4a6f1ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:46:51 +0200 Subject: [PATCH 1/4] Fix getHexagonRequiredNodeId methods with correct shell-based algorithm Replace three separate getHexagonRequiredNodeId1/2/3 methods with a single unified getHexagonRequiredNodeIds method implementing the correct algorithm. Two key fixes from the original pseudocode: 1. All n-relative references use n-2/n-3 instead of n-1/n-2 2. C2 segment formulas use D+5s-2 based calculations instead of Dp-based Agent-Logs-Url: https://github.com/chrxh/alien/sessions/b719d3ee-28a1-4698-8bed-6fa47d8a5ca2 Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com> --- source/EngineInterface/ShapeGenerator.h | 377 +++++++++++------------- 1 file changed, 175 insertions(+), 202 deletions(-) diff --git a/source/EngineInterface/ShapeGenerator.h b/source/EngineInterface/ShapeGenerator.h index bdd60e23c..fc42044be 100644 --- a/source/EngineInterface/ShapeGenerator.h +++ b/source/EngineInterface/ShapeGenerator.h @@ -32,9 +32,7 @@ class ShapeGenerator HOST_DEVICE ShapeGeneratorResult generateNextConstructionDataForSpiralHexagon(); HOST_DEVICE float getHexagonAngle(int n); - HOST_DEVICE int getHexagonRequiredNodeId1(int n); - HOST_DEVICE int getHexagonRequiredNodeId2(int n); - HOST_DEVICE int getHexagonRequiredNodeId3(int n); + HOST_DEVICE void getHexagonRequiredNodeIds(int n, int& r1, int& r2, int& r3); int _nodePos = 0; int _edgePos = 0; @@ -238,9 +236,7 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor int n = _nodePos; result.angle = getHexagonAngle(n); - result.requiredNodeId1 = getHexagonRequiredNodeId1(n); - result.requiredNodeId2 = getHexagonRequiredNodeId2(n); - result.requiredNodeId3 = getHexagonRequiredNodeId3(n); + getHexagonRequiredNodeIds(n, result.requiredNodeId1, result.requiredNodeId2, result.requiredNodeId3); result.numAdditionalConnections = 0; if (result.requiredNodeId1 != -1) { @@ -553,223 +549,200 @@ HOST_DEVICE float ShapeGenerator::getHexagonAngle(int n) } } -HOST_DEVICE int ShapeGenerator::getHexagonRequiredNodeId1(int n) +HOST_DEVICE void ShapeGenerator::getHexagonRequiredNodeIds(int n, int& r1, int& r2, int& r3) { - if (n <= 0) { - return -1; - } - - int k = 1; - while (3 * k * (k + 1) < n) { - ++k; - } - - int firstIndex = 3 * (k - 1) * k + 1; - int local = n - firstIndex; - int side = local / k; - int pos = local % k; - - if (k == 1) { - int ring1[6] = {-1, -1, -1, 2, 3, 4}; - return ring1[local]; - } - - int s = 3 * k * (k - 1) + 1; - int prevS = 3 * (k - 1) * (k - 2) + 1; - - switch (side) { - case 0: - if (pos <= 1) { - return s - 2; - } - return s - (pos + 1); - case 1: - if (pos == 0) { - return -1; - } - return s + k - 2 + pos; - case 2: - if ((k % 2 == 1) && pos == k - 1) { - return -1; - } - return s + 2 * k - 2 + pos; - case 3: - if ((k % 2 == 0) && pos == 2) { - return s + 3 * k - 1; - } - return s + 3 * k - 2 + pos; - case 4: - if (k == 2) { - if (pos == 0) { - return 12; + r1 = -1; + r2 = -1; + r3 = -1; + + if (n < 0) { + return; + } + + if (n <= 21) { + int baseTable[22][3] = {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {2, 1, 0}, {3, -1, -1}, {4, 0, -1}, {5, -1, -1}, + {5, -1, -1}, {-1, -1, -1}, {8, 5, 3}, {9, -1, -1}, {10, 3, -1}, {11, -1, -1}, {12, -1, -1}, {12, 3, 2}, + {14, -1, -1}, {15, 2, -1}, {2, 1, -1}, {17, -1, -1}, {17, 16, -1}, {16, -1, -1}}; + r1 = baseTable[n][0]; + r2 = baseTable[n][1]; + r3 = baseTable[n][2]; + return; + } + + auto shellStart = [](int s) { return 3 * s * s - 2 * s + 1; }; + + int s = 3; + while (shellStart(s + 1) <= n) { + ++s; + } + + int D = shellStart(s); + int Dp = shellStart(s - 1); + int t = n - D; + + if (s % 2 == 1) { + // ODD SHELL + if (t == 0) { + return; + } + + // Segment A: length 2*s - 2, range [1 .. 2*s-2] + if (1 <= t && t <= 2 * s - 2) { + int u = t - 1; + if (u % 2 == 0) { + int k = u / 2; + int y = Dp + (4 * s - 5) - 2 * k; + if (k < s - 2) { + r1 = n - 2; + r2 = y; + r3 = y - 2; + } else { + r1 = n - 2; + r2 = y; + r3 = y - 1; + } + } else { + r1 = n - 2; } - return 14; + return; } - return s + 4 * k - 2 + pos; - case 5: - if (pos == 0) { - return s + 5 * k - 2; - } - return prevS + k - pos; - default: - return -1; - } -} - -HOST_DEVICE int ShapeGenerator::getHexagonRequiredNodeId2(int n) -{ - if (n <= 0) { - return -1; - } - int k = 1; - while (3 * k * (k + 1) < n) { - ++k; - } - - int firstIndex = 3 * (k - 1) * k + 1; - int local = n - firstIndex; - int side = local / k; - int pos = local % k; - - if (k == 1) { - int ring1[6] = {-1, -1, -1, 1, -1, 0}; - return ring1[local]; - } - - switch (side) { - case 0: - if (pos == 0 || pos == k - 1) { - return -1; + // Separator after segment A + if (t == 2 * s - 1) { + return; } - return 3 * k * k - 3 * k - 2 - (pos - 1); - case 1: - if (pos % 2 == 0) { - return -1; - } - return 3 * k * k - 4 * k + 1 - (pos - 1); - case 2: - if (k % 2 == 1) { - if (pos == k - 1) { - return -1; + + // Segment B: length 2*s + 1, range [2*s .. 4*s] + if (2 * s <= t && t <= 4 * s) { + int u = t - 2 * s; + int z0 = D - (4 * s - 3); + if (u == 0) { + r1 = n - 2; + r2 = n - 3; + r3 = z0; + return; } - if (pos % 2 == 0) { - return 3 * k * k - 5 * k + 2 - pos; + if (u % 2 == 1) { + r1 = n - 2; + return; } - return -1; - } - if (pos % 2 == 1) { - return 3 * k * k - 5 * k + 1 - (pos - 1); - } - return -1; - case 3: - if (k % 2 == 1) { - if (pos == 0) { - return 3 * k * k - 2; + int j = (u - 1) / 2; + int z = z0 - 2 * j; + if (j < s - 1) { + r1 = n - 2; + r2 = z; + r3 = z - 2; + } else { + r1 = n - 2; + r2 = z; } - if (pos >= 2 && pos % 2 == 0) { - return 3 * k * k - 6 * k + 4 - (pos - 2); - } - return -1; + return; } - if (pos >= 2 && pos % 2 == 0) { - return 3 * k * k - 6 * k + 3 - ((pos - 2) / 2); + + // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] + if (4 * s + 1 <= t && t <= 5 * s - 1) { + int j = t - (4 * s + 1); + r1 = Dp - j; + r2 = Dp - j - 1; + return; } - return -1; - case 4: - if (k % 2 == 1) { - if (pos % 2 == 1) { - return 3 * k * k - 7 * k + 5 - (pos - 1); + + // Segment C2: length s + 1, range [5*s .. 6*s] + if (5 * s <= t && t <= 6 * s) { + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + r1 = n - 2; + return; + } + if (u == s) { + r1 = E - (s - 1); + return; } - return -1; + r1 = E - (u - 1); + r2 = E - u; + return; } - if (pos % 2 == 0) { - if (k == 2) { - if (pos == 0) { - return 3; + } else { + // EVEN SHELL + if (t == 0) { + return; + } + + // Segment A1: length 2*s, range [1 .. 2*s] + if (1 <= t && t <= 2 * s) { + int u = t - 1; + if (u % 2 == 0) { + int k = u / 2; + int y = Dp + (4 * s - 5) - 2 * k; + if (k < s - 1) { + r1 = n - 2; + r2 = y; + r3 = y - 2; + } else { + r1 = n - 2; + r2 = y; } - return -1; + } else { + r1 = n - 2; } - return 3 * k * k - 7 * k + 6 - pos; + return; } - return -1; - case 5: { - int prevFirstIndex = 3 * (k - 2) * (k - 1) + 1; - return prevFirstIndex + (k - 1 - pos); - } - default: - return -1; - } -} - -HOST_DEVICE int ShapeGenerator::getHexagonRequiredNodeId3(int n) -{ - if (n <= 0) { - return -1; - } - - int k = 1; - while (3 * k * (k + 1) < n) { - ++k; - } - - int firstIndex = 3 * (k - 1) * k + 1; - int local = n - firstIndex; - int side = local / k; - int pos = local % k; - - if (k == 1) { - int ring1[6] = {-1, -1, -1, 0, -1, -1}; - return ring1[local]; - } - switch (side) { - case 0: - return -1; - case 1: - if (pos % 2 == 0) { - return -1; - } - return 3 * k * k - 4 * k - 1 - (pos - 1); - case 2: - if (k % 2 == 1) { - if (pos % 2 == 0 && pos <= k - 3) { - if (k == 3) { - return 13; - } - return 3 * k * k - 5 * k - (pos / 2); + // Segment A2: length 2*s, range [2*s+1 .. 4*s] + if (2 * s + 1 <= t && t <= 4 * s) { + int u = t - (2 * s + 1); + int z0 = Dp + (2 * s - 3); + if (u == 0) { + r1 = n - 2; + return; } - return -1; - } - if (pos % 2 == 1 && pos <= k - 3) { - return 3 * k * k - 5 * k - pos; - } - return -1; - case 3: - if (k % 2 == 1) { - if (pos % 2 == 0) { - return 3 * k * k - 6 * k + 4 - pos; + if (u == 1) { + r1 = n - 3; + r2 = z0; + r3 = z0 - 1; + return; } - return -1; + if (u % 2 == 0) { + r1 = n - 2; + return; + } + int j = (u - 1) / 2; + int z = z0 - 2 * (j - 1) - 1; + if (j < s - 1) { + r1 = n - 2; + r2 = z; + r3 = z - 2; + } else { + r1 = n - 2; + r2 = z; + } + return; } - if (pos >= 2 && pos % 2 == 0) { - return 3 * k * k - 6 * k + 2 - (pos - 2); + + // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] + if (4 * s + 1 <= t && t <= 5 * s - 1) { + int j = t - (4 * s + 1); + r1 = Dp - j; + r2 = Dp - j - 1; + return; } - return -1; - case 4: - if (k % 2 == 1) { - if (pos % 2 == 1) { - return 3 * k * k - 7 * k + 3 - (pos - 1); + + // Segment C2: length s + 1, range [5*s .. 6*s] + if (5 * s <= t && t <= 6 * s) { + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + r1 = n - 2; + return; } - return -1; - } - if (pos % 2 == 0) { - return 3 * k * k - 7 * k + 4 - pos; + if (u == s) { + r1 = E - (s - 1); + return; + } + r1 = E - (u - 1); + r2 = E - u; + return; } - return -1; - case 5: - return -1; - default: - return -1; } } From 9ba5620f61ca482baa8249c6beb90477c2d86b18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:12:35 +0200 Subject: [PATCH 2/4] Unify getHexagonAngle and getHexagonRequiredNodeIds into single getHexagonConstructionData method Merge the two separate hexagon helper methods into a single getHexagonConstructionData(int n) that returns a complete ShapeGeneratorResult with both angle and required node IDs. Uses a shared base table for n<=21 containing both angle and node ID data, eliminating the separate lookup tables. Agent-Logs-Url: https://github.com/chrxh/alien/sessions/26b8ddd9-67b1-46f8-a642-d7f54aaeba32 Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com> --- source/EngineInterface/ShapeGenerator.h | 482 ++++++++++++------------ 1 file changed, 248 insertions(+), 234 deletions(-) diff --git a/source/EngineInterface/ShapeGenerator.h b/source/EngineInterface/ShapeGenerator.h index fc42044be..cb86639a8 100644 --- a/source/EngineInterface/ShapeGenerator.h +++ b/source/EngineInterface/ShapeGenerator.h @@ -31,8 +31,7 @@ class ShapeGenerator HOST_DEVICE ShapeGeneratorResult generateNextConstructionDataForZigzag(); HOST_DEVICE ShapeGeneratorResult generateNextConstructionDataForSpiralHexagon(); - HOST_DEVICE float getHexagonAngle(int n); - HOST_DEVICE void getHexagonRequiredNodeIds(int n, int& r1, int& r2, int& r3); + HOST_DEVICE ShapeGeneratorResult getHexagonConstructionData(int n); int _nodePos = 0; int _edgePos = 0; @@ -232,11 +231,7 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataForHexagon() { - ShapeGeneratorResult result; - int n = _nodePos; - - result.angle = getHexagonAngle(n); - getHexagonRequiredNodeIds(n, result.requiredNodeId1, result.requiredNodeId2, result.requiredNodeId3); + auto result = getHexagonConstructionData(_nodePos); result.numAdditionalConnections = 0; if (result.requiredNodeId1 != -1) { @@ -485,264 +480,283 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor return result; } -HOST_DEVICE float ShapeGenerator::getHexagonAngle(int n) +HOST_DEVICE ShapeGeneratorResult ShapeGenerator::getHexagonConstructionData(int n) { - if (n == 0) { - return 0.0f; - } - - int k = 1; - while (1 + 3 * k * (k + 1) <= n) { - ++k; - } - - int firstIndex = 1 + 3 * (k - 1) * k; - int local = n - firstIndex; - int side = local / k; - int pos = local % k; - bool odd = (k % 2 == 1); + ShapeGeneratorResult result; - if (k == 1) { - float ring1[6] = {60.0f, 60.0f, 120.0f, -120.0f, 120.0f, -120.0f}; - return ring1[local]; + if (n <= 0) { + return result; } - switch (side) { - case 0: - if (pos == 0) { - return odd ? 60.0f : -60.0f; - } - return 0.0f; - case 1: - return (pos % 2 == 0) ? (odd ? 120.0f : -120.0f) : (odd ? -120.0f : 120.0f); - case 2: - if (!odd) { - return (pos % 2 == 0) ? -120.0f : 120.0f; - } - if (pos == k - 2) { - return 60.0f; - } - if (pos == k - 1) { - return 120.0f; - } - return (pos % 2 == 0) ? -120.0f : 120.0f; - case 3: - if (odd) { - return (pos % 2 == 0) ? -120.0f : 120.0f; - } - if (pos == 0) { - return -120.0f; - } - if (pos == 1) { - return -60.0f; - } - return (pos % 2 == 0) ? 120.0f : -120.0f; - case 4: - return (pos % 2 == 0) ? 120.0f : -120.0f; - case 5: - if (pos < k - 1) { - return 0.0f; + if (n <= 21) { + struct BaseEntry + { + float angle; + int r1, r2, r3; + }; + BaseEntry baseTable[21] = { + {60.0f, -1, -1, -1}, // 1 + {60.0f, -1, -1, -1}, // 2 + {120.0f, -1, -1, -1}, // 3 + {-120.0f, 2, 1, 0}, // 4 + {120.0f, 3, -1, -1}, // 5 + {-120.0f, 4, 0, -1}, // 6 + {-60.0f, 5, -1, -1}, // 7 + {0.0f, 5, -1, -1}, // 8 + {-120.0f, -1, -1, -1}, // 9 + {120.0f, 8, 5, 3}, // 10 + {-120.0f, 9, -1, -1}, // 11 + {120.0f, 10, 3, -1}, // 12 + {-120.0f, 11, -1, -1}, // 13 + {-60.0f, 12, -1, -1}, // 14 + {120.0f, 12, 3, 2}, // 15 + {-120.0f, 14, -1, -1}, // 16 + {0.0f, 15, 2, -1}, // 17 + {120.0f, 2, 1, -1}, // 18 + {60.0f, 17, -1, -1}, // 19 + {0.0f, 17, 16, -1}, // 20 + {0.0f, 16, -1, -1}, // 21 + }; + auto const& e = baseTable[n - 1]; + result.angle = e.angle; + result.requiredNodeId1 = e.r1; + result.requiredNodeId2 = e.r2; + result.requiredNodeId3 = e.r3; + return result; + } + + // --- Compute angle using ring decomposition --- + { + int k = 1; + while (1 + 3 * k * (k + 1) <= n) { + ++k; } - return odd ? -120.0f : 120.0f; - default: - return 0.0f; - } -} -HOST_DEVICE void ShapeGenerator::getHexagonRequiredNodeIds(int n, int& r1, int& r2, int& r3) -{ - r1 = -1; - r2 = -1; - r3 = -1; - - if (n < 0) { - return; - } - - if (n <= 21) { - int baseTable[22][3] = {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {2, 1, 0}, {3, -1, -1}, {4, 0, -1}, {5, -1, -1}, - {5, -1, -1}, {-1, -1, -1}, {8, 5, 3}, {9, -1, -1}, {10, 3, -1}, {11, -1, -1}, {12, -1, -1}, {12, 3, 2}, - {14, -1, -1}, {15, 2, -1}, {2, 1, -1}, {17, -1, -1}, {17, 16, -1}, {16, -1, -1}}; - r1 = baseTable[n][0]; - r2 = baseTable[n][1]; - r3 = baseTable[n][2]; - return; + int firstIndex = 1 + 3 * (k - 1) * k; + int local = n - firstIndex; + int side = local / k; + int pos = local % k; + bool odd = (k % 2 == 1); + + switch (side) { + case 0: + result.angle = (pos == 0) ? (odd ? 60.0f : -60.0f) : 0.0f; + break; + case 1: + result.angle = (pos % 2 == 0) ? (odd ? 120.0f : -120.0f) : (odd ? -120.0f : 120.0f); + break; + case 2: + if (!odd) { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } else if (pos == k - 2) { + result.angle = 60.0f; + } else if (pos == k - 1) { + result.angle = 120.0f; + } else { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } + break; + case 3: + if (odd) { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } else if (pos == 0) { + result.angle = -120.0f; + } else if (pos == 1) { + result.angle = -60.0f; + } else { + result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; + } + break; + case 4: + result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; + break; + case 5: + result.angle = (pos < k - 1) ? 0.0f : (odd ? -120.0f : 120.0f); + break; + default: + break; + } } - auto shellStart = [](int s) { return 3 * s * s - 2 * s + 1; }; + // --- Compute required node IDs using shell decomposition --- + { + auto shellStart = [](int s) { return 3 * s * s - 2 * s + 1; }; - int s = 3; - while (shellStart(s + 1) <= n) { - ++s; - } + int s = 3; + while (shellStart(s + 1) <= n) { + ++s; + } - int D = shellStart(s); - int Dp = shellStart(s - 1); - int t = n - D; + int D = shellStart(s); + int Dp = shellStart(s - 1); + int t = n - D; - if (s % 2 == 1) { - // ODD SHELL - if (t == 0) { - return; - } + if (s % 2 == 1) { + // ODD SHELL + if (t == 0) { + return result; + } - // Segment A: length 2*s - 2, range [1 .. 2*s-2] - if (1 <= t && t <= 2 * s - 2) { - int u = t - 1; - if (u % 2 == 0) { - int k = u / 2; - int y = Dp + (4 * s - 5) - 2 * k; - if (k < s - 2) { - r1 = n - 2; - r2 = y; - r3 = y - 2; + // Segment A: length 2*s - 2, range [1 .. 2*s-2] + if (1 <= t && t <= 2 * s - 2) { + int u = t - 1; + if (u % 2 == 0) { + int k = u / 2; + int y = Dp + (4 * s - 5) - 2 * k; + if (k < s - 2) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 1; + } } else { - r1 = n - 2; - r2 = y; - r3 = y - 1; + result.requiredNodeId1 = n - 2; } - } else { - r1 = n - 2; + return result; } - return; - } - // Separator after segment A - if (t == 2 * s - 1) { - return; - } - - // Segment B: length 2*s + 1, range [2*s .. 4*s] - if (2 * s <= t && t <= 4 * s) { - int u = t - 2 * s; - int z0 = D - (4 * s - 3); - if (u == 0) { - r1 = n - 2; - r2 = n - 3; - r3 = z0; - return; - } - if (u % 2 == 1) { - r1 = n - 2; - return; + // Separator after segment A + if (t == 2 * s - 1) { + return result; } - int j = (u - 1) / 2; - int z = z0 - 2 * j; - if (j < s - 1) { - r1 = n - 2; - r2 = z; - r3 = z - 2; - } else { - r1 = n - 2; - r2 = z; + + // Segment B: length 2*s + 1, range [2*s .. 4*s] + if (2 * s <= t && t <= 4 * s) { + int u = t - 2 * s; + int z0 = D - (4 * s - 3); + if (u == 0) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = n - 3; + result.requiredNodeId3 = z0; + return result; + } + if (u % 2 == 1) { + result.requiredNodeId1 = n - 2; + return result; + } + int j = (u - 1) / 2; + int z = z0 - 2 * j; + if (j < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + result.requiredNodeId3 = z - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + } + return result; } - return; - } - // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] - if (4 * s + 1 <= t && t <= 5 * s - 1) { - int j = t - (4 * s + 1); - r1 = Dp - j; - r2 = Dp - j - 1; - return; - } + // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] + if (4 * s + 1 <= t && t <= 5 * s - 1) { + int j = t - (4 * s + 1); + result.requiredNodeId1 = Dp - j; + result.requiredNodeId2 = Dp - j - 1; + return result; + } - // Segment C2: length s + 1, range [5*s .. 6*s] - if (5 * s <= t && t <= 6 * s) { - int u = t - 5 * s; - int E = D + 5 * s - 2; - if (u == 0) { - r1 = n - 2; - return; + // Segment C2: length s + 1, range [5*s .. 6*s] + if (5 * s <= t && t <= 6 * s) { + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + result.requiredNodeId1 = n - 2; + return result; + } + if (u == s) { + result.requiredNodeId1 = E - (s - 1); + return result; + } + result.requiredNodeId1 = E - (u - 1); + result.requiredNodeId2 = E - u; + return result; } - if (u == s) { - r1 = E - (s - 1); - return; + } else { + // EVEN SHELL + if (t == 0) { + return result; } - r1 = E - (u - 1); - r2 = E - u; - return; - } - } else { - // EVEN SHELL - if (t == 0) { - return; - } - // Segment A1: length 2*s, range [1 .. 2*s] - if (1 <= t && t <= 2 * s) { - int u = t - 1; - if (u % 2 == 0) { - int k = u / 2; - int y = Dp + (4 * s - 5) - 2 * k; - if (k < s - 1) { - r1 = n - 2; - r2 = y; - r3 = y - 2; + // Segment A1: length 2*s, range [1 .. 2*s] + if (1 <= t && t <= 2 * s) { + int u = t - 1; + if (u % 2 == 0) { + int k = u / 2; + int y = Dp + (4 * s - 5) - 2 * k; + if (k < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + } } else { - r1 = n - 2; - r2 = y; + result.requiredNodeId1 = n - 2; } - } else { - r1 = n - 2; + return result; } - return; - } - // Segment A2: length 2*s, range [2*s+1 .. 4*s] - if (2 * s + 1 <= t && t <= 4 * s) { - int u = t - (2 * s + 1); - int z0 = Dp + (2 * s - 3); - if (u == 0) { - r1 = n - 2; - return; - } - if (u == 1) { - r1 = n - 3; - r2 = z0; - r3 = z0 - 1; - return; - } - if (u % 2 == 0) { - r1 = n - 2; - return; - } - int j = (u - 1) / 2; - int z = z0 - 2 * (j - 1) - 1; - if (j < s - 1) { - r1 = n - 2; - r2 = z; - r3 = z - 2; - } else { - r1 = n - 2; - r2 = z; + // Segment A2: length 2*s, range [2*s+1 .. 4*s] + if (2 * s + 1 <= t && t <= 4 * s) { + int u = t - (2 * s + 1); + int z0 = Dp + (2 * s - 3); + if (u == 0) { + result.requiredNodeId1 = n - 2; + return result; + } + if (u == 1) { + result.requiredNodeId1 = n - 3; + result.requiredNodeId2 = z0; + result.requiredNodeId3 = z0 - 1; + return result; + } + if (u % 2 == 0) { + result.requiredNodeId1 = n - 2; + return result; + } + int j = (u - 1) / 2; + int z = z0 - 2 * (j - 1) - 1; + if (j < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + result.requiredNodeId3 = z - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + } + return result; } - return; - } - // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] - if (4 * s + 1 <= t && t <= 5 * s - 1) { - int j = t - (4 * s + 1); - r1 = Dp - j; - r2 = Dp - j - 1; - return; - } - - // Segment C2: length s + 1, range [5*s .. 6*s] - if (5 * s <= t && t <= 6 * s) { - int u = t - 5 * s; - int E = D + 5 * s - 2; - if (u == 0) { - r1 = n - 2; - return; + // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] + if (4 * s + 1 <= t && t <= 5 * s - 1) { + int j = t - (4 * s + 1); + result.requiredNodeId1 = Dp - j; + result.requiredNodeId2 = Dp - j - 1; + return result; } - if (u == s) { - r1 = E - (s - 1); - return; + + // Segment C2: length s + 1, range [5*s .. 6*s] + if (5 * s <= t && t <= 6 * s) { + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + result.requiredNodeId1 = n - 2; + return result; + } + if (u == s) { + result.requiredNodeId1 = E - (s - 1); + return result; + } + result.requiredNodeId1 = E - (u - 1); + result.requiredNodeId2 = E - u; + return result; } - r1 = E - (u - 1); - r2 = E - u; - return; } } + + return result; } From f38d641fa3b8021b2127f50c3a1ccaabc932ebb2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:34:08 +0200 Subject: [PATCH 3/4] Inline getHexagonConstructionData into generateNextConstructionDataForHexagon Merge the separate helper method into the single hexagon construction method. Ring decomposition (angle) and shell decomposition (node IDs) now flow together in one method without separate scoped blocks. Agent-Logs-Url: https://github.com/chrxh/alien/sessions/e3cb635f-3518-449e-92cb-7503c19f6df4 Co-authored-by: chrxh <73127001+chrxh@users.noreply.github.com> --- source/EngineInterface/ShapeGenerator.h | 512 +++++++++++------------- 1 file changed, 228 insertions(+), 284 deletions(-) diff --git a/source/EngineInterface/ShapeGenerator.h b/source/EngineInterface/ShapeGenerator.h index cb86639a8..402874e28 100644 --- a/source/EngineInterface/ShapeGenerator.h +++ b/source/EngineInterface/ShapeGenerator.h @@ -31,8 +31,6 @@ class ShapeGenerator HOST_DEVICE ShapeGeneratorResult generateNextConstructionDataForZigzag(); HOST_DEVICE ShapeGeneratorResult generateNextConstructionDataForSpiralHexagon(); - HOST_DEVICE ShapeGeneratorResult getHexagonConstructionData(int n); - int _nodePos = 0; int _edgePos = 0; int _connectedNodePos2 = 0; @@ -231,7 +229,234 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataForHexagon() { - auto result = getHexagonConstructionData(_nodePos); + ShapeGeneratorResult result; + int n = _nodePos; + + if (n <= 0) { + ++_nodePos; + return result; + } + + if (n <= 21) { + struct BaseEntry + { + float angle; + int r1, r2, r3; + }; + BaseEntry baseTable[21] = { + {60.0f, -1, -1, -1}, // 1 + {60.0f, -1, -1, -1}, // 2 + {120.0f, -1, -1, -1}, // 3 + {-120.0f, 2, 1, 0}, // 4 + {120.0f, 3, -1, -1}, // 5 + {-120.0f, 4, 0, -1}, // 6 + {-60.0f, 5, -1, -1}, // 7 + {0.0f, 5, -1, -1}, // 8 + {-120.0f, -1, -1, -1}, // 9 + {120.0f, 8, 5, 3}, // 10 + {-120.0f, 9, -1, -1}, // 11 + {120.0f, 10, 3, -1}, // 12 + {-120.0f, 11, -1, -1}, // 13 + {-60.0f, 12, -1, -1}, // 14 + {120.0f, 12, 3, 2}, // 15 + {-120.0f, 14, -1, -1}, // 16 + {0.0f, 15, 2, -1}, // 17 + {120.0f, 2, 1, -1}, // 18 + {60.0f, 17, -1, -1}, // 19 + {0.0f, 17, 16, -1}, // 20 + {0.0f, 16, -1, -1}, // 21 + }; + auto const& e = baseTable[n - 1]; + result.angle = e.angle; + result.requiredNodeId1 = e.r1; + result.requiredNodeId2 = e.r2; + result.requiredNodeId3 = e.r3; + } else { + // Ring decomposition for angle + int k = 1; + while (1 + 3 * k * (k + 1) <= n) { + ++k; + } + int firstIndex = 1 + 3 * (k - 1) * k; + int local = n - firstIndex; + int side = local / k; + int pos = local % k; + bool odd = (k % 2 == 1); + + switch (side) { + case 0: + result.angle = (pos == 0) ? (odd ? 60.0f : -60.0f) : 0.0f; + break; + case 1: + result.angle = (pos % 2 == 0) ? (odd ? 120.0f : -120.0f) : (odd ? -120.0f : 120.0f); + break; + case 2: + if (!odd) { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } else if (pos == k - 2) { + result.angle = 60.0f; + } else if (pos == k - 1) { + result.angle = 120.0f; + } else { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } + break; + case 3: + if (odd) { + result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; + } else if (pos == 0) { + result.angle = -120.0f; + } else if (pos == 1) { + result.angle = -60.0f; + } else { + result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; + } + break; + case 4: + result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; + break; + case 5: + result.angle = (pos < k - 1) ? 0.0f : (odd ? -120.0f : 120.0f); + break; + default: + break; + } + + // Shell decomposition for required node IDs + auto shellStart = [](int s) { return 3 * s * s - 2 * s + 1; }; + + int s = 3; + while (shellStart(s + 1) <= n) { + ++s; + } + + int D = shellStart(s); + int Dp = shellStart(s - 1); + int t = n - D; + + if (s % 2 == 1) { + // ODD SHELL + if (1 <= t && t <= 2 * s - 2) { + // Segment A: length 2*s - 2 + int u = t - 1; + if (u % 2 == 0) { + int j = u / 2; + int y = Dp + (4 * s - 5) - 2 * j; + if (j < s - 2) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 1; + } + } else { + result.requiredNodeId1 = n - 2; + } + } else if (2 * s <= t && t <= 4 * s) { + // Segment B: length 2*s + 1 + int u = t - 2 * s; + int z0 = D - (4 * s - 3); + if (u == 0) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = n - 3; + result.requiredNodeId3 = z0; + } else if (u % 2 == 1) { + result.requiredNodeId1 = n - 2; + } else { + int j = (u - 1) / 2; + int z = z0 - 2 * j; + if (j < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + result.requiredNodeId3 = z - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + } + } + } else if (4 * s + 1 <= t && t <= 5 * s - 1) { + // Segment C1: length s - 1 + int j = t - (4 * s + 1); + result.requiredNodeId1 = Dp - j; + result.requiredNodeId2 = Dp - j - 1; + } else if (5 * s <= t && t <= 6 * s) { + // Segment C2: length s + 1 + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + result.requiredNodeId1 = n - 2; + } else if (u == s) { + result.requiredNodeId1 = E - (s - 1); + } else { + result.requiredNodeId1 = E - (u - 1); + result.requiredNodeId2 = E - u; + } + } + } else { + // EVEN SHELL + if (1 <= t && t <= 2 * s) { + // Segment A1: length 2*s + int u = t - 1; + if (u % 2 == 0) { + int j = u / 2; + int y = Dp + (4 * s - 5) - 2 * j; + if (j < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + result.requiredNodeId3 = y - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = y; + } + } else { + result.requiredNodeId1 = n - 2; + } + } else if (2 * s + 1 <= t && t <= 4 * s) { + // Segment A2: length 2*s + int u = t - (2 * s + 1); + int z0 = Dp + (2 * s - 3); + if (u == 0) { + result.requiredNodeId1 = n - 2; + } else if (u == 1) { + result.requiredNodeId1 = n - 3; + result.requiredNodeId2 = z0; + result.requiredNodeId3 = z0 - 1; + } else if (u % 2 == 0) { + result.requiredNodeId1 = n - 2; + } else { + int j = (u - 1) / 2; + int z = z0 - 2 * (j - 1) - 1; + if (j < s - 1) { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + result.requiredNodeId3 = z - 2; + } else { + result.requiredNodeId1 = n - 2; + result.requiredNodeId2 = z; + } + } + } else if (4 * s + 1 <= t && t <= 5 * s - 1) { + // Segment C1: length s - 1 + int j = t - (4 * s + 1); + result.requiredNodeId1 = Dp - j; + result.requiredNodeId2 = Dp - j - 1; + } else if (5 * s <= t && t <= 6 * s) { + // Segment C2: length s + 1 + int u = t - 5 * s; + int E = D + 5 * s - 2; + if (u == 0) { + result.requiredNodeId1 = n - 2; + } else if (u == s) { + result.requiredNodeId1 = E - (s - 1); + } else { + result.requiredNodeId1 = E - (u - 1); + result.requiredNodeId2 = E - u; + } + } + } + } result.numAdditionalConnections = 0; if (result.requiredNodeId1 != -1) { @@ -479,284 +704,3 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor } return result; } - -HOST_DEVICE ShapeGeneratorResult ShapeGenerator::getHexagonConstructionData(int n) -{ - ShapeGeneratorResult result; - - if (n <= 0) { - return result; - } - - if (n <= 21) { - struct BaseEntry - { - float angle; - int r1, r2, r3; - }; - BaseEntry baseTable[21] = { - {60.0f, -1, -1, -1}, // 1 - {60.0f, -1, -1, -1}, // 2 - {120.0f, -1, -1, -1}, // 3 - {-120.0f, 2, 1, 0}, // 4 - {120.0f, 3, -1, -1}, // 5 - {-120.0f, 4, 0, -1}, // 6 - {-60.0f, 5, -1, -1}, // 7 - {0.0f, 5, -1, -1}, // 8 - {-120.0f, -1, -1, -1}, // 9 - {120.0f, 8, 5, 3}, // 10 - {-120.0f, 9, -1, -1}, // 11 - {120.0f, 10, 3, -1}, // 12 - {-120.0f, 11, -1, -1}, // 13 - {-60.0f, 12, -1, -1}, // 14 - {120.0f, 12, 3, 2}, // 15 - {-120.0f, 14, -1, -1}, // 16 - {0.0f, 15, 2, -1}, // 17 - {120.0f, 2, 1, -1}, // 18 - {60.0f, 17, -1, -1}, // 19 - {0.0f, 17, 16, -1}, // 20 - {0.0f, 16, -1, -1}, // 21 - }; - auto const& e = baseTable[n - 1]; - result.angle = e.angle; - result.requiredNodeId1 = e.r1; - result.requiredNodeId2 = e.r2; - result.requiredNodeId3 = e.r3; - return result; - } - - // --- Compute angle using ring decomposition --- - { - int k = 1; - while (1 + 3 * k * (k + 1) <= n) { - ++k; - } - - int firstIndex = 1 + 3 * (k - 1) * k; - int local = n - firstIndex; - int side = local / k; - int pos = local % k; - bool odd = (k % 2 == 1); - - switch (side) { - case 0: - result.angle = (pos == 0) ? (odd ? 60.0f : -60.0f) : 0.0f; - break; - case 1: - result.angle = (pos % 2 == 0) ? (odd ? 120.0f : -120.0f) : (odd ? -120.0f : 120.0f); - break; - case 2: - if (!odd) { - result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; - } else if (pos == k - 2) { - result.angle = 60.0f; - } else if (pos == k - 1) { - result.angle = 120.0f; - } else { - result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; - } - break; - case 3: - if (odd) { - result.angle = (pos % 2 == 0) ? -120.0f : 120.0f; - } else if (pos == 0) { - result.angle = -120.0f; - } else if (pos == 1) { - result.angle = -60.0f; - } else { - result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; - } - break; - case 4: - result.angle = (pos % 2 == 0) ? 120.0f : -120.0f; - break; - case 5: - result.angle = (pos < k - 1) ? 0.0f : (odd ? -120.0f : 120.0f); - break; - default: - break; - } - } - - // --- Compute required node IDs using shell decomposition --- - { - auto shellStart = [](int s) { return 3 * s * s - 2 * s + 1; }; - - int s = 3; - while (shellStart(s + 1) <= n) { - ++s; - } - - int D = shellStart(s); - int Dp = shellStart(s - 1); - int t = n - D; - - if (s % 2 == 1) { - // ODD SHELL - if (t == 0) { - return result; - } - - // Segment A: length 2*s - 2, range [1 .. 2*s-2] - if (1 <= t && t <= 2 * s - 2) { - int u = t - 1; - if (u % 2 == 0) { - int k = u / 2; - int y = Dp + (4 * s - 5) - 2 * k; - if (k < s - 2) { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = y; - result.requiredNodeId3 = y - 2; - } else { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = y; - result.requiredNodeId3 = y - 1; - } - } else { - result.requiredNodeId1 = n - 2; - } - return result; - } - - // Separator after segment A - if (t == 2 * s - 1) { - return result; - } - - // Segment B: length 2*s + 1, range [2*s .. 4*s] - if (2 * s <= t && t <= 4 * s) { - int u = t - 2 * s; - int z0 = D - (4 * s - 3); - if (u == 0) { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = n - 3; - result.requiredNodeId3 = z0; - return result; - } - if (u % 2 == 1) { - result.requiredNodeId1 = n - 2; - return result; - } - int j = (u - 1) / 2; - int z = z0 - 2 * j; - if (j < s - 1) { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = z; - result.requiredNodeId3 = z - 2; - } else { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = z; - } - return result; - } - - // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] - if (4 * s + 1 <= t && t <= 5 * s - 1) { - int j = t - (4 * s + 1); - result.requiredNodeId1 = Dp - j; - result.requiredNodeId2 = Dp - j - 1; - return result; - } - - // Segment C2: length s + 1, range [5*s .. 6*s] - if (5 * s <= t && t <= 6 * s) { - int u = t - 5 * s; - int E = D + 5 * s - 2; - if (u == 0) { - result.requiredNodeId1 = n - 2; - return result; - } - if (u == s) { - result.requiredNodeId1 = E - (s - 1); - return result; - } - result.requiredNodeId1 = E - (u - 1); - result.requiredNodeId2 = E - u; - return result; - } - } else { - // EVEN SHELL - if (t == 0) { - return result; - } - - // Segment A1: length 2*s, range [1 .. 2*s] - if (1 <= t && t <= 2 * s) { - int u = t - 1; - if (u % 2 == 0) { - int k = u / 2; - int y = Dp + (4 * s - 5) - 2 * k; - if (k < s - 1) { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = y; - result.requiredNodeId3 = y - 2; - } else { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = y; - } - } else { - result.requiredNodeId1 = n - 2; - } - return result; - } - - // Segment A2: length 2*s, range [2*s+1 .. 4*s] - if (2 * s + 1 <= t && t <= 4 * s) { - int u = t - (2 * s + 1); - int z0 = Dp + (2 * s - 3); - if (u == 0) { - result.requiredNodeId1 = n - 2; - return result; - } - if (u == 1) { - result.requiredNodeId1 = n - 3; - result.requiredNodeId2 = z0; - result.requiredNodeId3 = z0 - 1; - return result; - } - if (u % 2 == 0) { - result.requiredNodeId1 = n - 2; - return result; - } - int j = (u - 1) / 2; - int z = z0 - 2 * (j - 1) - 1; - if (j < s - 1) { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = z; - result.requiredNodeId3 = z - 2; - } else { - result.requiredNodeId1 = n - 2; - result.requiredNodeId2 = z; - } - return result; - } - - // Segment C1: length s - 1, range [4*s+1 .. 5*s-1] - if (4 * s + 1 <= t && t <= 5 * s - 1) { - int j = t - (4 * s + 1); - result.requiredNodeId1 = Dp - j; - result.requiredNodeId2 = Dp - j - 1; - return result; - } - - // Segment C2: length s + 1, range [5*s .. 6*s] - if (5 * s <= t && t <= 6 * s) { - int u = t - 5 * s; - int E = D + 5 * s - 2; - if (u == 0) { - result.requiredNodeId1 = n - 2; - return result; - } - if (u == s) { - result.requiredNodeId1 = E - (s - 1); - return result; - } - result.requiredNodeId1 = E - (u - 1); - result.requiredNodeId2 = E - u; - return result; - } - } - } - - return result; -} From 3a6cce3082d899f786c44315ab1d3ea286330643 Mon Sep 17 00:00:00 2001 From: Christian Heinemann Date: Thu, 9 Apr 2026 16:56:10 +0200 Subject: [PATCH 4/4] Comment adjusted --- source/EngineInterface/ShapeGenerator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/EngineInterface/ShapeGenerator.h b/source/EngineInterface/ShapeGenerator.h index 402874e28..aac788d98 100644 --- a/source/EngineInterface/ShapeGenerator.h +++ b/source/EngineInterface/ShapeGenerator.h @@ -272,7 +272,7 @@ HOST_DEVICE ShapeGeneratorResult ShapeGenerator::generateNextConstructionDataFor result.requiredNodeId2 = e.r2; result.requiredNodeId3 = e.r3; } else { - // Ring decomposition for angle + // Shell decomposition for angle int k = 1; while (1 + 3 * k * (k + 1) <= n) { ++k;