@houstonp/rubiks-cube 2.1.0 → 3.0.0

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 (76) hide show
  1. package/README.md +304 -77
  2. package/package.json +18 -8
  3. package/src/{core.js → core/index.js} +72 -41
  4. package/src/rubiksCube/index.js +3 -0
  5. package/src/rubiksCube/rubiksCubeController.js +111 -0
  6. package/src/{three → rubiksCube3D}/centerPiece.js +37 -2
  7. package/src/{three → rubiksCube3D}/cornerPiece.js +56 -2
  8. package/src/rubiksCube3D/cubeConfig.js +87 -0
  9. package/src/rubiksCube3D/cubeSettings.js +30 -0
  10. package/src/{three → rubiksCube3D}/edgePiece.js +2 -1
  11. package/src/rubiksCube3D/index.js +3 -0
  12. package/src/rubiksCube3D/rubiksCube3D.js +383 -0
  13. package/src/{three → rubiksCube3D}/sticker.js +5 -4
  14. package/src/state/index.js +4 -0
  15. package/src/state/rubiksCubeState.js +471 -0
  16. package/src/state/slice.js +236 -0
  17. package/src/state/stickerState.js +185 -0
  18. package/src/{camera → webComponent}/cameraState.js +17 -25
  19. package/src/webComponent/constants.js +67 -0
  20. package/src/webComponent/index.js +7 -0
  21. package/src/webComponent/rubiksCubeElement.js +379 -0
  22. package/src/{settings.js → webComponent/settings.js} +36 -23
  23. package/tests/common.js +3 -20
  24. package/tests/core.test.js +56 -0
  25. package/tests/rubiksCube.solves.test.js +41 -0
  26. package/tests/rubiksCube3D.solves.test.js +185 -0
  27. package/tests/rubiksCubeState.solves.test.js +35 -0
  28. package/tests/testScrambles.js +194 -0
  29. package/types/{core.d.ts → core/index.d.ts} +45 -48
  30. package/types/rubiksCube/index.d.ts +3 -0
  31. package/types/rubiksCube/rubiksCubeController.d.ts +62 -0
  32. package/types/rubiksCube3D/centerPiece.d.ts +27 -0
  33. package/types/rubiksCube3D/cornerPiece.d.ts +38 -0
  34. package/types/rubiksCube3D/cubeConfig.d.ts +32 -0
  35. package/types/rubiksCube3D/cubeSettings.d.ts +33 -0
  36. package/types/{three → rubiksCube3D}/edgePiece.d.ts +5 -3
  37. package/types/rubiksCube3D/index.d.ts +3 -0
  38. package/types/rubiksCube3D/rubiksCube3D.d.ts +120 -0
  39. package/types/rubiksCube3D/sticker.d.ts +18 -0
  40. package/types/state/index.d.ts +5 -0
  41. package/types/state/rubiksCubeState.d.ts +108 -0
  42. package/types/state/slice.d.ts +46 -0
  43. package/types/state/stickerState.d.ts +34 -0
  44. package/types/webComponent/cameraState.d.ts +22 -0
  45. package/types/webComponent/constants.d.ts +57 -0
  46. package/types/webComponent/index.d.ts +6 -0
  47. package/types/webComponent/rubiksCubeElement.d.ts +89 -0
  48. package/types/{settings.d.ts → webComponent/settings.d.ts} +5 -8
  49. package/src/cube/animationSlice.js +0 -205
  50. package/src/cube/animationState.js +0 -96
  51. package/src/cube/cubeSettings.js +0 -19
  52. package/src/cube/cubeState.js +0 -337
  53. package/src/cube/stickerState.js +0 -188
  54. package/src/index.js +0 -621
  55. package/src/three/cube.js +0 -492
  56. package/tests/cube.five.test.js +0 -126
  57. package/tests/cube.four.test.js +0 -126
  58. package/tests/cube.seven.test.js +0 -126
  59. package/tests/cube.six.test.js +0 -126
  60. package/tests/cube.three.test.js +0 -151
  61. package/tests/cube.two.test.js +0 -125
  62. package/types/camera/cameraState.d.ts +0 -19
  63. package/types/cube/animationSlice.d.ts +0 -26
  64. package/types/cube/animationState.d.ts +0 -41
  65. package/types/cube/cubeSettings.d.ts +0 -17
  66. package/types/cube/cubeState.d.ts +0 -47
  67. package/types/cube/stickerState.d.ts +0 -21
  68. package/types/index.d.ts +0 -87
  69. package/types/three/centerPiece.d.ts +0 -15
  70. package/types/three/cornerPiece.d.ts +0 -24
  71. package/types/three/cube.d.ts +0 -130
  72. package/types/three/sticker.d.ts +0 -15
  73. /package/src/{debouncer.js → webComponent/debouncer.js} +0 -0
  74. /package/src/{globals.ts → webComponent/globals.ts} +0 -0
  75. /package/types/{debouncer.d.ts → webComponent/debouncer.d.ts} +0 -0
  76. /package/types/{globals.d.ts → webComponent/globals.d.ts} +0 -0
