Skip to content

Instantly share code, notes, and snippets.

@amazari
Created November 13, 2013 22:18
Show Gist options
  • Save amazari/7457521 to your computer and use it in GitHub Desktop.
Save amazari/7457521 to your computer and use it in GitHub Desktop.
module GameSkeleton where
import Window
import Keyboard
import Random
{-- Part 1: Model the user input ----------------------------------------------
What information do you need to represent all relevant user input?
Task: Redefine `UserInput` to include all of the information you need.
Redefine `userInput` to be a signal that correctly models the user
input as described by `UserInput`.
------------------------------------------------------------------------------}
type UserInput = (Int, Int)
data Input = Input Float (Int, Int) (Int, Int)
direction = foldp (\{x,y} -> \(prevX, prevY) -> let norm = sqrt <| x^2 + y^2
in if norm == sqrt 1
then (x,-y)
else (prevX,prevY)) (1,0) Keyboard.arrows
{-- Part 2: Model the game ----------------------------------------------------
What information do you need to represent the entire game?
Tasks: Redefine `GameState` to represent your particular game.
Redefine `defaultGame` to represent your initial game state.
For example, if you want to represent many objects that just have a position,
your GameState might just be a list of coordinates and your default game might
be an empty list (no objects at the start):
type GameState = { objects : [(Float,Float)] }
defaultGame = { objects = [] }
------------------------------------------------------------------------------}
{--type SnakeSlice = (Int,Int)
type BoardSize = (Int,Int) --}
type GameState = {snakeSlices:[(Int,Int)], boardSize:(Int,Int), apple:(Int,Int)}
defaultGame : GameState
defaultGame = {snakeSlices = [(0, 0),(1, 0), (1, 1)],
boardSize = (8, 8),
apple = (4, 5)
}
{-- Part 3: Update the game ---------------------------------------------------
How does the game step from one state to another based on user input?
Task: redefine `stepGame` to use the UserInput and GameState
you defined in parts 1 and 2. Maybe use some helper functions
to break up the work, stepping smaller parts of the game.
------------------------------------------------------------------------------}
collidesWith (x1, y1) (x2, y2) = x1 == x2 && y1 == y2
tileAhead (hX, hY) (dirX, dirY) (bW, bH) = ((hX + dirX) `mod` bW, (hY + dirY) `mod` bH)
randomAppleX = Random.range 0 7 direction
randomAppleY = Random.range 0 7 direction
randomApple = lift2 (\x -> \y -> (x, y)) randomAppleX randomAppleY
stepGame : Input -> GameState -> GameState
stepGame (Input delta dir randomApple) {snakeSlices,boardSize,apple} =
let
(hX ,hY) = head snakeSlices
newHead = tileAhead (hX, hY) dir boardSize
ateApple = newHead `collidesWith` apple
-- any (\(x, y) -> x ==)snakeSlices
fedHead = if ateApple then [tileAhead newHead dir boardSize] else []
in
{snakeSlices = fedHead ++ newHead :: take ((length snakeSlices) - 1) snakeSlices
,boardSize = boardSize
,apple = if ateApple then randomApple else apple
}
{-- Part 4: Display the game --------------------------------------------------
How should the GameState be displayed to the user?
Task: redefine `display` to use the GameState you defined in part 2.
------------------------------------------------------------------------------}
tileSize = 25
translatedPos: (Int,Int) -> (Float, Float) -> (Float, Float)
translatedPos (tileX,tileY) (oX, oY) = (toFloat tileX * tileSize + oX, (toFloat -tileY) * tileSize + oY)
tile: Color -> (Int,Int) -> (Float, Float) -> Form
tile color tilePos origin =
square (toFloat tileSize)
|> filled color
|> (move <| translatedPos tilePos origin)
display : (Int,Int) -> GameState -> Element
display (w,h) {snakeSlices,boardSize,apple} =
let (bw,bh) = boardSize
(realW, realH) = (bw*tileSize, bh*tileSize)
origin = (-((toFloat realW) - tileSize) / 2, (((toFloat realH) - tileSize)) / 2)
snakeTiles = map (\t -> tile red t origin) snakeSlices
boardRep = rect (toFloat realW) (toFloat realH) |> filled green
appleTile = tile yellow apple origin
in container w h middle <| collage realW realH <| boardRep :: appleTile :: snakeTiles
{-- That's all folks! ---------------------------------------------------------
The following code puts it all together and shows it on screen.
------------------------------------------------------------------------------}
delta = fps 10
input = sampleOn delta (lift3 Input delta direction randomApple)
gameState = foldp stepGame defaultGame input
main = lift2 display Window.dimensions gameState
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment