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

35 lines
1.3 KiB
Scala

package snake
/** m03 rules: the pure game rules. Each function takes a state and returns a new one. */
object Rules:
def move(p: Point, dir: Direction): Point =
val d = Model.delta(dir)
Point(p.x + d.x, p.y + d.y)
def inBounds(state: GameState, p: Point): Boolean =
p.x >= 0 && p.x < state.width && p.y >= 0 && p.y < state.height
// Validate against `dir` (last moved), not `nextDir`: Up then Left within one tick must not fold the snake back on itself.
def turn(state: GameState, dir: Direction): GameState =
if state.status == Status.Playing && dir != Model.opposite(state.dir) then state.copy(nextDir = dir)
else state
def advance(state: GameState): GameState =
if state.status != Status.Playing then state
else
val d = state.nextDir
val head = move(state.snake.head, d)
val eating = state.apple.contains(head)
// When not eating, the tail leaves its cell this step, so the head may move into it.
val body = if eating then state.snake else Util.dropLast(state.snake)
if !inBounds(state, head) || Util.contains(body, head, _ == _) then
state.copy(dir = d, status = Status.GameOver)
else
state.copy(
snake = head :: body,
dir = d,
apple = if eating then None else state.apple,
score = state.score + (if eating then 1 else 0)
)