content/posts/coding/haskell-snake.md
8bfcbb82
 ---
 title: Writing a snake clone in Haskell, part 1
 date: 2017-11-16
 tags:
   - coding
   - haskell
 ---
 
 After my recent dive into Haskell I was keen to try a small project to
 test out what I had learned. After watching a bunch of YouTube videos
 from various Haskell conferences I came across one by
 [Moss Collum](https://github.com/moss) where he describes how he built
 a series of Rogue-like games in Haskell over the course of a week.
 
 I took a look at Moss' [code](https://github.com/moss/haskell-roguelike-challenge)
 and thought it was a pretty neat idea, however I wanted to try and make
 a snake game instead (nostalgia for the Nokia 3310, I guess). If you don't
 know what snake is, here's a sweet GIF of a russian guy getting a perfect game:
 
7f8395f3
 {{<figure src="https://media.giphy.com/media/8D0yR4ylkAC1G/giphy.gif">}}
8bfcbb82
 
 You move a snake around the screen trying to gobble up pieces of food. The snake
 moves forward 1 space every second or so autonomously, and each piece
 of food you eat makes the snake grow 1 space longer. You die if the snake hits
 the walls or its own tail.
 
 The snake games that I saw on Hackage all seemed to be projects for the author
 to learn how to use a specific library, and I found that as a consequence the
 code logic was somewhat obscured. I wanted something *much* simpler:
 a terminal application controlled by sending keypresses to `stdin`, and with
 ASCII "graphics". I specifically wanted to avoid using game libraries; after all, my aim
 was to exercise my Haskell knowledge, not to make a novel gaming experience!
 
 
 ### Let's go
 
 All of the code described here is available [on Github](https://github.com/jbweston/haskell-snake).
 
 #### First iteration
 
 I started out by looking at some of Moss' code to see an example of how
 I could proceed. I decided that the first thing I would do
 would be to have a snake of fixed length moving around the screen
 in response to keypresses: no "food" to grow the snake, no boundaries,
 no collision detection and (most importantly) the snake does not move
 by itself.
 
 The best way of proceeding seemed to be to model the game as a sequence
 of transformations on an initial state of the game's world. The
 transformations to apply are determined by the commands typed by the
 player. Moss' code took advantage of Haskell's lazy IO to get an
 (infinite) list of keypresses from `stdin` and then used this
 as the sequence of transformations. This is captured by the
 following code:
 
 ```haskell
 parseInput :: [Char] -> [Direction]
 ...
 advance :: World -> Direction -> World
 ...
 input <- getContents
 let states = scanl advance initialWorld (parseInput input)
 ```
 
 The last two lines are from the `main` function, and the preceding
 lines are the type signatures necessary to understand them. We
 can see that we first take the raw input from the user (via the
 `getContents` IO action) and parse the sequence of raw keypresses
 (the infinite list of `Char`) into a sequence of `Direction`s in
 which to move the snake. We then do a left scan of the `advance`
 function over this sequence of directions, starting with the
 world in its initial state, to generate a sequence of states
 of the world! `parseInput` also handles quitting the game when
 the user presses `q`. We model this by terminating the
 sequence of directions when we detect that `q` was typed.
 
 Once we have this sequence of game worlds we just need to
 draw them to the screen. Naively I initially did the
 following [^1]:
 
 ```haskell
 drawWorld :: World -> IO ()
 ...
 mapM_ (\s -> clearScreen >> drawWorld s) states
 ```
 
 i.e. I cleared the screen before drawing the new state. Unfortunately
 this caused the screen to flicker every time the world state
 updated, and I guessed (correctly) that it was because of the
 `clearScreen` taking just long enough to be noticeable. My solution
 was instead to "update" the screen:
 
 ```haskell
 drawUpdate :: (World, World) -> IO ()
 ...
 mapM_ drawUpdate $ zip states (tail states)
 ```
 
 `drawUpdate` is actually pretty dumb; it just "deletes" the snake
 in the previous world by writing a space character to every position
 the snake occupied, then draws the snake position in the new world
 by writing a `@` at every position it occupies.
 
 The result can be seen below
 
 <video src="/images/snake/basic.webm" autoplay loop></video>
 
 This is smashing, but is clearly not really a snake game yet!
 We have to add a few more ingredients to make it more like
 the game I remember from the old Nokia phones.
 
 [^1]: `mapM_` maps a function that returns an IO action (more generally,
      any monadic value), and then sequences those actions.
 
 #### Adding extra ingredients
 
 The first thing to do was to actually make it possible to lose the game.
 This involved detecting collisions between the snake and itself or with
 the boundary. After these additions I had something that looks like this:
 
 <video src="/images/snake/with-walls.webm" autoplay loop></video>
 
 The final piece of the puzzle (for now) was to add the food that could
 be eaten and would reappear in a random location. This led to the
 final iteration:
 
 <video src="/images/snake/simple-complete.webm" autoplay loop></video>
 
 This is already starting to look a lot like what I had initially envisioned!
 The next step (which I will detail in a subsequent post) is to make the
 snake move in the last direction selected every second or so. This will
 probably require a rewrite of much of the code; we'll need to have
 another "source" for direction commands, and probably different threads
 to to do the waiting.
 
 
 ### Thoughts
 
 Writing this short program was really a lot of fun. In addition, it
 taught me a bunch of stuff about writing Haskell programs! Below
 are a few points that I came to appreciate during this project.
 
 
 #### Type signatures are your documentation
 
 I was startled by how much intention could be gleaned just from the
 type signatures and sensibly naming the functions. Given that I had
 some context about the program as a whole I found that the meaning
 of most of the functions became self evident. For example, given that
 I know that the  `World` datatype contains the state of the game world,
 and `Direction` is an order to move the snake in a particular
 direction, the meaning of
 
 ```haskell
 advance :: World -> Direction -> World
 ```
 
 is obviously "advance the state of the game world in response to
 an order to move in a particular direction".
 
 I realise that my perspective on this is pretty skewed due to the short length of
 the program I was writing (you can hold the context of the whole program in
 your mind at once), but I get the impression that even with longer programs
 this concept that the type declarations *are* (for many functions) your documentation
 is quite prevalent. This is very different to Python, for example, where we are
 encouraged to document every function and detail its parameters.
 
 
 #### If your program compiles, chances are it is correct
 
 I had read this claim on several places on the web and was initially sceptical,
 but can now anecdotally confirm it to be true! I reckon this surprising property
 of Haskell is due to the fact that Haskell programs naturally need to be decomposed
 into teeny weeny functions that do literally only one thing. As far as I can tell
 this need to decompose your program into much smaller pieces than you otherwise
 would is a consequence of Haskell's purity. We can't hold any mutable state in "variables",
 and each function returns an output and does nothing else, so there's not really much
 "room" to do much else than just quickly compute a value and return it. It thus
 becomes abundantly clear when you are writing a function whether it is correct or not,
 as you often only have to verify that a few expressions are correct.
 
 Let's take the `advance` function (before we added the food) as an example.
 We want it to move the snake
 in a particular direction, unless that direction is the *opposite* direction
 to the direction in which the snake is currently moving (in which case
 `advance` should not change the state of the world). In code:
 
 ```haskell
 advance :: World -> Direction -> World
 advance w newDir
     | newDir == opposite (direction w) = w
     | otherwise = World { snake = slither (snake w) newDir
                         , direction = newDir
                         }
 ```
 
 The above code is obviously correct; if the new direction is opposite to the
 current direction, then just return the current world state, otherwise
 return a state of the world where the snake has slithered in the new direction.
 Of course we still need to verify that `opposite` and `slither` are implemented
 correctly, but because they have similarly restricted scopes it becomes just as
 easy to verify their correctness.