Files
functional-programming-snake/scala/solutions/View.scala
T
2026-10-29 00:07:27 +01:00

41 lines
1.7 KiB
Scala

package snake
/** A thing to draw. The picture is plain data; drawing it is somebody else's job (m07). */
enum Shape:
case Rect(x: Int, y: Int, w: Int, h: Int, color: String)
case Text(x: Int, y: Int, text: String, color: String, size: Int, align: String)
/** A picture: shapes drawn in order. */
type Scene = List[Shape]
/** m06 view: the picture is plain data (a list of shapes); drawing it is somebody else's job (m07). */
object View:
val CELL: Int = 20
private def rect(x: Int, y: Int, w: Int, h: Int, color: String): Shape = Shape.Rect(x, y, w, h, color)
private def text(x: Int, y: Int, str: String, size: Int, align: String): Shape =
Shape.Text(x, y, str, "#ffffff", size, align)
// One cell, inset by 1px so neighbouring segments show a gap.
private def cell(p: Point, color: String): Shape = rect(p.x * CELL + 1, p.y * CELL + 1, CELL - 2, CELL - 2, color)
private def overlay(state: GameState): Scene =
val cx = state.width * CELL / 2
val cy = state.height * CELL / 2
def banner(title: String, hint: String): Scene =
List(text(cx, cy, title, 32, "center"), text(cx, cy + 30, hint, 16, "center"))
state.status match
case Status.Paused => banner("Paused", "Press Space to resume")
case Status.GameOver => banner("Game Over", "Press R to restart")
case Status.Won => banner("You Win!", "Press R to restart")
case Status.Playing => Nil
def view(state: GameState): Scene =
List(rect(0, 0, state.width * CELL, state.height * CELL, "#111111")) ++
state.apple.map(cell(_, "#e53935")).toList ++
state.snake.zipWithIndex.map((p, i) => cell(p, if i == 0 then "#7cb342" else "#43a047")) ++
List(text(6, 18, s"Score: ${state.score}", 16, "left")) ++
overlay(state)