Compare commits
17 Commits
tryingoutm
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e20ae7fa0b | |||
| 184194d21e | |||
| 5c9dbc991f | |||
| 200fd4e85f | |||
| f7a2e30832 | |||
| e679acbcec | |||
| 1351935159 | |||
|
|
85231d6241 | ||
| c4db0ec011 | |||
| 7e33974d34 | |||
| 80179e9b68 | |||
| 9617ed1a02 | |||
| dc8c433d0d | |||
| 3329e127d9 | |||
| 3c715d33c1 | |||
| ea45836250 | |||
| 0c779c7a5b |
@ -7,9 +7,9 @@ open abstract class CrossSolver {
|
|||||||
/**
|
/**
|
||||||
* Solve all crosses, look for a minimal set of moves for each color's cross.
|
* Solve all crosses, look for a minimal set of moves for each color's cross.
|
||||||
*/
|
*/
|
||||||
abstract fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>>
|
abstract fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray>
|
||||||
|
|
||||||
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
val solveCrosses = solveCrosses(edgeModel)
|
val solveCrosses = solveCrosses(edgeModel)
|
||||||
val between = Duration.between(now, Instant.now())
|
val between = Duration.between(now, Instant.now())
|
||||||
@ -18,7 +18,7 @@ open abstract class CrossSolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun printResults(results: Map<Int, List<Int>>) {
|
fun printResults(results: Map<Int, IntArray>) {
|
||||||
println("results: ")
|
println("results: ")
|
||||||
results.forEach { color, moveList ->
|
results.forEach { color, moveList ->
|
||||||
println("> color ${colorLetter(color)}, moves (${moveList.size}) ${moveList.map { it -> decodeMove(it) }}")
|
println("> color ${colorLetter(color)}, moves (${moveList.size}) ${moveList.map { it -> decodeMove(it) }}")
|
||||||
@ -29,64 +29,40 @@ open abstract class CrossSolver {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Let's look for symmetries.
|
* 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>) {
|
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) }}")
|
println("Scramble: ${moves.map { decodeMove(it) }}")
|
||||||
|
|
||||||
|
val usedModel = EdgeModel.withMoves(moves)
|
||||||
val usedModel = EdgeModel(moves)
|
|
||||||
println(usedModel)
|
println(usedModel)
|
||||||
|
|
||||||
// val baseSolve = CrossSolverBase().solveCrossesTimed(usedModel)
|
// val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(usedModel)
|
||||||
// CrossSolver.printResults(baseSolve)
|
// CrossSolver.printResults(upgradedSolve)
|
||||||
|
|
||||||
val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(usedModel)
|
|
||||||
CrossSolver.printResults(upgradedSolve)
|
|
||||||
//
|
//
|
||||||
val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(usedModel)
|
// val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(usedModel)
|
||||||
CrossSolver.printResults(upgradedSolveSkip)
|
// CrossSolver.printResults(upgradedSolveSkip)
|
||||||
|
//
|
||||||
|
// val solveCrossesTimed = CrossSolverIterator().solveCrossesTimed(usedModel)
|
||||||
|
// CrossSolver.printResults(solveCrossesTimed)
|
||||||
|
|
||||||
|
val s3 = CrossSolverIteratorUpgraded().solveCrossesTimed(usedModel)
|
||||||
|
CrossSolver.printResults(s3)
|
||||||
|
|
||||||
// val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel)
|
// val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel)
|
||||||
// allCrossMoveCountUpgradedSkip.forEach { color, moves ->
|
// allCrossMoveCountUpgradedSkip.forEach { color, moves ->
|
||||||
// println("skip upgrade cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}")
|
// println("skip upgrade cross for color: ${color} in ${moves.size}: ${moves.joinToString(" ")}")
|
||||||
// }
|
// }
|
||||||
|
// val baseSolve = CrossSolverBase().solveCrossesTimed(usedModel)
|
||||||
|
// CrossSolver.printResults(baseSolve)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
package be.nielandt
|
package be.nielandt
|
||||||
|
|
||||||
import be.nielandt.counter.CounterBasic
|
|
||||||
import be.nielandt.counter.CounterTieredFactory
|
import be.nielandt.counter.CounterTieredFactory
|
||||||
|
|
||||||
class CrossSolverBase : CrossSolver() {
|
class CrossSolverBase : CrossSolver() {
|
||||||
/**
|
/**
|
||||||
* Solve the minimal cross for all colors.
|
* Solve the minimal cross for all colors.
|
||||||
*/
|
*/
|
||||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||||
|
|
||||||
for (moveCount in 1..8) {
|
for (moveCount in 1..8) {
|
||||||
// build a counter of moveCount big
|
// build a counter of moveCount big
|
||||||
@ -24,7 +23,7 @@ class CrossSolverBase : CrossSolver() {
|
|||||||
if (!moveCounts.containsKey(color)) {
|
if (!moveCounts.containsKey(color)) {
|
||||||
val crossSolved = afterMoves.crossSolved(color)
|
val crossSolved = afterMoves.crossSolved(color)
|
||||||
if (crossSolved) {
|
if (crossSolved) {
|
||||||
moveCounts[color] = counter.counter.toList()
|
moveCounts[color] = counter.counter.copyOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/main/kotlin/be/nielandt/CrossSolverIterator.kt
Normal file
54
src/main/kotlin/be/nielandt/CrossSolverIterator.kt
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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) }}")
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/main/kotlin/be/nielandt/CrossSolverIteratorUpgraded.kt
Normal file
44
src/main/kotlin/be/nielandt/CrossSolverIteratorUpgraded.kt
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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,8 +7,9 @@ import be.nielandt.counter.CounterBasic
|
|||||||
*/
|
*/
|
||||||
class CrossSolverUpgraded : CrossSolver() {
|
class CrossSolverUpgraded : CrossSolver() {
|
||||||
|
|
||||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||||
|
var iteratorCount = 0
|
||||||
for (moveCount in 1..8) {
|
for (moveCount in 1..8) {
|
||||||
println("all cross move count upgrade doing $moveCount")
|
println("all cross move count upgrade doing $moveCount")
|
||||||
// build a counter of moveCount big
|
// build a counter of moveCount big
|
||||||
@ -18,6 +19,7 @@ class CrossSolverUpgraded : CrossSolver() {
|
|||||||
while (edgeModelFactory.hasNext()) {
|
while (edgeModelFactory.hasNext()) {
|
||||||
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
||||||
val next = edgeModelFactory.getNext()
|
val next = edgeModelFactory.getNext()
|
||||||
|
iteratorCount++
|
||||||
|
|
||||||
// check crosses that have not been found yet
|
// check crosses that have not been found yet
|
||||||
(0..5).forEach { color ->
|
(0..5).forEach { color ->
|
||||||
@ -25,16 +27,18 @@ class CrossSolverUpgraded : CrossSolver() {
|
|||||||
val crossSolved = next.crossSolved(color)
|
val crossSolved = next.crossSolved(color)
|
||||||
if (crossSolved) {
|
if (crossSolved) {
|
||||||
// what is the move combination we're looking at?
|
// what is the move combination we're looking at?
|
||||||
moveCounts[color] = counter.counter.toList()
|
moveCounts[color] = counter.counter.copyOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// break if we have found hem all
|
// break if we have found hem all
|
||||||
if (moveCounts.keys.size == 6) {
|
if (moveCounts.keys.size == 6) {
|
||||||
|
println("iteratorCount = ${iteratorCount}")
|
||||||
return moveCounts
|
return moveCounts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println("iteratorCount = ${iteratorCount}")
|
||||||
return moveCounts
|
return moveCounts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,8 +7,9 @@ import be.nielandt.counter.CounterSkip
|
|||||||
*/
|
*/
|
||||||
class CrossSolverUpgradedSkip : CrossSolver() {
|
class CrossSolverUpgradedSkip : CrossSolver() {
|
||||||
|
|
||||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, IntArray> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Int>>()
|
val moveCounts = mutableMapOf<Int, IntArray>()
|
||||||
|
var iteratorCount = 0
|
||||||
for (moveCount in 1..8) {
|
for (moveCount in 1..8) {
|
||||||
println("all cross move count upgrade doing $moveCount")
|
println("all cross move count upgrade doing $moveCount")
|
||||||
// build a counter of moveCount big
|
// build a counter of moveCount big
|
||||||
@ -18,6 +19,7 @@ class CrossSolverUpgradedSkip : CrossSolver() {
|
|||||||
while (edgeModelFactory.hasNext()) {
|
while (edgeModelFactory.hasNext()) {
|
||||||
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
// get the next model, using the internal counter which simply iterates over possible combinations of moves
|
||||||
val next = edgeModelFactory.getNext()
|
val next = edgeModelFactory.getNext()
|
||||||
|
iteratorCount++
|
||||||
|
|
||||||
// check crosses that have not been found yet
|
// check crosses that have not been found yet
|
||||||
(0..5).forEach { color ->
|
(0..5).forEach { color ->
|
||||||
@ -25,16 +27,18 @@ class CrossSolverUpgradedSkip : CrossSolver() {
|
|||||||
val crossSolved = next.crossSolved(color)
|
val crossSolved = next.crossSolved(color)
|
||||||
if (crossSolved) {
|
if (crossSolved) {
|
||||||
// what is the move combination we're looking at?
|
// what is the move combination we're looking at?
|
||||||
moveCounts[color] = counter.counter.toList()
|
moveCounts[color] = counter.counter.copyOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// break if we have found hem all
|
// break if we have found hem all
|
||||||
if (moveCounts.keys.size == 6) {
|
if (moveCounts.keys.size == 6) {
|
||||||
|
println("iteratorCount = ${iteratorCount}")
|
||||||
return moveCounts
|
return moveCounts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println("iteratorCount = ${iteratorCount}")
|
||||||
return moveCounts
|
return moveCounts
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,51 +26,17 @@ package be.nielandt
|
|||||||
|
|
||||||
class EdgeModel {
|
class EdgeModel {
|
||||||
|
|
||||||
val model: Array<Int>
|
lateinit var model: IntArray
|
||||||
|
|
||||||
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)
|
* Create an edgemodel through the companion object.
|
||||||
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 constructor()
|
||||||
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)
|
|
||||||
|
|
||||||
constructor() {
|
fun copyOf(model: EdgeModel): EdgeModel {
|
||||||
// do a sanity check
|
return EdgeModel.withModel(model.model)
|
||||||
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.
|
* Do a single move and calculate the resulting edge model.
|
||||||
@ -125,7 +91,6 @@ class EdgeModel {
|
|||||||
copyOf[s[5]] = model[s[7]]
|
copyOf[s[5]] = model[s[7]]
|
||||||
copyOf[s[7]] = model[s[5]]
|
copyOf[s[7]] = model[s[5]]
|
||||||
}
|
}
|
||||||
|
|
||||||
when (move) {
|
when (move) {
|
||||||
F -> nonPrime(F_indices)
|
F -> nonPrime(F_indices)
|
||||||
F_ -> prime(F_indices)
|
F_ -> prime(F_indices)
|
||||||
@ -146,7 +111,7 @@ class EdgeModel {
|
|||||||
D_ -> prime(D_indices)
|
D_ -> prime(D_indices)
|
||||||
D2 -> double(D_indices)
|
D2 -> double(D_indices)
|
||||||
}
|
}
|
||||||
return EdgeModel(copyOf)
|
return EdgeModel.withModel(copyOf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,14 +136,6 @@ class EdgeModel {
|
|||||||
return trimMargin
|
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 {
|
fun doMoves(f: Collection<Int>): EdgeModel {
|
||||||
var edgeModel = this
|
var edgeModel = this
|
||||||
f.forEach {
|
f.forEach {
|
||||||
@ -187,8 +144,12 @@ class EdgeModel {
|
|||||||
return edgeModel
|
return edgeModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doMoves(vararg f: Int): EdgeModel {
|
fun doMoves(f: IntArray): EdgeModel {
|
||||||
return this.doMoves(f.toList())
|
var edgeModel = this
|
||||||
|
f.forEach {
|
||||||
|
edgeModel = edgeModel.doMove(it)
|
||||||
|
}
|
||||||
|
return edgeModel
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,5 +186,62 @@ 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
66
src/main/kotlin/be/nielandt/EdgeModelFactoryIterator.kt
Normal file
66
src/main/kotlin/be/nielandt/EdgeModelFactoryIterator.kt
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
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
|
const val R2 = 17
|
||||||
|
|
||||||
fun decodeMove(i: Int): String {
|
fun decodeMove(i: Int): String {
|
||||||
return when(i) {
|
return when (i) {
|
||||||
F -> "F"
|
F -> "F"
|
||||||
B -> "B"
|
B -> "B"
|
||||||
U -> "U"
|
U -> "U"
|
||||||
@ -48,18 +48,18 @@ fun decodeMove(i: Int): String {
|
|||||||
L2 -> "L2"
|
L2 -> "L2"
|
||||||
R2 -> "R2"
|
R2 -> "R2"
|
||||||
else -> {
|
else -> {
|
||||||
println("i = ${i}")
|
println("i = $i")
|
||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun classOf(move: Int): Int {
|
fun classOf(move: Int): Int {
|
||||||
return (move%6) / 2
|
return (move % 6) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseMoves(s: String): List<Int> {
|
fun parseMoves(s: String): IntArray {
|
||||||
return s.split(" ", ",", ";").filter { it?.length > 0 }.map { parseMove(it) }.toList()
|
return s.split(" ", ",", ";").filter { it?.length > 0 }.map { parseMove(it) }.toIntArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseMove(s: String): Int {
|
fun parseMove(s: String): Int {
|
||||||
@ -91,10 +91,46 @@ fun parseMove(s: String): Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun randomMoves(amount: Int): Array<Int> {
|
/**
|
||||||
|
* Get a proper scramble set of moves. Disallow the obvious symmetries.
|
||||||
|
*/
|
||||||
|
fun randomMoves(amount: Int): IntArray {
|
||||||
val rgen = Random()
|
val rgen = Random()
|
||||||
return Array(amount) {
|
val result = IntArray(amount)
|
||||||
rgen.nextInt(18)
|
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 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.
|
* Empty counter, all 0 values for each digit.
|
||||||
*/
|
*/
|
||||||
var counter: Array<Int> = Array(size) { 0 }
|
var counter: IntArray = IntArray(size) { 0 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last (highest significance) index that overflowed and has been changed in the counter. Could be null, if it never overflowed.
|
* The last (highest significance) index that overflowed and has been changed in the counter. Could be null, if it never overflowed.
|
||||||
|
|||||||
@ -61,3 +61,12 @@ 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) {
|
class CounterBuffer(size: Int) : Counter(size, 18) {
|
||||||
|
|
||||||
val buffer = mutableListOf<Array<Int>>()
|
val buffer = mutableListOf<IntArray>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// initialise the buffer of valid counters
|
// initialise the buffer of valid counters
|
||||||
val counterBasic = CounterBasic(size)
|
val counterBasic = CounterBasic(size)
|
||||||
do {
|
do {
|
||||||
if (counterBasic.isValid()) {
|
if (counterBasic.isValid()) {
|
||||||
buffer.add(counterBasic.counter)
|
buffer.add(counterBasic.counter.copyOf())
|
||||||
}
|
}
|
||||||
} while (counterBasic.increase())
|
} while (counterBasic.increase())
|
||||||
println("Init of counter buffer, ${buffer.size} valid combos")
|
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
|
* 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
|
* 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 {
|
class CounterTiered : Counter(8) {
|
||||||
|
|
||||||
private val moveIterator: Iterator<Array<Int>>
|
private val moveIterator: Iterator<IntArray> = listOf<IntArray>().iterator()
|
||||||
|
|
||||||
override fun increase(): Boolean {
|
override fun increase(): Boolean {
|
||||||
if (!this.moveIterator.hasNext())
|
if (!this.moveIterator.hasNext())
|
||||||
@ -18,20 +18,14 @@ class CounterTiered : Counter {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constructor(size: Int) : super(size, 18) {
|
|
||||||
this.moveIterator = moveIterator().iterator()
|
|
||||||
this.increase()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun atMax(): Boolean {
|
override fun atMax(): Boolean {
|
||||||
return !this.moveIterator.hasNext()
|
return !this.moveIterator.hasNext()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MoveIterator(val classes: List<List<Int>>) : Iterator<Array<Int>> {
|
private class MoveIterator(val classes: List<IntArray>) : Iterator<IntArray> {
|
||||||
|
|
||||||
var currentClassIndex = 0
|
var currentClassIndex = 0
|
||||||
lateinit var currentMoves: Iterator<Array<Int>>
|
lateinit var currentMoves: Iterator<IntArray>
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -40,11 +34,11 @@ class CounterTiered : Counter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doClass(index: Int) {
|
private fun doClass(index: Int) {
|
||||||
val fillIn = fillIn(0, classes[index], Array(classes.size) { 0 })
|
val fillIn = fillIn(0, classes[index], IntArray(classes.size) { 0 })
|
||||||
currentMoves = fillIn.toList().iterator()
|
currentMoves = fillIn.toList().iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun next(): Array<Int> {
|
override fun next(): IntArray {
|
||||||
val next = currentMoves.next()
|
val next = currentMoves.next()
|
||||||
if (!currentMoves.hasNext()) {
|
if (!currentMoves.hasNext()) {
|
||||||
nextClass()
|
nextClass()
|
||||||
@ -65,73 +59,17 @@ class CounterTiered : Counter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
class CounterTieredFactory {
|
||||||
companion object {
|
companion object {
|
||||||
fun create(size: Int): CounterTiered {
|
fun create(size: Int): CounterTiered {
|
||||||
return CounterTiered(size)
|
return CounterTiered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
* Expand the class ints into the full range of moves.
|
||||||
*
|
*
|
||||||
@ -159,8 +97,8 @@ const val D2 = 15
|
|||||||
const val L2 = 16
|
const val L2 = 16
|
||||||
const val R2 = 17
|
const val R2 = 17
|
||||||
*/
|
*/
|
||||||
fun fillIn(index: Int, classes: List<Int>, moveList: Array<Int>): List<Array<Int>> {
|
fun fillIn(index: Int, classes: IntArray, moveList: IntArray): List<IntArray> {
|
||||||
val result = mutableListOf<Array<Int>>()
|
val result = mutableListOf<IntArray>()
|
||||||
|
|
||||||
// if the movelist is complete, finish it
|
// if the movelist is complete, finish it
|
||||||
if (index == classes.size) {
|
if (index == classes.size) {
|
||||||
|
|||||||
55
src/main/kotlin/be/nielandt/counter/VariableCounter.kt
Normal file
55
src/main/kotlin/be/nielandt/counter/VariableCounter.kt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
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()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
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}")
|
||||||
|
}
|
||||||
70
src/main/kotlin/be/nielandt/iterator/ValidClassesIterator.kt
Normal file
70
src/main/kotlin/be/nielandt/iterator/ValidClassesIterator.kt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
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,13 +1,82 @@
|
|||||||
package be.nielandt.iterator
|
package be.nielandt.iterator
|
||||||
|
|
||||||
class ValidMoveIterator: Iterator<Array<Int>> {
|
import be.nielandt.counter.VariableCounter
|
||||||
|
import be.nielandt.decodeMove
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
/**
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
* 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 next(): Array<Int> {
|
override fun hasNext(): Boolean = this.expansionCounter.hasNext()
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@Test
|
||||||
fun testSingleMove() {
|
fun testSingleMove() {
|
||||||
val edgeModel = EdgeModel()
|
val edgeModel = EdgeModel.solved()
|
||||||
(0..5).forEach { color ->
|
(0..5).forEach { color ->
|
||||||
assertTrue(edgeModel.crossSolved(color))
|
assertTrue(edgeModel.crossSolved(color))
|
||||||
}
|
}
|
||||||
@ -15,7 +15,7 @@ class EdgeModelTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSingleMoves() {
|
fun testSingleMoves() {
|
||||||
val edgeModel = EdgeModel()
|
val edgeModel = EdgeModel.solved()
|
||||||
println(edgeModel)
|
println(edgeModel)
|
||||||
val final = edgeModel.doMove(F)
|
val final = edgeModel.doMove(F)
|
||||||
println(final)
|
println(final)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user