@@ -0,0 +1,185 @@
1
+ // @ts-check
2
+ import { CubeTypes, Faces } from '../core';
3
+ /** @import {Face, CubeType} from '../core' */
4
+ /** @import {vector} from './rubiksCubeState' */
5
+
6
+ /**
7
+ * @typedef StickerState
8
+ * @property {Face[][]} Face.U
9
+ * @property {Face[][]} Face.D
10
+ * @property {Face[][]} Face.F
11
+ * @property {Face[][]} Face.B
12
+ * @property {Face[][]} Face.L
13
+ * @property {Face[][]} Face.R
14
+ **/
15
+
16
+ const ERROR_MARGIN = 0.0001;
17
+ const LayerCount = {
18
+ [CubeTypes.Two]: 2,
19
+ [CubeTypes.Three]: 3,
20
+ [CubeTypes.Four]: 4,
21
+ [CubeTypes.Five]: 5,
22
+ [CubeTypes.Six]: 6,
23
+ [CubeTypes.Seven]: 7,
24
+ };
25
+
26
+ /**
27
+ * @param {vector} stickerDirection
28
+ * @param {vector} piecePosition
29
+ * @param {number[]} layers
30
+ * @returns {{face: Face, i: number, j: number}}
31
+ */
32
+ export function getStickerFaceIndex(stickerDirection, piecePosition, layers) {
33
+ const last = layers.length - 1;
34
+ /** @type {(val: number) => number} */
35
+ const layerIndex = (val) => {
36
+ for (let i = 0; i < layers.length; i++) {
37
+ if (Math.abs(val - layers[i]) < ERROR_MARGIN) {
38
+ return i;
39
+ }
40
+ }
41
+ throw new Error(`Failed to get layer number. position ${val} not found in layers ${layers}`);
42
+ };
43
+ if (stickerDirection.x === 1) return { face: Faces.R, i: last - layerIndex(piecePosition.y), j: last - layerIndex(piecePosition.z) };
44
+ if (stickerDirection.x === -1) return { face: Faces.L, i: last - layerIndex(piecePosition.y), j: layerIndex(piecePosition.z) };
45
+ if (stickerDirection.y === 1) return { face: Faces.U, i: layerIndex(piecePosition.z), j: layerIndex(piecePosition.x) };
46
+ if (stickerDirection.y === -1) return { face: Faces.D, i: last - layerIndex(piecePosition.z), j: layerIndex(piecePosition.x) };
47
+ if (stickerDirection.z === 1) return { face: Faces.F, i: last - layerIndex(piecePosition.y), j: layerIndex(piecePosition.x) };
48
+ if (stickerDirection.z === -1) return { face: Faces.B, i: last - layerIndex(piecePosition.y), j: last - layerIndex(piecePosition.x) };
49
+ throw new Error(`StickerDirection is not a standard unit vector. vector: ${stickerDirection}`);
50
+ }
51
+
52
+ /**
53
+ *
54
+ * @param {CubeType} cubeType
55
+ * @return {StickerState}
56
+ */
57
+ export const defaultStickerState = (cubeType) => {
58
+ const n = LayerCount[cubeType];
59
+ if (n == null) {
60
+ throw new Error(`Invalid CubeType`);
61
+ }
62
+ return initialStickerState(n);
63
+ };
64
+
65
+ /**
66
+ *
67
+ * @param {number} layerCount
68
+ * @returns {StickerState}
69
+ */
70
+ const initialStickerState = (layerCount) => {
71
+ const state = {
72
+ [Faces.R]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.R)),
73
+ [Faces.U]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.U)),
74
+ [Faces.F]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.F)),
75
+ [Faces.B]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.B)),
76
+ [Faces.D]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.D)),
77
+ [Faces.L]: Array.from({ length: layerCount }, () => Array.from({ length: layerCount }, () => Faces.L)),
78
+ };
79
+ return state;
80
+ };
81
+
82
+ /**
83
+ *
84
+ * @param {CubeType} cubeType
85
+ * @return {StickerState}
86
+ */
87
+ export const getEmptyStickerState = (cubeType) => {
88
+ const n = LayerCount[cubeType];
89
+ if (n == null) {
90
+ throw new Error(`Invalid CubeType`);
91
+ }
92
+ return emptyStickerState(n);
93
+ };
94
+ /**
95
+ *
96
+ * @param {number} layerCount
97
+ * @returns {StickerState}
98
+ */
99
+ const emptyStickerState = (layerCount) => {
100
+ const state = {
101
+ [Faces.R]: Array.from({ length: layerCount }, () => []),
102
+ [Faces.U]: Array.from({ length: layerCount }, () => []),
103
+ [Faces.F]: Array.from({ length: layerCount }, () => []),
104
+ [Faces.B]: Array.from({ length: layerCount }, () => []),
105
+ [Faces.D]: Array.from({ length: layerCount }, () => []),
106
+ [Faces.L]: Array.from({ length: layerCount }, () => []),
107
+ };
108
+ return state;
109
+ };
110
+
111
+ /**
112
+ * @param {StickerState} stickerState
113
+ * @returns {string}
114
+ */
115
+ export function toKociemba(stickerState) {
116
+ return `${stickerState.U.flat().join('')}${stickerState.R.flat().join('')}${stickerState.F.flat().join('')}${stickerState.D.flat().join('')}${stickerState.L.flat().join('')}${stickerState.B.flat().join('')}`;
117
+ }
118
+
119
+ /**
120
+ * @param {string} kociembaString
121
+ * @returns {StickerState | undefined} stickerState
122
+ */
123
+ export function fromKociemba(kociembaString) {
124
+ switch (kociembaString.length) {
125
+ case 6 * 2 * 2:
126
+ return fromKociembaWithLayerCount(kociembaString, 2);
127
+ case 6 * 3 * 3:
128
+ return fromKociembaWithLayerCount(kociembaString, 3);
129
+ case 6 * 4 * 4:
130
+ return fromKociembaWithLayerCount(kociembaString, 4);
131
+ case 6 * 5 * 5:
132
+ return fromKociembaWithLayerCount(kociembaString, 5);
133
+ case 6 * 6 * 6:
134
+ return fromKociembaWithLayerCount(kociembaString, 6);
135
+ case 6 * 7 * 7:
136
+ return fromKociembaWithLayerCount(kociembaString, 7);
137
+ default:
138
+ console.error(`Invalid state string length.`);
139
+ return;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * @param {string} kociembaString
145
+ * @param {number} layerCount
146
+ * @returns {StickerState | undefined } stickerState
147
+ */
148
+ function fromKociembaWithLayerCount(kociembaString, layerCount) {
149
+ let stickerState = emptyStickerState(layerCount);
150
+ for (let i = 0; i < 6; i++) {
151
+ const faceString = kociembaString.slice(i * layerCount ** 2, (i + 1) * layerCount ** 2);
152
+ for (let j = 0; j < layerCount; j++) {
153
+ const rowString = faceString.slice(j * layerCount, (j + 1) * layerCount);
154
+ for (let k = 0; k < layerCount; k++) {
155
+ const face = Object.values(Faces).find((face) => rowString[k] === face);
156
+ if (!face) {
157
+ return undefined;
158
+ }
159
+ switch (i) {
160
+ case 0:
161
+ stickerState.U[j][k] = face;
162
+ break;
163
+ case 1:
164
+ stickerState.R[j][k] = face;
165
+ break;
166
+ case 2:
167
+ stickerState.F[j][k] = face;
168
+ break;
169
+ case 3:
170
+ stickerState.D[j][k] = face;
171
+ break;
172
+ case 4:
173
+ stickerState.L[j][k] = face;
174
+ break;
175
+ case 5:
176
+ stickerState.B[j][k] = face;
177
+ break;
178
+ default:
179
+ throw new Error(`Invalid value for i - [${i}]. i should be between [0,5] inclusive.`);
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return stickerState;
185
+ }
@@ -1,5 +1,6 @@
1
1
  // @ts-check
2
- import { PeekStates, PeekTypes } from '../core';
2
+ import { PeekActions, PeekStates } from './constants';
3
+ /** @import {PeekAction, PeekState} from './constants' */
3
4
 
4
5
  export class CameraState {
5
6
  /**
@@ -14,51 +15,48 @@ export class CameraState {
14
15
  }
15
16
 
16
17
  /**
17
- * @param {import("../core").PeekType} peekType
18
+ * @param {PeekAction} action
18
19
  */
19
- peekCamera(peekType) {
20
- switch (peekType) {
21
- case PeekTypes.Horizontal:
20
+ peekCamera(action) {
21
+ switch (action) {
22
+ case PeekActions.Horizontal:
22
23
  this.Right = !this.Right;
23
24
  break;
24
- case PeekTypes.Vertical:
25
+ case PeekActions.Vertical:
25
26
  this.Up = !this.Up;
26
27
  break;
27
- case PeekTypes.Right:
28
+ case PeekActions.Right:
28
29
  this.Right = true;
29
30
  break;
30
- case PeekTypes.Left:
31
+ case PeekActions.Left:
31
32
  this.Right = false;
32
33
  break;
33
- case PeekTypes.Up:
34
+ case PeekActions.Up:
34
35
  this.Up = true;
35
36
  break;
36
- case PeekTypes.Down:
37
+ case PeekActions.Down:
37
38
  this.Up = false;
38
39
  break;
39
- case PeekTypes.RightUp:
40
+ case PeekActions.RightUp:
40
41
  this.Right = true;
41
42
  this.Up = true;
42
43
  break;
43
- case PeekTypes.RightDown:
44
+ case PeekActions.RightDown:
44
45
  this.Right = true;
45
46
  this.Up = false;
46
47
  break;
47
- case PeekTypes.LeftUp:
48
+ case PeekActions.LeftUp:
48
49
  this.Right = false;
49
50
  this.Up = true;
50
51
  break;
51
- case PeekTypes.LeftDown:
52
+ case PeekActions.LeftDown:
52
53
  this.Right = false;
53
54
  this.Up = false;
54
55
  break;
55
- default:
56
- console.error(`Invalid peekType:[${peekType}]. valid values are [${Object.values(PeekTypes)}] `);
57
- break;
58
56
  }
59
57
  }
60
58
  /**
61
- * @returns {import("../core").PeekState}
59
+ * @returns {PeekState}
62
60
  */
63
61
  toPeekState() {
64
62
  if (this.Right && this.Up) {
@@ -70,12 +68,6 @@ export class CameraState {
70
68
  if (this.Right && !this.Up) {
71
69
  return PeekStates.RightDown;
72
70
  }
73
- if (!this.Right && !this.Up) {
74
- return PeekStates.LeftDown;
75
- }
76
- console.error(
77
- `Invalid CameraState right and up values must be true or false. Actual values: right[${this.Right}] up[${this.Up}]. Default RightUp returned`,
78
- );
79
- return PeekStates.RightUp;
71
+ return PeekStates.LeftDown;
80
72
  }
81
73
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @typedef CameraOptions
3
+ * @property {number} [cameraSpeedMs]
4
+ */
5
+
6
+ /**
7
+ * @typedef {typeof AnimationStyles[keyof typeof AnimationStyles]} AnimationStyle
8
+ */
9
+ export const AnimationStyles = Object.freeze({
10
+ Exponential: 'exponential',
11
+ Linear: 'linear',
12
+ Next: 'next',
13
+ Fixed: 'fixed',
14
+ Match: 'match',
15
+ });
16
+
17
+ /**
18
+ * @typedef {typeof PeekStates [keyof typeof PeekStates]} PeekState
19
+ */
20
+ export const PeekStates = Object.freeze({
21
+ RightUp: 'rightUp',
22
+ RightDown: 'rightDown',
23
+ LeftUp: 'leftUp',
24
+ LeftDown: 'leftDown',
25
+ });
26
+
27
+ /**
28
+ * @typedef {typeof PeekActions [keyof typeof PeekActions]} PeekAction
29
+ */
30
+ export const PeekActions = Object.freeze({
31
+ Horizontal: 'horizontal',
32
+ Vertical: 'vertical',
33
+ Right: 'right',
34
+ Left: 'left',
35
+ Up: 'up',
36
+ Down: 'down',
37
+ RightUp: 'rightUp',
38
+ RightDown: 'rightDown',
39
+ LeftUp: 'leftUp',
40
+ LeftDown: 'leftDown',
41
+ });
42
+
43
+ /**
44
+ * @typedef {typeof AttributeNames[keyof typeof AttributeNames]} AttributeName
45
+ */
46
+ export const AttributeNames = {
47
+ /** @type {'cube-type'} */
48
+ cubeType: 'cube-type',
49
+ /** @type {'piece-gap'} */
50
+ pieceGap: 'piece-gap',
51
+ /** @type {'animation-speed-ms'} */
52
+ animationSpeed: 'animation-speed-ms',
53
+ /** @type {'animation-style'} */
54
+ animationStyle: 'animation-style',
55
+ /** @type {'camera-speed-ms'} */
56
+ cameraSpeed: 'camera-speed-ms',
57
+ /** @type {'camera-radius'} */
58
+ cameraRadius: 'camera-radius',
59
+ /** @type {'camera-field-of-view'} */
60
+ cameraFieldOfView: 'camera-field-of-view',
61
+ /** @type {'camera-peek-angle-horizontal'} */
62
+ cameraPeekAngleHorizontal: 'camera-peek-angle-horizontal',
63
+ /** @type {'camera-peek-angle-vertical'} */
64
+ cameraPeekAngleVertical: 'camera-peek-angle-vertical',
65
+ /** @type {'logo'} */
66
+ logo: 'logo',
67
+ };
@@ -0,0 +1,7 @@
1
+ // @ts-check
2
+ /** @typedef {import("./constants").PeekState} PeekState */
3
+ /** @typedef {import("./constants").PeekAction} PeekAction */
4
+ /** @typedef {import("./constants").CameraOptions} CameraOptions */
5
+ /** @typedef {import('./constants').AnimationStyle} AnimationStyle */
6
+ export { RubiksCubeElement } from './rubiksCubeElement';
7
+ export { AttributeNames, PeekStates, PeekActions, AnimationStyles } from './constants';