Skip to content

Instantly share code, notes, and snippets.

@AndrewTweddle
Last active August 29, 2015 13:56
Show Gist options
  • Select an option

  • Save AndrewTweddle/9177615 to your computer and use it in GitHub Desktop.

Select an option

Save AndrewTweddle/9177615 to your computer and use it in GitHub Desktop.
A solver using Scala's foldLeft to solve the Johnny Hates Math problem found at http://www.spoj.com/problems/ANARC07J/ (NB: this is to find all solutions to the problem, not to satisfy the SPOJ IO specification)
package jhm
case class SolverUsingFoldLeft( digits: String, total: Int, maxDigitsPerNumber: Int = 5
) extends JHMSolver(digits, total, maxDigitsPerNumber) {
case class PartialSolution( val partialStr: String, val partialNumber: Int,
val subTotal: Int, val numbersInReverse: List[Int] )
{
def runningSubTotal = subTotal + partialNumber
def isInitialSolution = partialStr == ""
def isZero = partialStr == "0"
def isMaxLength = partialStr.length == maxDigitsPerNumber
}
override def solve(digits: String, total: Int, maxDigitsPerNumber: Int = 5): List[List[Int]] = {
def StartNewPartialNumber(par: PartialSolution, newPartialStr: String,
newPartialNumber: Int)= PartialSolution(
partialStr = newPartialStr,
partialNumber = newPartialNumber,
subTotal = par.runningSubTotal,
numbersInReverse = if (par.isInitialSolution) List.empty // don't prepend zero
else par.partialNumber :: par.numbersInReverse
)
def buildUpSolutions(partialSolutions: List[PartialSolution], nextDigit: Char): List[PartialSolution] = {
def expandSolution(par: PartialSolution): List[PartialSolution] = {
val nextDigitAsStr = nextDigit.toString
val nextDigitAsInt = nextDigitAsStr.toInt
val parSolWithStartOfNewNumber = StartNewPartialNumber(par, nextDigitAsStr, nextDigitAsInt)
if (parSolWithStartOfNewNumber.runningSubTotal > total)
List.empty // No point in trying an even bigger number
else {
if (par.isZero || par.isMaxLength || par.isInitialSolution) List(parSolWithStartOfNewNumber)
else {
val parSolWithLargerNumber = PartialSolution(
partialStr = par.partialStr + nextDigit,
partialNumber = 10 * par.partialNumber + nextDigit.toString.toInt,
subTotal = par.subTotal,
numbersInReverse = par.numbersInReverse
)
if (parSolWithLargerNumber.runningSubTotal > total) List(parSolWithStartOfNewNumber)
else List(parSolWithStartOfNewNumber, parSolWithLargerNumber)
}
}
}
partialSolutions flatMap expandSolution
}
val initialPartialSolution = PartialSolution(
partialStr = "", partialNumber = 0, subTotal = 0, numbersInReverse = List())
val allSolutions = digits.foldLeft(List(initialPartialSolution))(buildUpSolutions)
def completePartialSolution(par: PartialSolution): PartialSolution = PartialSolution(
partialStr = "",
partialNumber = 0,
subTotal = par.runningSubTotal,
numbersInReverse = par.partialNumber :: par.numbersInReverse
)
allSolutions map completePartialSolution filter (_.subTotal == total) map (_.numbersInReverse.reverse)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment