User01110 commited on
Commit
f86877c
·
1 Parent(s): 89c2146

Randomize demo cube scrambles

Browse files
Files changed (2) hide show
  1. app.js +28 -5
  2. index.html +2 -2
app.js CHANGED
@@ -2,6 +2,9 @@
2
 
3
  const FACES = ["U", "R", "F", "D", "L", "B"];
4
  const FACE_NAMES = {U: "Top", R: "Right", F: "Front", D: "Bottom", L: "Left", B: "Back"};
 
 
 
5
  const COLOR_PRESETS = [
6
  {name: "white", label: "White", hex: "#f4f4f5"},
7
  {name: "yellow", label: "Yellow", hex: "#facc15"},
@@ -103,6 +106,26 @@ const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, millise
103
  const nextPaint = () => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
104
  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  async function transitionTransform(element, transform, duration, easing = "cubic-bezier(.4,.01,.18,1)") {
107
  element.style.transition = `transform ${Math.round(duration)}ms ${easing}`;
108
  await nextPaint();
@@ -764,17 +787,17 @@ function loadSolvedCube() {
764
  chooseView("HOME");
765
  }
766
 
767
- function loadDemoCube() {
768
  hideEntryMessage();
769
  try {
770
- const scramble = ["R", "U", "F2", "L'", "D", "B2"];
771
  let canonical = FACES.map(face => face.repeat(9)).join("");
772
  scramble.forEach(move => canonical = applyCanonicalMove(canonical, move));
773
  replaceCubeState(coloredFacesFromCanonical(canonical, SOLVED_COLORS));
774
- showEntryMessage(`Demo loaded: ${scramble.join(" ")}`, "success");
775
  chooseView("HOME");
776
  } catch (error) {
777
- showEntryMessage(error.message || "The demo cube could not be loaded.");
778
  }
779
  }
780
 
@@ -1056,7 +1079,7 @@ function initialize() {
1056
  initializeCameraControls();
1057
  $("clearBtn").addEventListener("click", clearCube);
1058
  $("solvedBtn").addEventListener("click", loadSolvedCube);
1059
- $("demoBtn").addEventListener("click", loadDemoCube);
1060
  $("solveBtn").addEventListener("click", solveCube);
1061
  $("prevBtn").addEventListener("click", () => { stopPlayback(); stepSolution(-1); });
1062
  $("nextBtn").addEventListener("click", () => { stopPlayback(); stepSolution(1); });
 
2
 
3
  const FACES = ["U", "R", "F", "D", "L", "B"];
4
  const FACE_NAMES = {U: "Top", R: "Right", F: "Front", D: "Bottom", L: "Left", B: "Back"};
5
+ const FACE_AXES = {U: "Y", D: "Y", R: "X", L: "X", F: "Z", B: "Z"};
6
+ const SCRAMBLE_SUFFIXES = ["", "'", "2"];
7
+ const DEMO_SCRAMBLE_LENGTH = 20;
8
  const COLOR_PRESETS = [
9
  {name: "white", label: "White", hex: "#f4f4f5"},
10
  {name: "yellow", label: "Yellow", hex: "#facc15"},
 
106
  const nextPaint = () => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
107
  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
108
 
109
+ function randomInteger(maximum) {
110
+ const values = new Uint32Array(1);
111
+ const limit = 0x100000000 - (0x100000000 % maximum);
112
+ do window.crypto.getRandomValues(values); while (values[0] >= limit);
113
+ return values[0] % maximum;
114
+ }
115
+
116
+ function randomScramble(length = DEMO_SCRAMBLE_LENGTH) {
117
+ const scramble = [];
118
+ let previousAxis = null;
119
+ for (let index = 0; index < length; index++) {
120
+ const availableFaces = FACES.filter(face => FACE_AXES[face] !== previousAxis);
121
+ const face = availableFaces[randomInteger(availableFaces.length)];
122
+ const suffix = SCRAMBLE_SUFFIXES[randomInteger(SCRAMBLE_SUFFIXES.length)];
123
+ scramble.push(`${face}${suffix}`);
124
+ previousAxis = FACE_AXES[face];
125
+ }
126
+ return scramble;
127
+ }
128
+
129
  async function transitionTransform(element, transform, duration, easing = "cubic-bezier(.4,.01,.18,1)") {
130
  element.style.transition = `transform ${Math.round(duration)}ms ${easing}`;
131
  await nextPaint();
 
787
  chooseView("HOME");
788
  }
789
 
790
+ function loadRandomDemoCube() {
791
  hideEntryMessage();
792
  try {
793
+ const scramble = randomScramble();
794
  let canonical = FACES.map(face => face.repeat(9)).join("");
795
  scramble.forEach(move => canonical = applyCanonicalMove(canonical, move));
796
  replaceCubeState(coloredFacesFromCanonical(canonical, SOLVED_COLORS));
797
+ showEntryMessage(`Random demo loaded: ${scramble.join(" ")}`, "success");
798
  chooseView("HOME");
799
  } catch (error) {
800
+ showEntryMessage(error.message || "A random demo cube could not be loaded.");
801
  }
802
  }
803
 
 
1079
  initializeCameraControls();
1080
  $("clearBtn").addEventListener("click", clearCube);
1081
  $("solvedBtn").addEventListener("click", loadSolvedCube);
1082
+ $("demoBtn").addEventListener("click", loadRandomDemoCube);
1083
  $("solveBtn").addEventListener("click", solveCube);
1084
  $("prevBtn").addEventListener("click", () => { stopPlayback(); stepSolution(-1); });
1085
  $("nextBtn").addEventListener("click", () => { stopPlayback(); stepSolution(1); });
index.html CHANGED
@@ -103,7 +103,7 @@
103
  <div class="preset-row">
104
  <button class="soft-btn" id="clearBtn">Clear</button>
105
  <button class="soft-btn" id="solvedBtn">Solved example</button>
106
- <button class="soft-btn accent" id="demoBtn">Try demo</button>
107
  </div>
108
  <button class="solve-btn" id="solveBtn" disabled><span>Solve my cube</span><i>→</i></button>
109
  <div class="status-message" id="entryMessage" role="status" aria-live="polite"></div>
@@ -147,6 +147,6 @@
147
  <button class="remove-color" id="removeColor">Clear this sticker</button>
148
  </div>
149
 
150
- <script src="./app.js?v=20260810-cube-v2" defer></script>
151
  </body>
152
  </html>
 
103
  <div class="preset-row">
104
  <button class="soft-btn" id="clearBtn">Clear</button>
105
  <button class="soft-btn" id="solvedBtn">Solved example</button>
106
+ <button class="soft-btn accent" id="demoBtn">Random demo</button>
107
  </div>
108
  <button class="solve-btn" id="solveBtn" disabled><span>Solve my cube</span><i>→</i></button>
109
  <div class="status-message" id="entryMessage" role="status" aria-live="polite"></div>
 
147
  <button class="remove-color" id="removeColor">Clear this sticker</button>
148
  </div>
149
 
150
+ <script src="./app.js?v=20260810-random-demo-v1" defer></script>
151
  </body>
152
  </html>