package net.tixxit.sniped.arithsolver import scala.annotation.switch object Solver { final val Add = 0 final val Sub = 1 final val Mul = 2 final val Div = 3 private val workBuffers = new ThreadLocal[Array[Int]]() private def orderValues(soln: Int, values: Array[Int]): Array[Int] = { var work = workBuffers.get() if (work == null) { work = new Array[Int](4) workBuffers.set(work) } // Re-order the values. var i = 0 while (i < 4) { val j = (soln >>> (i * 2)) & 0x3 work(i) = values(j) i += 1 } work } private def getOp(soln: Int, i: Int): Int = (soln >>> (i * 2 + 8)) & 0x3 private def evalSolution(soln: Int, values: Array[Int]): Int = { // Re-order the values. val work = orderValues(soln, values) // Apply the operations, in order. var i = 0 while (i < 3) { val x = work(0) val y = work(i + 1) work(0) = (getOp(soln, i): @switch) match { case Add => x + y case Sub => x - y case Mul => x * y case Div => x / y } i += 1 } work(0) } private def isValid(soln: Int): Boolean = { val a = soln & 0x3 val b = (soln >>> 2) & 0x3 val c = (soln >>> 4) & 0x3 val d = (soln >>> 6) & 0x3 a != b && a != c && a != d && b != c && b != d && c != d } private def printSolution(soln: Int, values: Array[Int]): String = { val work = orderValues(soln, values) var out = s"(((${work(0)}" var i = 0 while (i < 3) { val x = work(i + 1) (getOp(soln, i): @switch) match { case Add => out += s" + $x)" case Sub => out += s" - $x)" case Mul => out += s" * $x)" case Div => out += s" / $x)" } i += 1 } out += s" = ${evalSolution(soln, values)}" out } def solve(nums: Array[Int], result: Int): Unit = { val solutions = scala.collection.mutable.HashSet.empty[String] var i = 0 while (i < (1 << 14)) { if (isValid(i) && evalSolution(i, nums) == result) solutions += printSolution(i, nums) i += 1 } solutions.foreach { out => println(out) } } def solve(a: Int, b: Int, c: Int, d: Int, result: Int): Unit = solve(Array(a, b, c, d), result) }