CubeletInfo[,,] PerformRotationOnCubelets(CubeletInfo[,,] cubelets, FaceRotation rot, bool setParent = false) { var newCubelets = new CubeletInfo[3, 3, 3]; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { for (int z = 0; z < 3; z++) { if (x != 1 || y != 1 || z != 1) { if (rot.OnAxis(x, y, z)) { if (setParent) { cubelets[x, y, z].Cubelet.parent = OnAxis; } var otherCubelet = cubelets[rot.MapX(x, y, z), rot.MapY(x, y, z), rot.MapZ(x, y, z)]; newCubelets[x, y, z] = new CubeletInfo(otherCubelet.Cubelet, rot.Rotation(90) * otherCubelet.Rotation); } else { newCubelets[x, y, z] = cubelets[x, y, z]; } } } } } return(newCubelets); }
IEnumerator WaitForSerialNumber() { yield return(null); var table = @"L’,F’;D’,U’;U,B’;F,B;L,D;R’,U;U’,F;B’,L’;B,R;D,L;R,D’;F’,R’".Split(';').Select(row => row.Split(',').Select(str => _moves[str]).ToArray()).ToArray(); var colorNames = "Yellow|Blue|Red|Green|Orange|White".Split('|'); // Find a combination of colors that generates a non-trivial solution int retries = 10; retry: var colors = Enumerable.Range(0, 6).ToArray().Shuffle(); var columnShifts = newArray(colors[0] + 1, colors[1] + 1, colors[2] + 1); var serialIgnore = colors[3]; var colR = colors[4]; // color of the R (right) face var ser = Bomb.GetSerialNumber().Remove(serialIgnore, 1); var rows = ser.Select(ch => ch >= '0' && ch <= '9' ? ch - '0' : ch - 'A' + 10).Select(n => (n / 3 + columnShifts[n % 3]) % table.Length).ToArray(); var moves1 = (colR >= 1 && colR <= 3) ? rows.SelectMany(r => table[r]).ToList() : rows.Select(r => table[r][0]).Concat(rows.Select(r => table[r][1])).ToList(); var moves2 = moves1.ToList(); switch (colR) { case 2: // red case 0: // yellow for (int i = 0; i < 5; i++) { moves2[i] = moves2[i].Reverse; } break; case 3: // green case 5: // white for (int i = 0; i < 5; i++) { var t = moves2[i]; moves2[i] = moves2[9 - i]; moves2[9 - i] = t; } break; } // Now try to minimize the sequence var ix = 0; _solveMoves.Clear(); _solveMoves.AddRange(moves2); while (ix < _solveMoves.Count) { var n = 1; var affected = new List <int>(); for (int j = ix + 1; j < _solveMoves.Count; j++) { if (_solveMoves[j] == _solveMoves[ix]) { n++; affected.Add(j); } else if (_solveMoves[j] == _solveMoves[ix].Reverse) { n--; affected.Add(j); } else if (!_solveMoves[ix].OppositeSide.Contains(_solveMoves[j])) { break; } } switch ((n % 4 + 4) % 4) { case 0: // the moves cancel each other out completely. for (int k = affected.Count - 1; k >= 0; k--) { _solveMoves.RemoveAt(affected[k]); } _solveMoves.RemoveAt(ix); ix = 0; continue; case 3: // e.g. 3 of the same move ⇒ reverse move for (int k = affected.Count - 1; k >= 0; k--) { _solveMoves.RemoveAt(affected[k]); } _solveMoves[ix] = _solveMoves[ix].Reverse; ix = 0; continue; } ix++; } // At this point, if the sequence is shorter than 8 moves, we want to generate a different sequence of colors. if (_solveMoves.Count < 8 && retries-- > 0) { goto retry; } // Set all the stickers to the desired colors and populate the _cubelets array _cubelets = new CubeletInfo[3, 3, 3]; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { for (int z = 0; z < 3; z++) { if (x != 1 || y != 1 || z != 1) { _cubelets[x, y, z] = new CubeletInfo(OffAxis.Find(string.Format("Cubelet ({0}, {1}, {2})", x, y, z)), Quaternion.identity); for (int i = 0; i < _faces.Length; i++) { var sticker = _cubelets[x, y, z].Cubelet.Find(string.Format("{0} sticker", _faces[i])); if (sticker != null) { sticker.GetComponent <MeshRenderer>().material = StickerMaterials[colors[i]]; } } } } } } _colorblind = ColorblindMode.ColorblindModeActive; if (_colorblind) { SetColorblindMode(); } for (var i = 0; i < ColorblindTexts.Length; i++) { ColorblindTexts[i].text = colorNames[colors[i / 2]].Substring(0, 1); } Debug.LogFormat("[Rubik's Cube #{0}] Face colors: {1}", _moduleId, string.Join(", ", new[] { 0, 1, 2, 4, 3 }.Select(i => string.Format("{0}={1}", _faces[i], colorNames[colors[i]])).ToArray())); Debug.LogFormat("[Rubik's Cube #{0}] Column shifts: U={1}, L={2}, F={3}", _moduleId, columnShifts[0], columnShifts[1], columnShifts[2]); Debug.LogFormat("[Rubik's Cube #{0}] Ignoring serial number character #{1}: {2}", _moduleId, serialIgnore + 1, string.Join(", ", rows.Select((r, rIx) => string.Format("{0}={1}/{2}", ser[rIx], table[r][0].Name, table[r][1].Name)).ToArray())); if (colR >= 1 && colR <= 3) { Debug.LogFormat("[Rubik's Cube #{0}] R face is red/green/blue. Moves now: {1}", _moduleId, string.Join(" ", moves1.Select(m => m.Name).ToArray())); } else { Debug.LogFormat("[Rubik's Cube #{0}] R face is NOT red/green/blue. Moves now: {1}", _moduleId, string.Join(" ", moves1.Select(m => m.Name).ToArray())); } if (colR == 0 || colR == 2) { Debug.LogFormat("[Rubik's Cube #{0}] R face is red/yellow: change the first five moves to their opposites.", _moduleId); } else if (colR == 3 || colR == 5) { Debug.LogFormat("[Rubik's Cube #{0}] R face is green/white: reverse the order of all the moves.", _moduleId); } Debug.LogFormat("[Rubik's Cube #{0}] Solution: {1}", _moduleId, string.Join(" ", moves2.Select(m => m.Name).ToArray())); Debug.LogFormat("[Rubik's Cube #{0}] Minimized solution: {1}", _moduleId, string.Join(" ", _solveMoves.Select(m => m.Name).ToArray())); _cubeletsSolved = new Transform[3, 3, 3]; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { for (int z = 0; z < 3; z++) { if (x != 1 || y != 1 || z != 1) { _cubeletsSolved[x, y, z] = _cubelets[x, y, z].Cubelet; } } } } Module.OnActivate += delegate { var pusherMoveInfos = @" B = F002 C002 E311 B311 B’ = B111 E111 C022 F022 D = B211 H211 A201 D201 D’ = D001 A001 H011 B011 F = H111 K111 I022 L022 F’ = L002 I002 K311 H311 L = C032 I032 G301 A301 L’ = A101 G101 I012 C012 R = D101 J101 L012 F012 R’ = F032 L032 J301 D301 U = J001 G001 K011 E011 U’ = E211 K211 G201 J201 " .Split('\n') .Select(s => s.Trim()) .Where(s => s.Length > 1) .Select(s => s.Split('=')) .Select(inf => new { Move = _moves[inf[0].Trim()], Pushers = inf[1].Trim().Split(' ').Select(str => Pushers[str[0] - 'A']).ToArray(), Rotations = inf[1].Trim().Split(' ').Select(str => new Vector3((str[1] - '0') * 90, (str[2] - '0') * 90, (str[3] - '0') * 90)).ToArray() }) .ToArray(); for (int pix = 0; pix < Pushers.Length; pix++) { SetPusherEvents(new Pusher( selectable: Pushers[pix], moves: pusherMoveInfos.Where(inf => inf.Pushers.Contains(Pushers[pix])).Select(inf => inf.Move).ToArray(), moveIndexes: pusherMoveInfos.Where(inf => inf.Pushers.Contains(Pushers[pix])).Select(inf => Array.IndexOf(inf.Pushers, Pushers[pix])).ToArray(), localPos: pix % 3 == 0 ? new Vector3(3.01f, 4 * (pix / 9) - 2, 4 * ((pix / 3) % 3) - 2) : pix % 3 == 1 ? new Vector3(4 * (pix / 9) - 2, 4 * ((pix / 3) % 3) - 2, -3.01f) : new Vector3(4 * (pix / 9) - 2, 3.01f, 4 * ((pix / 3) % 3) - 2), localAngles: pusherMoveInfos.Where(inf => inf.Pushers.Contains(Pushers[pix])).Select(inf => inf.Rotations[Array.IndexOf(inf.Pushers, Pushers[pix])]).ToArray() )); } if (!_mysteryHidden) { PerformInitialRotations(); } Bomb.OnBombExploded += delegate { if (!_isSolved && _performedMoves.Count > 0) { Debug.LogFormat("[Rubik's Cube #{0}] Moves performed before bomb exploded: {1}", _moduleId, string.Join(" ", _performedMoves.Reverse().Select(m => m.Name).ToArray())); } }; Reset.OnInteract += delegate { Reset.AddInteractionPunch(); Audio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.ButtonPress, Reset.transform); if (_isSolved || _performedMoves.Count == 0) { return(false); } Debug.LogFormat("[Rubik's Cube #{0}] Moves performed before reset: {1}", _moduleId, string.Join(" ", _performedMoves.Reverse().Select(m => m.Name).ToArray())); _queue.Enqueue(_resetSpeed); while (_performedMoves.Count > 0) { _queue.Enqueue(_performedMoves.Pop().Reverse); } _queue.Enqueue(_normalRotationSpeed); return(false); }; MainSelectable.OnCancel += delegate { if (_selectedPusher != null) { _selectedPusher.MeshRenderer.enabled = false; _selectedPusher = null; } return(true); }; }; }