private KMSelectable.OnInteractHandler GetSelectableHandler(int ix) { return(delegate { Audio.PlayGameSoundAtTransform(KMSoundOverride.SoundEffect.ButtonPress, SelectableBoxes[ix].transform); SelectableBoxes[ix].AddInteractionPunch(); if (_selectableSymbols[ix] == null) { // The user clicked on a symbol that is already on the net; allow that and do nothing. return false; } if (ix != _selected) { // Just update the selection _selected = ix; } else { var tsk = new RotateTask { From = _selectableSymbols[ix].Orientation, To = (_selectableSymbols[ix].Orientation + 1) % 4 }; _selectableSymbols[ix] = new FaceSymbol(_selectableSymbols[ix].Symbol, tsk.To); _queues[ix].Enqueue(tsk); } AssignSymbols(); return false; }); }
public HalfCube(FaceSymbol top, FaceSymbol left, FaceSymbol front) { Top = top; Left = left; Front = front; }
void Start() { _moduleId = _moduleIdCounter++; var numbers = Enumerable.Range(0, 26).Where(i => i != 20).ToList(); // exclude “U” because that’s a valid command (u-turn = 180) for (int i = 0; i < 6; i++) { var ix = Rnd.Range(0, numbers.Count); _tpLetters[i] = (char)('A' + numbers[ix]); TpLetters[i].text = _tpLetters[i].ToString(); TpLetters[i].gameObject.SetActive(false); numbers.RemoveAt(ix); } for (int i = 0; i < 5; i++) { _selectableSymbolObjs[i] = SelectableBoxes[i].transform.Find("Symbol").GetComponent <MeshRenderer>(); _selectableFrameObjs[i] = SelectableBoxes[i].transform.Find("Frame").GetComponent <MeshRenderer>(); _selectableScreenObjs[i] = SelectableBoxes[i].transform.Find("Screen").GetComponent <MeshRenderer>(); _queues[i] = new Queue <RotateTask>(); StartCoroutine(rotator(i)); } for (int i = 0; i < 6; i++) { _placeableSymbolObjs[i] = PlaceableBoxes[i].transform.Find("Symbol").GetComponent <MeshRenderer>(); _placeableFrameObjs[i] = PlaceableBoxes[i].transform.Find("Frame").GetComponent <MeshRenderer>(); _placeableScreenObjs[i] = PlaceableBoxes[i].transform.Find("Screen").GetComponent <MeshRenderer>(); } for (int i = 0; i < 25; i++) { if (i % 5 != 0) { MainSelectable.Children[i] = null; } } // Generate the rules List <int> symbolIxs; var rnd = RuleSeedable.GetRNG(); Debug.LogFormat("[Pattern Cube #{0}] Using rule seed: {1}", _moduleId, rnd.Seed); string[] groupStrs = new string[2]; if (rnd.Seed == 1) { groupStrs[0] = "X1,A3,B1;Y0,X1,A1;B0,D1,C2;Z1,A2,X0;Y2,B0,A2;Y3,C1,B0;" + "X2,C0,A1;X1,Y2,B0;C2,A3,D1;Z1,X3,B1;A2,C3,Y2;D1,B2,Y0;" + "X2,C2,B1;X1,A2,D2;X2,C3,Y0;D3,A0,B3;X0,Z2,C1;A0,Y3,D0;" + "D0,B0,X0;X1,C1,D0;Y0,D0,X3;C3,B3,A1;Z1,D0,X0;C1,D0,Y2"; groupStrs[1] = "X1,E0,F0;X0,E3,Y1;H1,G1,F1;Y3,Z3,E1;Z3,F1,E2;G1,Z1,F1;" + "E0,X2,G1;X0,F0,Y2;G1,E2,H3;F1,Y2,Z0;G2,E2,Z1;F1,Z1,H2;" + "G1,X1,F0;H3,X2,E2;Y1,X3,G3;H1,E3,F0;G0,Z2,Y0;Z0,H2,E3;" + "X3,H1,F0;G1,H3,X0;X3,H3,Y0;E0,F0,G1;Z3,Y3,H1;Z2,H3,G2"; symbolIxs = new List <int> { 90, 91, 92, 93, 100, 101, 102, 103, 110, 111, 112 }; } else { var skip = rnd.Next(0, 100); for (var i = 0; i < skip; i++) { rnd.NextDouble(); } symbolIxs = Enumerable.Range(0, 120).ToList(); rnd.ShuffleFisherYates(symbolIxs); var groupsTemplates = new[] { "ABX,AXY,BCD,AXZ,ABY,BCY,ACX,BXY,ACD,BXZ,ACY,BDY,BCX,ADX,CXY,ABD,CXZ,ADY,BDX,CDX,DXY,ABC,DXZ,CDY", "EFX,EXY,FGH,EYZ,EFZ,FGZ,EGX,FXY,EGH,FYZ,EGZ,FHZ,FGX,EHX,GXY,EFH,GYZ,EHZ,FHX,GHX,HXY,EFG,HYZ,GHZ" }; for (var i = 0; i < 2; i++) { var grs = groupsTemplates[i].Split(','); var arr = new List <string>(); for (var j = 0; j < grs.Length; j++) { var smbs = grs[j].Select(ch => ch.ToString()).ToList(); rnd.ShuffleFisherYates(smbs); for (var k = 0; k < smbs.Count; k++) { smbs[k] = smbs[k] + rnd.Next(0, 4); } arr.Add(smbs.JoinString(",")); } groupStrs[i] = arr.JoinString(";"); } } HalfCube[][] groups = groupStrs.Select(str => str.Split(';').Select(hci => hci.Split(',').Select(fc => new FaceSymbol(fc[0], fc[1] - '0')).ToArray()).Select(arr => new HalfCube(arr[0], arr[1], arr[2])).ToArray()).ToArray(); // Generate a puzzle _puzzle = Data.Nets[Rnd.Range(0, Data.Nets.Length)]; HalfCube[] frontHalfCubes, backHalfCubes; if (Rnd.Range(0, 2) == 0) { frontHalfCubes = groups[0]; backHalfCubes = groups[1]; } else { frontHalfCubes = groups[1]; backHalfCubes = groups[0]; } var frontHalfCube = frontHalfCubes[Rnd.Range(0, frontHalfCubes.Length)]; var symbolsAlready = new[] { frontHalfCube.Top.Symbol, frontHalfCube.Left.Symbol, frontHalfCube.Front.Symbol }; var backHalfCubeCandidates = backHalfCubes.Where(ag => !new[] { ag.Top.Symbol, ag.Left.Symbol, ag.Front.Symbol }.Intersect(symbolsAlready).Any()).ToArray(); var backHalfCube = backHalfCubeCandidates[Rnd.Range(0, backHalfCubeCandidates.Length)]; FaceSymbol right, back, bottom; switch (Rnd.Range(0, 3)) { case 0: back = new FaceSymbol(backHalfCube.Front.Symbol, (backHalfCube.Front.Orientation + 3) % 4); right = new FaceSymbol(backHalfCube.Top.Symbol, (backHalfCube.Top.Orientation + 3) % 4); bottom = new FaceSymbol(backHalfCube.Left.Symbol, (backHalfCube.Left.Orientation + 3) % 4); break; case 1: back = new FaceSymbol(backHalfCube.Top.Symbol, backHalfCube.Top.Orientation); right = new FaceSymbol(backHalfCube.Left.Symbol, (backHalfCube.Left.Orientation + 1) % 4); bottom = new FaceSymbol(backHalfCube.Front.Symbol, backHalfCube.Front.Orientation); break; default: back = new FaceSymbol(backHalfCube.Left.Symbol, (backHalfCube.Left.Orientation + 2) % 4); right = new FaceSymbol(backHalfCube.Front.Symbol, (backHalfCube.Front.Orientation + 2) % 4); bottom = new FaceSymbol(backHalfCube.Top.Symbol, (backHalfCube.Top.Orientation + 1) % 4); break; } _faceGivenByHighlight = Rnd.Range(0, 6); var faceGivenFully = (new[] { 0, 1, 4 }.Contains(_faceGivenByHighlight) ? new[] { 2, 3, 5 } : new[] { 0, 1, 4 })[Rnd.Range(0, 3)]; _facesRevealed.Add(faceGivenFully); _solution = new[] { frontHalfCube.Top, frontHalfCube.Front, right, back, frontHalfCube.Left, bottom }; _selectableSymbols = _solution.Except(new[] { _solution[faceGivenFully] }).ToArray().Shuffle(); for (int i = 0; i < _selectableSymbols.Length; i++) { _selectableSymbols[i] = new FaceSymbol(_selectableSymbols[i].Symbol, Rnd.Range(0, 4)); if (_selectableSymbols[i].Symbol == _solution[_faceGivenByHighlight].Symbol) { _highlightedPosition = i; } } // Populate the selectable boxes for (int i = 0; i < 5; i++) { _selectableSymbolObjs[i].material.mainTexture = SymbolTextures[symbolIxs["ABCDEFGHXYZ".IndexOf(_selectableSymbols[i].Symbol)]]; _selectableSymbolObjs[i].transform.localEulerAngles = new Vector3(90, _selectableSymbols[i].Orientation * 90, 0); _selectableFrameObjs[i].material = FrameRed; _selectableScreenObjs[i].material = _selectableSymbols[i].Symbol == _solution[_faceGivenByHighlight].Symbol ? ScreenLight : ScreenDark; SelectableBoxes[i].OnInteract = GetSelectableHandler(i); } // Arrange the placeable boxes const float x1 = -.8f; const float x2 = .8f; const float y1 = -.8f; const float y2 = .8f; const float w = (x2 - x1) / 5.5f; const float h = (y2 - y1) / 5.5f; for (int y = 0; y < _puzzle.Faces.GetLength(1); y++) { for (int x = 0; x < _puzzle.Faces.GetLength(0); x++) { if (_puzzle.Faces[x, y] == null) { continue; } var fi = _puzzle.Faces[x, y]; _placeableSymbolObjs[fi.Face].transform.localEulerAngles = new Vector3(90, (fi.Orientation + _solution[fi.Face].Orientation) * 90, 0); _placeableSymbolObjs[fi.Face].material.mainTexture = SymbolTextures[symbolIxs["ABCDEFGHXYZ".IndexOf(_solution[fi.Face].Symbol)]]; _placeableSymbolObjs[fi.Face].gameObject.SetActive(fi.Face == faceGivenFully); _placeableFrameObjs[fi.Face].material = fi.Face == faceGivenFully ? FrameGreen : FrameYellow; _placeableScreenObjs[fi.Face].material = fi.Face == _faceGivenByHighlight ? ScreenLight : ScreenDark; PlaceableBoxes[fi.Face].transform.localPosition = new Vector3(x1 + w * (x + 2), 0, y1 + h * (_puzzle.Faces.GetLength(1) - y - .5f)) * .1f; PlaceableBoxes[fi.Face].OnInteract = GetPlaceableHandler(fi); MainSelectable.Children[(5 - _puzzle.Faces.GetLength(1) + y) * 5 + x + 1] = PlaceableBoxes[fi.Face]; } } MainSelectable.UpdateChildren(SelectableBoxes[0]); // Set the correct mesh for the module front var id = "ModuleFront_" + _puzzle.ID; ModuleFront.mesh = NetMeshes.First(m => m.name == id); Log(@"=svg[Puzzle:]<svg xmlns='http://www.w3.org/2000/svg' viewBox='-3 -3 1206 {0}'>{1}</svg>", /* {0} */ 120 * _puzzle.Faces.GetLength(1) + 6, /* {1} */ Enumerable.Range(0, _puzzle.Faces.GetLength(1)).SelectMany(y => Enumerable.Range(0, _puzzle.Faces.GetLength(0)).Select(x => _puzzle.Faces[x, y] == null ? null : _puzzle.Faces[x, y].Face == faceGivenFully ? svg(x, y, symbolIxs["ABCDEFGHXYZ".IndexOf(_solution[_puzzle.Faces[x, y].Face].Symbol)], (_solution[_puzzle.Faces[x, y].Face].Orientation + _puzzle.Faces[x, y].Orientation) % 4) : svg(x, y, highlighted: _puzzle.Faces[x, y].Face == _faceGivenByHighlight))).JoinString()); Log(@"=svg[Symbols:]<svg xmlns='http://www.w3.org/2000/svg' viewBox='-3 -3 1206 126'>{0}</svg>", _selectableSymbols.Select((s, ix) => svgPath(ix, 0, symbolIxs["ABCDEFGHXYZ".IndexOf(s.Symbol)], 0)).JoinString()); Log(@" The highlighted symbol is {0}.", "first,second,third,4th,5th".Split(',')[_highlightedPosition]); Log(@"=svg[Solution:]<svg xmlns='http://www.w3.org/2000/svg' viewBox='-3 -3 1206 {0}'>{1}</svg>", /* {0} */ 120 * _puzzle.Faces.GetLength(1) + 6, /* {1} */ Enumerable.Range(0, _puzzle.Faces.GetLength(1)).SelectMany(y => Enumerable.Range(0, _puzzle.Faces.GetLength(0)).Select(x => _puzzle.Faces[x, y] == null ? null : svg(x, y, symbolIxs["ABCDEFGHXYZ".IndexOf(_solution[_puzzle.Faces[x, y].Face].Symbol)], (_solution[_puzzle.Faces[x, y].Face].Orientation + _puzzle.Faces[x, y].Orientation) % 4))).JoinString()); AssignSymbols(); // Because TP doesn’t set TwitchPlaysActive soon enough, we have to delay the TP letter initialization Module.OnActivate += delegate { AssignSymbols(); }; }