Info

Programmer by day, artist by night

Posts tagged Stanford University

The Animation assignment also referred to as the Breakout game is the 5th and final assignment from the CS193P course Developing iOS 8 Apps with Swift from Stanford University. Really happy to have finally finished this assignment. In my opinion this was the most complex of all the five assignments in this course.

Platform: iOS 9
Swift: 2.1

Full source code available here at the Github repository

All the 9 required tasks mentioned in page 2 of the specifications document were completed. Though device rotation is not mentioned as a requirement it does appear as a hint. I didn’t allow device rotation because it seemed to me that it would drastically affect the game play negatively.

The main challenge that I faced in completing this assignment was the nuance of using UIKit Dynamics to make a game. There were numerous issues that I was not fully clear in the beginning on how to implement them. So slowly chipped away each issue one by one before I had a clear picture of how they all fit together.

I am summarizing some of the main issues I had problems with below and how I solved them. Please see the inline documentation in the source code for all the issues and their implementation details.

  1. Creating the ball and animating it: The shape of the rectangular view of the ball as the collision boundary didn’t seem right. Though prior to iOS 9 I don’t think it was possible to do anything about it. Please see Variation on Dropit Demo from Lecture 12 on how I solved this by setting UIDynamicItemCollisionBoundsType to be an .Ellipse.
  2. Animating the paddle on pan gesture and having the ball collide. Hints are given in the assignment specifications on how to implement this, but since I hadn’t done it before it wasn’t clear what the outcome would look like.
    The solution is to add the paddle as a subview of the game view and additionally create a bezier path that acts as a collision boundary in the UIDynamicBehavior subclass. Then update that boundary repeatedly whenever the paddle moves.
    Please see the movePaddle and syncPaddleBoundary methods for details.
  3. When the paddle was moved too quickly when hitting a ball, the ball would often end up trapped inside the paddle. The way I solved this is first check if the new paddle view’s frame intersected with the balls frame using CGRectIntersectsRect. If the frames don’t intersect then update / sync the boundary.
  4. Bricks are setup similar to the paddle, where they are added to the game view and their colliding boundaries added to the UIDynamicBehavior subclass.
    The ball collides with the boundary and when a collision is detected, the brick is removed from the game view. A bricks array [String:Brick] is used to track all the bricks in the game view and match them against the NSCopying identifier from the collision delegate.
    For details please see the methods createBricks and collisionBehavior.
  5. Special bricks and what behavior they would cause were open ended in the assignment specifications. I used 4 kinds of special bricks, one kind requires 3 hits before it disappears and the other three drops special powers that cause:
    • paddles to become larger
    • paddles to become smaller
    • adds additional balls
  6. Pausing the game when user taps on Settings. This wasn’t too hard to implement, the main issue here is the moving ball(s). I used an array to capture the balls and remove them from the screen. When user came back, I re-created them and added back their linear velocity. Please see method settingsDidUpdate.
  7. Instead of putting up an alert when the game ends, a view is used (where it’s state is toggled) to show that the game is over indicating if you won or lost. This view is also used during startup. The startGame and gameOver methods show how this is done.

The following extra credit tasks were also attempted:

  • Use sophisticated Dynamic Animation. For example, you might find a creative way to use the action method in a behavior or use something like linear velocity in your calculations.
  • As mentioned above, creativity will be rewarded, especially interesting game-play settings.
  • Do some cool artistic design in your user-interface (either by drawing or using images).
  • Pausing your game when you navigate away from it (to go to settings) is a bit of a challenge (because you basically have to freeze the ball where it is, but when you come back, you have to get the ball going with the same linear velocity it had). Give it a try. It’s all about controlling the linear velocity of the ball.

Video Demo

Usually it doesn’t make much sense to repeat code from a lecture demo, but for the Dropit project I think it’s worth to post an article based on a slight variation using the new features of UIKit Dynamics available in iOS 9.

This is perhaps a good time to mention that all the CS193P assignment solutions so far created has been based on Swift 2.1 and iOS 9, whereas the Stanford U. lectures and demos are based on Swift 1.2 and iOS 8.

The motivation to create the variation was a result of attempting to implement assignment 5. Particularly the ball which is a UIView and ideally should be round, even though UIViews are obviously rectangles. The good news is that iOS 9 provides a collisionBoundsType property which can be easily overridden in UIView:

class SphereView: UIView {
    // iOS 9 specific
    override var collisionBoundsType: UIDynamicItemCollisionBoundsType {
        return .Ellipse
    }
}

This sets the bounds of the view to be an ellipse and allows the right boundary collisions
as you might expect from a ball or sphere.

dropit-spaces-between-spheres dropit-no-spaces-between-spheres

The UIFieldBehavior new in iOS 9, also seems very interesting with properties like: dragField, springField, electricField, magneticField, noiseFieldWithSmoothness and more, which opens the door to new possibilities of animation in your apps. The Dropit variation also adds the noiseFieldWithSmoothness behavior for some cool
visual effects.

dropit-spheres-in-noise-field

