Created
September 2, 2016 12:18
-
-
Save waynejo/46a18f4603c0f3fb99cdcb42402e1a79 to your computer and use it in GitHub Desktop.
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 lascala.turtle | |
import lascala.turtle.common._ | |
object BasicOO { | |
class Turtle(log: String => Unit) { | |
var currentPosition: Position = initialPosition | |
var currentAngle: Angle = 0.0.degree | |
var currentColor: PenColor = initialColor | |
var currentPenState: PenState = initialPenState | |
def move(distance: Distance) = { | |
log(f"Move $distance%.1f") | |
val newPosition = currentPosition.move(distance, currentAngle) | |
if (currentPenState == PenState.Down) dummyDrawLine(log, currentPosition, newPosition, currentColor) | |
currentPosition = newPosition | |
} | |
def turn(angle: Angle) = { | |
log(f"Turn ${angle.degree}%.1f") | |
currentAngle = (currentAngle.degree + angle.degree).degree | |
} | |
def penUp() = { | |
log("Pen up") | |
currentPenState = PenState.Up | |
} | |
def penDown() = { | |
log("Pen down") | |
currentPenState = PenState.Down | |
} | |
def setColor(color:PenColor) = { | |
log(s"SetColor $color") | |
currentColor = color | |
} | |
} | |
} |
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 lascala.turtle | |
package object common { | |
type Distance = Double | |
case class Angle(degree: Double) { | |
def toRadian: Double = degree / 180 * math.Pi | |
} | |
implicit class AngleUnit(val angle: Double) extends AnyVal { | |
def degree: Angle = Angle(angle) | |
} | |
sealed trait PenState | |
object PenState { | |
case object Up extends PenState | |
case object Down extends PenState | |
} | |
sealed trait PenColor | |
object PenColor { | |
case object Black extends PenColor | |
case object Red extends PenColor | |
case object Blue extends PenColor | |
} | |
case class Position(x: Double, y: Double) { | |
def move(distance: Distance, angle: Angle): Position = | |
Position(x + distance * (math cos angle.toRadian), y + distance * (math sin angle.toRadian)) | |
override def toString(): String = f"($x%.1f, $y%.1f)" | |
} | |
implicit class DoubleRound2(val d: Double) extends AnyVal { | |
def round2: Double = (math rint d * 100) / 100.0 | |
} | |
val (initialPosition, initialColor, initialPenState) = (Position(0, 0), PenColor.Black, PenState.Down) | |
def dummyDrawLine(log: String => Unit, oldPos: Position, newPos: Position, color: PenColor): Unit = | |
log(s"...Draw line from $oldPos to $newPos using $color") | |
object Functional { | |
class PipedObject[T] private[Functional] (value:T) | |
{ | |
def |>[R] (f : T => R) = f(this.value) | |
} | |
implicit def toPiped[T] (value:T) = new PipedObject[T](value) | |
} | |
} |
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 lascala.turtle | |
import lascala.turtle.BasicOO.Turtle | |
import lascala.turtle.common.Angle | |
import lascala.turtle.common._ | |
class TurtleApi { | |
def validateDistance(distanceStr:String): Float = { | |
try { | |
distanceStr.toFloat | |
} catch { | |
case e:Exception => { | |
val msg = s"Invalid distance '$distanceStr' [$e]" | |
throw new RuntimeException(msg) | |
} | |
} | |
} | |
def validateAngle(angleStr:String): Angle = { | |
try { | |
angleStr.toDouble.degree | |
} catch { | |
case e:Exception => { | |
val msg = s"Invalid angle '$angleStr' [$e]" | |
throw new RuntimeException(msg) | |
} | |
} | |
} | |
def validateColor(colorStr:String): PenColor = { | |
colorStr match { | |
case "Black" => PenColor.Black | |
case "Blue" => PenColor.Blue | |
case "Red" => PenColor.Red | |
case _ => | |
val msg = s"Color '$colorStr' is not recognized" | |
throw new RuntimeException(msg) | |
} | |
} | |
var turtle = new Turtle(s => println(s)) | |
def exec(commandStr:String) = { | |
val tokens = commandStr.split(' ').toList.map(_.trim) | |
tokens match { | |
case "Move" :: distanceStr :: Nil => | |
val distance = validateDistance(distanceStr) | |
turtle.move(distance) | |
case "Turn" :: angleStr :: Nil => | |
val angle = validateAngle(angleStr) | |
turtle.turn(angle) | |
case "Pen" :: "Up" :: Nil => | |
turtle.penUp() | |
case "Pen" :: "Down" :: Nil => | |
turtle.penDown() | |
case "SetColor" :: colorStr :: Nil => | |
val color = validateColor(colorStr) | |
turtle.setColor(color) | |
case _ => | |
val msg = s"Instruction '$commandStr' is not recognized" | |
throw new RuntimeException(msg) | |
} | |
} | |
} |
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 lascala.turtle | |
import lascala.turtle.BasicFP.TurtleState | |
import lascala.turtle.BasicOO._ | |
import lascala.turtle.common._ | |
import utest._ | |
object TurtleAPITest extends TestSuite { | |
val tests = this { | |
'Move { | |
val turtleAPI = new TurtleApi() | |
turtleAPI.exec("Move 1.0") | |
val Position(x, y) = turtleAPI.turtle.currentPosition | |
assert((x - 1.0).abs < 0.000001) | |
assert((y - 0.0).abs < 0.000001) | |
} | |
'Turn { | |
val turtleAPI = new TurtleApi() | |
turtleAPI.exec("Turn 90.0") | |
assert((turtleAPI.turtle.currentAngle.degree - 90.0).abs < 0.000001) | |
} | |
'PenUp { | |
val turtleAPI = new TurtleApi() | |
turtleAPI.exec("Pen Up") | |
assert(turtleAPI.turtle.currentPenState == PenState.Up) | |
} | |
'PenDown { | |
val turtleAPI = new TurtleApi() | |
turtleAPI.exec("Pen Down") | |
assert(turtleAPI.turtle.currentPenState == PenState.Down) | |
} | |
'SetColor { | |
val turtleAPI = new TurtleApi() | |
turtleAPI.exec("SetColor Blue") | |
assert(turtleAPI.turtle.currentColor == PenColor.Blue) | |
} | |
'DrawPolygon { | |
def drawPolygon(n:Int) = { | |
val turtleAPI = new TurtleApi() | |
def angle = 360.0 / n.toDouble | |
def angleDegrees = angle.degree | |
// define a function that draws one side | |
//def oneSide(state:TurtleState, sideNumber:Int) = state |> move(100.0) |> turn(angleDegrees) | |
def drawOneSide() = { | |
turtleAPI.exec("Move 100.0") | |
turtleAPI.exec(s"Turn $angle") | |
} | |
(1 to n) foreach (v => drawOneSide()) | |
} | |
drawPolygon(5) | |
} | |
'TriggerError { | |
def triggerError() = { | |
val turtleApi = new TurtleApi() | |
turtleApi.exec("Move bad") | |
} | |
intercept[RuntimeException] { | |
triggerError() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment