cubegin 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +674 -0
  3. package/NOTICE +11 -0
  4. package/README.md +49 -0
  5. package/dist/scramble-core/src/batch.mjs +18 -0
  6. package/dist/scramble-core/src/generator.d.mts +35 -0
  7. package/dist/scramble-core/src/generator.mjs +136 -0
  8. package/dist/scramble-core/src/generators/clock.d.mts +11 -0
  9. package/dist/scramble-core/src/generators/clock.mjs +32 -0
  10. package/dist/scramble-core/src/generators/cube-random-turns.d.mts +11 -0
  11. package/dist/scramble-core/src/generators/cube-random-turns.mjs +54 -0
  12. package/dist/scramble-core/src/generators/four-by-four.d.mts +14 -0
  13. package/dist/scramble-core/src/generators/four-by-four.mjs +43 -0
  14. package/dist/scramble-core/src/generators/megaminx.d.mts +11 -0
  15. package/dist/scramble-core/src/generators/megaminx.mjs +18 -0
  16. package/dist/scramble-core/src/generators/pyraminx.d.mts +11 -0
  17. package/dist/scramble-core/src/generators/pyraminx.mjs +17 -0
  18. package/dist/scramble-core/src/generators/skewb.d.mts +11 -0
  19. package/dist/scramble-core/src/generators/skewb.mjs +17 -0
  20. package/dist/scramble-core/src/generators/square1.d.mts +11 -0
  21. package/dist/scramble-core/src/generators/square1.mjs +28 -0
  22. package/dist/scramble-core/src/generators/three-by-three.d.mts +25 -0
  23. package/dist/scramble-core/src/generators/three-by-three.mjs +85 -0
  24. package/dist/scramble-core/src/generators/two-by-two.d.mts +11 -0
  25. package/dist/scramble-core/src/generators/two-by-two.mjs +17 -0
  26. package/dist/scramble-core/src/random-source.d.mts +7 -0
  27. package/dist/scramble-core/src/random-source.mjs +8 -0
  28. package/dist/scramble-core/src/solvers/min2phase/coord-cube.mjs +10 -0
  29. package/dist/scramble-core/src/solvers/min2phase/cubie-cube.mjs +246 -0
  30. package/dist/scramble-core/src/solvers/min2phase/engine.mjs +1281 -0
  31. package/dist/scramble-core/src/solvers/min2phase/search-wca.mjs +21 -0
  32. package/dist/scramble-core/src/solvers/min2phase/search.mjs +25 -0
  33. package/dist/scramble-core/src/solvers/min2phase/tools.mjs +169 -0
  34. package/dist/scramble-core/src/solvers/min2phase/util.mjs +30 -0
  35. package/dist/scramble-core/src/solvers/pyraminx-solver.d.mts +17 -0
  36. package/dist/scramble-core/src/solvers/pyraminx-solver.mjs +350 -0
  37. package/dist/scramble-core/src/solvers/skewb-solver.d.mts +15 -0
  38. package/dist/scramble-core/src/solvers/skewb-solver.mjs +399 -0
  39. package/dist/scramble-core/src/solvers/sq12phase/full-cube.mjs +212 -0
  40. package/dist/scramble-core/src/solvers/sq12phase/search.mjs +520 -0
  41. package/dist/scramble-core/src/solvers/sq12phase/shape.mjs +214 -0
  42. package/dist/scramble-core/src/solvers/sq12phase/square.mjs +135 -0
  43. package/dist/scramble-core/src/solvers/threephase/center.mjs +798 -0
  44. package/dist/scramble-core/src/solvers/threephase/edge.mjs +632 -0
  45. package/dist/scramble-core/src/solvers/threephase/full-cube.mjs +554 -0
  46. package/dist/scramble-core/src/solvers/threephase/search.mjs +262 -0
  47. package/dist/scramble-core/src/solvers/threephase/tables.mjs +201 -0
  48. package/dist/scramble-core/src/solvers/two-by-two-solver.d.mts +15 -0
  49. package/dist/scramble-core/src/solvers/two-by-two-solver.mjs +298 -0
  50. package/dist/scramble-core.d.mts +15 -0
  51. package/dist/scramble-core.mjs +15 -0
  52. package/dist/scramble-image/src/color.d.mts +12 -0
  53. package/dist/scramble-image/src/color.mjs +11 -0
  54. package/dist/scramble-image/src/render.d.mts +10 -0
  55. package/dist/scramble-image/src/render.mjs +71 -0
  56. package/dist/scramble-image/src/renderers/clock.d.mts +6 -0
  57. package/dist/scramble-image/src/renderers/clock.mjs +145 -0
  58. package/dist/scramble-image/src/renderers/cube-isometric.d.mts +8 -0
  59. package/dist/scramble-image/src/renderers/cube-isometric.mjs +204 -0
  60. package/dist/scramble-image/src/renderers/cube-net.d.mts +8 -0
  61. package/dist/scramble-image/src/renderers/cube-net.mjs +52 -0
  62. package/dist/scramble-image/src/renderers/megaminx-isometric.d.mts +9 -0
  63. package/dist/scramble-image/src/renderers/megaminx-isometric.mjs +320 -0
  64. package/dist/scramble-image/src/renderers/megaminx.d.mts +9 -0
  65. package/dist/scramble-image/src/renderers/megaminx.mjs +173 -0
  66. package/dist/scramble-image/src/renderers/pyraminx-isometric.d.mts +9 -0
  67. package/dist/scramble-image/src/renderers/pyraminx-isometric.mjs +185 -0
  68. package/dist/scramble-image/src/renderers/pyraminx.d.mts +9 -0
  69. package/dist/scramble-image/src/renderers/pyraminx.mjs +111 -0
  70. package/dist/scramble-image/src/renderers/skewb-isometric.d.mts +9 -0
  71. package/dist/scramble-image/src/renderers/skewb-isometric.mjs +233 -0
  72. package/dist/scramble-image/src/renderers/skewb.d.mts +9 -0
  73. package/dist/scramble-image/src/renderers/skewb.mjs +187 -0
  74. package/dist/scramble-image/src/renderers/square1.d.mts +10 -0
  75. package/dist/scramble-image/src/renderers/square1.mjs +253 -0
  76. package/dist/scramble-image/src/svg/svg-document.d.mts +6 -0
  77. package/dist/scramble-image/src/svg/svg-document.mjs +7 -0
  78. package/dist/scramble-image/src/svg/svg-elements.d.mts +15 -0
  79. package/dist/scramble-image/src/svg/svg-elements.mjs +25 -0
  80. package/dist/scramble-image/src/svg/svg-serialize.mjs +29 -0
  81. package/dist/scramble-image.d.mts +15 -0
  82. package/dist/scramble-image.mjs +15 -0
  83. package/dist/scramble-puzzle/src/algorithm.d.mts +8 -0
  84. package/dist/scramble-puzzle/src/algorithm.mjs +16 -0
  85. package/dist/scramble-puzzle/src/algorithm2.mjs +16 -0
  86. package/dist/scramble-puzzle/src/clock/clock-definition.d.mts +8 -0
  87. package/dist/scramble-puzzle/src/clock/clock-definition.mjs +18 -0
  88. package/dist/scramble-puzzle/src/clock/clock-definition2.mjs +18 -0
  89. package/dist/scramble-puzzle/src/clock/clock-parser.d.mts +18 -0
  90. package/dist/scramble-puzzle/src/clock/clock-parser.mjs +35 -0
  91. package/dist/scramble-puzzle/src/clock/clock-parser2.mjs +35 -0
  92. package/dist/scramble-puzzle/src/clock/clock-state.d.mts +8 -0
  93. package/dist/scramble-puzzle/src/clock/clock-state.mjs +212 -0
  94. package/dist/scramble-puzzle/src/clock/clock-state2.d.mts +13 -0
  95. package/dist/scramble-puzzle/src/clock/clock-state2.mjs +212 -0
  96. package/dist/scramble-puzzle/src/cube/cube-definition.d.mts +9 -0
  97. package/dist/scramble-puzzle/src/cube/cube-definition.mjs +18 -0
  98. package/dist/scramble-puzzle/src/cube/cube-definition2.mjs +18 -0
  99. package/dist/scramble-puzzle/src/cube/cube-move.d.mts +4 -0
  100. package/dist/scramble-puzzle/src/cube/cube-move2.d.mts +17 -0
  101. package/dist/scramble-puzzle/src/cube/cube-parser.d.mts +7 -0
  102. package/dist/scramble-puzzle/src/cube/cube-parser.mjs +60 -0
  103. package/dist/scramble-puzzle/src/cube/cube-parser2.mjs +60 -0
  104. package/dist/scramble-puzzle/src/cube/cube-state.d.mts +12 -0
  105. package/dist/scramble-puzzle/src/cube/cube-state.mjs +187 -0
  106. package/dist/scramble-puzzle/src/cube/cube-state2.d.mts +15 -0
  107. package/dist/scramble-puzzle/src/cube/cube-state2.mjs +187 -0
  108. package/dist/scramble-puzzle/src/errors.d.mts +15 -0
  109. package/dist/scramble-puzzle/src/errors.mjs +24 -0
  110. package/dist/scramble-puzzle/src/errors2.mjs +30 -0
  111. package/dist/scramble-puzzle/src/events.d.mts +5 -0
  112. package/dist/scramble-puzzle/src/events.mjs +90 -0
  113. package/dist/scramble-puzzle/src/events2.d.mts +98 -0
  114. package/dist/scramble-puzzle/src/events2.mjs +109 -0
  115. package/dist/scramble-puzzle/src/index.mjs +22 -0
  116. package/dist/scramble-puzzle/src/megaminx/megaminx-definition.d.mts +8 -0
  117. package/dist/scramble-puzzle/src/megaminx/megaminx-definition.mjs +18 -0
  118. package/dist/scramble-puzzle/src/megaminx/megaminx-definition2.mjs +18 -0
  119. package/dist/scramble-puzzle/src/megaminx/megaminx-parser.d.mts +5 -0
  120. package/dist/scramble-puzzle/src/megaminx/megaminx-parser.mjs +57 -0
  121. package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.d.mts +20 -0
  122. package/dist/scramble-puzzle/src/megaminx/megaminx-parser2.mjs +57 -0
  123. package/dist/scramble-puzzle/src/megaminx/megaminx-state.d.mts +9 -0
  124. package/dist/scramble-puzzle/src/megaminx/megaminx-state.mjs +112 -0
  125. package/dist/scramble-puzzle/src/megaminx/megaminx-state2.d.mts +14 -0
  126. package/dist/scramble-puzzle/src/megaminx/megaminx-state2.mjs +112 -0
  127. package/dist/scramble-puzzle/src/puzzle-definition.d.mts +19 -0
  128. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.d.mts +8 -0
  129. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition.mjs +18 -0
  130. package/dist/scramble-puzzle/src/pyraminx/pyraminx-definition2.mjs +18 -0
  131. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.d.mts +5 -0
  132. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser.mjs +34 -0
  133. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.d.mts +21 -0
  134. package/dist/scramble-puzzle/src/pyraminx/pyraminx-parser2.mjs +34 -0
  135. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.d.mts +11 -0
  136. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state.mjs +90 -0
  137. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.d.mts +14 -0
  138. package/dist/scramble-puzzle/src/pyraminx/pyraminx-state2.mjs +90 -0
  139. package/dist/scramble-puzzle/src/registry.d.mts +11 -0
  140. package/dist/scramble-puzzle/src/registry.mjs +13 -0
  141. package/dist/scramble-puzzle/src/skewb/skewb-definition.d.mts +8 -0
  142. package/dist/scramble-puzzle/src/skewb/skewb-definition.mjs +18 -0
  143. package/dist/scramble-puzzle/src/skewb/skewb-definition2.mjs +18 -0
  144. package/dist/scramble-puzzle/src/skewb/skewb-parser.d.mts +5 -0
  145. package/dist/scramble-puzzle/src/skewb/skewb-parser.mjs +33 -0
  146. package/dist/scramble-puzzle/src/skewb/skewb-parser2.d.mts +14 -0
  147. package/dist/scramble-puzzle/src/skewb/skewb-parser2.mjs +33 -0
  148. package/dist/scramble-puzzle/src/skewb/skewb-state.d.mts +11 -0
  149. package/dist/scramble-puzzle/src/skewb/skewb-state.mjs +75 -0
  150. package/dist/scramble-puzzle/src/skewb/skewb-state2.d.mts +14 -0
  151. package/dist/scramble-puzzle/src/skewb/skewb-state2.mjs +75 -0
  152. package/dist/scramble-puzzle/src/square1/square1-definition.d.mts +8 -0
  153. package/dist/scramble-puzzle/src/square1/square1-definition.mjs +18 -0
  154. package/dist/scramble-puzzle/src/square1/square1-definition2.mjs +18 -0
  155. package/dist/scramble-puzzle/src/square1/square1-parser.d.mts +17 -0
  156. package/dist/scramble-puzzle/src/square1/square1-parser.mjs +43 -0
  157. package/dist/scramble-puzzle/src/square1/square1-parser2.mjs +47 -0
  158. package/dist/scramble-puzzle/src/square1/square1-state.d.mts +9 -0
  159. package/dist/scramble-puzzle/src/square1/square1-state.mjs +115 -0
  160. package/dist/scramble-puzzle/src/square1/square1-state2.d.mts +21 -0
  161. package/dist/scramble-puzzle/src/square1/square1-state2.mjs +115 -0
  162. package/dist/scramble-puzzle.d.mts +25 -0
  163. package/dist/scramble-puzzle.mjs +23 -0
  164. package/package.json +37 -0