With debugEnabled for UIDynamicAnimator (by adding a Swift bridging header *), you can see the noise field in action as it shifts by adding random noise. To enable UIView debugging, the following code needs to be added in the bridging header file:

@import UIKit;

@interface UIDynamicAnimator (AAPLDebugInterfaceOnly)

// Used in DropitViewController.swift file:
// lazilyCreatedDynamicAnimator.debugEnabled = true
@property (nonatomic, getter=isDebugEnabled) BOOL debugEnabled;
@end

Full source code of the demo is available here at Github:
https://github.com/sanjibahmad/Variation-on-Dropit-Demo

Video Demo

For more on what’s new in UIKit Dynamics in iOS 9, please see the WWDC 2015 video: What’s New in UIKit Dynamics and Visual Effects

* Please see this article on how to add the Swift bridging header: Adding a Swift Bridging Header

This is the 4th assignment from the course Developing iOS 8 Apps with Swift, Stanford University, CS193p, Winter 2015. There is one more assignment left in this course.

Platform: iOS 9, Swift: 2.1

Full source code available here at Github repository

Smashtag is a Twitter based app that allows users to:

  • perform Twitter search queries
  • view Tweet details (including images, links, users, hashtags)
  • save 100 most recent queries in a Recent tab
  • browse Tweet images in Colllection View

All the 10 Required Tasks were completed. In addition the following Extra Credit items were implemented:

  • In the Users section of your new UITableViewController, list not only users mentioned in the Tweet, but also the user who posted the Tweet in the first place.
  • When you click on a user in the Users section, search not only for Tweets that mention that user, but also for Tweets which were posted by that user.
  • Make the “most recent searches” table be editable (i.e. let the user swipe left to delete the ones they don’t like).
  • Add some UI which displays a new view controller showing a UICollectionView of the first image (or all the images if you want) in all the Tweets that match the search. When a user clicks on an image in this UICollectionView, segue to showing them the Tweet.
  • It would be cool to have “pinching” on the UICollectionView make the cell’s size get larger and smaller (i.e. showing more or fewer images).

Video Demo

The Graphing Calculator project is a continuation of the previous 2 assignments from the Stanford University CS193P course Developing iOS 8 Apps with Swift, available for free on iTunes. This is the third and final assignment in the Calculator series.

Full source code available here at Github repository

For the other 2 projects, please see:
CalculatorBrain: Assignment 2, Stanford University Winter 2015 (iOS)
Calculator: Assignment 1, Stanford University Winter 2015 (iOS)

Graphing-Calculator_cs193p_Stanford-University

This project provides graphing features in addition to the regular calculator functions. Graphs can be plotted by entering expressions where M is the independent variable. Please see examples below.

To plot M, enter:

M, Graph

To plot sin(M), enter:

M, Sin, Graph

To plot M x cos(M), enter:

M, M, cos, x, Graph

Some interesting notes

  • The CalculatorBrain is reused to calculate the values of M for graphing
  • Plot values are set in the GraphingViewController as the data source of GraphingView
  • To fix the sluggish performance when zoomed out and panned, only the number of plots required for the screen width are calculated
  • Graph scale and origin is stored in NSUserDefaults
  • Upon device rotation, the graph is centered and adjusted slightly with the width and height change ratio

Video demo

CalculatorBrainThis project CalculatorBrain is a continuation of the previous project Calculator: Assignment 1, Stanford University Winter 2015 (iOS)

Source code available at Github

The ViewController code is now more lean and better organized since all calculation related logic has been moved to the model.

The project covers all the required tasks and most extra credit tasks.

In addition to the features listed in the previous project Calculator, this assignment provides:

  • A separate model for all calculations
  • Additional scientific functions
  • Memory functions
  • An Undo button (which previously functioned as the Backspace button)
  • Replaces the previous History function with a better implementation
  • Provides error messages

Two items were not implemented as described in the Extra Credit Hints section in the project specifications document:

  • The error messages come from the model with full error text instead of error codes for the ViewController to translate
  • Error handling is not implemented by associating any value (a function) with UnaryOperations and BinaryOperations

Video Demo:

calculator-assignment-1-stanford-university-ios-winter-2015Provides RPL (Reverse Polish Notation) calculator, where numbers are entered first then operations. For example, to add 6 and 4, you would:

6 Enter, 4 Enter, +
or 6 Enter, 4 +

This assignment solution covers all the required tasks including the ones listed under extra credit. Solution is Swift 2.0 and iOS 9.0 compatible.

Source code available at Github

Notes:

1. Overloaded the enter function for user input, because we want add to add it the history. The enter function is also called from other places in the code where we don’t want to add to history.

2. As mentioned in the assignment hints, floating point implementation was possible to add with a single-line of code:

if (digit != ".") || (digit == "." && display.text!.rangeOfString(".") == nil)

3. Pi implementation does not use the performOperation function but inline code since it’s easy to add:

case "π": displayValue = M_PI; enter()

Video Demo:

From the Course Programming Methodology CS 106A Offered at Stanford University

