From 16dfcc33cdad1272c7a524e84172bcc95a2b2027 Mon Sep 17 00:00:00 2001 From: Joachim Date: Fri, 24 Aug 2018 23:14:07 +0200 Subject: [PATCH] added a slower, yet optimized version... hrummm --- src/main/kotlin/be/nielandt/Counter.kt | 29 +++++++++ src/main/kotlin/be/nielandt/CrossSolver.kt | 74 +++++++++++++++++++--- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/be/nielandt/Counter.kt b/src/main/kotlin/be/nielandt/Counter.kt index fafdaec..58f0e25 100644 --- a/src/main/kotlin/be/nielandt/Counter.kt +++ b/src/main/kotlin/be/nielandt/Counter.kt @@ -1,5 +1,7 @@ package be.nielandt +import kotlin.math.min + /** * Counter for X digits of a given base. */ @@ -42,6 +44,33 @@ class Counter(size: Int, val base: Int = 10) { return true } + fun increaseAndSkipInvalid(): Boolean { + var lmi = lastModifiedIndex + var last = increase() + lmi = min(lastModifiedIndex, lmi) + // are we having an invalid situation? this would be two consecutive moves on the same face + while (containsConsecutiveSameFaceMoves() && !atMax()) { + last = increase() + lmi = min(lastModifiedIndex, lmi) + } + // we have to set the lastmodified index to the lowest point that it got to... otherwise we might be skipping some cases + this.lastModifiedIndex = lmi + return last + } + + /** + * Are there two moves in the current counter / chain that act on the same face? This would be F+F2 for example. + */ + private fun containsConsecutiveSameFaceMoves(): Boolean { + for (i in 1 until this.counter.size) { + val current = Move.values()[this.counter[i]] + val previous = Move.values()[this.counter[i - 1]] + if (current sameFace previous) + return true + } + return false + } + /** * How many digits does this counter contain? */ diff --git a/src/main/kotlin/be/nielandt/CrossSolver.kt b/src/main/kotlin/be/nielandt/CrossSolver.kt index 804df56..00eef19 100644 --- a/src/main/kotlin/be/nielandt/CrossSolver.kt +++ b/src/main/kotlin/be/nielandt/CrossSolver.kt @@ -44,13 +44,17 @@ fun main(args: Array) { println(scrambledModel) // doAllCrossMoveCounts(scrambledModel) - val allCrossMoveCount = allCrossMoveCount(scrambledModel) - allCrossMoveCount.forEach { color, moves -> - println("cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}") - } +// val allCrossMoveCount = allCrossMoveCount(scrambledModel) +// allCrossMoveCount.forEach { color, moves -> +// println("cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}") +// } val allCrossMoveCountUpgraded = allCrossMoveCountUpgraded(scrambledModel) - allCrossMoveCount.forEach { color, moves -> - println("cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}") + allCrossMoveCountUpgraded.forEach { color, moves -> + println("upgrade cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}") + } + val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel) + allCrossMoveCountUpgradedSkip.forEach { color, moves -> + println("skip upgrade cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}") } } @@ -90,6 +94,47 @@ fun crossMoveCount(edgeModel: EdgeModel, color: Color): List? { return null } +/** + * Solve the minimal cross for all colors. Try to upgrade the method... Can we cache the 'previous results'? + */ +fun allCrossMoveCountUpgradedSkip(edgeModel: EdgeModel): Map> { + val start = Instant.now() + val moveCounts = mutableMapOf>() + + for (moveCount in 1..8) { + println("all cross move count upgrade doing $moveCount") + // build a counter of moveCount big + val counter = Counter(moveCount, Move.values().size) + val edgeModelFactory = EdgeModelFactory(edgeModel, counter, true) + + println("moveCounts = ${moveCounts}") + + while (edgeModelFactory.hasNext()) { + // get the next model, using the internal counter which simply iterates over possible combinations of moves + val next = edgeModelFactory.getNext() + + // check crosses that have not been found yet + Color.values().forEach { color -> + if (!moveCounts.containsKey(color)) { + val crossSolved = next.crossSolved(color) + if (crossSolved) { + // what is the move combination we're looking at? + val moves = Move.combo(counter) + moveCounts[color] = moves + } + } + } + // break if we have found hem all + if (moveCounts.keys.size == Color.values().size) { + println("Execution time: ${Duration.between(start, Instant.now()).toMillis() / 1000}s") +// println("counter.skipInvalidCount = ${counter.skipInvalidCount}") + return moveCounts + } + } + } + println("Execution time: ${Duration.between(start, Instant.now()).toMillis() / 1000}s") + return moveCounts +} /** * Solve the minimal cross for all colors. Try to upgrade the method... Can we cache the 'previous results'? */ @@ -104,7 +149,9 @@ fun allCrossMoveCountUpgraded(edgeModel: EdgeModel): Map> { val edgeModelFactory = EdgeModelFactory(edgeModel, counter) while (edgeModelFactory.hasNext()) { + // get the next model, using the internal counter which simply iterates over possible combinations of moves val next = edgeModelFactory.getNext() + // check crosses that have not been found yet Color.values().forEach { color -> if (!moveCounts.containsKey(color)) { @@ -134,7 +181,7 @@ fun allCrossMoveCountUpgraded(edgeModel: EdgeModel): Map> { * * This is probably equivalent to 8 nested for loops, you'd be able to keep track of temporary solutions there too.... */ -class EdgeModelFactory(val original: EdgeModel, val counter: Counter) { +class EdgeModelFactory(val original: EdgeModel, val counter: Counter, val skip: Boolean = false) { // keep a modified version of the edgemodel for each digit in the counter, from left to right private val history: MutableList = mutableListOf() @@ -161,7 +208,7 @@ class EdgeModelFactory(val original: EdgeModel, val counter: Counter) { val moves = Move.combo(counter) // we have a history to work with... only redo what's necessary for (i in counter.getLastModifiedIndex() until counter.size()) { - var start: EdgeModel? = null + var start: EdgeModel? start = if (i == 0) original else @@ -169,8 +216,14 @@ class EdgeModelFactory(val original: EdgeModel, val counter: Counter) { history[i] = start.doMove(Move.values()[counter.digit(i)]) } // increase the counter for next time - if (!counter.increase()) { - this.hasNext = false + if(!skip) { + if (!counter.increase()) { + this.hasNext = false + } + } else { + if (!counter.increaseAndSkipInvalid()) { + this.hasNext = false + } } // the last item in the history is now the edgemodel we need to test... return history.last() @@ -186,6 +239,7 @@ fun allCrossMoveCount(edgeModel: EdgeModel): Map> { for (moveCount in 1..8) { // build a counter of moveCount big + println("allCrossMoveCount basic doing $moveCount") val counter = Counter(moveCount, Move.values().size) // count up, each state of the counter corresponds to a combination of moves