removed enum, increased time!
This commit is contained in:
parent
ff81c3e7c8
commit
532b1cb85f
@ -1,16 +1,14 @@
|
|||||||
package be.nielandt
|
package be.nielandt
|
||||||
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counter for X digits of a given base.
|
* Counter for X digits of a given base.
|
||||||
*/
|
*/
|
||||||
open class Counter(size: Int, val base: Int = 10) {
|
open class Counter(size: Int, val base: Int = 18) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty counter, all 0 values for each digit.
|
* Empty counter, all 0 values for each digit.
|
||||||
*/
|
*/
|
||||||
protected var counter: Array<Int> = Array(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.
|
* The last (highest significance) index that overflowed and has been changed in the counter. Could be null, if it never overflowed.
|
||||||
@ -40,33 +38,6 @@ open class Counter(size: Int, val base: Int = 10) {
|
|||||||
return true
|
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?
|
* How many digits does this counter contain?
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import kotlin.math.min
|
|||||||
/**
|
/**
|
||||||
* Counter for X digits of a given base. Skips situations where faces are the same.
|
* Counter for X digits of a given base. Skips situations where faces are the same.
|
||||||
*/
|
*/
|
||||||
class CounterSkipSameFaces(size: Int, base: Int = 10): Counter(size, base) {
|
class CounterSkip(size: Int): Counter(size, 18) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increase the counter.
|
* Increase the counter.
|
||||||
@ -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<Move>>
|
abstract fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>>
|
||||||
|
|
||||||
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, List<Move>> {
|
fun solveCrossesTimed(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||||
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,10 +18,10 @@ open abstract class CrossSolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun printResults(results: Map<Int, List<Move>>) {
|
fun printResults(results: Map<Int, List<Int>>) {
|
||||||
println("results: ")
|
println("results: ")
|
||||||
results.forEach { color, moveList ->
|
results.forEach { color, moveList ->
|
||||||
println("> color ${colorLetter(color)}, moves (${moveList.size}) $moveList")
|
println("> color ${colorLetter(color)}, moves (${moveList.size}) ${moveList.map { it -> decodeMove(it) }}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,23 +62,26 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
|
|
||||||
// do a fixed scramble for testing purposes
|
// do a fixed scramble for testing purposes
|
||||||
val fixedMoves = Move.parse("L L_ R R2")
|
// 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}")
|
println("fixedMoves = ${fixedMoves}")
|
||||||
|
|
||||||
|
|
||||||
// scramble random
|
// scramble random
|
||||||
val moves = Move.random(10)
|
val randomMoves = randomMoves(20)
|
||||||
println("Scramble: $moves")
|
|
||||||
val scrambledModel = EdgeModel(moves)
|
val moves = fixedMoves
|
||||||
println(scrambledModel)
|
println("Scramble: ${moves.map { decodeMove(it) }}")
|
||||||
|
|
||||||
|
|
||||||
|
val usedModel = EdgeModel(moves)
|
||||||
|
println(usedModel)
|
||||||
|
|
||||||
// val baseSolve = CrossSolverBase().solveCrossesTimed(scrambledModel)
|
// val baseSolve = CrossSolverBase().solveCrossesTimed(scrambledModel)
|
||||||
// CrossSolver.printResults(baseSolve)
|
// CrossSolver.printResults(baseSolve)
|
||||||
|
|
||||||
val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(scrambledModel)
|
val upgradedSolve = CrossSolverUpgraded().solveCrossesTimed(usedModel)
|
||||||
CrossSolver.printResults(upgradedSolve)
|
CrossSolver.printResults(upgradedSolve)
|
||||||
|
|
||||||
val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(scrambledModel)
|
val upgradedSolveSkip = CrossSolverUpgradedSkip().solveCrossesTimed(usedModel)
|
||||||
CrossSolver.printResults(upgradedSolveSkip)
|
CrossSolver.printResults(upgradedSolveSkip)
|
||||||
|
|
||||||
// val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel)
|
// val allCrossMoveCountUpgradedSkip = allCrossMoveCountUpgradedSkip(scrambledModel)
|
||||||
|
|||||||
@ -4,26 +4,24 @@ 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<Move>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Move>>()
|
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||||
|
|
||||||
for (moveCount in 1..8) {
|
for (moveCount in 1..8) {
|
||||||
// build a counter of moveCount big
|
// build a counter of moveCount big
|
||||||
println("allCrossMoveCount basic doing $moveCount")
|
println("allCrossMoveCount basic doing $moveCount")
|
||||||
val counter = Counter(moveCount, Move.values().size)
|
val counter = Counter(moveCount, 18)
|
||||||
|
|
||||||
// count up, each state of the counter corresponds to a combination of moves
|
// count up, each state of the counter corresponds to a combination of moves
|
||||||
do {
|
do {
|
||||||
// what is the move combination we're looking at?
|
|
||||||
val moves = Move.combo(counter)
|
|
||||||
// execute the moves
|
// execute the moves
|
||||||
val afterMoves = edgeModel.doMoves(moves)
|
val afterMoves = edgeModel.doMoves(counter.counter)
|
||||||
// check crosses that have not been found yet
|
// check crosses that have not been found yet
|
||||||
(0..5).forEach { color ->
|
(0..5).forEach { color ->
|
||||||
if (!moveCounts.containsKey(color)) {
|
if (!moveCounts.containsKey(color)) {
|
||||||
val crossSolved = afterMoves.crossSolved(color)
|
val crossSolved = afterMoves.crossSolved(color)
|
||||||
if (crossSolved) {
|
if (crossSolved) {
|
||||||
moveCounts[color] = moves
|
moveCounts[color] = counter.counter.toList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,12 @@ package be.nielandt
|
|||||||
*/
|
*/
|
||||||
class CrossSolverUpgraded : CrossSolver() {
|
class CrossSolverUpgraded : CrossSolver() {
|
||||||
|
|
||||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Move>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Move>>()
|
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||||
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
|
||||||
val counter = Counter(moveCount, Move.values().size)
|
val counter = Counter(moveCount, 18)
|
||||||
val edgeModelFactory = EdgeModelFactory(edgeModel, counter)
|
val edgeModelFactory = EdgeModelFactory(edgeModel, counter)
|
||||||
|
|
||||||
while (edgeModelFactory.hasNext()) {
|
while (edgeModelFactory.hasNext()) {
|
||||||
@ -23,8 +23,7 @@ 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?
|
||||||
val moves = Move.combo(counter)
|
moveCounts[color] = counter.counter.toList()
|
||||||
moveCounts[color] = moves
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,12 @@ package be.nielandt
|
|||||||
*/
|
*/
|
||||||
class CrossSolverUpgradedSkip : CrossSolver() {
|
class CrossSolverUpgradedSkip : CrossSolver() {
|
||||||
|
|
||||||
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Move>> {
|
override fun solveCrosses(edgeModel: EdgeModel): Map<Int, List<Int>> {
|
||||||
val moveCounts = mutableMapOf<Int, List<Move>>()
|
val moveCounts = mutableMapOf<Int, List<Int>>()
|
||||||
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
|
||||||
val counter = CounterSkipSameFaces(moveCount, Move.values().size)
|
val counter = CounterSkip(moveCount)
|
||||||
val edgeModelFactory = EdgeModelFactory(edgeModel, counter)
|
val edgeModelFactory = EdgeModelFactory(edgeModel, counter)
|
||||||
|
|
||||||
while (edgeModelFactory.hasNext()) {
|
while (edgeModelFactory.hasNext()) {
|
||||||
@ -23,8 +23,7 @@ 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?
|
||||||
val moves = Move.combo(counter)
|
moveCounts[color] = counter.counter.toList()
|
||||||
moveCounts[color] = moves
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ package be.nielandt
|
|||||||
- | 18 |
|
- | 18 |
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
| 12 | 00 | 04 | 08 |
|
| 12 | 00 | 04 | 08 |
|
||||||
|15 O 13|03 G 01|07 R 05|11 B 09|
|
|15 O 13|03 G 01|07 R_indices 05|11 B_indices 09|
|
||||||
| 14 | 02 | 06 | 10 |
|
| 14 | 02 | 06 | 10 |
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
- | 20 |
|
- | 20 |
|
||||||
@ -28,16 +28,16 @@ class EdgeModel {
|
|||||||
|
|
||||||
val model: Array<Int>
|
val model: Array<Int>
|
||||||
|
|
||||||
private val F = intArrayOf(13, 18, 7, 20, 3, 0, 1, 2)
|
private val F_indices = intArrayOf(13, 18, 7, 20, 3, 0, 1, 2)
|
||||||
private val B = intArrayOf(8, 9, 10, 11, 16, 15, 22, 5)
|
private val B_indices = intArrayOf(8, 9, 10, 11, 16, 15, 22, 5)
|
||||||
private val L = intArrayOf(3, 23, 9, 19, 12, 13, 14, 15)
|
private val L_indices = intArrayOf(3, 23, 9, 19, 12, 13, 14, 15)
|
||||||
private val U = intArrayOf(16, 17, 18, 19, 0, 12, 8, 4)
|
private val U_indices = intArrayOf(16, 17, 18, 19, 0, 12, 8, 4)
|
||||||
private val D = intArrayOf(2, 6, 10, 14, 20, 21, 22, 23)
|
private val D_indices = intArrayOf(2, 6, 10, 14, 20, 21, 22, 23)
|
||||||
private val R = intArrayOf(4, 5, 6, 7, 1, 17, 11, 21)
|
private val R_indices = intArrayOf(4, 5, 6, 7, 1, 17, 11, 21)
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// do a sanity check
|
// do a sanity check
|
||||||
val entries = mutableListOf(F, B, L, U, D, R).flatMap { it.asList() }.groupBy { it }.entries
|
val entries = mutableListOf(F_indices, B_indices, L_indices, U_indices, D_indices, R_indices).flatMap { it.asList() }.groupBy { it }.entries
|
||||||
// println("entries = ${entries}")
|
// println("entries = ${entries}")
|
||||||
if (entries.any {
|
if (entries.any {
|
||||||
it.value.size != 2
|
it.value.size != 2
|
||||||
@ -57,7 +57,8 @@ class EdgeModel {
|
|||||||
|
|
||||||
constructor(randomMoves: Int) {
|
constructor(randomMoves: Int) {
|
||||||
val edgeModel = EdgeModel()
|
val edgeModel = EdgeModel()
|
||||||
val doMoves = edgeModel.doMoves(Move.random(randomMoves))
|
val r: Array<Int> = randomMoves(randomMoves)
|
||||||
|
val doMoves = edgeModel.doMoves(r)
|
||||||
this.model = doMoves.model
|
this.model = doMoves.model
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ class EdgeModel {
|
|||||||
this.model = model
|
this.model = model
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(moves: List<Move>) {
|
constructor(moves: List<Int>) {
|
||||||
val edgeModel = EdgeModel()
|
val edgeModel = EdgeModel()
|
||||||
val newModel = edgeModel.doMoves(moves)
|
val newModel = edgeModel.doMoves(moves)
|
||||||
this.model = newModel.model
|
this.model = newModel.model
|
||||||
@ -74,7 +75,7 @@ class EdgeModel {
|
|||||||
/**
|
/**
|
||||||
* Do a single move and calculate the resulting edge model.
|
* Do a single move and calculate the resulting edge model.
|
||||||
*/
|
*/
|
||||||
fun doMove(move: Move): EdgeModel {
|
fun doMove(move: Int): EdgeModel {
|
||||||
val copyOf = this.model.copyOf()
|
val copyOf = this.model.copyOf()
|
||||||
// execute the move
|
// execute the move
|
||||||
|
|
||||||
@ -126,24 +127,24 @@ class EdgeModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (move) {
|
when (move) {
|
||||||
Move.F -> nonPrime(F)
|
F -> nonPrime(F_indices)
|
||||||
Move.F_ -> prime(F)
|
F_ -> prime(F_indices)
|
||||||
Move.F2 -> double(F)
|
F2 -> double(F_indices)
|
||||||
Move.B -> nonPrime(B)
|
B -> nonPrime(B_indices)
|
||||||
Move.B_ -> prime(B)
|
B_ -> prime(B_indices)
|
||||||
Move.B2 -> double(B)
|
B2 -> double(B_indices)
|
||||||
Move.L -> nonPrime(L)
|
L -> nonPrime(L_indices)
|
||||||
Move.L_ -> prime(L)
|
L_ -> prime(L_indices)
|
||||||
Move.L2 -> double(L)
|
L2 -> double(L_indices)
|
||||||
Move.R -> nonPrime(R)
|
R -> nonPrime(R_indices)
|
||||||
Move.R_ -> prime(R)
|
R_ -> prime(R_indices)
|
||||||
Move.R2 -> double(R)
|
R2 -> double(R_indices)
|
||||||
Move.U -> nonPrime(U)
|
U -> nonPrime(U_indices)
|
||||||
Move.U_ -> prime(U)
|
U_ -> prime(U_indices)
|
||||||
Move.U2 -> double(U)
|
U2 -> double(U_indices)
|
||||||
Move.D -> nonPrime(D)
|
D -> nonPrime(D_indices)
|
||||||
Move.D_ -> prime(D)
|
D_ -> prime(D_indices)
|
||||||
Move.D2 -> double(D)
|
D2 -> double(D_indices)
|
||||||
}
|
}
|
||||||
return EdgeModel(copyOf)
|
return EdgeModel(copyOf)
|
||||||
}
|
}
|
||||||
@ -170,7 +171,7 @@ class EdgeModel {
|
|||||||
return trimMargin
|
return trimMargin
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doMoves(f: Collection<Move>): EdgeModel {
|
fun doMoves(f: Array<Int>) : EdgeModel {
|
||||||
var edgeModel = this
|
var edgeModel = this
|
||||||
f.forEach {
|
f.forEach {
|
||||||
edgeModel = edgeModel.doMove(it)
|
edgeModel = edgeModel.doMove(it)
|
||||||
@ -178,10 +179,21 @@ class EdgeModel {
|
|||||||
return edgeModel
|
return edgeModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doMoves(vararg f: Move): EdgeModel {
|
fun doMoves(f: Collection<Int>): EdgeModel {
|
||||||
|
var edgeModel = this
|
||||||
|
f.forEach {
|
||||||
|
edgeModel = edgeModel.doMove(it)
|
||||||
|
}
|
||||||
|
return edgeModel
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doMoves(vararg f: Int): EdgeModel {
|
||||||
return this.doMoves(f.toList())
|
return this.doMoves(f.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass any of the colors WHITE, YELLOW, RED, ...
|
||||||
|
*/
|
||||||
fun crossSolved(color: Int): Boolean {
|
fun crossSolved(color: Int): Boolean {
|
||||||
return when (color) {
|
return when (color) {
|
||||||
WHITE -> {
|
WHITE -> {
|
||||||
|
|||||||
@ -16,9 +16,9 @@ class EdgeModelFactory(val original: EdgeModel, val counter: Counter) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
// init the history
|
// init the history
|
||||||
this.history.add(original.doMove(Move.values()[counter.digit(0)]))
|
this.history.add(original.doMove(counter.digit(0)))
|
||||||
for (i in 1 until counter.size()) {
|
for (i in 1 until counter.size()) {
|
||||||
this.history.add(this.history.last().doMove(Move.values()[counter.digit(i)]))
|
this.history.add(this.history.last().doMove(counter.digit(i)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,14 +31,13 @@ class EdgeModelFactory(val original: EdgeModel, val counter: Counter) {
|
|||||||
val lastOverflowIndex = counter.lastModifiedIndex
|
val lastOverflowIndex = counter.lastModifiedIndex
|
||||||
// we only need to redo everything starting from the lastoverflowindex
|
// we only need to redo everything starting from the lastoverflowindex
|
||||||
// these are our moves, but we can salvage everything up to lastoverflowindex
|
// these are our moves, but we can salvage everything up to lastoverflowindex
|
||||||
val moves = Move.combo(counter)
|
|
||||||
// we have a history to work with... only redo what's necessary
|
// we have a history to work with... only redo what's necessary
|
||||||
for (i in counter.lastModifiedIndex until counter.size()) {
|
for (i in counter.lastModifiedIndex until counter.size()) {
|
||||||
var start: EdgeModel = if (i == 0)
|
var start: EdgeModel = if (i == 0)
|
||||||
original
|
original
|
||||||
else
|
else
|
||||||
history[i - 1]
|
history[i - 1]
|
||||||
history[i] = start.doMove(Move.values()[counter.digit(i)])
|
history[i] = start.doMove(counter.digit(i))
|
||||||
}
|
}
|
||||||
// increase the counter for next time
|
// increase the counter for next time
|
||||||
if (!counter.increase()) {
|
if (!counter.increase()) {
|
||||||
|
|||||||
@ -2,75 +2,95 @@ package be.nielandt
|
|||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
// constant values for all the moves
|
||||||
* All the possible moves on the cube.
|
|
||||||
*/
|
|
||||||
enum class Move {
|
|
||||||
// these are purposely put in this order: Move.index % 6 will result in the same value for the same face
|
// these are purposely put in this order: Move.index % 6 will result in the same value for the same face
|
||||||
F, B, U, D, L, R,
|
const val F = 0
|
||||||
F_, B_, U_, D_, L_, R_,
|
const val B = 1
|
||||||
F2, B2, U2, D2, L2, R2;
|
const val U = 2
|
||||||
|
const val D = 3
|
||||||
|
const val L = 4
|
||||||
|
const val R = 5
|
||||||
|
|
||||||
/**
|
const val F_ = 6
|
||||||
* Static methods for the Move object.
|
const val B_ = 7
|
||||||
*/
|
const val U_ = 8
|
||||||
companion object {
|
const val D_ = 9
|
||||||
/**
|
const val L_ = 10
|
||||||
* Make a random set of moves that makes sense.
|
const val R_ = 11
|
||||||
*/
|
|
||||||
fun random(amount: Int): List<Move> {
|
const val F2 = 12
|
||||||
|
const val B2 = 13
|
||||||
|
const val U2 = 14
|
||||||
|
const val D2 = 15
|
||||||
|
const val L2 = 16
|
||||||
|
const val R2 = 17
|
||||||
|
|
||||||
|
fun decodeMove(i: Int): String {
|
||||||
|
return when(i) {
|
||||||
|
F -> "F"
|
||||||
|
B -> "B"
|
||||||
|
U -> "U"
|
||||||
|
D -> "D"
|
||||||
|
L -> "L"
|
||||||
|
R -> "R"
|
||||||
|
|
||||||
|
F_ -> "F_"
|
||||||
|
B_ -> "B_"
|
||||||
|
U_ -> "U_"
|
||||||
|
D_ -> "D_"
|
||||||
|
L_ -> "L_"
|
||||||
|
R_ -> "R_"
|
||||||
|
|
||||||
|
F2 -> "F2"
|
||||||
|
B2 -> "B2"
|
||||||
|
U2 -> "U2"
|
||||||
|
D2 -> "D2"
|
||||||
|
L2 -> "L2"
|
||||||
|
R2 -> "R2"
|
||||||
|
else -> {
|
||||||
|
println("i = ${i}")
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseMoves(s: String): List<Int> {
|
||||||
|
return s.split(" ", ",", ";").filter { it?.length > 0 }.map { parseMove(it) }.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseMove(s: String): Int {
|
||||||
|
return when (s) {
|
||||||
|
"F" -> F
|
||||||
|
"B" -> B
|
||||||
|
"U" -> U
|
||||||
|
"D" -> D
|
||||||
|
"L" -> L
|
||||||
|
"R" -> R
|
||||||
|
|
||||||
|
"F_" -> F_
|
||||||
|
"B_" -> B_
|
||||||
|
"U_" -> U_
|
||||||
|
"D_" -> D_
|
||||||
|
"L_" -> L_
|
||||||
|
"R_" -> R_
|
||||||
|
|
||||||
|
"F2" -> F2
|
||||||
|
"B2" -> B2
|
||||||
|
"U2" -> U2
|
||||||
|
"D2" -> D2
|
||||||
|
"L2" -> L2
|
||||||
|
"R2" -> R2
|
||||||
|
else -> {
|
||||||
|
println("s = ${s}")
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun randomMoves(amount: Int): Array<Int> {
|
||||||
val rgen = Random()
|
val rgen = Random()
|
||||||
val result = mutableListOf<Move>()
|
return Array(amount) {
|
||||||
while (result.size < amount) {
|
rgen.nextInt(18)
|
||||||
val randomMove = Move.values()[rgen.nextInt(Move.values().size)]
|
|
||||||
// check if it makes sense?
|
|
||||||
if (result.isNotEmpty() && result.last() otherFace randomMove)
|
|
||||||
result.add(randomMove)
|
|
||||||
else if (result.isEmpty())
|
|
||||||
result.add(randomMove)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the given counter, which contains digits that correspond with the amount of Moves, to generate a list of Moves.
|
|
||||||
* Highest significant digits of the counter are added first (are first in the result list).
|
|
||||||
*/
|
|
||||||
fun combo(counter: Counter): List<Move> {
|
|
||||||
val res = mutableListOf<Move>()
|
|
||||||
for (i in 0 until counter.size()) {
|
|
||||||
res.add(Move.values()[counter.digit(i)])
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a set of moves, separated by spaces, using the Move.enum names.
|
|
||||||
*/
|
|
||||||
fun parse(s: String): List<Move> {
|
|
||||||
val result = mutableListOf<Move>()
|
|
||||||
s.split(" ", ",", ";").forEach {
|
|
||||||
if (it.isNotEmpty()) {
|
|
||||||
result.add(Move.valueOf(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this as `Move otherFace Move`, a quick way to check if the moves manipulate the same face or not.
|
|
||||||
* Example: `Move.F otherFace Move.U_ == false`
|
|
||||||
*/
|
|
||||||
infix fun otherFace(otherMove: Move): Boolean {
|
|
||||||
return this.toString().substring(0, 1) != otherMove.toString().substring(0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are both moves on the same face? Would be true for F2 and F_, for example.
|
|
||||||
*/
|
|
||||||
infix fun sameFace(otherMove: Move): Boolean {
|
|
||||||
return !otherFace(otherMove)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +1,24 @@
|
|||||||
package be.nielandt
|
package be.nielandt
|
||||||
|
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class EdgeModelTest {
|
class EdgeModelTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun singleMoveAlwaysOneSolvedCross() {
|
fun testSingleMove() {
|
||||||
// try each move
|
val edgeModel = EdgeModel()
|
||||||
Move.values().forEach { move ->
|
(0..5).forEach { color ->
|
||||||
val doMove = EdgeModel().doMove(move)
|
assertTrue(edgeModel.crossSolved(color))
|
||||||
val count = (0..5).map { color ->
|
|
||||||
val crossSolved = doMove.crossSolved(color)
|
|
||||||
crossSolved
|
|
||||||
}.count { it }
|
|
||||||
assertEquals(1, count)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSingleMoves() {
|
||||||
|
val edgeModel = EdgeModel()
|
||||||
|
println(edgeModel)
|
||||||
|
val final = edgeModel.doMove(F)
|
||||||
|
println(final)
|
||||||
|
assertTrue(final.crossSolved(BLUE))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user