Skip to content

Instantly share code, notes, and snippets.

@KWMalik
Forked from supki/GameDef.scala
Created November 21, 2012 19:07
Show Gist options
  • Save KWMalik/4126954 to your computer and use it in GitHub Desktop.
Save KWMalik/4126954 to your computer and use it in GitHub Desktop.
Functional programming course at Coursera week 7.
package streams
import common._
trait GameDef {
case class Pos(x: Int, y: Int) {
def dx(d: Int) = copy(x = x + d, y)
def dy(d: Int) = copy(x, y = y + d)
}
val startPos: Pos
val goal: Pos
type Terrain = Pos => Boolean
val terrain: Terrain
sealed abstract class Move
case object Left extends Move
case object Right extends Move
case object Up extends Move
case object Down extends Move
def startBlock: Block = Block(startPos, startPos)
case class Block(b1: Pos, b2: Pos) {
require(b1.x <= b2.x && b1.y <= b2.y, "Invalid block position: b1=" + b1 + ", b2=" + b2)
def dx(d1: Int, d2: Int) = Block(b1.dx(d1), b2.dx(d2))
def dy(d1: Int, d2: Int) = Block(b1.dy(d1), b2.dy(d2))
def left = if (isStanding) dy(-2, -1)
else if (b1.x == b2.x) dy(-1, -2)
else dy(-1, -1)
def right = if (isStanding) dy(1, 2)
else if (b1.x == b2.x) dy(2, 1)
else dy(1, 1)
def up = if (isStanding) dx(-2, -1)
else if (b1.x == b2.x) dx(-1, -1)
else dx(-1, -2)
def down = if (isStanding) dx(1, 2)
else if (b1.x == b2.x) dx(1, 1)
else dx(2, 1)
def neighbors: List[(Block, Move)] = List((left, Left), (right, Right), (up, Up), (down, Down))
def legalNeighbors: List[(Block, Move)] = neighbors.filter(_._1.isLegal)
def isStanding: Boolean = b1 == b2
def isLegal: Boolean = terrain(b1) && terrain(b2)
}
}
package streams
import common._
trait Solver extends GameDef {
def done(b: Block): Boolean = b == Block(goal, goal)
def neighborsWithHistory(b: Block, history: List[Move]): Stream[(Block, List[Move])] =
b.legalNeighbors.map(x => x match {case (s,t) => (s, t :: history)}).toStream
def newNeighborsOnly(neighbors: Stream[(Block, List[Move])],
explored: Set[Block]): Stream[(Block, List[Move])] =
neighbors filterNot (explored contains _._1)
def from(initial: Stream[(Block, List[Move])],
explored: Set[Block]): Stream[(Block, List[Move])] = initial match {
case (b,h) #:: xs => {
val ys = newNeighborsOnly(neighborsWithHistory(b,h), explored)
(b,h) #:: from(xs ++ ys, explored + b)
}
case _ => Stream.empty
}
lazy val pathsFromStart: Stream[(Block, List[Move])] = from(Stream((startBlock, Nil)), Set.empty)
lazy val pathsToGoal: Stream[(Block, List[Move])] = pathsFromStart.filter(b => done(b._1))
lazy val solution: List[Move] = pathsToGoal match {
case x #:: _ => x._2.reverse
case _ => Nil
}
}
package streams
import common._
trait StringParserTerrain extends GameDef {
val level: String
def terrainFunction(levelVector: Vector[Vector[Char]]): Pos => Boolean =
p => if (p.x < 0 || p.y < 0) false
else if (p.x > levelVector.length - 1) false
else if (p.y > levelVector(0).length - 1) false
else levelVector(p.x)(p.y) != '-'
def findChar(c: Char, levelVector: Vector[Vector[Char]]): Pos = {
def x = levelVector.indexWhere(_.indexWhere(_ == c) > -1)
def y = levelVector(x).indexWhere(_ == c)
Pos(x, y)
}
private lazy val vector: Vector[Vector[Char]] =
Vector(level.split("\n").map(str => Vector(str: _*)): _*)
lazy val terrain: Terrain = terrainFunction(vector)
lazy val startPos: Pos = findChar('S', vector)
lazy val goal: Pos = findChar('T', vector)
}
@valtih1978
Copy link

valtih1978 commented Jun 29, 2017

You can specify the terrainFunction more concisely

  	case Pos(y,x) => x >= 0 && y >= 0 &&
  		y < vector.length && x < vector(0).length &&
  		vector(y)(x) != '-'

findChar can also be shortened if you first find the y

  	val y = level.indexWhere(row => row contains c)
  	val x = level(y).indexOf(c)
  	Pos(y,x)

You can alsu use -> operator for making the tuples instead of (,):

    def neighbors = List(left -> Left, right -> Right, up -> Up, down -> Down)

There is no need for match in neighborsWithHistory. Instead of

legalNeighbors map(x => x match {case (s,t) => (s, t :: history)}

you simply write map function in curly braces

legalNeighbors map{case (s,t) => (s, t :: history)}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment