WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Checkpoint 6: Changing Gears

Forums > 100 Days of SwiftUI

Enjoying the updated videos!

For Checkpoint 6 Paul challenges us to write a Car struct. Here's my attempt. Try it on your own before looking at my solution.

struct Car {
    let model: String     // constant! probably won't change
    let seatCount: Int    // same!
    private(set) var currentGear = 1  // only change via an internal method.

    enum GearDirection {
        case up, down, neutral
    }

    public mutating func changeGear(_ direction: GearDirection) {
        switch direction {
        case .down : currentGear -= 1
            if currentGear < 1 {currentGear = 1}
        case .up :   currentGear += 1
            if currentGear > 10 { currentGear = 10 }
        case .neutral:
            currentGear = 1  // arbitrary selection
        }
        print("The \(model) is in gear: \(currentGear)")
    }
}

// Test Code
var prefect = Car(model: "Ford Prefect", seatCount: 4, currentGear: 3)
prefect.changeGear(.up)
prefect.changeGear(.neutral) // Jump right to Gear 1.
prefect.changeGear(.down)  // try this line a couple of times. try to get below zero.

I tried to add validation code as a property observer. In the willSet clause you get a free variable newValue. I checked to see if newValue was valid ( 1 to 10). If it was outside the range, I wasn't sure how to change it. That must come in a later lesson?

BONUS QUESTION: What does the playground compiler do if you add another option to the GearDirection enum? Try adding reverse to the enum. What does the compiler do? See Enumerations for more details.

Don't forget your towel!

1      

I tried to add validation code as a property observer. In the willSet clause you get a free variable newValue. I checked to see if newValue was valid ( 1 to 10). If it was outside the range, I wasn't sure how to change it. That must come in a later lesson?

You would do it in didSet.

    private(set) var currentGear = 1 {
        didSet {
            currentGear = min(max(currentGear, 1), 10)
        }
    }

1      

Here is my take on solving this:

struct Car {
    let model: String // Once a car is made, the model doesn't change
    let numberOfSeats: Int // Same with the number of seats
    private(set) var currentGear = 1 // New instance will start in 1st gear

    mutating func shiftUp() {
        if currentGear + 1 > 10 { // check if shifting will exceed the top gear
            print("You are already in the top gear!")
        } else {
            currentGear += 1
        }
    }

    mutating func shiftDown() {
        if currentGear - 1 < 1 { // check if shifting will exceed the bottom gear
            print("You are alredy in the lowest gear!")
        } else {
            currentGear -= 1
        }
    }
}

3      

I came up with this solution. Not sure if this is an overkill to solve it like this. My goal was to minimize effort on code change when a cars would get more, less or other gears.

enum Gear: Int, CaseIterable {
    case reverse = 0
    case parking = 1
    case first = 2
    case second = 3
    case third = 4
    case fourth = 5
    case fivth = 6
    case sixth = 7
}

struct Car {
    let model: String
    let seats: Int
    private(set) var currentGear: Gear = Gear.parking

    func toString() -> String {
        "This model \"\(model)\" has \(seats) seats and is currently in \(currentGear) gear!"
    }

    mutating func gearUp() {
        if currentGear.rawValue < Gear.sixth.rawValue {
            currentGear = next()
        }
    }

    mutating func gearDown() {
        if currentGear.rawValue > Gear.reverse.rawValue {
            currentGear = previous()
        }
    }

    private func previous() -> Gear {
        let all = Gear.allCases
        let idx = all.firstIndex(of: currentGear)!
        let previous = all.index(before: idx)
        return Gear(rawValue: previous) ?? currentGear
    }

    private func next() -> Gear {
        let all = Gear.allCases
        let idx = all.firstIndex(of: currentGear)!
        let next = all.index(after: idx)
        return Gear(rawValue: next) ?? currentGear
    }
}

var bmw = Car(model: "BMW 318i", seats: 4)
print(bmw.toString())
bmw.gearUp()
bmw.gearUp()
bmw.gearDown()
print(bmw.toString())

   

Daniel posts a clever implementation and states:

Not sure if this is an overkill to solve it like this. My goal was to minimize effort on code change when a cars would get more, less or other gears.

Well done! Indeed, this is overkill. But only in the sense that this was a simple homework exercise! On the otherhand, your solution shows a great understanding of the 'keep it simple' principles and a forward looking vision of code reuse.

These are hard skills to teach, and you're demonstrating them early. Nice!

Keep posting, it will be nice to follow your progress. Also, since you're demonstrating advanced techniques, please jump in and answer other's questions! This will help in a few ways.

First, and foremost, if you are trying to solve other coder's SwiftUI problems, you'll gain a better understanding of the concepts which will help you solidify your understanding.

Second, this is a site dedicated to helping folks all over the world build their skills. This site thrives on contributions from all sorts. Please contribute.

Third, it's great fun!

   

Looking at the solutions above, worried my approach might be overly simplistic but thought I'd share just in case. This is for a manual transmission. What do you think?

struct BMW {

    // Properties
    //Both the model and seat number properties will not change, hence the "let" constants
    let model: String = "M4"
    let noOfSeats: Int = 4

    // currentSpeed variable added to determine gear shifts since assignment said: "it's traveling around," implying at minimum a gear of 1 as the starting point
    var currentSpeed: Int = 10
    // "private" to prevent bypass of currentSpeed method and "set" to allow outside reading access of currentGear.
    private(set) var currentGear: Int

    //initializing since I want to modify the currentSpeed and currentGear properties
    init(model: String, noOfSeats:Int, currentSpeed: Int) {
    switch currentSpeed {
            case 0...10:
                currentGear = 1
            case 11...20:
                currentGear = 2
            case 21...30:
                currentGear = 3
            case 31...40:
                currentGear = 4
            case 41...50:
                currentGear = 5
            default:
                currentGear = 6
            }
        }
    }
//Testing one instance 
var bmwM4 = BMW(model: "M4", noOfSeats: 4, currentSpeed: 56)
print(bmwM4.currentGear)

   

Mario is worried:

worried my approach might be overly simplistic. This is for a manual transmission. What do you think?

You get full points for meeting the requirements for this challenge! Mind you, I would not drive a car using your software!!

The goal isn't to implement a Tesla-level transmission solution. You just needed to write a Car struct. Well done. It's great that you're thinking ahead and pondering your designs. You'll need these skills in later challenges.

Keep coding! And ask more questions!

1      

Well, after running through Day 9 three times and still feeling like I only took in about 10% of it, I pushed on into Days 10 and 11 and finally made it to Checkpoint 6. I'd love some feedback as to whether I've covered all of what was required here. In any case, it was good fun and a welcome break from those pesky closures.

struct Car {
    let owner: String
    let model: String
    let numSeats: Int
    static let maxGear = 10
    var currentGear = 1
    let gearWords = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "...er, tenth"]

    mutating func changeGear(currentGear: Int, shiftNum: Int){
        let newGear = currentGear + shiftNum
        if newGear > 0 && newGear <= Car.maxGear {
            print("Driving \(owner)'s \(numSeats)-seater \(model) and shifting into \(gearWords[newGear-1]) gear!")
            self.currentGear = newGear
                } else {
            print("Take it easy - you're out of gears!")
                }
    }
}

// Buy my car...
var myCar = Car(owner: "Sam", model: "Mustang", numSeats: 3)

// Take her for a spin...
for i in 1...Car.maxGear {
    myCar.changeGear(currentGear: i, shiftNum: 1)
}

   

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.