eudaimonious
6/4/2014 - 1:29 AM

Swift Guided Tour Solutions

/*
 Swift Programming Language Guide
 "A Swift Tour" Solutions
 https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-XID_1
 
 These are the solutions to all the "experiments" in the pre-release Swift Programming Guide 
 (released on the same day Apple announced Swift). A couple of things worth noting:
 
 1. Swift syntax, e.g. array declarations, has changed since I releasd these. So this code will 
    probably cause some errors when you paste it into a playground. Should be easy enough to fix 
    (and maybe a good exercise unto itself? :) )
 2. As some of the commenters have pointed out, I messed up a few solutions. So, please be sure 
    to check the comments for the correct answers. 
*/

import Cocoa

// Create a constant with an explicit type of Float and a value of 4.
let valueOfFour: Float = 4.0

// Try removing the conversion to String from the last line. What error do you get?
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
// let widthLabel = label + width

// Use \() to include a floating-point calculation in a string and to include someone’s name in a greeting.
let height:Float = 68
let name = "Yoshi"
let myHeight = "\(name)'s height is \(height + 0.5) inches"

// Change optionalName to nil. What greeting do you get? Add an else clause that sets a different greeting if optionalName is nil.
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
teamScore

var optionalString: String? = "Hello"
optionalString == nil

var optionalName: String? = nil
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
} else {
    greeting = "Hello, Yoshi"
}
greeting

// Try removing the default case. What error do you get?
let vegetable = "red pepper"
switch vegetable {
case "celery":
    let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
    let vegetableComment = "That would make a good tea sandwich."
case let x where x.hasSuffix("pepper"):
    let vegetableComment = "Is it a spicy \(x)?"
default:
    let vegetableComment = "Everything tastes good in soup."
}

// Add another variable to keep track of which kind of number was the largest, as well as what that largest number was.
let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largestKind = ""

for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
            largestKind = kind
        }
    }
}
largest
largestKind

// Remove the day parameter. Add a parameter to include today’s lunch special in the greeting.
func greet(name: String, special: String) -> String {
    return "Hello \(name)! Today's special is \(special)."
}
greet("Bob", "Meatloaf")

// Write a function that calculates the average of its arguments.
func average (numbers:Int...) -> Float {
    var sum = 0
    var total = 0
    
    for n in numbers {
        sum += n
        total++
    }
    
    return Float(sum / total)
}
average(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// Rewrite the closure to return zero for all odd numbers.
var numbers = [20, 19, 7, 12]
numbers.map({
    (number: Int) -> Int in
    var result = 0
    if number % 2 == 0 {
        result = 3 * number
    }
    return result
})

// Add a constant property with let, and add another method that takes an argument.
class Shape {
    var numberOfSides = 0
    let numberOfDimensions = 3
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
    func isNDimensional(dimensions:Int) -> Bool {
        var response = false
        if (numberOfDimensions == dimensions) {
            response = true
        }
        return response
    }
}
var shape = Shape()
shape.isNDimensional(3)

// Make another subclass of NamedShape called Circle that takes a radius and a name as arguments to its initializer. Implement an area and a describe method on the Circle class.
class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

class Square: NamedShape {
    var sideLength: Double
    
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }
    
    func area() ->  Double {
        return sideLength * sideLength
    }
    
    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

class Circle: NamedShape {
    var radius: Double = 0;
    
    init(radius: Double, name: String) {
        self.radius = radius;
        super.init(name:name)
    }
    
    func area() -> Double {
        return M_PI * radius * radius
    }
    
    override func simpleDescription() -> String {
        return "A circle with radius of \(radius)"
    }
}

let test1 = Circle(radius: 9.9, name: "my test circle")
test1.area()
test1.simpleDescription()

// Write a function that compares two Rank values by comparing their raw values.
enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
        case .Ace:
            return "ace"
        case .Jack:
            return "jack"
        case .Queen:
            return "queen"
        case .King:
            return "king"
        default:
            return String(self.toRaw())
        }
    }
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw()

func isSameRank (first: Rank, second: Rank) -> Bool {
    return first.toRaw() == second.toRaw()
}

isSameRank (Rank.Ace, Rank.Queen)
isSameRank (Rank.Two, Rank.Two)

// Add a color method to Suit that returns “black” for spades and clubs, and returns “red” for hearts and diamonds.
enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func simpleDescription() -> String {
        switch self {
        case .Spades:
            return "spades"
        case .Hearts:
            return "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
    func color () -> String {
        switch self {
        case .Spades:
            return "black"
        case .Clubs:
            return "black"
        case .Hearts:
            return "red"
        case .Diamonds:
            return "red"
        }
    }
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
hearts.color()
Suit.Spades.color()

// Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit.
struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

func createDeck() -> Card[] {
    var deck = Array (count: 52, repeatedValue: Card(rank: .Ace, suit: .Spades))
    var suits = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs];
    var counter = 0;
    
    for i in 1...13 {
        for suit in suits {
            deck[counter++] = Card (rank: Rank.fromRaw(i)!, suit: suit)
        }
    }
    
    return deck
}

func printDeck (deck: Card[]) {
    for card in deck {
        println (card.simpleDescription())
    }
}

let deck = createDeck()
printDeck(deck)

// Add a third case to ServerResponse and to the switch.
enum ServerResponse {
    case Result(String, String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm", "14:09h")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset, daylight):
    let serverResponse = "Sunrise is at \(sunrise), sunset is at \(sunset), and total daylight is \(daylight)."
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

// Write an enumeration that conforms to this protocol.
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

enum SimpleEnum: ExampleProtocol {
    case A, B, AA, BB
    
    var simpleDescription: String {
        get {
            switch self {
            case .A:
                return "A simple enum: A"
            case .B:
                return "A simple enum: B"
            case .AA:
                return "A simple enum: AA"
            case .BB:
                return "A simple enum: BB"
            }
        }
    }
    
    mutating func adjust() {
        switch self {
        case .A:
            self = A
        case .B:
            self = B
        case .AA:
            self = A
        case .BB:
            self = B
        }
    }
}
var c = SimpleEnum.AA
c.simpleDescription
c.adjust()
c.simpleDescription

// Write an extension for the Double type that adds an absoluteValue property.
extension Double {
    var abs: Double {
        get {
            return fabs(self)
        }
    }
}

var myDouble = -17.8
myDouble.abs

// Modify the anyCommonElements function to make a function that returns an array of the elements that any two sequences have in common.
func commonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Array<T.GeneratorType.Element> {
    var result = Array<T.GeneratorType.Element>()
    
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                result.append(lhsItem)
            }
        }
    }
    return result
}
var result = commonElements([1, 2, 3], [3, 2])
println(result)