Created
October 5, 2017 16:41
-
-
Save odrianoaliveira/9ae7858f4bd2b6258d004b745a79a940 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
class Pouring(capacity: Vector[Int]) { | |
//states | |
type State = Vector[Int] | |
val initialState = capacity map (x => 0) | |
trait Move { | |
def change(state: State): State | |
} | |
case class Empty(glass: Int) extends Move { | |
override def change(state: State) = state updated(glass, 0) | |
} | |
case class Fill(glass: Int) extends Move { | |
override def change(state: State) = state updated(glass, capacity(glass)) | |
} | |
case class Pour(from: Int, to: Int) extends Move { | |
override 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 glasses = capacity.indices | |
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) { | |
private def trackState(xs: List[Move]): State = xs match { | |
case Nil => initialState | |
case move :: xs1 => move change trackState(xs1) | |
} | |
// def endState: State = trackState(history) | |
// or | |
// def endState: State = (history foldRight initialState) (_ change _) | |
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 | |
} | |
val problem = new Pouring(Vector(4, 7)) | |
problem.moves | |
problem.pathSets.take(3).toList | |
problem.solutions(6) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment