From 50b947e78a7b86006c96ff9899e325e351cf50ff Mon Sep 17 00:00:00 2001 From: Emil Goldsmith Olesen Date: Thu, 9 May 2019 09:52:57 +0400 Subject: [PATCH 1/3] Minor code cleanup --- lib/solve.js | 14 ++++++-------- src/solve.coffee | 10 ++-------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/solve.js b/lib/solve.js index d263e3a..2aa5769 100644 --- a/lib/solve.js +++ b/lib/solve.js @@ -813,14 +813,14 @@ solution = null; phase1search = function(state) { var depth, m, ref, results; - depth = 0; results = []; for (depth = m = 1, ref = maxDepth; (1 <= ref ? m <= ref : m >= ref); depth = 1 <= ref ? ++m : --m) { phase1(state, depth); if (solution !== null) { break; + } else { + results.push(void 0); } - results.push(depth++); } return results; }; @@ -863,8 +863,9 @@ phase2(state, depth); if (solution !== null) { break; + } else { + results.push(void 0); } - results.push(depth++); } return results; }; @@ -904,11 +905,8 @@ state = freeStates.pop().init(this); phase1search(state); freeStates.push(state); - // Trim the trailing space - if (solution.length > 0) { - solution = solution.substring(0, solution.length - 1); - } - return solution; + // Trim the trailing space and return + return solution.trim(); }; faceNums = { diff --git a/src/solve.coffee b/src/solve.coffee index b91459b..53b4439 100644 --- a/src/solve.coffee +++ b/src/solve.coffee @@ -616,11 +616,9 @@ Cube::solveUpright = (maxDepth=22) -> solution = null phase1search = (state) -> - depth = 0 for depth in [1..maxDepth] phase1(state, depth) break if solution isnt null - depth++ phase1 = (state, depth) -> if depth is 0 @@ -646,7 +644,6 @@ Cube::solveUpright = (maxDepth=22) -> for depth in [1..maxDepth - state.depth] phase2(state, depth) break if solution isnt null - depth++ phase2 = (state, depth) -> if depth is 0 @@ -665,11 +662,8 @@ Cube::solveUpright = (maxDepth=22) -> phase1search(state) freeStates.push(state) - # Trim the trailing space - if solution.length > 0 - solution = solution.substring(0, solution.length - 1) - - solution + # Trim the trailing space and return + solution.trim() faceNums = U: 0 From 56eafd42006e05561435e35db6817f1036376371 Mon Sep 17 00:00:00 2001 From: Emil Goldsmith Olesen Date: Thu, 9 May 2019 09:55:02 +0400 Subject: [PATCH 2/3] Allow for starting in phase 2 --- lib/solve.js | 26 +++++++++++++++----------- src/solve.coffee | 25 ++++++++++++++----------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/lib/solve.js b/lib/solve.js index 2aa5769..1b6a1cc 100644 --- a/lib/solve.js +++ b/lib/solve.js @@ -776,18 +776,22 @@ // Initialize phase 2 coordinates init2(top = true) { - if (this.parent === null) { + if (this.parent === null && !top) { return; } - // For other states, the phase 2 state is computed based on - // parent's state. + // If parent is null then this is the initial call which must mean + // the cube started in phase 2 so there is no need for this // Already assigned for the initial state - this.parent.init2(false); - this.URFtoDLF = this.move('URFtoDLF', this.parent.URFtoDLF, this.lastMove); - this.FRtoBR = this.move('FRtoBR', this.parent.FRtoBR, this.lastMove); - this.parity = this.move('parity', this.parent.parity, this.lastMove); - this.URtoUL = this.move('URtoUL', this.parent.URtoUL, this.lastMove); - this.UBtoDF = this.move('UBtoDF', this.parent.UBtoDF, this.lastMove); + if (this.parent !== null) { + // For other states, the phase 2 state is computed based on + // parent's state. + this.parent.init2(false, false); + this.URFtoDLF = this.move('URFtoDLF', this.parent.URFtoDLF, this.lastMove); + this.FRtoBR = this.move('FRtoBR', this.parent.FRtoBR, this.lastMove); + this.parity = this.move('parity', this.parent.parity, this.lastMove); + this.URtoUL = this.move('URtoUL', this.parent.URtoUL, this.lastMove); + this.UBtoDF = this.move('UBtoDF', this.parent.UBtoDF, this.lastMove); + } if (top) { // This is the initial phase 2 state. Get the URtoDF coordinate // by merging URtoUL and UBtoDF @@ -814,7 +818,7 @@ phase1search = function(state) { var depth, m, ref, results; results = []; - for (depth = m = 1, ref = maxDepth; (1 <= ref ? m <= ref : m >= ref); depth = 1 <= ref ? ++m : --m) { + for (depth = m = 0, ref = maxDepth; (0 <= ref ? m <= ref : m >= ref); depth = 0 <= ref ? ++m : --m) { phase1(state, depth); if (solution !== null) { break; @@ -859,7 +863,7 @@ // Initialize phase 2 coordinates state.init2(); results = []; - for (depth = m = 1, ref = maxDepth - state.depth; (1 <= ref ? m <= ref : m >= ref); depth = 1 <= ref ? ++m : --m) { + for (depth = m = 0, ref = maxDepth - state.depth; (0 <= ref ? m <= ref : m >= ref); depth = 0 <= ref ? ++m : --m) { phase2(state, depth); if (solution !== null) { break; diff --git a/src/solve.coffee b/src/solve.coffee index 53b4439..8644c4f 100644 --- a/src/solve.coffee +++ b/src/solve.coffee @@ -579,19 +579,22 @@ Cube::solveUpright = (maxDepth=22) -> # Initialize phase 2 coordinates init2: (top=true) -> - if @parent is null + if @parent is null and not top # Already assigned for the initial state return - # For other states, the phase 2 state is computed based on - # parent's state. - @parent.init2(false) + # If parent is null then this is the initial call which must mean + # the cube started in phase 2 so there is no need for this + if @parent isnt null + # For other states, the phase 2 state is computed based on + # parent's state. + @parent.init2(false, false) - @URFtoDLF = @move('URFtoDLF', @parent.URFtoDLF, @lastMove) - @FRtoBR = @move('FRtoBR', @parent.FRtoBR, @lastMove) - @parity = @move('parity', @parent.parity, @lastMove) - @URtoUL = @move('URtoUL', @parent.URtoUL, @lastMove) - @UBtoDF = @move('UBtoDF', @parent.UBtoDF, @lastMove) + @URFtoDLF = @move('URFtoDLF', @parent.URFtoDLF, @lastMove) + @FRtoBR = @move('FRtoBR', @parent.FRtoBR, @lastMove) + @parity = @move('parity', @parent.parity, @lastMove) + @URtoUL = @move('URtoUL', @parent.URtoUL, @lastMove) + @UBtoDF = @move('UBtoDF', @parent.UBtoDF, @lastMove) if top # This is the initial phase 2 state. Get the URtoDF coordinate @@ -616,7 +619,7 @@ Cube::solveUpright = (maxDepth=22) -> solution = null phase1search = (state) -> - for depth in [1..maxDepth] + for depth in [0..maxDepth] phase1(state, depth) break if solution isnt null @@ -641,7 +644,7 @@ Cube::solveUpright = (maxDepth=22) -> # Initialize phase 2 coordinates state.init2() - for depth in [1..maxDepth - state.depth] + for depth in [0..maxDepth - state.depth] phase2(state, depth) break if solution isnt null From 56f0a16a93c5096d80f217ae34eea32d33502b54 Mon Sep 17 00:00:00 2001 From: Emil Goldsmith Olesen Date: Thu, 9 May 2019 10:11:30 +0400 Subject: [PATCH 3/3] Update cube solver tests --- spec/cube.spec.coffee | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/spec/cube.spec.coffee b/spec/cube.spec.coffee index 1bc7c22..073392d 100644 --- a/spec/cube.spec.coffee +++ b/spec/cube.spec.coffee @@ -53,8 +53,24 @@ describe 'Cube', -> moves = Cube.inverse "F B' R" expect(moves).toBe "R' B F'" - # ignore because Travis is slow - xit 'should solve a solved cube :) ', -> + # It seems Cube init state is reset between tests so we keep it all in one + # Due to Travis being slow we skip this but if you change algorithm you should + # run it locally + xit 'should solve cubes', -> Cube.initSolver() + # Should solve empty cube cube = new Cube - expect(cube.solve()).toBe "R L U2 R L F2 R2 U2 R2 F2 R2 U2 F2 L2" + expect(cube.solve()).toBe "" + + # Should solve trivial cube efficiently + cube.move("U'") + expect(cube.solve()).toBe "U" + + # Should solve random cube + cube = Cube.random() + # Should not be solved initially + expect(cube.isSolved()).toBeFalse + solution = cube.solve() + cube.move(solution) + # Solution should have solved the cube + expect(cube.isSolved()).toBeTrue