Last active
September 3, 2020 17:53
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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