Skip to content

Instantly share code, notes, and snippets.

@ggb
Last active May 18, 2016 19:30
Show Gist options
  • Select an option

  • Save ggb/edcda03567f9e6700d39 to your computer and use it in GitHub Desktop.

Select an option

Save ggb/edcda03567f9e6700d39 to your computer and use it in GitHub Desktop.

Revisions

  1. ggb revised this gist May 18, 2016. 3 changed files with 116 additions and 53 deletions.
    3 changes: 3 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    elm-stuff/
    *.html
    *.js
    147 changes: 94 additions & 53 deletions LunarLander.elm
    Original file line number Diff line number Diff line change
    @@ -1,36 +1,70 @@
    module LunarLander where
    module LunarLander exposing (..)

    import Text
    import Window
    import Keyboard
    import Color exposing (black, darkGrey, white)
    import Graphics.Element exposing (Element, image)
    import Graphics.Collage exposing (Form, collage, move, rect, filled, toForm, text)
    import Time exposing (fps)
    import Window exposing (Size, resizes)
    import Keyboard exposing (KeyCode, downs, ups)
    import Html.App as App
    import Color exposing (black, lightGrey, white)
    import Element exposing (Element, image, toHtml)
    import Collage exposing (Form, collage, move, rect, filled, toForm, text)
    import AnimationFrame exposing (times)
    import Time exposing (Time, every)


    subscriptions : Lander -> Sub Msg
    subscriptions model =
    Sub.batch
    [ downs Keydown
    , ups Keyup
    , times Frame
    , resizes Resize
    ]


    main : Program Never
    main =
    App.program
    { init = (lander, Cmd.none)
    , view = draw >> toHtml
    , update = updateLander
    , subscriptions = subscriptions
    }


    {-
    MODEL
    -}
    type Msg
    = Frame Time
    | Keydown KeyCode
    | Keyup KeyCode
    | Resize Size


    type Status
    = Ready
    | Thrust
    | Landed
    | Crashed

    type Status = Ready | Thrust | Landed | Crashed

    type alias Lander =
    { position: Float
    , velocity: Float
    , fuel: Float
    , status: Status
    , width: Int
    , height: Int
    }


    lander : Lander
    lander = { position=500.0, fuel=30, velocity=1, status=Ready}
    lander = { position=500.0, fuel=30, velocity=1, status=Ready, width=800, height=600}


    {-
    VIEW
    -}

    createText : String -> a -> Form
    createText pre val =
    toString val
    @@ -50,58 +84,65 @@ drawLander status =
    Landed -> image 30 30 "lander_landed.png"


    draw : Lander -> (Int, Int) -> Element
    draw currentLander (width, height) =
    let w' = toFloat width
    h' = toFloat height
    draw : Lander -> Element
    draw {width, height, status, position, fuel, velocity} =
    let
    w' = toFloat width
    h' = toFloat height
    in
    collage width height
    [ move (0, h' / 4) (filled black (rect w' (h' / 2)))
    , move (0, -h' / 4) (filled darkGrey (rect w' (h' / 2)))
    , move (0, currentLander.position) (toForm <| drawLander currentLander.status)
    , move (w'/2 - 65, h'/2 - 30) (createText "Fuel: " currentLander.fuel)
    , move (w'/2 - 70, h'/2 - 50) (createText "Velocity: " (truncate currentLander.velocity))
    , move (w'/2 - 60, h'/2 - 70) (createText "System: " currentLander.status) ]
    , move (0, -h' / 4) (filled lightGrey (rect w' (h' / 2)))
    , move (0, position) (drawLander status |> toForm)
    , move (w'/2 - 65, h'/2 - 30) (createText "Fuel: " fuel)
    , move (w'/2 - 70, h'/2 - 50) (createText "Velocity: " (truncate velocity))
    , move (w'/2 - 60, h'/2 - 70) (createText "System: " status) ]


    {-
    UPDATE / CONTROL
    -}

    calculateVelocity : (Float, { a | y:number }) -> Lander -> Lander
    calculateVelocity (val, arrow) acc =
    if acc.position < 0.0 && acc.velocity <= 3
    then { acc | status = Landed }
    else if acc.position < 0.0
    then { acc | status = Crashed }
    else if arrow.y == 1 && acc.fuel > 0
    then { acc | velocity = acc.velocity - 1
    , fuel = acc.fuel - 1
    calculateVelocity : (Float, Maybe Int) -> Lander -> Lander
    calculateVelocity (val, arrow) lander =
    let
    {position, velocity, fuel} = lander
    in
    if position < 0.0 && velocity <= 3 then
    { lander | status = Landed }
    else if position < 0.0 then
    { lander | status = Crashed }
    else if arrow == Just 38 && fuel > 0 then
    { lander | velocity = velocity - 1
    , fuel = fuel - 1
    , status = Thrust }
    else { acc | velocity = acc.velocity + val / 200
    , status = Ready }
    else
    { lander | velocity = velocity + val / 200 }


    calculatePosition : Lander -> Lander
    calculatePosition currentLander =
    case currentLander.status of
    Ready -> { currentLander | position = currentLander.position - currentLander.velocity }
    _ -> currentLander


    updateLander : (Float, { a | y:number }) -> Lander -> Lander
    updateLander ele acc =
    calculateVelocity ele acc |> calculatePosition


    update : Signal Lander
    update =
    Signal.foldp updateLander lander
    (Signal.map2 (,)
    (fps 30)
    Keyboard.arrows)


    main : Signal Element
    main =
    Signal.map2 draw update Window.dimensions
    calculatePosition lander =
    case lander.status of
    Ready ->
    { lander | position = lander.position - lander.velocity }
    _ ->
    lander


    updateLander : Msg -> Lander -> (Lander, Cmd Msg)
    updateLander msg lander =
    let
    updatePosition val lander =
    (calculateVelocity (7, val) lander
    |> calculatePosition, Cmd.none)
    in
    case msg of
    Frame _ ->
    updatePosition Nothing lander
    Keydown val ->
    updatePosition (Just val) lander
    Keyup val ->
    { lander | status = Ready }
    |> updatePosition Nothing
    Resize {width, height} ->
    { lander | width = width, height = height }
    |> updatePosition Nothing
    19 changes: 19 additions & 0 deletions elm-package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    {
    "version": "1.0.0",
    "summary": "helpful summary of your project, less than 80 characters",
    "repository": "https://github.com/user/project.git",
    "license": "BSD3",
    "source-directories": [
    "."
    ],
    "exposed-modules": [],
    "dependencies": {
    "elm-lang/animation-frame": "1.0.0 <= v < 2.0.0",
    "elm-lang/core": "4.0.0 <= v < 5.0.0",
    "elm-lang/html": "1.0.0 <= v < 2.0.0",
    "elm-lang/keyboard": "1.0.0 <= v < 2.0.0",
    "elm-lang/window": "1.0.0 <= v < 2.0.0",
    "evancz/elm-graphics": "1.0.0 <= v < 2.0.0"
    },
    "elm-version": "0.17.0 <= v < 0.18.0"
    }
  2. Gregor revised this gist Dec 17, 2015. 1 changed file with 45 additions and 33 deletions.
    78 changes: 45 additions & 33 deletions LunarLander.elm
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,10 @@ import Graphics.Collage exposing (Form, collage, move, rect, filled, toForm, tex
    import Time exposing (fps)


    {-
    MODEL
    -}

    type Status = Ready | Thrust | Landed | Crashed

    type alias Lander =
    @@ -23,39 +27,9 @@ lander : Lander
    lander = { position=500.0, fuel=30, velocity=1, status=Ready}


    calculateVelocity : (Float, { a | y:number }) -> Lander -> Lander
    calculateVelocity (val, arrow) acc =
    if acc.position < 0.0 && acc.velocity <= 3
    then { acc | status = Landed }
    else if acc.position < 0.0
    then { acc | status = Crashed }
    else if arrow.y == 1 && acc.fuel > 0
    then { acc | velocity = acc.velocity - 1
    , fuel = acc.fuel - 1
    , status = Thrust }
    else { acc | velocity = acc.velocity + val / 200
    , status = Ready }


    calculatePosition : Lander -> Lander
    calculatePosition currentLander =
    case currentLander.status of
    Ready -> { currentLander | position = currentLander.position - currentLander.velocity }
    _ -> currentLander


    updateLander : (Float, { a | y:number }) -> Lander -> Lander
    updateLander ele acc =
    calculateVelocity ele acc |> calculatePosition


    update : Signal Lander
    update =
    Signal.foldp updateLander lander
    (Signal.map2 (,)
    (fps 30)
    Keyboard.arrows)

    {-
    VIEW
    -}

    createText : String -> a -> Form
    createText pre val =
    @@ -90,6 +64,44 @@ draw currentLander (width, height) =
    , move (w'/2 - 60, h'/2 - 70) (createText "System: " currentLander.status) ]


    {-
    UPDATE / CONTROL
    -}

    calculateVelocity : (Float, { a | y:number }) -> Lander -> Lander
    calculateVelocity (val, arrow) acc =
    if acc.position < 0.0 && acc.velocity <= 3
    then { acc | status = Landed }
    else if acc.position < 0.0
    then { acc | status = Crashed }
    else if arrow.y == 1 && acc.fuel > 0
    then { acc | velocity = acc.velocity - 1
    , fuel = acc.fuel - 1
    , status = Thrust }
    else { acc | velocity = acc.velocity + val / 200
    , status = Ready }


    calculatePosition : Lander -> Lander
    calculatePosition currentLander =
    case currentLander.status of
    Ready -> { currentLander | position = currentLander.position - currentLander.velocity }
    _ -> currentLander


    updateLander : (Float, { a | y:number }) -> Lander -> Lander
    updateLander ele acc =
    calculateVelocity ele acc |> calculatePosition


    update : Signal Lander
    update =
    Signal.foldp updateLander lander
    (Signal.map2 (,)
    (fps 30)
    Keyboard.arrows)


    main : Signal Element
    main =
    Signal.map2 draw update Window.dimensions
  3. Gregor revised this gist Dec 17, 2015. 1 changed file with 57 additions and 19 deletions.
    76 changes: 57 additions & 19 deletions LunarLander.elm
    Original file line number Diff line number Diff line change
    @@ -3,55 +3,93 @@ module LunarLander where
    import Text
    import Window
    import Keyboard
    import Color exposing (..)
    import Graphics.Element exposing (..)
    import Graphics.Collage exposing (..)
    import Color exposing (black, darkGrey, white)
    import Graphics.Element exposing (Element, image)
    import Graphics.Collage exposing (Form, collage, move, rect, filled, toForm, text)
    import Time exposing (fps)


    type Status = Ready | Thrust | Landed | Crashed

    type alias Lander =
    { position: Float
    , velocity: Float
    , fuel: Float
    , status: Status
    }


    lander : Lander
    lander = { position=500.0, fuel=30, velocity=1, status=Ready}


    calculateVelocity : (Float, { a | y:number }) -> Lander -> Lander
    calculateVelocity (val, arrow) acc =
    if | acc.position < 0.0 && acc.velocity <= 3 -> { acc | status <- Landed }
    | acc.position < 0.0 -> { acc | status <- Crashed }
    | arrow.y == 1 && acc.fuel > 0 -> { acc | velocity <- acc.velocity - 1
    , fuel <- acc.fuel - 1
    , status <- Thrust }
    | otherwise -> { acc | velocity <- acc.velocity + val / 200
    , status <- Ready }
    if acc.position < 0.0 && acc.velocity <= 3
    then { acc | status = Landed }
    else if acc.position < 0.0
    then { acc | status = Crashed }
    else if arrow.y == 1 && acc.fuel > 0
    then { acc | velocity = acc.velocity - 1
    , fuel = acc.fuel - 1
    , status = Thrust }
    else { acc | velocity = acc.velocity + val / 200
    , status = Ready }


    calculatePosition : Lander -> Lander
    calculatePosition currentLander =
    case currentLander.status of
    Ready -> { currentLander | position <- currentLander.position - currentLander.velocity }
    Ready -> { currentLander | position = currentLander.position - currentLander.velocity }
    _ -> currentLander

    updateLander ele acc = calculateVelocity ele acc |> calculatePosition

    update = Signal.foldp updateLander lander <| Signal.map2 (,) (fps 30) Keyboard.arrows
    updateLander : (Float, { a | y:number }) -> Lander -> Lander
    updateLander ele acc =
    calculateVelocity ele acc |> calculatePosition

    createText pre val = text
    <| Text.color white
    <| Text.monospace
    <| Text.append (Text.fromString pre) (Text.fromString <| toString val)

    update : Signal Lander
    update =
    Signal.foldp updateLander lander
    (Signal.map2 (,)
    (fps 30)
    Keyboard.arrows)


    createText : String -> a -> Form
    createText pre val =
    toString val
    |> Text.fromString
    |> Text.append (Text.fromString pre)
    |> Text.monospace
    |> Text.color white
    |> text


    drawLander : Status -> Element
    drawLander status =
    case status of
    Ready -> image 30 30 "lander_ready.png"
    Thrust -> image 30 30 "lander_thrust.png"
    Crashed -> image 30 30 "lander_crashed.png"
    Landed -> image 30 30 "lander_landed.png"


    draw : Lander -> (Int, Int) -> Element
    draw currentLander (width, height) =
    let w' = toFloat width
    h' = toFloat height
    in
    collage width height
    [ move (0, h' / 4) (filled black (rect w' (h' / 2)))
    [ move (0, h' / 4) (filled black (rect w' (h' / 2)))
    , move (0, -h' / 4) (filled darkGrey (rect w' (h' / 2)))
    , move (0, currentLander.position) (toForm <| drawLander currentLander.status)
    , move (w'/2 - 65, h'/2 - 30) (createText "Fuel: " currentLander.fuel)
    , move (w'/2 - 70, h'/2 - 50) (createText "Velocity: " (truncate currentLander.velocity))
    , move (w'/2 - 60, h'/2 - 70) (createText "System: " currentLander.status) ]


    main : Signal Element
    main = Signal.map2 draw update Window.dimensions
    main =
    Signal.map2 draw update Window.dimensions
  4. Gregor revised this gist May 16, 2015. No changes.
  5. ggb revised this gist Apr 28, 2015. 4 changed files with 0 additions and 0 deletions.
    Binary file added lander_crashed.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added lander_landed.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added lander_ready.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
    Binary file added lander_thrust.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  6. ggb renamed this gist Apr 28, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  7. ggb created this gist Apr 28, 2015.
    57 changes: 57 additions & 0 deletions LunarLander
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    module LunarLander where

    import Text
    import Window
    import Keyboard
    import Color exposing (..)
    import Graphics.Element exposing (..)
    import Graphics.Collage exposing (..)
    import Time exposing (fps)

    type Status = Ready | Thrust | Landed | Crashed
    lander = { position=500.0, fuel=30, velocity=1, status=Ready}

    calculateVelocity (val, arrow) acc =
    if | acc.position < 0.0 && acc.velocity <= 3 -> { acc | status <- Landed }
    | acc.position < 0.0 -> { acc | status <- Crashed }
    | arrow.y == 1 && acc.fuel > 0 -> { acc | velocity <- acc.velocity - 1
    , fuel <- acc.fuel - 1
    , status <- Thrust }
    | otherwise -> { acc | velocity <- acc.velocity + val / 200
    , status <- Ready }

    calculatePosition currentLander =
    case currentLander.status of
    Ready -> { currentLander | position <- currentLander.position - currentLander.velocity }
    _ -> currentLander

    updateLander ele acc = calculateVelocity ele acc |> calculatePosition

    update = Signal.foldp updateLander lander <| Signal.map2 (,) (fps 30) Keyboard.arrows

    createText pre val = text
    <| Text.color white
    <| Text.monospace
    <| Text.append (Text.fromString pre) (Text.fromString <| toString val)

    drawLander status =
    case status of
    Ready -> image 30 30 "lander_ready.png"
    Thrust -> image 30 30 "lander_thrust.png"
    Crashed -> image 30 30 "lander_crashed.png"
    Landed -> image 30 30 "lander_landed.png"

    draw currentLander (width, height) =
    let w' = toFloat width
    h' = toFloat height
    in
    collage width height
    [ move (0, h' / 4) (filled black (rect w' (h' / 2)))
    , move (0, -h' / 4) (filled darkGrey (rect w' (h' / 2)))
    , move (0, currentLander.position) (toForm <| drawLander currentLander.status)
    , move (w'/2 - 65, h'/2 - 30) (createText "Fuel: " currentLander.fuel)
    , move (w'/2 - 70, h'/2 - 50) (createText "Velocity: " (truncate currentLander.velocity))
    , move (w'/2 - 60, h'/2 - 70) (createText "System: " currentLander.status) ]

    main : Signal Element
    main = Signal.map2 draw update Window.dimensions