Having spent more hours than I am willing to admit, finally solved Karel the Robot Problem 3 (from Assignment 1).

Please don’t look at the solution until you have solved it yourself. Otherwise you will be depriving yourself of a cool mental accomplishment.

Having said that, here’s my train of thoughts as I was trying to solve the problem:

1. Thought that ignoring the checkerboard might lead to a simpler solution. Think linearly about Karel dropping beepers alternatively on each move “over a single horizontal line” till the end is reached. Later turn the horizontal line into a checkerboard. Made some progress but the solution started getting increasingly complex.

2. Realized that the core of the problem is really the turns Karel needs to make while traversing through the checkerboard. Dropping beepers at alternate locations isn’t the real problem. So I ignored the beeper issue. This lead to a cleaner solution.

3. Karel’s movement itself shouldn’t be in any if/else control statement. It makes a mess of the code because of too many if/else checks. Karel should just move forward. Then figure out which direction it should face. You can see this behavior in lines 26-29 below. Lines 31-49 shows the logic behind setting Karel’s direction.

4. Finally the beeper code is in line 17, 19. Karel moves twice in each iteration of the while loop. Line 19 checks for even-count columns in Karel’s world. Line 21 puts a last beeper for odd-count column worlds.

5. Line 15 checks for a single-count column world.

I Googled for other solutions to compare after solving the problem. Feeling happy that the solution below is 50 lines of code. If you can think of a simpler solution then please let me know.

/*
 * File: CheckerboardKarel.java
 * ----------------------------
 * When you finish writing it, the CheckerboardKarel class should draw
 * a checkerboard using beepers, as described in Assignment 1.  You
 * should make sure that your program works for all of the sample
 * worlds supplied in the starter folder.
 */

import stanford.karel.*;

public class CheckerboardKarel extends SuperKarel {

	public void run() {
		if (frontIsBlocked()) turnLeft();		
		while (frontIsClear()) {
			if (noBeepersPresent()) putBeeper();
			moveKarelForward();
			if (frontIsClear()) {
				moveKarelForward();
				if (noBeepersPresent()) putBeeper();
			}
		}
	}
	
	private void moveKarelForward() {
		move();
		setKarelsDirection();
	}
	
	private void setKarelsDirection() {
		if (facingEast()) {
			if (frontIsBlocked()) {
				turnLeft();
			}
		} else if (facingWest()) {
			if (frontIsBlocked()) {
				turnRight();
			}
		} else if (facingNorth()) {
			if (rightIsBlocked()) {
				if (leftIsClear()) {
					turnLeft();	
				}				
			} else if (leftIsBlocked()) {
				turnRight();
			}
		}
	}
}

Testing Checkerboard Karel in different worlds:

Assignment 3 (Set Card Matching Game with History) from “Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University” took a bit longer than usual to complete. The major highlights of the assignment are:

  • Set card matching in addition to the playing card game implemented in the last assignment
  • Status history access via segueing through Navigation Bar button

With an object oriented approach, it was easy to keep the logic in the CardMatchingGame model the same for both Set Card and Playing Card. Here is a list of changes since the previous assignment:

  • Allowing 2 or 3 card for Playing card game
  • Not disabling match-mode slider during gameplay, as it doesn’t make sense to click Redeal card button twice for a new match mode
    • Previous behavior:
      • Click Re-deal button
      • Choose match-mode
      • Click Re-deal button
    • Current behavior:
      • Choose match-mode
      • Click Re-deal button
  • Status moved out of the model into the ViewController
  • Removed cheat mode for debugging

Download Solution to Assignment 3: Set Card Matching Game with History

Here is the latest update to the Matchismo card game model. The polymorphism principle was applied by removing the reference to PlayingCardDeck in CardGameViewController and replacing it with a generic Deck. A sub-class PlayingCardGameViewController was created which overrode the abstract method createDeck in CardGameViewController.

Update to the Matchismo Card Game Models Based on Lecture 6 (Polymorphism principle applied)

Update to the Matchismo Card Game Models Based on Lecture 6 (Polymorphism principle applied)

Lecture 5 from “Developing iOS7 Apps for iPhone and iPad (Fall 2013) by Stanford University” explained View Controller life cycles. Here is a simple experiment to see it in action.

Notice the viewDidLoad method runs only once. Whereas viewWillAppear and viewDidAppear runs every time the view comes alive. And as the view goes away, viewWillDisappear and viewDidDisappear runs.

Even though it’s almost a child-like experiment, it’s the experience that helps reinforce learning. To experiment on your own, create an Xcode project and choose Tabbed Application from the templates. In the FirstViewController.m file, add the following code. We simply print out a log message as a view appears and disappears from screen.

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    NSLog(@"--Hello--");    
    NSLog(@"Step 1: view did load");
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSLog(@"Step 2: view will appear");
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"Step 3: view did appear");
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    NSLog(@"Step 4: view will disappear");
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    NSLog(@"Step 5: view did disappear");
    NSLog(@"--Bye--");
}

Feel free to add more sophisticated views and watch them in action 🙂