Homework 2 (80 points)

Download the skeleton file Pi.elm and use it as a starting point for the following problems. Look for all Debug.todos, which point out where you should implement your solutions. Once you are done, follow the submission instructions below. Note that you will need to install a couple packages:

% elm install elm/random
% elm install elm/time

Problem 1: Estimating Pi

In this problem, you will write a program that estimates the value of π. You will also get practice with the basics of programming web applications in Elm by implementing a simple animation — using the Time, Random, and 2D graphics libraries — to accompany the estimation process.

The idea behind estimating π for this problem is simple: throw darts randomly at the unit square and keep track of how many fall within the circle that is centered in the square. According to the areas of circles and squares, the fraction of points within the circle is an estimate of π / 4.

The application will be organized in a familiar way:

main = 
  Browser.element
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

2.1.1 -- The "Model" (5 points)

First, we define the following type alias to describe points:

type alias Point = { x:Float, y:Float }

Next, we define the model to keep track of the state the simulation at any given point:

type alias Model =
  { hits : List Point
  , misses : List Point
  , hitCount : Int
  , missCount : Int
  }

The first two components of Model record which points "hit" inside the unit circle, and which points "missed." We maintain two integer counters for the lengths of these lists, to avoid recomputation.

Define the initial configuration:

init : Flags -> (Model, Cmd Msg)

2.1.2 -- The "Controller" (45 points)

The application will track two kinds of a messages: Tick events that trigger the generation of a random Point, and RandomPoint events when a new random point has been generated.

type Msg = Tick | RandomPoint Point

Using the Time library or Browser.Events library, implement subscriptions to trigger a Tick every so often. Exactly how long (for example, every 100 milliseconds or every 1 second) is up to you.

subscriptions : Model -> Sub Msg

Use Random.generate (not Random.seed) to generate new points. Your solution should define and use the following Random.Generator of Points. Notice how Random provides primitive Generators for base types, which can be used to construct Generators for more complex types, such as Point.

pointGenerator : Generator Point

Finally, implement the update function; every time a new Point is generated, the new Model should reflect whether the Point is a hit or miss.

update : Msg -> Model -> (Model, Cmd Msg)

2.1.3 -- The "View" (30 points)

The last component is to render the current state of the simulation to the screen. For this, implement the function:

view : Model -> Html Msg

Although the particular details are largely up to you, your rendering should:

  1. draw dots for each randomly generated point, using different colors to distinguish hits and misses; and
  2. display the current estimate of π based on these points.

You have (at least) two options for drawing 2D graphics:

  1. The timjs/elm-collage package exposes several modules, including:

    • Collage for defining freeform graphics, comprising shapes, lines, colors, etc (e.g. see circle, filled, group, etc.);
    • Collage.Text for styling text; and
    • Collage.Render for building HTML.

    If you choose this route, then run:

    % elm install timjs/elm-collage
    % elm install avh4/elm-color
  2. Alternatively, you can use the elm/svg package to create SVG graphics with CSS (e.g. see svg and circle).

    If you choose this route, then run:

    % elm install elm/svg

The choice is up to you. With either approach, you may find it useful to define helper functions, such as the following, for the two subtasks above:

pointsToCircles : Color -> List Point -> List Shape  -- if using timjs/elm-collage
pointsToCircles : String -> List Point -> List Svg   -- if using elm/svg

estimatePi : Model -> Float

For reference, here's a sample. Be creative!

2.1.4 (10 extra credit points based on voting)

You will receive full points for the parts above as long as everything is working, no matter how pretty (or ugly) the results are. These last few remaining points are reserved for solutions that are particularly pleasing.

To help get the creative juices flowing, here are some possible ideas for making the animation prettier:

  • Make more recent dots darker than older ones
  • Make the dartboard more colorful
  • Have π appear in the background of the dartboard
  • Use a different shape for the dartboard
  • Vary the size of the board and dots based on window size
  • Use Vega/Vega-Lite to visualize the accuracy of the estimate over time

In the coming weeks, we will generate a poll based on everyone's solutions to this problem. You may receive points for this problem based on the results of the voting. More details to follow.


Grading and Submission Instructions

Submit the following three files:

  • The file Pi.elm updated with your changes. You are free to modify these files as you wish, as long as you do not change any type signatures that are provided.

  • Your elm.json file, which specifies the library dependencies for your solution.

  • A 200-by-200 pixel thumbnail image of your animation called ThumbPi.EXT, where EXT is a standard image format such as png, jpg, or gif. This thumbnail will be used to help generate a gallery on the forthcoming voting page, where each thumbnail will link to the corresponding animation. So you will want to choose an accurate and compelling preview of your animation to entice people to view it.

Your solution will be graded using a combination of automated grading scripts and manual review. It is a good idea for you to design some test cases of your own to exercise more sample behaviors than just the ones provided in the writeup. We also reserve the right to take into account the organization and style of your code when assigning grades.

If you are not able to finish all parts of the assignment, make sure that all of your submitted files compile successfully. If not, you risk getting zero points for the assignment. In particular, for each file Foo.elm, make sure that it can be loaded into the Elm REPL

% elm repl
> import Foo
>

and that it can be compiled:

% elm make Foo.elm
Success! Compiled 1 module.

Submitting Your Code

We will use the cs223-win-21 Subversion repository on PhoenixForge. You should have done this by now.

Start by navigating to the folder where you checked out your repo. Next, create a subfolder for this assignment and populate it with the skeleton code:

% cd USER-cs223-win-21
% svn mkdir hw2
% cd hw2
% wget http://www.classes.cs.uchicago.edu/archive/2020/spring/22300-1/assignments/hw2/Pi.elm

If wget or a similar tool (such as curl) is not available on your machine, download and save the skeleton files provided above in some other way. Then add only these files to your repo:

% svn add Pi.elm
% svn add elm.json
% svn add ThumbPi.EXT

Make sure you choose the same exact names for directories and files that you create (except that EXT should be replaced with the actual file extension).

So, after you run elm init to create an elm.json file, change "source-directories" in elm.json to be ["."]. This way, you can compile and run your files (through elm repl and elm make) without putting them in the src/ subdirectory (which you can rmdir).

Once you are ready to submit:

% svn commit -m "hw2 submission"

You can resubmit as many times as you wish, and we will grade the most recent versions submitted. Late days, if any, will be computed based on your submission times.

As a sanity check, you can visit the Web-based frontend for your repository to make sure that you have submitted your files as intended:

https://phoenixforge.cs.uchicago.edu/projects/USER-cs223-win-21/repository