/// m06 view: the picture is plain data (a list of shapes); drawing it is somebody else's job (m07). module Snake.View open Snake.Model /// A thing to draw. type Shape = | Rect of x: int * y: int * w: int * h: int * color: string | Text of x: int * y: int * text: string * color: string * size: int * align: string /// A picture: shapes drawn in order. type Scene = Shape list let CELL = 20 let private text x y str size align = Text(x, y, str, "#ffffff", size, align) // One cell, inset by 1px so neighbouring segments show a gap. let private cell (p: Point) color = Rect(p.X * CELL + 1, p.Y * CELL + 1, CELL - 2, CELL - 2, color) let private overlay (state: GameState) : Scene = let cx = state.Width * CELL / 2 let cy = state.Height * CELL / 2 let banner title hint = [ text cx cy title 32 "center"; text cx (cy + 30) hint 16 "center" ] match state.Status with | Paused -> banner "Paused" "Press Space to resume" | GameOver -> banner "Game Over" "Press R to restart" | Won -> banner "You Win!" "Press R to restart" | Playing -> [] let view (state: GameState) : Scene = [ Rect(0, 0, state.Width * CELL, state.Height * CELL, "#111111") ] @ (state.Apple |> Option.map (fun a -> cell a "#e53935") |> Option.toList) @ (state.Snake |> List.mapi (fun i p -> cell p (if i = 0 then "#7cb342" else "#43a047"))) @ [ text 6 18 $"Score: {state.Score}" 16 "left" ] @ overlay state