diff --git a/assign2/README.md b/assign2/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..de5faa49e60027d5cbfe7798e647931a330e4501
--- /dev/null
+++ b/assign2/README.md
@@ -0,0 +1,214 @@
+# Assignment 2: Twos
+
+## Goals
+Use the routines you implemented for assign1 in building the *Twos* game.
+Specifically, you will create an application having a model that emulates the logic of the 2048
+   app [here](https://play2048.co/) in a SwiftUI app.
+
+A brief video demonstrating the main points of the project is at the bottom of
+this page.
+
+## Creating the Project
+
+You will once again need to create a Swift project in Xcode.
+For this project, do not select "Include tests", since we will not use them.
+
+## Game Rules
+ 1. The board consists of a 4x4 grid of rectangles.
+ 2. Move the board contents Up, Down, Left, and Right, combining compatible
+    numbers into their sums.
+ 3. The game's "goal" is to achieve the highest score, and the game continues
+    as long as the player is able to keep moving.
+
+## Board Details
+First, set your simulated phone to an **iPhone 12**. This will give us a
+common platform.
+
+The elements of your view should be the following:
+ * 4 X 4 rectangular "tiles", implemented by `Text View`.
+ * A `Button` labeled 'New Game'
+ * `Button`s labeled 'Left', 'Right', 'Up', and 'Down'.
+ * A `Picker` or `Toggle`, consisting of options "Random"
+   (random), and "Determ" (deterministic). 
+ * A `Text View` where you will show the current score.
+
+The actions should be as follows:
+ * Activating the `New Game` button should cause the game to be restarted,
+   calling `newgame()` with the `rand` initializer argument (see below)
+   defined by the current state of the picker or toggle, followed by *two*
+   `spawn()`s.
+ * Activating directional arrows should cause a *collapse* towards the
+   indicated direction, followed by a spawn *if the collapse modified the
+   board*.
+ * Changing Random/Determ does not affect the current game, it only changes
+   subsequent games.
+ * A running score should be shown in the text view.
+
+
+## Model Details
+Define your model by augmenting the `Twos` model from **assign1** to
+ensure the following properties are externally visible:
+ * `var board: [[Tile]]`
+ * `var score: Int`
+
+Property `score` shows the current game score, calculated by
+incrementing your total by the resulting sum each time two identical numbers combine.
+For example, initial spawns of two '2's leaves your score at 0, but if you
+combine them in the next move that will add 4 
+points to your score. Combining two '4's into an '8' later on adds 8 
+points, etc.
+
+
+Your model should also have the following externally-visible methods:
+ * `newgame(rand: Bool)` - reinitializes all model state. The value of
+   `rand` should be derived from the Random/Deterministic segmented button.
+   Note that this method should *not* call `spawn()` (calling `newgame` just
+   initializes an empty game). Instead, the "action" for the newgame button
+   should call `newgame()`, followed by two `spawn()`s.
+ * `collapse(dir: Direction) -> Bool`, collapse the model's board in the
+   indicated direction, in place. Return `true` if movement occurred. You
+   should define Direction to be an enum consisting of "Left", "Right",
+   "Up", and "Down". Coincidentally, these are also the labels of the
+   directional buttons.
+ * `spawn()`: which randomly chooses to create a new '2' or a '4', and puts
+   it in an open tile, if there is one.  See `Randomized and Deterministic Spawning` below.
+
+Your model may have other externally visible controls and state, only
+the above is required.  All of this state should be kept in the
+`Twos` class defined in a file called `model.swift`.
+
+## Game Play
+ * Pressing `New Game` should produce a brand new game on the display, with two
+   newly-spawned tiles, each either a "2" or a "4".
+ * Pressing `Left`, `Right`, `Up`, or `Down` should cause the underlying model
+   to react as in `assign1`. The visible buttons should correspond to that
+   model, and the score should be updated.
+    * A new tile is spawned afterwards if at least one tile has moved or
+      combined with another.
+    * When your app determines that there are no more possible moves in any
+      direction it displays an alert showing the current score, with an action
+      that allows the alert to be dismissed.
+ * Pressing either `Random` or `Determ` (deterministic) controls the random
+   seed used by future new games. See below.
+
+
+## Randomized and Deterministic Spawning
+Swift has a beautiful new way of creating random values (e.g.
+`Int.random(in:... , using: ...`).  However, we are going to create our own pseudorandom generator
+for this method to make the game repeatable for debugging and testing.
+
+You need to create a new file: `Random.swift`, and copy the code below:
+```
+struct SeededGenerator: RandomNumberGenerator {
+    let seed: UInt64
+    var curr: UInt64
+    init(seed: UInt64 = 0) {
+        self.seed = seed
+        curr = seed
+    }
+    
+    mutating func next() -> UInt64  {
+        curr = (103 &+ curr) &* 65537
+        curr = (103 &+ curr) &* 65537
+        curr = (103 &+ curr) &* 65537
+        return curr
+    }
+}
+```
+
+To create a pseudorandom generator with Seed = 14, your code should be written like this:
+```
+var seededGenerator = SeededGenerator(seed: 14)
+```
+To generate a number in 1 to 16 by using this generator, your code would look like:
+```
+var newRandomNumber = Int.random(in: 1...16, using: &seededGenerator)
+```
+More generally, you can define (if you prefer)
+```
+var generator: RandomNumberGenerator = SeededGenerator(seed: 14)
+var newRandomNumber = Int.random(in: 1...16, using: &generator)
+```
+This allows you to use the same syntax with the system random number generator:
+```
+generator = SystemRandomNumberGenerator()
+```
+which will provide better randomness. We will refer to `seededGenerator`
+below, but you can use either form.
+
+
+Your app has only two randomized decisions: whether to spawn a '2' or a '4',
+and where to put the newly spawned value:
+ * '2's and '4's have equal probability. 
+ * Choose the open tile to fill by the following:
+    * number the open tiles by traversing the grid by row, and left-to-right
+      within each row. The first open tile has index `0`.
+
+For example, with:
+```
+     | 0 2 0 2 |
+     | 0 0 4 8 |
+     | 2 2 4 8 |
+     | 4 2 0 4 |
+```
+conceptually number the open spots:
+```
+     | 0   1  |
+     | 2 3    |
+     |        |
+     |     4  |
+
+```
+Choose among them by randomly selecting an index from 0 to 4. You can do this by
+running `index = Int.random(in: 0...4, using: &seededGenerator)`. 
+
+Use the randomGenerator to make both random choices. We want your deterministic
+mode to exactly match ours, **so use the following ordering**:
+ * Use `seededGenerator` to decide the value of the new tile.
+ * Use `seededGenerator` to decide where to place the new tile.
+ 
+This ordering is important; otherwise your random decisions may not match ours. 
+ 
+For this assignment, you should:
+ * Reinitialize seededGenerator each time starting a new game
+ * Use either a random seed in 1 to 1000 if your game mode is `random` or the system
+   random number generator. You can use a random seed by running:
+   `seededGenerator = SeededGenerator(seed: UInt64(Int.random(in:1...1000)))`
+ * **Important** Use seed = 14 if your game mode is `determ`
+
+
+
+### Grading / Testing
+Our grading will not be automated.
+
+We will award points as follows:
+
+ * (10 pts) Display is layed out with correct controls.
+ * (5 pts) Click new game (in random mode) multiple times and see different
+   initial conditions, all with 2 buttons displayed, each either a '2' or a '4'
+ * (10 pts) Gameplay is correct, numbers move as expected, combine as expected.
+ * (5 pts) Scores are correct. This can be checked even without determinism,
+   but in deterministic mode:
+    * Click "New Game". Should have a score of 0.
+    * Click "new game, right, right, up, up, right, right" should give a score of 36.
+ * (10 pts) Determinism works:
+    * in deterministic mode a new game reproduces the sequences shown above, i.e.:
+       1. Click "new game, right, right, up, up, right, right" results in a
+          score of 36, and tiles 16, 2, 4, and 4.
+       2. See demo video for details.
+       
+ * (10 pts) Overall look and feel. It's an app! Your app should be well layed
+   out, clear, and attractive. We are not grading how closely it looks to
+   the one shown in the video, though different values should have distinct
+   colors, at least through 128.
+
+Notes:
+ * Your game should look relatively close to the provided video in coloration
+   and layout.
+ * You do not need to worry about orientation changes.
+ * We are not looking at your code other than to scan for plagiarism.
+ * We do not care if you implement the "tiles" by changing the appearance
+   of 16 static views (easiest), or if you use fewer buttons and move
+   them about.
+
+[![Watch the video](assign2.png)](assign2.mp4)
diff --git a/assign2/assign2.mp4 b/assign2/assign2.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..222d870c271a3b100dae9b451a914e52e6de971f
Binary files /dev/null and b/assign2/assign2.mp4 differ
diff --git a/assign2/assign2.png b/assign2/assign2.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e6e207c8f3fc58253cd7302c9d18052ffabd78a
Binary files /dev/null and b/assign2/assign2.png differ