Created
June 17, 2014 02:27
-
-
Save js1972/e87794839e1ac894c2ec to your computer and use it in GitHub Desktop.
Solution to the Water Pouring problem in Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package week7 | |
class Pouring(capacity: Vector[Int]) { | |
// States | |
type State = Vector[Int] | |
val initialState = capacity map (x => 0) | |
// Moves | |
trait Move { | |
def change(state: State): State | |
} | |
case class Empty(glass: Int) extends Move { | |
def change(state: State) = state updated (glass, 0) | |
} | |
case class Fill(glass: Int) extends Move { | |
def change(state: State) = state updated (glass, capacity(glass)) | |
} | |
case class Pour(from: Int, to: Int) extends Move { | |
def change(state: State) = { | |
val amount = state(from) min (capacity(to) - state(to)) | |
state updated (from, state(from) - amount) updated (to, state(to) + amount) | |
} | |
} | |
val glasses = 0 until capacity.length | |
val moves = | |
(for (g <- glasses) yield Empty(g)) ++ | |
(for (g <- glasses) yield Fill(g)) ++ | |
(for (from <- glasses; to <- glasses if from != to) yield Pour(from, to)) | |
// Paths | |
class Path(history: List[Move], val endState: State) { | |
def extend(move: Move) = new Path(move :: history, move change endState) | |
override def toString = (history.reverse mkString " ") + "--> " + endState | |
} | |
val initialPath = new Path(Nil, initialState) | |
def from(paths: Set[Path], explored: Set[State]): Stream[Set[Path]] = | |
if (paths.isEmpty) Stream.empty | |
else { | |
val more = for { | |
path <- paths | |
next <- moves map path.extend | |
if !(explored contains next.endState) | |
} yield next | |
paths #:: from(more, explored ++ (more map (_.endState))) | |
} | |
val pathSets = from(Set(initialPath), Set(initialState)) | |
def solutions(target: Int): Stream[Path] = | |
for { | |
pathSet <- pathSets | |
path <- pathSet | |
if path.endState contains target | |
} yield path | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package week7 | |
object test { | |
/** | |
* Solution to the Water Pouring Problem. | |
* | |
* Create a pouring object specifying the number of glasses (containers) | |
* and their volumes in a Vector. | |
* Call the solutions method with the volume you wish to find with | |
* the result being a Stream of the moves required to get there... | |
*/ | |
val problem = new Pouring(Vector(4, 9, 19)) //> problem : week7.Pouring = week7.Pouring@6dce272d | |
problem.moves //> res0: scala.collection.immutable.IndexedSeq[Product with Serializable with w | |
//| eek7.test.problem.Move] = Vector(Empty(0), Empty(1), Empty(2), Fill(0), Fill | |
//| (1), Fill(2), Pour(0,1), Pour(0,2), Pour(1,0), Pour(1,2), Pour(2,0), Pour(2, | |
//| 1)) | |
problem.solutions(17) //> res1: Stream[week7.test.problem.Path] = Stream(Fill(0) Pour(0,2) Fill(1) Fil | |
//| l(0) Pour(0,2) Pour(1,2)--> Vector(0, 0, 17), ?) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment