LMU ☀️ CMSI 3801
LANGUAGES AND AUTOMATA I
HOMEWORK #4 PARTIAL ANSWERS
exercises.swift
// Hello, these are homework answers, and homework is to help you learn,
// so this file contains a lot of superfluous comments to explain some
// things about Swift that I think make for good learning moments. As
// always, your homework submissions should have appropriate comments
// and not comments that try to teach your reader about Swift.

import Foundation


// Because change returns a result, we need to make a real error type.
struct NegativeAmountError: Error {}

// We didn’t talk about typealias in class, but it’s cool
typealias ChangeResult = Result<(Int, Int, Int, Int), NegativeAmountError>

// The _ is required of course, since you have to pass the tests.
func change(_ amount: Int) -> ChangeResult {
    if amount < 0 {
        return .failure(NegativeAmountError())
    }
    let (quarters, afterQuarters) = amount.quotientAndRemainder(dividingBy: 25)
    let (dimes, afterDimes) = afterQuarters.quotientAndRemainder(dividingBy: 10)
    let (nickels, pennies) = afterDimes.quotientAndRemainder(dividingBy: 5)
    return .success((quarters, dimes, nickels, pennies))
}


extension String {
    var stretched: String {
        return self
            .filter { !$0.isWhitespace }
            .enumerated()
            .map{ String(repeating: String($1), count: $0 + 1) }
            .joined()
    }
}


extension Array {
    func mapThenUnique<T>(mapper: (Element) -> T) -> Set<T> {
        return Set(self.map(mapper))
    }
}


// This is the most direct way, but fancier solutions probably exist
func powers(of base: Int, through limit: Int, consume: (Int) -> Void) {
    var power = 1
    while power <= limit {
        consume(power)
        power *= base
    }
}


protocol Animal {
    var name: String { get }
    var sound: String { get }
    func speak() -> String
}

extension Animal {
    func speak() -> String {
        return "\(name) says \(sound)"
    }
}

// You should have been able to infer these from the test case. :)
struct Cow: Animal {
    let name: String
    let sound = "moooo"
}

struct Horse: Animal {
    let name: String
    let sound = "neigh"
}

struct Sheep: Animal {
    let name: String
    let sound = "baaaa"
}


struct Sayer {
    let phrase: String
    func and(_ word: String) -> Sayer {
        return Sayer(phrase: "\(self.phrase) \(word)")
    }
}

func say(_ word: String) -> Sayer {
    return Sayer(phrase: word)
}


// Yay, a generic function. Look how nice this looks in Swift compared to Java.
// Functions are functions, and can be called without the functional interface
// method (e.g., apply) that is requried in Java.
func twice<T>(_ f: (T) -> T, appliedTo x: T) -> T {
    return f(f(x))
}


// I think it’s important to use nice short parameter names here. You got the
// argument labels from the test, but remember they look pretty funny inside
// the code. Here a and n are good. Their purpose is basically documented in
// the function definition line and the body is only one line, so it’s fine.
func uppercasedFirst(of a: [String], longerThan n: Int) -> String? {
    return a.first(where: { $0.count > n })?.uppercased()
}


struct Quaternion: CustomStringConvertible, Equatable {
    let a: Double
    let b: Double
    let c: Double
    let d: Double

    static let ZERO = Quaternion()
    static let I = Quaternion(b: 1)
    static let J = Quaternion(c: 1)
    static let K = Quaternion(d: 1)

    init(a: Double = 0, b: Double = 0, c: Double = 0, d: Double = 0) {
        self.a = a
        self.b = b
        self.c = c
        self.d = d
    }

    var coefficients: [Double] {
        return [self.a, self.b, self.c, self.d]
    }

    var description: String {
        var base = "\(self.a)+\(self.b)i+\(self.c)j+\(self.d)k"
        base = base.replacingOccurrences(of: "+-", with: "-")
        return base
    }
}

func +(q1: Quaternion, q2: Quaternion) -> Quaternion {
    return Quaternion(
        a: q1.a + q2.a,
        b: q1.b + q2.b,
        c: q1.c + q2.c,
        d: q1.d + q2.d
    )
}

func -(q1: Quaternion, q2: Quaternion) -> Quaternion {
    return Quaternion(
        a: q1.a - q2.a,
        b: q1.b - q2.b,
        c: q1.c - q2.c,
        d: q1.d - q2.d
    )
}

func *(q1: Quaternion, q2: Quaternion) -> Quaternion {
    return Quaternion(
        a: q2.a * q1.a - q2.b * q1.b - q2.c * q1.c - q2.d * q1.d,
        b: q2.a * q1.b + q2.b * q1.a - q2.c * q1.d + q2.d * q1.c,
        c: q2.a * q1.c + q2.b * q1.d + q2.c * q1.a - q2.d * q1.b,
        d: q2.a * q1.d - q2.b * q1.c + q2.c * q1.b + q2.d * q1.a
    )
}