Compare commits
No commits in common. "master" and "tryingoutmirror" have entirely different histories.
master
...
tryingoutm
@ -7,9 +7,9 @@ open abstract class CrossSolver {
|
||||
/**
|
||||
* Solve all crosses, look for a minimal set of moves for each color's cross.
|
||||
*/
|
||||
abstract fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray>
|
||||
abstract fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>>
|
||||
|
||||
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||
val now = Instant.now()
|
||||
val solveCrosses = solveCrosses(edgeModel)
|
||||
val between = Duration.between(now, Instant.now())
|
||||
@ -18,7 +18,7 @@ open abstract class CrossSolver {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun printResults(results: Map<Int, IntArray>) {
|
||||
fun printResults(results: Map<Int, List<Int>>) {
|
||||
println("results: ")
|
||||
results.forEach { color, moveList ->
|
||||
println("> color ${colorLetter(color)}, moves (${moveList.size}) ${moveList.map { it -> decodeMove(it) }}")
|
||||
@ -29,40 +29,64 @@ open abstract class CrossSolver {
|
||||
|
||||
/**
|
||||
* Let's look for symmetries.
|
||||
*
|
||||
* - no changes: base times: 72s, 29s, 61s
|
||||
* - changed list<int> in edgemodel to intarray: 51s, 21s, 35s
|
||||
* - new version, optimised now avoid recalc: 47s, 21s, 34s, 14s, (401592291, 147023415, 67382002, 67381995)
|
||||
*/
|
||||
fun main(args: Array<String>) {
|
||||
/**
|
||||
* choose your moves, fixed or random?
|
||||
*/
|
||||
// val moves = parseMoves("U2 F2 U2 D R2 F2 R2 B2 U' D2 L B L2 U2 L B' U L R B".replace('\'', '_'))
|
||||
val moves = randomMoves(20)
|
||||
|
||||
// val u2 = Move.U2
|
||||
// val doMove = edgeModel.doMove(Move.U2)
|
||||
// println(u2)
|
||||
// println(doMove)
|
||||
// println("doMove.whiteCrossSolved() = ${doMove.whiteCrossSolved()}")
|
||||
|
||||
// val message = EdgeModel().doMoves(Move.R, Move.U, Move.R_)
|
||||
// println(message)
|
||||
// println("message.whiteCrossSolved() = ${message.whiteCrossSolved()}")
|
||||
//
|
||||
// val doMoves = EdgeModel().doMoves(Move.random(15))
|
||||
// println("random 15 moves = ${doMoves}")
|
||||
// println("doMoves.whiteCrossSolved() = ${doMoves.whiteCrossSolved()}")
|
||||
|
||||
|
||||
// val begin = Instant.now()
|
||||
// var i: Long = 0
|
||||
// while (Duration.between(begin, Instant.now()) < Duration.ofMinutes(1)) {
|
||||
// EdgeModel().doMoves(Move.random(15))
|
||||
// i++
|
||||
// }
|
||||
// println("i = ${i}")
|
||||
//
|
||||
// val counter = Counter(4, 3)
|
||||
// while (counter.increase()) {
|
||||
// println("counter = ${counter}")
|
||||
// }
|
||||
|
||||
|
||||
// do a fixed scramble for testing purposes
|
||||
// noskip Move.enum 30s, skip Move.enum 32s
|
||||
val fixedMoves = parseMoves("L_, D, U, L2, F, D, B, D, U2, D, B_, F2, D2, U_, R, D2, R_, L, B_, R")
|
||||
println("fixedMoves = ${fixedMoves}")
|
||||
// scramble random
|
||||
val randomMoves = randomMoves(20)
|
||||
|
||||
val moves = fixedMoves
|
||||
println("Scramble: ${moves.map { decodeMove(it) }}")
|
||||
|
||||
val usedModel = EdgeModel.withMoves(moves)
|
||||
|
||||
val usedModel = EdgeModel(moves)
|
||||
println(usedModel)
|
||||
|
||||
// val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(usedModel)
|
||||
// CrossSolver.printResults(upgradedSolve)
|
||||
//
|
||||
// val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(usedModel)
|
||||
// CrossSolver.printResults(upgradedSolveSkip)
|
||||
//
|
||||
// val solveCrossesTimed = CrossSolverIterator().solveCrossesTimed(usedModel)
|
||||
// CrossSolver.printResults(solveCrossesTimed)
|
||||
// val baseSolve = CrossSolverBase().solveCrossesTimed(usedModel)
|
||||
// CrossSolver.printResults(baseSolve)
|
||||
|
||||
val s3 = CrossSolverIteratorUpgraded().solveCrossesTimed(usedModel)
|
||||
CrossSolver.printResults(s3)
|
||||
val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(usedModel)
|
||||
CrossSolver.printResults(upgradedSolve)
|
||||
//
|
||||
val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(usedModel)
|
||||
CrossSolver.printResults(upgradedSolveSkip)
|
||||
|
||||
// val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel)
|
||||
// allCrossMoveCountUpgradedSkip.forEach { color, moves ->
|
||||
// println("skip upgrade cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}")
|
||||
// }
|
||||
// val baseSolve = CrossSolverBase().solveCrossesTimed(usedModel)
|
||||
// CrossSolver.printResults(baseSolve)
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package be.nielandt
|
||||
|
||||
import be.nielandt.counter.CounterBasic
|
||||
import be.nielandt.counter.CounterTieredFactory
|
||||
|
||||
class CrossSolverBase : CrossSolver() {
|
||||
/**
|
||||
* Solve the minimal cross for all colors.
|
||||
*/
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||
|
||||
for (moveCount in 1..8) {
|
||||
// build a counter of moveCount big
|
||||
@ -23,7 +24,7 @@ class CrossSolverBase : CrossSolver() {
|
||||
if (!moveCounts.containsKey(color)) {
|
||||
val crossSolved = afterMoves.crossSolved(color)
|
||||
if (crossSolved) {
|
||||
moveCounts[color] = counter.counter.copyOf()
|
||||
moveCounts[color] = counter.counter.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
package be.nielandt
|
||||
|
||||
import be.nielandt.iterator.ValidClassMoveIterator
|
||||
|
||||
class CrossSolverIterator : CrossSolver() {
|
||||
/**
|
||||
* Solve the minimal cross for all colors.
|
||||
*/
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||
var iteratorCount = 0
|
||||
|
||||
for (moveCount in 1..8) {
|
||||
// build a counter of moveCount big
|
||||
println("crossSolverIterator doing $moveCount")
|
||||
val iterator = ValidClassMoveIterator(moveCount)
|
||||
|
||||
// count up, each state of the counter corresponds to a combination of moves
|
||||
while (iterator.hasNext()) {
|
||||
val moves = iterator.next()
|
||||
iteratorCount++
|
||||
// execute the moves
|
||||
val afterMoves = edgeModel.doMoves(moves.toList())
|
||||
// check crosses that have not been found yet
|
||||
(0..5).forEach { color ->
|
||||
if (!moveCounts.containsKey(color)) {
|
||||
val crossSolved = afterMoves.crossSolved(color)
|
||||
if (crossSolved) {
|
||||
moveCounts[color] = moves
|
||||
}
|
||||
}
|
||||
}
|
||||
if (moveCounts.keys.size == 6) {
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
return@solveCrosses moveCounts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
|
||||
return moveCounts
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val start = EdgeModel.solved().doMoves(randomMoves(20))
|
||||
val solver = CrossSolverIterator()
|
||||
val solveCrossesTimed = solver.solveCrossesTimed(start)
|
||||
solveCrossesTimed.forEach { t, u ->
|
||||
println("t $t u ${u.map { decodeMove(it) }}")
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package be.nielandt
|
||||
|
||||
import be.nielandt.iterator.ValidClassMoveIterator
|
||||
|
||||
/**
|
||||
* This solver avoids redoing edgemodel manipulations. Should be equivalent to X nested for loops.
|
||||
*/
|
||||
class CrossSolverIteratorUpgraded : CrossSolver() {
|
||||
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||
var iteratorCount = 0
|
||||
for (moveCount in 1..8) {
|
||||
println("all cross move count upgrade doing $moveCount")
|
||||
// build a counter of moveCount big
|
||||
val counter = ValidClassMoveIterator(moveCount)
|
||||
val edgeModelFactory = EdgeModelFactoryIterator(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()
|
||||
iteratorCount++
|
||||
|
||||
// check crosses that have not been found yet
|
||||
(0..5).forEach { color ->
|
||||
if (!moveCounts.containsKey(color)) {
|
||||
val crossSolved = next.crossSolved(color)
|
||||
if (crossSolved) {
|
||||
// what is the move combination we're looking at?
|
||||
moveCounts[color] = edgeModelFactory.movesOfCurrent().copyOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
// break if we have found hem all
|
||||
if (moveCounts.keys.size == 6) {
|
||||
println("iteratorCount = $iteratorCount")
|
||||
return moveCounts
|
||||
}
|
||||
}
|
||||
}
|
||||
println("had to do it all... iteratorCount = $iteratorCount")
|
||||
return moveCounts
|
||||
}
|
||||
}
|
||||
@ -7,9 +7,8 @@ import be.nielandt.counter.CounterBasic
|
||||
*/
|
||||
class CrossSolverUpgraded : CrossSolver() {
|
||||
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||
var iteratorCount = 0
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||
for (moveCount in 1..8) {
|
||||
println("all cross move count upgrade doing $moveCount")
|
||||
// build a counter of moveCount big
|
||||
@ -19,7 +18,6 @@ class CrossSolverUpgraded : CrossSolver() {
|
||||
while (edgeModelFactory.hasNext()) {
|
||||
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
||||
val next = edgeModelFactory.getNext()
|
||||
iteratorCount++
|
||||
|
||||
// check crosses that have not been found yet
|
||||
(0..5).forEach { color ->
|
||||
@ -27,18 +25,16 @@ class CrossSolverUpgraded : CrossSolver() {
|
||||
val crossSolved = next.crossSolved(color)
|
||||
if (crossSolved) {
|
||||
// what is the move combination we're looking at?
|
||||
moveCounts[color] = counter.counter.copyOf()
|
||||
moveCounts[color] = counter.counter.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
// break if we have found hem all
|
||||
if (moveCounts.keys.size == 6) {
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
return moveCounts
|
||||
}
|
||||
}
|
||||
}
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
return moveCounts
|
||||
}
|
||||
}
|
||||
@ -7,9 +7,8 @@ import be.nielandt.counter.CounterSkip
|
||||
*/
|
||||
class CrossSolverUpgradedSkip : CrossSolver() {
|
||||
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||
var iteratorCount = 0
|
||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||
for (moveCount in 1..8) {
|
||||
println("all cross move count upgrade doing $moveCount")
|
||||
// build a counter of moveCount big
|
||||
@ -19,7 +18,6 @@ class CrossSolverUpgradedSkip : CrossSolver() {
|
||||
while (edgeModelFactory.hasNext()) {
|
||||
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
||||
val next = edgeModelFactory.getNext()
|
||||
iteratorCount++
|
||||
|
||||
// check crosses that have not been found yet
|
||||
(0..5).forEach { color ->
|
||||
@ -27,18 +25,16 @@ class CrossSolverUpgradedSkip : CrossSolver() {
|
||||
val crossSolved = next.crossSolved(color)
|
||||
if (crossSolved) {
|
||||
// what is the move combination we're looking at?
|
||||
moveCounts[color] = counter.counter.copyOf()
|
||||
moveCounts[color] = counter.counter.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
// break if we have found hem all
|
||||
if (moveCounts.keys.size == 6) {
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
return moveCounts
|
||||
}
|
||||
}
|
||||
}
|
||||
println("iteratorCount = ${iteratorCount}")
|
||||
return moveCounts
|
||||
|
||||
}
|
||||
|
||||
@ -26,17 +26,51 @@ package be.nielandt
|
||||
|
||||
class EdgeModel {
|
||||
|
||||
lateinit var model: IntArray
|
||||
val model: Array<Int>
|
||||
|
||||
/**
|
||||
* Create an edgemodel through the companion object.
|
||||
*/
|
||||
private constructor()
|
||||
private val F_indices = intArrayOf(13, 18, 7, 20, 3, 0, 1, 2)
|
||||
private val B_indices = intArrayOf(8, 9, 10, 11, 16, 15, 22, 5)
|
||||
private val L_indices = intArrayOf(3, 23, 9, 19, 12, 13, 14, 15)
|
||||
private val U_indices = intArrayOf(16, 17, 18, 19, 0, 12, 8, 4)
|
||||
private val D_indices = intArrayOf(2, 6, 10, 14, 20, 21, 22, 23)
|
||||
private val R_indices = intArrayOf(4, 5, 6, 7, 1, 17, 11, 21)
|
||||
|
||||
fun copyOf(model: EdgeModel): EdgeModel {
|
||||
return EdgeModel.withModel(model.model)
|
||||
constructor() {
|
||||
// do a sanity check
|
||||
val entries = mutableListOf(F_indices, B_indices, L_indices, U_indices, D_indices, R_indices).flatMap { it.asList() }.groupBy { it }.entries
|
||||
// println("entries = ${entries}")
|
||||
if (entries.any {
|
||||
it.value.size != 2
|
||||
}) {
|
||||
throw RuntimeException("each index should occur exactly twice in the arrays")
|
||||
}
|
||||
|
||||
model = arrayOf(
|
||||
GREEN, GREEN, GREEN, GREEN,
|
||||
RED, RED, RED, RED,
|
||||
BLUE, BLUE, BLUE, BLUE,
|
||||
ORANGE, ORANGE, ORANGE, ORANGE,
|
||||
WHITE, WHITE, WHITE, WHITE,
|
||||
YELLOW, YELLOW, YELLOW, YELLOW
|
||||
)
|
||||
}
|
||||
|
||||
constructor(randomMoves: Int) {
|
||||
val edgeModel = EdgeModel()
|
||||
val r: Array<Int> = randomMoves(randomMoves)
|
||||
val doMoves = edgeModel.doMoves(r)
|
||||
this.model = doMoves.model
|
||||
}
|
||||
|
||||
constructor(model: Array<Int>) {
|
||||
this.model = model
|
||||
}
|
||||
|
||||
constructor(moves: List<Int>) {
|
||||
val edgeModel = EdgeModel()
|
||||
val newModel = edgeModel.doMoves(moves)
|
||||
this.model = newModel.model
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a single move and calculate the resulting edge model.
|
||||
@ -91,6 +125,7 @@ class EdgeModel {
|
||||
copyOf[s[5]] = model[s[7]]
|
||||
copyOf[s[7]] = model[s[5]]
|
||||
}
|
||||
|
||||
when (move) {
|
||||
F -> nonPrime(F_indices)
|
||||
F_ -> prime(F_indices)
|
||||
@ -111,7 +146,7 @@ class EdgeModel {
|
||||
D_ -> prime(D_indices)
|
||||
D2 -> double(D_indices)
|
||||
}
|
||||
return EdgeModel.withModel(copyOf)
|
||||
return EdgeModel(copyOf)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,6 +171,14 @@ class EdgeModel {
|
||||
return trimMargin
|
||||
}
|
||||
|
||||
fun doMoves(f: Array<Int>) : EdgeModel {
|
||||
var edgeModel = this
|
||||
f.forEach {
|
||||
edgeModel = edgeModel.doMove(it)
|
||||
}
|
||||
return edgeModel
|
||||
}
|
||||
|
||||
fun doMoves(f: Collection<Int>): EdgeModel {
|
||||
var edgeModel = this
|
||||
f.forEach {
|
||||
@ -144,12 +187,8 @@ class EdgeModel {
|
||||
return edgeModel
|
||||
}
|
||||
|
||||
fun doMoves(f: IntArray): EdgeModel {
|
||||
var edgeModel = this
|
||||
f.forEach {
|
||||
edgeModel = edgeModel.doMove(it)
|
||||
}
|
||||
return edgeModel
|
||||
fun doMoves(vararg f: Int): EdgeModel {
|
||||
return this.doMoves(f.toList())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,62 +225,5 @@ class EdgeModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val F_indices = intArrayOf(13, 18, 7, 20, 3, 0, 1, 2)
|
||||
private val B_indices = intArrayOf(8, 9, 10, 11, 16, 15, 22, 5)
|
||||
private val L_indices = intArrayOf(3, 23, 9, 19, 12, 13, 14, 15)
|
||||
private val U_indices = intArrayOf(16, 17, 18, 19, 0, 12, 8, 4)
|
||||
private val D_indices = intArrayOf(2, 6, 10, 14, 20, 21, 22, 23)
|
||||
private val R_indices = intArrayOf(4, 5, 6, 7, 1, 17, 11, 21)
|
||||
|
||||
fun solved(): EdgeModel {
|
||||
val edgeModel = EdgeModel()
|
||||
// do a sanity check
|
||||
val entries = mutableListOf(F_indices, B_indices, L_indices, U_indices, D_indices, R_indices).flatMap { it.asList() }.groupBy { it }.entries
|
||||
// println("entries = ${entries}")
|
||||
if (entries.any {
|
||||
it.value.size != 2
|
||||
}) {
|
||||
throw RuntimeException("each index should occur exactly twice in the arrays")
|
||||
}
|
||||
|
||||
val model = intArrayOf(
|
||||
GREEN, GREEN, GREEN, GREEN,
|
||||
RED, RED, RED, RED,
|
||||
BLUE, BLUE, BLUE, BLUE,
|
||||
ORANGE, ORANGE, ORANGE, ORANGE,
|
||||
WHITE, WHITE, WHITE, WHITE,
|
||||
YELLOW, YELLOW, YELLOW, YELLOW
|
||||
)
|
||||
edgeModel.model = model
|
||||
return edgeModel
|
||||
}
|
||||
|
||||
fun withRandomMoves(randomMoves: Int): EdgeModel {
|
||||
val edgeModel = EdgeModel()
|
||||
val r: IntArray = randomMoves(randomMoves)
|
||||
val doMoves = edgeModel.doMoves(r.toList())
|
||||
edgeModel.model = doMoves.model
|
||||
return edgeModel
|
||||
}
|
||||
|
||||
fun withModel(model: IntArray): EdgeModel {
|
||||
val edgeModel = EdgeModel()
|
||||
edgeModel.model = model
|
||||
return edgeModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a list of moves and do them on a solved edgemodel.
|
||||
*/
|
||||
fun withMoves(moves: IntArray): EdgeModel {
|
||||
val edgeModel = EdgeModel.solved()
|
||||
val newModel = edgeModel.doMoves(moves)
|
||||
edgeModel.model = newModel.model
|
||||
return edgeModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
package be.nielandt
|
||||
|
||||
/**
|
||||
* This thing helps us to create edgemodels using a counter. The advantage is that the edgemodel doesn't need to be calculated
|
||||
* completely from scratch: previous states are kept, so if, e.g., the third digit changes in the counter (of length 5),
|
||||
* the previous state that was calculated using the first two states is used to perform move 3,4,5 on.
|
||||
*
|
||||
* This is probably equivalent to 8 nested for loops, you'd be able to keep track of temporary solutions there too....
|
||||
*/
|
||||
class EdgeModelFactoryIterator(val original: EdgeModel, val counter: Iterator<IntArray>) {
|
||||
// keep a modified version of the edgemodel for each digit in the counter, from left to right
|
||||
private val history: MutableList<EdgeModel> = mutableListOf()
|
||||
private var previous:IntArray
|
||||
private var lastMoves: IntArray
|
||||
|
||||
init {
|
||||
// init the history
|
||||
val firstOne = counter.next()
|
||||
lastMoves = firstOne
|
||||
this.history.add(original.doMove(firstOne[0]))
|
||||
for (i in 1 until firstOne.size) {
|
||||
this.history.add(this.history.last().doMove(firstOne[i]))
|
||||
}
|
||||
// keep track of the 'previous move that was performed'
|
||||
previous = firstOne
|
||||
}
|
||||
|
||||
fun hasNext(): Boolean {
|
||||
return counter.hasNext()
|
||||
}
|
||||
|
||||
fun movesOfCurrent() : IntArray {
|
||||
return previous
|
||||
}
|
||||
|
||||
fun getNext(): EdgeModel {
|
||||
// the next set of moves
|
||||
val moves = counter.next()
|
||||
this.lastMoves = moves
|
||||
// figure out the first index that differs
|
||||
val lastModifiedIndex = firstDifferingIndex(previous, moves)
|
||||
// we only need to redo everything starting from the lastoverflowindex
|
||||
// these are our moves, but we can salvage everything up to lastoverflowindex
|
||||
// we have a history to work with... only redo what's necessary
|
||||
for (i in lastModifiedIndex until moves.size) {
|
||||
var start: EdgeModel = if (i == 0)
|
||||
original
|
||||
else
|
||||
history[i - 1]
|
||||
history[i] = start.doMove(moves[i])
|
||||
}
|
||||
// bump the previous value
|
||||
previous = moves
|
||||
// the last item in the history is now the edgemodel we need to test...
|
||||
return history.last()
|
||||
}
|
||||
|
||||
private fun firstDifferingIndex(previous: IntArray, moves: IntArray): Int {
|
||||
previous.forEachIndexed { index, i ->
|
||||
if(previous[index] != moves[index])
|
||||
return index
|
||||
}
|
||||
// nothing changed.. that's probably impossible
|
||||
throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,7 @@ const val L2 = 16
|
||||
const val R2 = 17
|
||||
|
||||
fun decodeMove(i: Int): String {
|
||||
return when (i) {
|
||||
return when(i) {
|
||||
F -> "F"
|
||||
B -> "B"
|
||||
U -> "U"
|
||||
@ -48,18 +48,18 @@ fun decodeMove(i: Int): String {
|
||||
L2 -> "L2"
|
||||
R2 -> "R2"
|
||||
else -> {
|
||||
println("i = $i")
|
||||
println("i = ${i}")
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun classOf(move: Int): Int {
|
||||
return (move % 6) / 2
|
||||
return (move%6) / 2
|
||||
}
|
||||
|
||||
fun parseMoves(s: String): IntArray {
|
||||
return s.split(" ", ",", ";").filter { it?.length > 0 }.map { parseMove(it) }.toIntArray()
|
||||
fun parseMoves(s: String): List<Int> {
|
||||
return s.split(" ", ",", ";").filter { it?.length > 0 }.map { parseMove(it) }.toList()
|
||||
}
|
||||
|
||||
fun parseMove(s: String): Int {
|
||||
@ -91,46 +91,10 @@ fun parseMove(s: String): Int {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a proper scramble set of moves. Disallow the obvious symmetries.
|
||||
*/
|
||||
fun randomMoves(amount: Int): IntArray {
|
||||
fun randomMoves(amount: Int): Array<Int> {
|
||||
val rgen = Random()
|
||||
val result = IntArray(amount)
|
||||
for (i in 0 until result.size) {
|
||||
// create valid options for the next one
|
||||
val options = mutableListOf<Int>()
|
||||
if (i == 0) {
|
||||
// all options
|
||||
options.addAll(0..17)
|
||||
}
|
||||
// if there's two before us, we can't add a third of the same class
|
||||
else if (i > 1 && classOf(result[i - 1]) == classOf(result[i - 2])) {
|
||||
options.addAll(
|
||||
(0..17).filter { classOf(it) != classOf(result[i - 1]) }
|
||||
)
|
||||
} else {
|
||||
// all options except the previous one
|
||||
// also disallow same-face solutions
|
||||
options.addAll(
|
||||
(0..17)
|
||||
// can't be the same face move
|
||||
.filter {
|
||||
it % 6 != result[i - 1] % 6
|
||||
}
|
||||
)
|
||||
}
|
||||
result[i] = options[rgen.nextInt(options.size)]
|
||||
return Array(amount) {
|
||||
rgen.nextInt(18)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
printMoves(randomMoves(50))
|
||||
}
|
||||
|
||||
fun printMoves(moves: IntArray) {
|
||||
println(moves.map { decodeMove(it) }.joinToString(","))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ open abstract class Counter(size: Int, val base: Int = 18) {
|
||||
/**
|
||||
* Empty counter, all 0 values for each digit.
|
||||
*/
|
||||
var counter: IntArray = IntArray(size) { 0 }
|
||||
var counter: Array<Int> = Array(size) { 0 }
|
||||
|
||||
/**
|
||||
* The last (highest significance) index that overflowed and has been changed in the counter. Could be null, if it never overflowed.
|
||||
|
||||
@ -61,12 +61,3 @@ class CounterBasic(size: Int) : Counter(size, 18) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val counterBasic = CounterBasic(7)
|
||||
var count = 0
|
||||
while(counterBasic.increase())
|
||||
count++
|
||||
println("count = ${count}")
|
||||
|
||||
}
|
||||
|
||||
@ -7,14 +7,14 @@ import be.nielandt.classOf
|
||||
*/
|
||||
class CounterBuffer(size: Int) : Counter(size, 18) {
|
||||
|
||||
val buffer = mutableListOf<IntArray>()
|
||||
val buffer = mutableListOf<Array<Int>>()
|
||||
|
||||
init {
|
||||
// initialise the buffer of valid counters
|
||||
val counterBasic = CounterBasic(size)
|
||||
do {
|
||||
if (counterBasic.isValid()) {
|
||||
buffer.add(counterBasic.counter.copyOf())
|
||||
buffer.add(counterBasic.counter)
|
||||
}
|
||||
} while (counterBasic.increase())
|
||||
println("Init of counter buffer, ${buffer.size} valid combos")
|
||||
|
||||
@ -7,9 +7,9 @@ import be.nielandt.decodeMove
|
||||
* 1) tier1 : axes / move classes (FB/UD/RL) -> three classes, but multiple sizes (1 or 2) possible
|
||||
* 2) tier2: each block of class (22, 11, 2, 11, 0, ...) needs to be expanded into the full range of related moves
|
||||
*/
|
||||
class CounterTiered : Counter(8) {
|
||||
class CounterTiered : Counter {
|
||||
|
||||
private val moveIterator: Iterator<IntArray> = listOf<IntArray>().iterator()
|
||||
private val moveIterator: Iterator<Array<Int>>
|
||||
|
||||
override fun increase(): Boolean {
|
||||
if (!this.moveIterator.hasNext())
|
||||
@ -18,14 +18,20 @@ class CounterTiered : Counter(8) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
constructor(size: Int) : super(size, 18) {
|
||||
this.moveIterator = moveIterator().iterator()
|
||||
this.increase()
|
||||
}
|
||||
|
||||
override fun atMax(): Boolean {
|
||||
return !this.moveIterator.hasNext()
|
||||
}
|
||||
|
||||
private class MoveIterator(val classes: List<IntArray>) : Iterator<IntArray> {
|
||||
private class MoveIterator(val classes: List<List<Int>>) : Iterator<Array<Int>> {
|
||||
|
||||
var currentClassIndex = 0
|
||||
lateinit var currentMoves: Iterator<IntArray>
|
||||
lateinit var currentMoves: Iterator<Array<Int>>
|
||||
|
||||
|
||||
init {
|
||||
@ -34,11 +40,11 @@ class CounterTiered : Counter(8) {
|
||||
}
|
||||
|
||||
private fun doClass(index: Int) {
|
||||
val fillIn = fillIn(0, classes[index], IntArray(classes.size) { 0 })
|
||||
val fillIn = fillIn(0, classes[index], Array(classes.size) { 0 })
|
||||
currentMoves = fillIn.toList().iterator()
|
||||
}
|
||||
|
||||
override fun next(): IntArray {
|
||||
override fun next(): Array<Int> {
|
||||
val next = currentMoves.next()
|
||||
if (!currentMoves.hasNext()) {
|
||||
nextClass()
|
||||
@ -59,17 +65,73 @@ class CounterTiered : Counter(8) {
|
||||
|
||||
}
|
||||
|
||||
fun moveIterator(): Iterator<Array<Int>> {
|
||||
return MoveIterator(classIterator()).iterator()
|
||||
}
|
||||
|
||||
/**
|
||||
* These are the classes (FB/UD/RL), correctly configured (no illegal combinations here)
|
||||
*/
|
||||
fun classIterator(): List<List<Int>> {
|
||||
val classes = appendRandomClass(this.counter.size, listOf())
|
||||
return classes
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for classIterator()
|
||||
*/
|
||||
private fun appendRandomClass(size: Int, base: List<Int>): List<List<Int>> {
|
||||
val result = mutableListOf<List<Int>>()
|
||||
when {
|
||||
base.size < size - 1 -> // add all classes, but don't repeat a group already there
|
||||
(0..2).filter { if (base.isNotEmpty()) it != base.last() else true }
|
||||
.forEach { theClass ->
|
||||
// and both amounts, 1+2
|
||||
(1..2).forEach { amount ->
|
||||
val l = base.toMutableList()
|
||||
for (i in 1..amount) {
|
||||
l.add(theClass)
|
||||
}
|
||||
result.addAll(appendRandomClass(size, l))
|
||||
}
|
||||
}
|
||||
base.size == size -> {
|
||||
// we're done here
|
||||
result.add(base)
|
||||
}
|
||||
base.size == size - 1 -> // the base is not empty, only add class that is not at the end of the base list
|
||||
(0..2).filter { if (base.isEmpty()) true else it != base.last() }.forEach { theClass ->
|
||||
val l = base.toMutableList()
|
||||
l.add(theClass)
|
||||
result.add(l)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class CounterTieredFactory {
|
||||
companion object {
|
||||
fun create(size: Int): CounterTiered {
|
||||
return CounterTiered()
|
||||
return CounterTiered(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
var count = 0
|
||||
CounterTieredFactory.create(4).classIterator().forEach {
|
||||
println("it = ${it}")
|
||||
count++
|
||||
}
|
||||
println("count = ${count}")
|
||||
// CounterTieredFactory.create(7).moveIterator().forEach {
|
||||
// println("Arrays.tostring(it) = ${Arrays.toString(it)} ${it.map { decodeMove(it) }.toList()}")
|
||||
// count++
|
||||
// }
|
||||
// println("count = ${count}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the class ints into the full range of moves.
|
||||
*
|
||||
@ -97,8 +159,8 @@ const val D2 = 15
|
||||
const val L2 = 16
|
||||
const val R2 = 17
|
||||
*/
|
||||
fun fillIn(index: Int, classes: IntArray, moveList: IntArray): List<IntArray> {
|
||||
val result = mutableListOf<IntArray>()
|
||||
fun fillIn(index: Int, classes: List<Int>, moveList: Array<Int>): List<Array<Int>> {
|
||||
val result = mutableListOf<Array<Int>>()
|
||||
|
||||
// if the movelist is complete, finish it
|
||||
if (index == classes.size) {
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
package be.nielandt.counter
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* The variable counter has irregular base size for each digit.
|
||||
*
|
||||
* basesize: [1,3,2]
|
||||
* iterates:
|
||||
* - [0,0,0]
|
||||
* - [0,0,1]
|
||||
* - [0,1,0]
|
||||
* - [0,1,1]
|
||||
* - [0,2,0]
|
||||
* - [0,2,1]
|
||||
*/
|
||||
class VariableCounter(internal val baseSizes: IntArray) : Iterator<IntArray> {
|
||||
|
||||
// init the counter with 0's, we only have a maximum as our basesize
|
||||
val counter = IntArray(baseSizes.size) {
|
||||
when (it) {
|
||||
baseSizes.size - 1 -> -1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
// check if all elements in the counter has reached their maximum (basesize - 1)
|
||||
counter.forEachIndexed { index, sh ->
|
||||
if (sh < baseSizes[index] - 1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun next(): IntArray {
|
||||
for (i in this.counter.size - 1 downTo 0) {
|
||||
this.counter[i]++
|
||||
if (this.counter[i] == baseSizes[i]) {
|
||||
this.counter[i] = 0
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return counter.copyOf()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val counter = VariableCounter(intArrayOf(2, 3, 2))
|
||||
while (counter.hasNext()) {
|
||||
val next = counter.next()
|
||||
println("counter.next() = ${Arrays.toString(next)} ${counter.hasNext()}")
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
package be.nielandt.iterator
|
||||
|
||||
class ValidClassMoveIterator(val size: Int) : Iterator<IntArray> {
|
||||
|
||||
// current level of the iterator
|
||||
var classesIterator = ValidClassesIterator(size)
|
||||
var movesIterator: ValidMoveIterator
|
||||
|
||||
init {
|
||||
this.movesIterator = ValidMoveIterator(classesIterator.next())
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
// check if we have another move in the move iterator
|
||||
return if (this.movesIterator.hasNext()) {
|
||||
true
|
||||
} else {
|
||||
// the moves iterator does not has any more juice, move to the next class
|
||||
if (!this.classesIterator.hasNext()) {
|
||||
false
|
||||
} else {
|
||||
nextClass()
|
||||
this.movesIterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun next(): IntArray {
|
||||
// check if there's a valid move left
|
||||
if (!this.movesIterator.hasNext()) {
|
||||
nextClass()
|
||||
}
|
||||
// now we're sure there's something left
|
||||
return this.movesIterator.next()
|
||||
}
|
||||
|
||||
/**
|
||||
* Bump the 'current class'. This means we have a new moves iterator at our disposal.
|
||||
*/
|
||||
private fun nextClass() {
|
||||
val next = this.classesIterator.next()
|
||||
this.movesIterator = ValidMoveIterator(next)
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val validClassMoveIterator = ValidClassMoveIterator(8)
|
||||
var count=0
|
||||
while (validClassMoveIterator.hasNext()) {
|
||||
validClassMoveIterator.next()
|
||||
// println("Arrays.toString(validClassMoveIterator.next()) = ${validClassMoveIterator.next().map { decodeMove(it) }}")
|
||||
count++
|
||||
}
|
||||
println("count = ${count}")
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
package be.nielandt.iterator
|
||||
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
class ValidClassesIterator(val size: Int) : Iterator<List<Int>> {
|
||||
|
||||
private var classes: Iterator<List<Int>> = classIterator().iterator()
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return this.classes.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): List<Int> {
|
||||
return this.classes.next()
|
||||
}
|
||||
|
||||
/**
|
||||
* These are the classes (FB/UD/RL), correctly configured (no illegal combinations here)
|
||||
*/
|
||||
private fun classIterator(): List<List<Int>> {
|
||||
val classes = appendRandomClass(size, listOf())
|
||||
return classes
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for classIterator()
|
||||
*/
|
||||
private fun appendRandomClass(size: Int, base: List<Int>): List<List<Int>> {
|
||||
val result = mutableListOf<List<Int>>()
|
||||
when {
|
||||
base.size < size - 1 -> // add all classes, but don't repeat a group already there
|
||||
(0..2).filter { if (base.isNotEmpty()) it != base.last() else true }
|
||||
.forEach { theClass ->
|
||||
// and both amounts, 1+2
|
||||
(1..2).forEach { amount ->
|
||||
val l = base.toMutableList()
|
||||
for (i in 1..amount) {
|
||||
l.add(theClass)
|
||||
}
|
||||
result.addAll(appendRandomClass(size, l))
|
||||
}
|
||||
}
|
||||
base.size == size -> {
|
||||
// we're done here
|
||||
result.add(base)
|
||||
}
|
||||
base.size == size - 1 -> // the base is not empty, only add class that is not at the end of the base list
|
||||
(0..2).filter { if (base.isEmpty()) true else it != base.last() }.forEach { theClass ->
|
||||
val l = base.toMutableList()
|
||||
l.add(theClass)
|
||||
result.add(l)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val now = Instant.now()
|
||||
val iter = ValidClassesIterator(8)
|
||||
var count: Int = 0
|
||||
while(iter.hasNext()) {
|
||||
println("iter.next() = ${iter.next()}")
|
||||
count++
|
||||
}
|
||||
println("count = ${count}")
|
||||
println("Duration.between(Instant.now(), now) = ${Duration.between(now, Instant.now()).toMillis()}")
|
||||
}
|
||||
|
||||
@ -1,82 +1,13 @@
|
||||
package be.nielandt.iterator
|
||||
|
||||
import be.nielandt.counter.VariableCounter
|
||||
import be.nielandt.decodeMove
|
||||
import java.util.*
|
||||
class ValidMoveIterator: Iterator<Array<Int>> {
|
||||
|
||||
/**
|
||||
* Iterates over the different moves of the given specific classes.
|
||||
*/
|
||||
class ValidMoveIterator(val classes: List<Int>) : Iterator<IntArray> {
|
||||
|
||||
internal var expansionCounter: VariableCounter
|
||||
|
||||
/**
|
||||
* At initialisation time, create the internal expansion counter. This one will count appropriately for each class type,
|
||||
* depending on whether the class is alone or is a duplicate.
|
||||
*/
|
||||
init {
|
||||
// create the variable counter: if a class is 'alone', it can iterate over all 6 values. otherwise, each part can iterate over 3
|
||||
val intArray = IntArray(classes.size)
|
||||
var i = 0
|
||||
while (i < classes.size) {
|
||||
if (i < classes.size - 1 && classes[i] == classes[i + 1]) {
|
||||
intArray[i] = 3
|
||||
intArray[i + 1] = 3
|
||||
i += 2
|
||||
} else {
|
||||
intArray[i] = 6
|
||||
i++
|
||||
}
|
||||
}
|
||||
this.expansionCounter = VariableCounter(intArray)
|
||||
override fun hasNext(): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean = this.expansionCounter.hasNext()
|
||||
|
||||
override fun next(): IntArray {
|
||||
val next = this.expansionCounter.next()
|
||||
// translate this state into a list of moves
|
||||
var i = 0
|
||||
while (i < next.size) {
|
||||
// process the double situation
|
||||
if (i < classes.size-1 && classes[i] == classes[i + 1]) {
|
||||
// so, we're in the same state, the first counter will get the 'low' value, the second the 'high' value
|
||||
// for class FB, that would be F and B respectively
|
||||
// class 0 (FB) has to expand to 0,6,12 (F,F_F2) and 1,7,13 (B,B_,B2) respectively
|
||||
// class 1 (UD) has to expand to 2,8,14 (U,U_U2) and 3,9,15 (D,D_,D2) respectively
|
||||
// class 2 (LR) has to expand to 4,10,16 (L,L_L2) and 5,11,17 (R,R_,R2) respectively
|
||||
// next will contain 0,1,3, as the classes are a pair
|
||||
val c1 = (classes[i] * 2) + 6 * next[i]
|
||||
val c2 = (classes[i] * 2) + 6 * next[i + 1]+1
|
||||
next[i] = c1
|
||||
next[i + 1] = c2
|
||||
|
||||
// bump up the counter by two
|
||||
i += 2
|
||||
}
|
||||
// now the single situation
|
||||
else {
|
||||
// class 0 (FB) has to expand to 0,1,6,7,12,13 (F,B,F_,B_,F2,B2)
|
||||
// class 1 (UD) has to expand to 2,3,8,9,14,15 (U,D,U_,D_,U2,D2)
|
||||
// class 2 (LR) has to expand to 4,5,10,11,16,17 (L,R,L_,R_,L2,R2)
|
||||
next[i] = (classes[i] * 2) + ((next[i] / 2) * 6) + (next[i] % 2)
|
||||
i++
|
||||
}
|
||||
}
|
||||
return next
|
||||
override fun next(): Array<Int> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val validMoveIterator = ValidMoveIterator(listOf(0, 0, 2, 1, 2, 0, 1, 1))
|
||||
println("classes = ${validMoveIterator.classes}")
|
||||
println("basesizes = ${Arrays.toString(validMoveIterator.expansionCounter.baseSizes)}")
|
||||
var count = 0
|
||||
while (validMoveIterator.hasNext()) {
|
||||
println("Arrays.toString(validMoveIterator.next()) = ${Arrays.toString(validMoveIterator.next())}")
|
||||
println("validMoveIterator = ${validMoveIterator.next().map { decodeMove(it) }}")
|
||||
count++
|
||||
}
|
||||
println("count = $count")
|
||||
}
|
||||
@ -7,7 +7,7 @@ class EdgeModelTest {
|
||||
|
||||
@Test
|
||||
fun testSingleMove() {
|
||||
val edgeModel = EdgeModel.solved()
|
||||
val edgeModel = EdgeModel()
|
||||
(0..5).forEach { color ->
|
||||
assertTrue(edgeModel.crossSolved(color))
|
||||
}
|
||||
@ -15,7 +15,7 @@ class EdgeModelTest {
|
||||
|
||||
@Test
|
||||
fun testSingleMoves() {
|
||||
val edgeModel = EdgeModel.solved()
|
||||
val edgeModel = EdgeModel()
|
||||
println(edgeModel)
|
||||
val final = edgeModel.doMove(F)
|
||||
println(final)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user