Skip to content

Instantly share code, notes, and snippets.

@LesleyLai
Last active September 3, 2020 17:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LesleyLai/4ae6229e5e1437ea385a8694cec9e285 to your computer and use it in GitHub Desktop.
Save LesleyLai/4ae6229e5e1437ea385a8694cec9e285 to your computer and use it in GitHub Desktop.
A live-coded Monte Carlo Pi Estimator in the club meeting of the CU Computer Graphics Group. Copy it to https://elm-lang.org/try if you want to try to run it.
module Main exposing (..)
import Browser
import Html exposing (Html)
import Svg exposing (..)
import Svg.Attributes exposing (..)
import Svg.Lazy
import Task
import Time
import Random
-- MAIN
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Point = (Float, Float)
type alias Model =
{ points: List Point
, inCircleCount: Int
, total: Int }
init : () -> (Model, Cmd Msg)
init _ =
( { points=[], inCircleCount=0, total=0 }
, Cmd.batch
[ Task.perform Tick Time.now
]
)
-- UPDATE
type Msg
= Tick Time.Posix
| NewPoint (Float, Float)
radius = 200.0
point : Random.Generator (Float, Float)
point =
Random.pair (Random.float -radius radius) (Random.float -radius radius)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick _ ->
(model, Random.generate NewPoint point)
NewPoint pt ->
let { points, inCircleCount, total } = model in
( { points = pt :: points
, inCircleCount = inCircleCount + (if (inCircle pt) then 1 else 0)
, total = total + 1
}
, Cmd.none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every 1 Tick
-- VIEW
inCircle : Point -> Bool
inCircle (x, y) =
x * x + y * y < radius * radius
calculatePi : Model -> Float
calculatePi { inCircleCount, total } =
toFloat inCircleCount / (toFloat total) * 4.0
view : Model -> Html Msg
view model =
Html.div [] [
(svg
[ viewBox "0 0 400 400"
, width "400"
, height "400"
]
((Svg.Lazy.lazy2 circle [ cx (String.fromFloat radius)
, cy (String.fromFloat radius)
, r (String.fromFloat radius)
, fill "#1293D8" ] [])
:: (
model.points |> List.map
(\pt ->
let fillColor = if inCircle pt then
"#00ff00" else "#ff0000" in
let (x, y) = pt in
Svg.Lazy.lazy2 circle [ cx (String.fromFloat (radius + x))
, cy (String.fromFloat (radius + y))
, r "2"
, fill fillColor ] []
)
)))
, Html.p [] [text <| String.append "PI= " (calculatePi model |> String.fromFloat)]
, Html.p [] [text <| String.append "Iteration= " (model.total |> String.fromInt)]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment