static TurnSequenceMove[] CalculatedAllowedMovesForSlot(FtlSlot slot) { Turn u0 = new Turn(Side.Up, Rotation.Clockwise); Turn u1 = new Turn(Side.Up, Rotation.CounterClockwise); Turn u2 = new Turn(Side.Up, Rotation.Twice); Turn leftOfSlotUp = new Turn(slot.LeftOf, Rotation.CounterClockwise); Turn leftOfSlotDown = new Turn(slot.LeftOf, Rotation.Clockwise); Turn rightOfSlotUp = new Turn(slot.RightOf, Rotation.Clockwise); Turn rightOfSlotDown = new Turn(slot.RightOf, Rotation.CounterClockwise); var allowedMoves = new TurnSequence[] { new TurnSequence(u0), new TurnSequence(u1), new TurnSequence(u2), new TurnSequence(rightOfSlotUp, u0, rightOfSlotDown), new TurnSequence(rightOfSlotUp, u1, rightOfSlotDown), new TurnSequence(rightOfSlotUp, u2, rightOfSlotDown), new TurnSequence(leftOfSlotUp, u0, leftOfSlotDown), new TurnSequence(leftOfSlotUp, u1, leftOfSlotDown), new TurnSequence(leftOfSlotUp, u2, leftOfSlotDown), }.Select(x => new TurnSequenceMove(x)) .ToArray(); return(allowedMoves); }
static public CubeConstraint OtherSlotsConstraint(FtlSlot movingSlot) { var slotsToNotMove = AllFtlSlots .Where(x => !x.Home.Edge.InSameSpace(movingSlot.Home.Edge)); return(new CompoundConstraint(slotsToNotMove.Select(x => x.Home.Stationary))); }
static TurnSequenceMove[] CalculateMovesForPoppingCubeIntoTopRow(FtlSlot slot) { // !!! if there is already a cube in the top, // we might want to include the top turns, so cube currently in top, doesn't go into bottom. // !!! option: instead of adding this on, to SlotTurnGenerator, // just have extra step in solver to pop cube up, // then filter out any first moves that don't have both cubes in top // !!! also, when picking best move, perhaps secondary criteria is // to not put any other slot cubes in the slot we just vacated. Turn u0 = new Turn(Side.Up, Rotation.Clockwise); Turn u1 = new Turn(Side.Up, Rotation.CounterClockwise); Turn u2 = new Turn(Side.Up, Rotation.Twice); Turn leftOfSlotUp = new Turn(slot.LeftOf, Rotation.CounterClockwise); Turn leftOfSlotDown = new Turn(slot.LeftOf, Rotation.Clockwise); Turn rightOfSlotUp = new Turn(slot.RightOf, Rotation.Clockwise); Turn rightOfSlotDown = new Turn(slot.RightOf, Rotation.CounterClockwise); var allowedMoves = new TurnSequence[] { new TurnSequence(u0), new TurnSequence(u1), new TurnSequence(u2), new TurnSequence(rightOfSlotUp, u0, rightOfSlotDown), new TurnSequence(rightOfSlotUp, u1, rightOfSlotDown), new TurnSequence(rightOfSlotUp, u2, rightOfSlotDown), new TurnSequence(leftOfSlotUp, u0, leftOfSlotDown), new TurnSequence(leftOfSlotUp, u1, leftOfSlotDown), new TurnSequence(leftOfSlotUp, u2, leftOfSlotDown), }.Select(x => new TurnSequenceMove(x)) .ToArray(); return(allowedMoves); }
public SlotTurnGenerator(FtlSlot slot) { // Alternative to explicitly listing 9 valid moves // Have solver calculate subset of moves that don't violate constraints _defaultAllowedTurns = CalculatedAllowedMovesForSlot(slot); }
public void MustSolveCrossBeforePlacingFtl() { var nonSolvedCrossCube = new Cube().Apply(Turn.Parse("R")); var slot = new FtlSlot(Side.Front, Side.Right); Assert.Throws <System.InvalidOperationException>(() => Solver.PlaceSingleFtlPairFromTop(slot, nonSolvedCrossCube)); }
static public CompoundConstraint FindFtlPairAndSolveIt(FtlSlot slot, Cube cube) { CornerEdgePair src = slot.Home.Locate(cube); return(new CompoundConstraint( new CornerConstraint(src.Corner, slot.Home.Corner), new EdgeConstraint(src.Edge, slot.Home.Edge) )); }
[InlineData("RU'R'UF'U2FUF'U2F")] // RU'R'dR'U2RUR'U2R public void F2L(string knownSolution) { var solveTurns = TurnSequence.Parse(knownSolution); var cube = new Cube().Apply(solveTurns.Reverse()); Assert.True(cube.Apply(solveTurns).IsSolved, "not solved"); var pair = new FtlSlot(Side.Front, Side.Right); var prepSolution = Solver.PlaceSingleFtlPairFromTop(pair, cube); cube = cube.Apply(prepSolution); Assert_F2LSolved(cube); Assert_CrossSolved(cube); }
static public TurnSequence PlaceFtlPairs(Cube cube) { Constraints.VerifyConstraint(cube, Constraints.CrossConstraint, "Cross not solved"); var cur = cube; var turns = new List <Turn>(); FtlSlot easiestSlotToSolve = FindEasiestSlotToSolve(cur); while (easiestSlotToSolve != null) { int num = HoldingSlotCount(easiestSlotToSolve, cur); string debug = string.Join("\r\n", Constraints.AllFtlSlots.Select(slot => slot.Home.Examine(cur))); try{ var move = PlaceSingleFtlPairFromTop(easiestSlotToSolve, cur); turns.AddRange(move._turns); cur = cur.Apply(move); }catch (MoveNotFoundExcpetion) { string location = easiestSlotToSolve.Home.Locate(cur).ToString(); int i = 0; } easiestSlotToSolve = FindEasiestSlotToSolve(cur); } return(new TurnSequence(turns.ToArray())); // if parts of cube are in different slots // there are 2 options as to which cube you pop-up first // to move 1 slot up where there are no pairs in upper // there are only 6 option (3 leftish + 3 rightish) // to move 1 slot up where one of the pairs is already in upper // there are 4 Upper turns * (3 leftish + 3 rightish) = 24 options // Also 24 happens to be the Least Common Multiple of 8 edge positions & 12 corner positions // If we evaluate all of them, 2*6*24 ==> 288 positions we have to solve // but there are essenially only 12 possibilities (white-up:4 + white-to-theside:8) // knowledge: // white-on-the-side is better than white-up -> reduces possibility from 12 to 8 // case 1 or 2 (joined or side-op) are better than case 3 or 4 // joined incorrectly is the worse. }
static public TurnSequence PlaceSingleFtlPairFromTop(FtlSlot slot, Cube cube) { Constraints.VerifyConstraint(cube, Constraints.CrossConstraint, "Cross not solved"); var pair = slot.Home.Locate(cube); var holdingSlots = HoldingSlots(pair); var moveGenerator = new SlotTurnGenerator(slot); if (holdingSlots.Length == 1) { moveGenerator.SetFirstSlot(holdingSlots[0]); } // these are constraints to apply move to a solved cube, so constraints don't work on messed up cube return(Solver.GetStepsToAcheiveMatch(6, new CompoundConstraint( FindFtlPairAndSolveIt(slot, cube), Constraints.CrossConstraint, Constraints.OtherSlotsConstraint(slot) ), moveGenerator )); }
static int HoldingSlotCount(FtlSlot slot, Cube cube) => HoldingSlots(slot.Home.Locate(cube)).Length;
public void SetFirstSlot(FtlSlot firstSlot) { _firstMoveAllowedTurns = CalculateMovesForPoppingCubeIntoTopRow(firstSlot); }