class SelfContainedChannel extends AggregateProgram with SensorDefinitions {
def isObstacle = sense[Boolean]("obstacle")
def isSource = sense[Boolean]("source")
def isDestination = sense[Boolean]("target")
override def main(): Boolean =
branch(isObstacle){ false }{ channel(isSource, isDestination, 5) }
def channel(src: Boolean, dest: Boolean, width: Double): Boolean =
dilate(distanceTo(src) + distanceTo(dest) <= distanceBetween(src,dest), width)
type OB[T] = Builtins.Bounded[T]
def G[V:OB](src: Boolean, field: V, acc: V=>V, metric: =>Double): V =
rep( (Double.MaxValue, field) ){ dv =>
mux(src) { (0.0, field) } {
minHoodPlus {
val (d, v) = nbr { (dv._1, dv._2) }
(d + metric, acc(v))
} } }._2
def distanceTo(source: Boolean): Double =
G[Double](source, 0, _ + nbrRange(), nbrRange())
def broadcast[V:OB](source: Boolean, field: V): V =
G[V](source, field, x=>x, nbrRange())
def distanceBetween(source: Boolean, target: Boolean): Double =
broadcast(source, gradient(target))
def dilate(region: Boolean, width: Double): Boolean =
gradient(region) < width
}