cs193p – Assignment #1 Task #3

Add some more operations buttons to your calculator such that it has at least a dozen operations total (it can have even more if you like). You can choose whatever operations appeal to you. The buttons must arrange themselves nicely in portrait and landscape modes on all iPhone 6’s and 7’s.

Start adding the new operations to the brain model:

    private let operations: Dictionary<String,Operation> = [
        ...        
        "x²" : Operation.unaryOperation({ pow($0, 2) }),
        "x³" : Operation.unaryOperation({ pow($0, 3) }),
        "x⁻¹" : Operation.unaryOperation({ 1 / $0 }),
        "sin" : Operation.unaryOperation(sin),
        "tan" : Operation.unaryOperation(tan),
        "sinh" : Operation.unaryOperation(sinh),
        "cosh" : Operation.unaryOperation(cosh),
        "tanh" : Operation.unaryOperation(tanh),
        "ln" : Operation.unaryOperation(log),
        "log" : Operation.unaryOperation(log10),
        "eˣ" : Operation.unaryOperation(exp),
        "10ˣ" : Operation.unaryOperation({ pow(10, $0) }),
        "x!" : Operation.unaryOperation(factorial),
        "xʸ" : Operation.binaryOperation(pow),
        ]

Most of them are straight forward, only the factorial is not available as native function. The following implementation works really only for integer values, for non-integers you might want to implement a solution using gamma functions:

func factorial(_ op1: Double) -> Double {
    if (op1 <= 1.0) {
        return 1.0
    }
    return op1 * factorial(op1 - 1.0)
}

Adjusting different layouts for portrait and landscape using “installed” in story board for different size classes, would be nice … but still does not work for stacks. Just add the buttons:
cs193p-assignment-1-task-3-storyboard

And tag the buttons you want to show only in landscape mode with “1”, the ones you want to show only in portrait mode with “2” and leave the other ones untagged (with “0”).

A helper function hides and shoes them in the different modes, iterating recursively over the available views:

    private func adjustButtonLayout(for view: UIView, isPortrait: Bool) {
        for subview in view.subviews {
            if subview.tag == 1 {
                subview.isHidden = isPortrait
            } else if subview.tag == 2 {
                subview.isHidden = !isPortrait
            }
            if let stack = subview as? UIStackView {
                adjustButtonLayout(for: stack, isPortrait: isPortrait);
            }
        }
    }

The helper function needs to be called twice – at the beginning, and when the dimensions change:

    override func viewDidLoad() {
        super.viewDidLoad()
        adjustButtonLayout(for: view, isPortrait: traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular)
    }
    
    override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
        super.willTransition(to: newCollection, with: coordinator)
        adjustButtonLayout(for: view, isPortrait: newCollection.horizontalSizeClass == .compact && newCollection.verticalSizeClass == .regular)
    }

The complete code for the #3 is available on GitHub.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

cs193p – Assignment #1 Task #2

Your Calculator already works with floating point numbers (e.g. if you touch 3 ÷ 4 =, it will properly show 0.75), however, there is no way for the user to enter a floating point number directly. Fix this by allowing legal floating point numbers to be entered (e.g. “192.168.0.1” is not a legal floating point number!). You will need to have a “.” button in your calculator. Don’t worry too much about precision or significant digits in this assignment (doing so is Extra Credit).

… the button has already been added during the lecture. Because it has been copied from a digit button it points already to touchDigit. When the user is in the middle of typing, only add the digit if it is not a “.”, or if there is not already one on the display. For new new numbers, add a leading zero if necessary:

    @IBAction func touchDigit(_ sender: UIButton) {
        ...
        if userIsInTheMiddleOfTyping {
            ...
            if "." != digit || !textCurrentlyInDisplay.contains(".") {
                display.text = textCurrentlyInDisplay + digit
            }
        } else {
            display.text = "." == digit ? "0." : digit
            ...
        }        
    }

As requested in the hints we added only a single line, and adjusted another one.

The complete code for the #2 is available on GitHub.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

cs193p – Assignment #1 Extra Task #4

Please note, this blog entry is from a previous course. You might want to check out the current one.

Make one of your operation buttons be “generate a random number between 0 and 1”. This operation button is not a constant (since it changes each time you invoke it). Nor is it a unary operation (since it does not operate on anything).

In the interface builder change the name of a button to “rand”:

Storyboard calculator adding random function
Storyboard calculator adding random function

Add an operation without operands to the the calculator model:

private enum Operation {
  ...
  case NullaryOperation(() -> Double, String)
  ...
}

Continue reading “cs193p – Assignment #1 Extra Task #4”

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

cs193p – Assignment #1 Extra Task #3

Please note, this blog entry is from a previous course. You might want to check out the current one.

Figure out from the documentation how to use the NSNumberFormatter class to format your display so that it only shows 6 digits after the decimal point (instead of showing all digits that can be represented in a Double). This will eliminate the need for Autoshrink in your display. While you’re at it, make it so that numbers that are integers don’t have an unnecessary “.0” attached to them (e.g. show “4” rather than “4.0” as the result of the square root of sixteen). You can do all this for your description in the CalculatorBrain as well.

NSNumberFormatter uses country-specific number formats. Meaning if your country uses a comma instead of a dot as decimal separator – and your device is set accordingy – the number format will use that specific format. Up to now we only used a dot as decimal separator. We could continue to do that by forcing the number format e.g. by telling it we are always using the US format, or we just deal with it.

Let’s teal with it, starting by changing the the title of the comma button accordingly. First change the tag of it to “3”, than update its title:

private let decimalSeparator = NSNumberFormatter().decimalSeparator!

private func adjustButtonLayout(view: UIView, portrait: Bool) {
      ...
      if button.tag == 3 {
        button.setTitle(decimalSeparator, forState: .Normal)
      }
      ...
}

Continue reading “cs193p – Assignment #1 Extra Task #3”

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

cs193p – Assignment #1 Extra Task #2

Please note, this blog entry is from a previous course. You might want to check out the current one.

Change the computed instance variable displayValue to be an Optional Double rather than a Double. Its value should be nil if the contents of display.text cannot be interpreted as a Double. Setting its value to nil should clear the display out. You’ll have to modify the code that uses displayValue accordingly.

If there is no text, or the text cannot be translated to a number, return nil, otherwise the number. If there is a value, set the labels, otherwise reset them:

private var displayValue: Double? {
  get {
    if let text = display.text, value = Double(text) {
      return value
    }
    return nil
  }
  set {
    if let value = newValue {
      display.text = String(value)
      history.text = brain.description + (brain.isPartialResult ? " …" : " =")
    } else {
      display.text = "0"
      history.text = " "
      userIsInTheMiddleOfTyping = false
    }
  }
}

Continue reading “cs193p – Assignment #1 Extra Task #2”

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!