@@ -0,0 +1,204 @@
1
+ import { DEFAULT_CUBE_COLORS } from "../color.mjs";
2
+ import { createSvgDocument } from "../svg/svg-document.mjs";
3
+ import { path } from "../svg/svg-elements.mjs";
4
+ //#region .build/vendor/scramble-image/src/renderers/cube-isometric.ts
5
+ const PADDING = 6;
6
+ const VIEW_GAP = 28;
7
+ const STROKE = "#000000";
8
+ const STROKE_WIDTH = 2.5;
9
+ const FACE_ORDER = [
10
+ "R",
11
+ "U",
12
+ "F",
13
+ "L",
14
+ "D",
15
+ "B"
16
+ ];
17
+ const point = (x, y) => ({
18
+ x,
19
+ y
20
+ });
21
+ const transformFromCorners = (topLeft, topRight, bottomRight, bottomLeft) => ({
22
+ topLeft,
23
+ topRight,
24
+ bottomRight,
25
+ bottomLeft
26
+ });
27
+ const createCornerViewPoints = (geometry) => ({
28
+ top: point(geometry.centerX, geometry.topY),
29
+ leftTop: point(geometry.centerX - geometry.topHalfWidth, geometry.topEdgeY),
30
+ rightTop: point(geometry.centerX + geometry.topHalfWidth, geometry.topEdgeY),
31
+ center: point(geometry.centerX, geometry.centerY),
32
+ leftBottom: point(geometry.centerX - geometry.bottomHalfWidth, geometry.bottomEdgeY),
33
+ rightBottom: point(geometry.centerX + geometry.bottomHalfWidth, geometry.bottomEdgeY),
34
+ bottom: point(geometry.centerX, geometry.bottomY)
35
+ });
36
+ const frontView = createCornerViewPoints({
37
+ centerX: 84,
38
+ topY: 6,
39
+ topEdgeY: 42,
40
+ centerY: 80,
41
+ bottomEdgeY: 116,
42
+ bottomY: 160,
43
+ topHalfWidth: 74,
44
+ bottomHalfWidth: 74
45
+ });
46
+ const backView = createCornerViewPoints({
47
+ centerX: 84,
48
+ topY: 6,
49
+ topEdgeY: 42,
50
+ centerY: 80,
51
+ bottomEdgeY: 116,
52
+ bottomY: 160,
53
+ topHalfWidth: 74,
54
+ bottomHalfWidth: 74
55
+ });
56
+ const FRONT_VIEW_FACES = [
57
+ {
58
+ face: "U",
59
+ transform: transformFromCorners(frontView.leftTop, frontView.top, frontView.rightTop, frontView.center)
60
+ },
61
+ {
62
+ face: "F",
63
+ transform: transformFromCorners(frontView.leftTop, frontView.center, frontView.bottom, frontView.leftBottom)
64
+ },
65
+ {
66
+ face: "R",
67
+ transform: transformFromCorners(frontView.center, frontView.rightTop, frontView.rightBottom, frontView.bottom)
68
+ }
69
+ ];
70
+ const BACK_VIEW_FACES = [
71
+ {
72
+ face: "D",
73
+ transform: transformFromCorners(backView.leftTop, backView.top, backView.rightTop, backView.center)
74
+ },
75
+ {
76
+ face: "B",
77
+ transform: transformFromCorners(backView.leftTop, backView.center, backView.bottom, backView.leftBottom)
78
+ },
79
+ {
80
+ face: "L",
81
+ transform: transformFromCorners(backView.center, backView.rightTop, backView.rightBottom, backView.bottom)
82
+ }
83
+ ];
84
+ const interpolatePoint = (start, end, ratio) => ({
85
+ x: start.x + (end.x - start.x) * ratio,
86
+ y: start.y + (end.y - start.y) * ratio
87
+ });
88
+ const transformPoint = (pointValue, transform) => {
89
+ return interpolatePoint(interpolatePoint(transform.topLeft, transform.topRight, pointValue.x), interpolatePoint(transform.bottomLeft, transform.bottomRight, pointValue.x), pointValue.y);
90
+ };
91
+ const stickerPoints = (row, col, size, transform) => {
92
+ const left = col / size;
93
+ const right = (col + 1) / size;
94
+ const top = row / size;
95
+ const bottom = (row + 1) / size;
96
+ return [
97
+ transformPoint(point(left, top), transform),
98
+ transformPoint(point(right, top), transform),
99
+ transformPoint(point(right, bottom), transform),
100
+ transformPoint(point(left, bottom), transform)
101
+ ];
102
+ };
103
+ const polygonPath = (points) => {
104
+ const [firstPoint, ...remainingPoints] = points;
105
+ if (!firstPoint) return "";
106
+ return [
107
+ `M ${formatCoordinate(firstPoint.x)} ${formatCoordinate(firstPoint.y)}`,
108
+ ...remainingPoints.map((pointValue) => `L ${formatCoordinate(pointValue.x)} ${formatCoordinate(pointValue.y)}`),
109
+ "Z"
110
+ ].join(" ");
111
+ };
112
+ const formatCoordinate = (value) => Number(value.toFixed(3));
113
+ const lineworkPath = (segments) => segments.map(({ start, end }) => `M ${formatCoordinate(start.x)} ${formatCoordinate(start.y)} L ${formatCoordinate(end.x)} ${formatCoordinate(end.y)}`).join(" ");
114
+ const cubeFaceIndex = (face) => FACE_ORDER.indexOf(face);
115
+ const createStickerPolygonsForView = (state, colors, faces) => {
116
+ const stickers = [];
117
+ for (const { face, transform } of faces) {
118
+ const faceIndex = cubeFaceIndex(face);
119
+ const faceImage = state.image[faceIndex];
120
+ for (let row = 0; row < state.size; row += 1) for (let col = 0; col < state.size; col += 1) stickers.push({
121
+ points: stickerPoints(row, col, state.size, transform),
122
+ fill: colors[faceImage[row][col]]
123
+ });
124
+ }
125
+ return stickers;
126
+ };
127
+ const createStickerPolygons = (state, colors) => {
128
+ const frontViewStickers = createStickerPolygonsForView(state, colors, FRONT_VIEW_FACES);
129
+ const backViewStickers = createStickerPolygonsForView(state, colors, BACK_VIEW_FACES);
130
+ const [frontMinX, frontMinY, frontMaxX] = boundsFor(frontViewStickers);
131
+ const [backMinX, backMinY] = boundsFor(backViewStickers);
132
+ const backOffsetX = frontMaxX - frontMinX + VIEW_GAP;
133
+ const frontOffsetY = Math.max(0, backMinY - frontMinY);
134
+ const backOffsetY = Math.max(0, frontMinY - backMinY);
135
+ return [...frontViewStickers.map((sticker) => ({
136
+ points: translatePoints(sticker.points, -frontMinX, -frontMinY + frontOffsetY),
137
+ fill: sticker.fill
138
+ })), ...backViewStickers.map((sticker) => ({
139
+ points: translatePoints(sticker.points, backOffsetX - backMinX, -backMinY + backOffsetY),
140
+ fill: sticker.fill
141
+ }))];
142
+ };
143
+ const segmentKey = ({ start, end }) => {
144
+ const startKey = `${formatCoordinate(start.x)},${formatCoordinate(start.y)}`;
145
+ const endKey = `${formatCoordinate(end.x)},${formatCoordinate(end.y)}`;
146
+ return startKey < endKey ? `${startKey}|${endKey}` : `${endKey}|${startKey}`;
147
+ };
148
+ const createLineworkSegments = (stickers) => {
149
+ const segments = /* @__PURE__ */ new Map();
150
+ for (const sticker of stickers) for (let index = 0; index < sticker.points.length; index += 1) {
151
+ const segment = {
152
+ start: sticker.points[index],
153
+ end: sticker.points[(index + 1) % sticker.points.length]
154
+ };
155
+ segments.set(segmentKey(segment), segment);
156
+ }
157
+ return [...segments.values()];
158
+ };
159
+ const drawStickers = (stickers) => stickers.map((sticker) => path({
160
+ d: polygonPath(sticker.points.map((pointValue) => ({
161
+ x: pointValue.x + PADDING,
162
+ y: pointValue.y + PADDING
163
+ }))),
164
+ fill: sticker.fill,
165
+ stroke: "none"
166
+ }));
167
+ const drawLinework = (stickers) => path({
168
+ d: lineworkPath(createLineworkSegments(stickers.map((sticker) => ({
169
+ points: sticker.points.map((pointValue) => ({
170
+ x: pointValue.x + PADDING,
171
+ y: pointValue.y + PADDING
172
+ })),
173
+ fill: sticker.fill
174
+ })))),
175
+ fill: "none",
176
+ stroke: STROKE,
177
+ "stroke-linecap": "round",
178
+ "stroke-linejoin": "round",
179
+ "stroke-width": STROKE_WIDTH
180
+ });
181
+ const translatePoints = (points, offsetX, offsetY) => points.map((pointValue) => ({
182
+ x: pointValue.x + offsetX,
183
+ y: pointValue.y + offsetY
184
+ }));
185
+ const boundsFor = (stickers) => {
186
+ const points = stickers.flatMap((sticker) => sticker.points);
187
+ return [
188
+ Math.min(...points.map((pointValue) => pointValue.x)),
189
+ Math.min(...points.map((pointValue) => pointValue.y)),
190
+ Math.max(...points.map((pointValue) => pointValue.x)),
191
+ Math.max(...points.map((pointValue) => pointValue.y))
192
+ ];
193
+ };
194
+ const renderCubeIsometric = (state, colorScheme = {}) => {
195
+ const stickers = createStickerPolygons(state, {
196
+ ...DEFAULT_CUBE_COLORS,
197
+ ...colorScheme
198
+ });
199
+ const [, , maxX, maxY] = boundsFor(stickers);
200
+ const nodes = [...drawStickers(stickers), drawLinework(stickers)];
201
+ return createSvgDocument(Math.ceil(maxX + 2 * PADDING), Math.ceil(maxY + 2 * PADDING), nodes);
202
+ };
203
+ //#endregion
204
+ export { renderCubeIsometric };
@@ -0,0 +1,8 @@
1
+ import { CubeFacelet, CubeState } from "../../../scramble-puzzle/src/cube/cube-state.mjs";
2
+ import { HexColor } from "../color.mjs";
3
+
4
+ //#region .build/vendor/scramble-image/src/renderers/cube-net.d.ts
5
+ type CubeColorScheme = Partial<Record<CubeFacelet, HexColor>>;
6
+ declare const renderCubeNet: (state: CubeState, colorScheme?: CubeColorScheme) => string;
7
+ //#endregion
8
+ export { renderCubeNet };
@@ -0,0 +1,52 @@
1
+ import { DEFAULT_CUBE_COLORS } from "../color.mjs";
2
+ import { createSvgDocument } from "../svg/svg-document.mjs";
3
+ import { rect } from "../svg/svg-elements.mjs";
4
+ //#region .build/vendor/scramble-image/src/renderers/cube-net.ts
5
+ const GAP = 2;
6
+ const STICKER = 10;
7
+ const STROKE = "#000000";
8
+ const STROKE_WIDTH = 1;
9
+ const FACE_ORDER = [
10
+ "R",
11
+ "U",
12
+ "F",
13
+ "L",
14
+ "D",
15
+ "B"
16
+ ];
17
+ const createFaceOrigins = (unit) => ({
18
+ L: [GAP, 2 * GAP + unit],
19
+ D: [2 * GAP + unit, 3 * GAP + 2 * unit],
20
+ B: [4 * GAP + 3 * unit, 2 * GAP + unit],
21
+ R: [3 * GAP + 2 * unit, 2 * GAP + unit],
22
+ U: [2 * GAP + unit, GAP],
23
+ F: [2 * GAP + unit, 2 * GAP + unit]
24
+ });
25
+ const renderCubeNet = (state, colorScheme = {}) => {
26
+ const colors = {
27
+ ...DEFAULT_CUBE_COLORS,
28
+ ...colorScheme
29
+ };
30
+ const unit = state.size * STICKER;
31
+ const width = (unit + GAP) * 4 + GAP;
32
+ const height = (unit + GAP) * 3 + GAP;
33
+ const faceOrigins = createFaceOrigins(unit);
34
+ const nodes = [];
35
+ for (const [face, [originX, originY]] of Object.entries(faceOrigins)) {
36
+ const faceIndex = FACE_ORDER.indexOf(face);
37
+ const stickers = state.image[faceIndex];
38
+ for (let row = 0; row < state.size; row += 1) for (let col = 0; col < state.size; col += 1) nodes.push(rect({
39
+ x: originX + col * STICKER,
40
+ y: originY + row * STICKER,
41
+ width: STICKER,
42
+ height: STICKER,
43
+ fill: colors[stickers[row][col]],
44
+ stroke: STROKE,
45
+ "stroke-width": STROKE_WIDTH,
46
+ "shape-rendering": "crispEdges"
47
+ }));
48
+ }
49
+ return createSvgDocument(width, height, nodes);
50
+ };
51
+ //#endregion
52
+ export { renderCubeNet };
@@ -0,0 +1,9 @@
1
+ import { MegaminxFace } from "../../../scramble-puzzle/src/megaminx/megaminx-parser.mjs";
2
+ import { MegaminxState } from "../../../scramble-puzzle/src/megaminx/megaminx-state.mjs";
3
+ import { HexColor } from "../color.mjs";
4
+
5
+ //#region .build/vendor/scramble-image/src/renderers/megaminx-isometric.d.ts
6
+ type MegaminxIsometricColorScheme = Partial<Record<MegaminxFace, HexColor>>;
7
+ declare const renderMegaminxIsometricState: (state: MegaminxState, colorScheme?: MegaminxIsometricColorScheme) => string;
8
+ //#endregion
9
+ export { MegaminxIsometricColorScheme, renderMegaminxIsometricState };
@@ -0,0 +1,320 @@
1
+ import { MEGAMINX_FACES } from "../../../scramble-puzzle/src/megaminx/megaminx-parser.mjs";
2
+ import "../../../scramble-puzzle/src/index.mjs";
3
+ import { createSvgDocument } from "../svg/svg-document.mjs";
4
+ import { path } from "../svg/svg-elements.mjs";
5
+ //#region .build/vendor/scramble-image/src/renderers/megaminx-isometric.ts
6
+ const WIDTH = 410;
7
+ const HEIGHT = 190;
8
+ const PADDING = 8;
9
+ const VIEW_GAP = 24;
10
+ const FACE_RADIUS = 52;
11
+ const ADJACENT_DEPTH = .52;
12
+ const STROKE = "#000000";
13
+ const STROKE_WIDTH = 2.75;
14
+ const DEFAULT_MEGAMINX_COLORS = {
15
+ U: "#ffffff",
16
+ BL: "#ffcc00",
17
+ BR: "#0000b3",
18
+ R: "#dd0000",
19
+ F: "#006600",
20
+ L: "#8a1aff",
21
+ D: "#999999",
22
+ DR: "#ffffb3",
23
+ DBR: "#ff99ff",
24
+ B: "#71e600",
25
+ DBL: "#ff8433",
26
+ DL: "#88ddff"
27
+ };
28
+ const VIEW_SPECS = [{
29
+ centerFace: "F",
30
+ faceByEdge: [
31
+ "DL",
32
+ "L",
33
+ "U",
34
+ "R",
35
+ "DR"
36
+ ],
37
+ rotation: Math.PI / 2
38
+ }, {
39
+ centerFace: "B",
40
+ faceByEdge: [
41
+ "BL",
42
+ "DBL",
43
+ "D",
44
+ "DBR",
45
+ "BR"
46
+ ],
47
+ rotation: -Math.PI / 2
48
+ }];
49
+ const STICKER_ORIENTATIONS = {
50
+ U: {
51
+ mirrored: true,
52
+ rotation: 1
53
+ },
54
+ BL: {
55
+ mirrored: true,
56
+ rotation: 2
57
+ },
58
+ BR: {
59
+ mirrored: true,
60
+ rotation: 1
61
+ },
62
+ R: {
63
+ mirrored: true,
64
+ rotation: 3
65
+ },
66
+ F: {
67
+ mirrored: false,
68
+ rotation: 4
69
+ },
70
+ L: {
71
+ mirrored: true,
72
+ rotation: 0
73
+ },
74
+ D: {
75
+ mirrored: true,
76
+ rotation: 0
77
+ },
78
+ DR: {
79
+ mirrored: true,
80
+ rotation: 0
81
+ },
82
+ DBR: {
83
+ mirrored: true,
84
+ rotation: 2
85
+ },
86
+ B: {
87
+ mirrored: false,
88
+ rotation: 3
89
+ },
90
+ DBL: {
91
+ mirrored: true,
92
+ rotation: 4
93
+ },
94
+ DL: {
95
+ mirrored: true,
96
+ rotation: 1
97
+ }
98
+ };
99
+ const formatCoordinate = (value) => Number(value.toFixed(3));
100
+ const wrapPentagonIndex = (index) => (index + 5) % 5;
101
+ const wrapStickerIndex = (index) => (index + 10) % 10;
102
+ const averagePoint = (first, second) => ({
103
+ x: (first.x + second.x) / 2,
104
+ y: (first.y + second.y) / 2
105
+ });
106
+ const pentagon = (rotation) => [
107
+ 0,
108
+ 1,
109
+ 2,
110
+ 3,
111
+ 4
112
+ ].map((index) => {
113
+ const angle = rotation + 2 * Math.PI * index / 5;
114
+ return {
115
+ x: FACE_RADIUS * Math.cos(angle),
116
+ y: FACE_RADIUS * Math.sin(angle)
117
+ };
118
+ });
119
+ const projectPointToLine = (pointValue, lineStart, lineEnd) => {
120
+ const deltaX = lineEnd.x - lineStart.x;
121
+ const deltaY = lineEnd.y - lineStart.y;
122
+ const lengthSquared = deltaX * deltaX + deltaY * deltaY;
123
+ const ratio = ((pointValue.x - lineStart.x) * deltaX + (pointValue.y - lineStart.y) * deltaY) / lengthSquared;
124
+ return {
125
+ x: lineStart.x + ratio * deltaX,
126
+ y: lineStart.y + ratio * deltaY
127
+ };
128
+ };
129
+ const reflectPointAcrossLine = (pointValue, lineStart, lineEnd) => {
130
+ const projected = projectPointToLine(pointValue, lineStart, lineEnd);
131
+ return {
132
+ x: 2 * projected.x - pointValue.x,
133
+ y: 2 * projected.y - pointValue.y
134
+ };
135
+ };
136
+ const compressPointAwayFromLine = (pointValue, lineStart, lineEnd, scale) => {
137
+ const projected = projectPointToLine(pointValue, lineStart, lineEnd);
138
+ return {
139
+ x: projected.x + (pointValue.x - projected.x) * scale,
140
+ y: projected.y + (pointValue.y - projected.y) * scale
141
+ };
142
+ };
143
+ const adjacentBoundary = (centerBoundary, edgeIndex) => {
144
+ const lineStart = centerBoundary[edgeIndex];
145
+ const lineEnd = centerBoundary[(edgeIndex + 1) % centerBoundary.length];
146
+ return centerBoundary.map((pointValue) => compressPointAwayFromLine(reflectPointAcrossLine(pointValue, lineStart, lineEnd), lineStart, lineEnd, ADJACENT_DEPTH));
147
+ };
148
+ const stitchAdjacentBoundaries = (boundaries) => {
149
+ const sharedOuterPoints = boundaries.map((boundary, vertexIndex) => {
150
+ const currentFacePoint = boundary[wrapPentagonIndex(vertexIndex + 4)];
151
+ const previousFacePoint = boundaries[wrapPentagonIndex(vertexIndex - 1)][wrapPentagonIndex(vertexIndex + 1)];
152
+ return averagePoint(currentFacePoint, previousFacePoint);
153
+ });
154
+ return boundaries.map((boundary, edgeIndex) => boundary.map((pointValue, pointIndex) => {
155
+ if (pointIndex === wrapPentagonIndex(edgeIndex + 4)) return sharedOuterPoints[edgeIndex];
156
+ if (pointIndex === wrapPentagonIndex(edgeIndex + 2)) return sharedOuterPoints[wrapPentagonIndex(edgeIndex + 1)];
157
+ return pointValue;
158
+ }));
159
+ };
160
+ const createViewPlacements = (spec) => {
161
+ const centerBoundary = pentagon(spec.rotation);
162
+ const adjacentBoundaries = stitchAdjacentBoundaries(spec.faceByEdge.map((_, edgeIndex) => adjacentBoundary(centerBoundary, edgeIndex)));
163
+ const adjacentPlacements = spec.faceByEdge.map((face, edgeIndex) => ({
164
+ face,
165
+ boundary: adjacentBoundaries[edgeIndex]
166
+ }));
167
+ return [{
168
+ face: spec.centerFace,
169
+ boundary: centerBoundary
170
+ }, ...adjacentPlacements];
171
+ };
172
+ const translatePoint = (pointValue, offsetX, offsetY) => ({
173
+ x: pointValue.x + offsetX,
174
+ y: pointValue.y + offsetY
175
+ });
176
+ const translatePolygon = (points, offsetX, offsetY) => points.map((pointValue) => translatePoint(pointValue, offsetX, offsetY));
177
+ const translatePlacements = (placements, offsetX, offsetY) => placements.map(({ face, boundary }) => ({
178
+ face,
179
+ boundary: translatePolygon(boundary, offsetX, offsetY)
180
+ }));
181
+ const boundsForPolygons = (polygons) => {
182
+ const points = polygons.flat();
183
+ const xs = points.map((pointValue) => pointValue.x);
184
+ const ys = points.map((pointValue) => pointValue.y);
185
+ return {
186
+ minX: Math.min(...xs),
187
+ minY: Math.min(...ys),
188
+ maxX: Math.max(...xs),
189
+ maxY: Math.max(...ys)
190
+ };
191
+ };
192
+ const boundsForPlacements = (placements) => boundsForPolygons(placements.map((placement) => placement.boundary));
193
+ const layoutPlacements = () => {
194
+ const [leftView, rightView] = VIEW_SPECS.map(createViewPlacements);
195
+ const leftBounds = boundsForPlacements(leftView);
196
+ const rightBounds = boundsForPlacements(rightView);
197
+ const leftWidth = leftBounds.maxX - leftBounds.minX;
198
+ const rightWidth = rightBounds.maxX - rightBounds.minX;
199
+ const startX = (WIDTH - (leftWidth + VIEW_GAP + rightWidth)) / 2;
200
+ const viewHeight = HEIGHT - 2 * PADDING;
201
+ const leftHeight = leftBounds.maxY - leftBounds.minY;
202
+ const rightHeight = rightBounds.maxY - rightBounds.minY;
203
+ const leftOffsetY = PADDING + (viewHeight - leftHeight) / 2 - leftBounds.minY;
204
+ const rightOffsetY = PADDING + (viewHeight - rightHeight) / 2 - rightBounds.minY;
205
+ return [...translatePlacements(leftView, startX - leftBounds.minX, leftOffsetY), ...translatePlacements(rightView, startX + leftWidth + VIEW_GAP - rightBounds.minX, rightOffsetY)];
206
+ };
207
+ const FACE_PLACEMENTS = layoutPlacements();
208
+ const det = (a, b, c, d) => a * d - b * c;
209
+ const lineIntersection = (firstStart, firstEnd, secondStart, secondEnd) => {
210
+ const firstDet = det(firstStart.x, firstStart.y, firstEnd.x, firstEnd.y);
211
+ const secondDet = det(secondStart.x, secondStart.y, secondEnd.x, secondEnd.y);
212
+ const divisor = det(firstStart.x - firstEnd.x, firstStart.y - firstEnd.y, secondStart.x - secondEnd.x, secondStart.y - secondEnd.y);
213
+ return {
214
+ x: det(firstDet, firstStart.x - firstEnd.x, secondDet, secondStart.x - secondEnd.x) / divisor,
215
+ y: det(firstDet, firstStart.y - firstEnd.y, secondDet, secondStart.y - secondEnd.y) / divisor
216
+ };
217
+ };
218
+ const polygonPath = (points) => {
219
+ const [firstPoint, ...remainingPoints] = points;
220
+ if (!firstPoint) return "";
221
+ return [
222
+ `M ${formatCoordinate(firstPoint.x)} ${formatCoordinate(firstPoint.y)}`,
223
+ ...remainingPoints.map((pointValue) => `L ${formatCoordinate(pointValue.x)} ${formatCoordinate(pointValue.y)}`),
224
+ "Z"
225
+ ].join(" ");
226
+ };
227
+ const lineworkPath = (segments) => segments.map(({ start, end }) => `M ${formatCoordinate(start.x)} ${formatCoordinate(start.y)} L ${formatCoordinate(end.x)} ${formatCoordinate(end.y)}`).join(" ");
228
+ const createStickerPolygons = (boundary) => {
229
+ const edgePoints = [];
230
+ for (let index = 0; index < 5; index += 1) {
231
+ const current = boundary[index];
232
+ const next = boundary[(index + 1) % 5];
233
+ edgePoints[index] = {
234
+ x: .4 * next.x + .6 * current.x,
235
+ y: .4 * next.y + .6 * current.y
236
+ };
237
+ edgePoints[index + 5] = {
238
+ x: .6 * next.x + .4 * current.x,
239
+ y: .6 * next.y + .4 * current.y
240
+ };
241
+ }
242
+ const innerPentagon = [];
243
+ for (let index = 0; index < 5; index += 1) innerPentagon[index] = lineIntersection(edgePoints[index], edgePoints[5 + (3 + index) % 5], edgePoints[(index + 1) % 5], edgePoints[5 + (4 + index) % 5]);
244
+ const stickers = [];
245
+ for (let index = 0; index < 5; index += 1) {
246
+ stickers[2 * index] = [
247
+ boundary[index],
248
+ edgePoints[index],
249
+ innerPentagon[index],
250
+ edgePoints[5 + (4 + index) % 5]
251
+ ];
252
+ stickers[2 * index + 1] = [
253
+ edgePoints[index],
254
+ edgePoints[index + 5],
255
+ innerPentagon[(index + 1) % 5],
256
+ innerPentagon[index]
257
+ ];
258
+ }
259
+ stickers[10] = innerPentagon;
260
+ return stickers;
261
+ };
262
+ const stickerIndexForOrientation = (stickerIndex, orientation) => {
263
+ if (stickerIndex >= 10) return stickerIndex;
264
+ const offset = 2 * orientation.rotation;
265
+ if (orientation.mirrored) return wrapStickerIndex(offset - stickerIndex);
266
+ return wrapStickerIndex(stickerIndex + offset);
267
+ };
268
+ const colorForSticker = (facelet, colors) => colors[MEGAMINX_FACES[facelet] ?? "U"];
269
+ const createFaceStickers = (state, placement, colors) => {
270
+ const faceIndexValue = MEGAMINX_FACES.indexOf(placement.face);
271
+ const stickers = state.image[faceIndexValue];
272
+ const orientation = STICKER_ORIENTATIONS[placement.face];
273
+ return createStickerPolygons(placement.boundary).map((polygon, stickerIndex) => {
274
+ return {
275
+ points: polygon,
276
+ fill: colorForSticker(stickers[stickerIndexForOrientation(stickerIndex, orientation)], colors)
277
+ };
278
+ });
279
+ };
280
+ const segmentKey = ({ start, end }) => {
281
+ const startKey = `${formatCoordinate(start.x)},${formatCoordinate(start.y)}`;
282
+ const endKey = `${formatCoordinate(end.x)},${formatCoordinate(end.y)}`;
283
+ return startKey < endKey ? `${startKey}|${endKey}` : `${endKey}|${startKey}`;
284
+ };
285
+ const createLineworkSegments = (stickers) => {
286
+ const segments = /* @__PURE__ */ new Map();
287
+ for (const sticker of stickers) for (let index = 0; index < sticker.points.length; index += 1) {
288
+ const segment = {
289
+ start: sticker.points[index],
290
+ end: sticker.points[(index + 1) % sticker.points.length]
291
+ };
292
+ segments.set(segmentKey(segment), segment);
293
+ }
294
+ return [...segments.values()];
295
+ };
296
+ const drawStickers = (stickers) => stickers.map((sticker) => path({
297
+ d: polygonPath(sticker.points),
298
+ fill: sticker.fill,
299
+ stroke: "none"
300
+ }));
301
+ const drawLinework = (stickers) => path({
302
+ d: lineworkPath(createLineworkSegments(stickers)),
303
+ fill: "none",
304
+ stroke: STROKE,
305
+ "stroke-linecap": "round",
306
+ "stroke-linejoin": "round",
307
+ "stroke-width": STROKE_WIDTH
308
+ });
309
+ const drawFaces = (state, colors) => {
310
+ const stickers = FACE_PLACEMENTS.flatMap((placement) => createFaceStickers(state, placement, colors));
311
+ return [...drawStickers(stickers), drawLinework(stickers)];
312
+ };
313
+ const renderMegaminxIsometricState = (state, colorScheme = {}) => {
314
+ return createSvgDocument(WIDTH, HEIGHT, drawFaces(state, {
315
+ ...DEFAULT_MEGAMINX_COLORS,
316
+ ...colorScheme
317
+ }));
318
+ };
319
+ //#endregion
320
+ export { renderMegaminxIsometricState };
@@ -0,0 +1,9 @@
1
+ import { MegaminxFace } from "../../../scramble-puzzle/src/megaminx/megaminx-parser.mjs";
2
+ import { MegaminxState } from "../../../scramble-puzzle/src/megaminx/megaminx-state.mjs";
3
+ import { HexColor } from "../color.mjs";
4
+
5
+ //#region .build/vendor/scramble-image/src/renderers/megaminx.d.ts
6
+ type MegaminxColorScheme = Partial<Record<MegaminxFace, HexColor>>;
7
+ declare const renderMegaminxState: (state: MegaminxState, colorScheme?: MegaminxColorScheme) => string;
8
+ //#endregion
9
+ export { MegaminxColorScheme, renderMegaminxState };