BLACK FRIDAY: 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!

5      

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)
        }
    }

5      

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
        }
    }
}

9      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, 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!

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())

4      

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!

4      

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)

3      

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!

4      

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)
}

3      

Ben completed Day 10 and 11 and asks for feedback:

i'd love some feedback as to whether I've covered all of what was required here.

Nice! Who doesn't want to take a ride in a 'stang?

Don't worry so much about trying to cover 'all of what was required'. You're getting a lot of new info. And your code shows you are practicing. That's the important part. Practice writing harsh, apprentice level code. Get the code to compile and work. Working code = success!

Next, teach yourself to review other people's code. Try the Rubber Duck 🐤 technique to explain SwiftUI code to yourself. As you progress, you'll unlearn some techniques and get yourself on track to write fluid, Swifty code.

Feedback

    static let maxGear = 10  // <-- You coded a 'magic number' here.
    // Now you must keep the gearWords array synced with the maxGear variable. 
    // Program managers call this 'maintenance nightmare'
    let gearWords = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "...er, tenth"]

This is a snip from your code. See how you commanded this struct to have a maximum of 10 gears? Then you defined text labels for each of the gear. You're on Day 11? This is exactly the code you should be writing! ✔︎

However, this might not make the grade in a team environment. Program managers call this a maintenance nightmare.

Why? Because you now have the distinct possibility that the hard coded maxGear variable may not match the number of gears in your gearWords array! "That's unpossible!", you might say. Yet, it's these types of bugs that drive you insane.

So, instead, what might you do?

Computed Properties

Take a look at @twoStraws' article on computed properties. See -> Computed Properties

In your case, you have a gearWords array with some number of gears. It's quite possible that this number will change right before your company ships the application to thousands of users! Why not let your Car struct figure out how many gears your car has? This is where computed properties shine.

    // Definitive gears available in your Car.
    let gearWords = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "...er, tenth"]
    var maxGear: Int {
        gearWords.count  // <-- Allow your struct to calculate this. It will never be out of sync with your gearWords array.
    }

Keep coding!

3      

Thanks so much for the feedback, @Obelix!

That's great advice about the computed property for maxGear. My plan is to revisit each checkpoint at the end of the consolidation points to see where I can trim the fat and also apply any additional knowledge retrospectively.

4      

Hello! Here is my code for this challenge. I really like the solution I came up with, as it uses only one method. However, any opinions on how to make it more simplistic and elegant are welcome. I'm sure there's room for improvement. Thoughts?

import Cocoa

struct Car {
    let model: String
    let numberOfSeats: Int
    private(set) var currentGear: Int = 10 {
        willSet {
            print("Gear \(currentGear) is now changing to \(newValue)")
        }
    }

    enum GearDirection {
        case up, down
    }

    mutating func changeGears(withDirection gearDirection: GearDirection) {
        if (1...10).contains(currentGear) {
            if gearDirection == .up && currentGear + 1 <= 10 {
                currentGear += 1
            } else if gearDirection == .up {
                print("You cannot go above the highest gear!")
            }

            if gearDirection == .down && currentGear - 1 >= 1 {
                currentGear -= 1
            } else if gearDirection == .down {
                print("You cannot go below the lowest gear!")
            }
        } else {
            print("That is not a valid gear!")
        }
    }
}

var car = Car(model: "Mazda CX-30", numberOfSeats: 5, currentGear: 2)
car.changeGears(withDirection: .up)
car.currentGear

This would print, "Gear 2 is now changing to 3" at the bottom of the screen.

Thanks! :)

3      

Hi! I'm the kind of dev that only does what is required (a lazy one that is). The best code is the one that wasn't written at all.

Here is my take at checkpoint 6. Thoughts?

import Cocoa

struct Car {   
    enum shift {
        case up, down
    }
    let model: String
    let seats: Int
    private(set) var gear: Int = 10

    mutating func changeGear(shift: shift) -> Bool {
        var tmpGear = gear

        tmpGear += (shift == .up ? 1:-1) 
        if (tmpGear >= 1 && tmpGear <= 10) {
            gear = tmpGear
            print("\(shift == .up ? "Upshifted":"Downshifted") to gear \(gear).")
            return true
        }
        print("Couldn't \(shift == .up ? "upshift":"downshift") more, already in gear \(gear).")
        return false
    }
}

3      

Alphonso shares clever code and asks for feedback!

// --- Your code ---
if (tmpGear >= 1 && tmpGear <= 10) {
            gear = tmpGear
            // ... snip ...
        }

// --- Is this clearer? More Swifty? ---
if (1...10).contains(tmpGear) {  // <-- You might see this syntax to verify values in a range
            gear = tmpGear
            // ... snip ...
        }

Keep coding!

4      

I love that there are so many ways to tackle a problem with code :-)

Here is my implementation:

struct Car {
    let gears = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    let model: String
    let seats: Int

    func carDetails() {
        print("This car is a \(model) with \(seats) seats")
    }

    mutating func changeGear(gear: Int) {
        if gear < gears[0] || gear > gears[9] {
            print("This is an invalid gear")
        } else {
            print("You changed into gear \(gear)")
        }
    }
}

Then I can make the calls below :

var modely = Car(model: "Model Y", seats: 5)
modely.carDetails()
modely.changeGear(gear: 0)

and receive the following feedback:

This car is a Model Y with 5 seats
This is an invalid gear

3      

Stuart joins in sharing his take:

I love that there are so many ways to tackle a problem with code :-)

Observations


One observation I have for your solution... what gear am I currently in?
If I create a new car object, model3, how can I ask model3 to tell me what gear I'm currently in?

   let model3 = Car( type: "Model 3")  // <-- Create new car object
   let myCurrentGear = model3.??? // <-- How do I get current gear?

Also, this code looks a lot like Java, or C++

    if gear < gears[0] || gear > gears[9] {
         // ... snip ...
    }

You might look through other answers here for a more Swifty approach.

In particular, Swift provides some convenience methods for arrays. Here's a more Swifty way to get the first and last element of an array.

    if gear < gears.first || gear > gears.last {  // <-- get the first and the last elements of an array!
         // ... snip ...
    }

Keep Coding!

5      

Thank you, Obelix. I see you are a very active member on the forum. I appreciate all the time and effort you put in to help us!

5      

hi all.

i thought id share my code and wouldnt mind some feedback please. here in the uk i'm used to gears where i choose the number rather than shift up or down. so thats what i went with! have i taken the task too simply?

thanks

struct Car {

    let model: String
    let numberOfSeat: Int
    private(set) var gear = 0 {
        didSet { print("Your \(model) car gear has changed from \(oldValue) to \(gear)")}
    }

    mutating func changeGear (newGear:Int) {
        if newGear >= 0 && newGear <= 10 {
            self.gear = newGear
        } else {
            print("This gear is out of bounds! Choose between 0 (neutral) and 10")
            return
        }
    }
}

var myCar = Car(model: "Audi Q3", numberOfSeat: 5)
myCar.changeGear(newGear: 6)

3      

Hi everyone,

Here is my solution to Checkpoint 6 and I welcome any feeback you may please have for me. Thanks in advance! :)

/// Catches gears that are not found - anything below 1 or above 10
enum GearError: Error {
    case gearNotFound
}

struct Car {
    let model: String
    let numberOfSeats: Int
    var currentGear: Int

    init(model: String, numberofSeats: Int, currentGear: Int) {
        self.model = model
        self.numberOfSeats = numberofSeats
        self.currentGear = currentGear
    }

    /// Takes input of newGear, throws error if necessary, returns newGear
    mutating func gearChange(newGear: Int) throws -> Int {
        ///  Checks if gear is above or below max and throws error if that is so.
        if newGear < 1 || newGear > 10 {
            throw GearError.gearNotFound
        }

        /// Checks if newGear is above or below the currentGear.
         if newGear > currentGear {
            print("You up shifted your vehicle's gear!")
         } else if newGear < currentGear {
            print("You down shifted your vehicle's gear!")
         } else {
            print("You are going the same speed")
         }

        print("Your vehicle is in \(newGear)th gear!")
        /// returns the newGear
        return newGear
    }

}

var car = Car(model: "Outlander", numberofSeats: 7, currentGear: 1)
var shiftGears = 10

/// do catch block to catch errors.
do {
    _ = try car.gearChange(newGear: shiftGears)
} catch GearError.gearNotFound {
    print("Gear not found!")
}

4      

Coming from germany where I learned driving with a "manual" gear shift back in the days I also used an approach that lets you type the value instead going just "up", "down" etc. Going from 10 to 1 immediately might feel a little strange though ;-)

What do you think?

import UIKit

struct Car {
    let carModel = "Mercedes"
    let carSeats = 5
    private var currentGear = 1

    mutating func gearChange(newGear: Int) {
         if currentGear + newGear <= 10 && currentGear + newGear >= 1 {
         currentGear += newGear
             print("""
                    Model: \(carModel)
                    Seats: \(carSeats)
                    Gear: \(currentGear)
                    """)
         }
         else {
             print("This doesn't work")
         }
     }
}
var car = Car()
car.gearChange(newGear: 9) 

This will result in

Model: Mercedes Seats: 5 Gear: 10

3      

@tomn  

Here's my attempt. Any feedback welcome. I saw that some people used private(set) and enum. I didn't think of those and went another way with a bunch of if statements. Thanks for everything!

struct Car {
    let model: String
    let numberOfSeats: Int
    private var currentGear: Int

    init (model: String, seats: Int) {
        self.model = model
        self.numberOfSeats = seats
        self.currentGear = 1
    }

    mutating func changeGear(changeUp: Bool) {
        if currentGear == 1 && changeUp == false {
            print("Cannot shift down anymore. Already at \(currentGear).")
        } else if currentGear == 5 && changeUp {
            print("Cannot shift up anymore. Already at \(currentGear).")
        } else if changeUp {
            currentGear += 1
            print("\(model) shifted up to \(currentGear)")
        } else {
            currentGear -= 1
            print("\(model) shifted down to \(currentGear)")
        }
    }
}
var bmw = Car(model: "BMW X7", seats: 7)
bmw.changeGear(changeUp: true)

3      

Here is my solution to checkpoint-6. If any suggestions or feedback to give on this , you are welcomed ! Happy coding !

import Cocoa

struct Car {
    let model : String
    let noOfSeats : Int
    private(set) var currentGear : Int {
        willSet {
            if self.currentGear == -1 {
                print("car will be in nuetral gear")
            }
            print("changing the gear number from \(currentGear) to \(newValue)")
        }
    }
    let maxGearNo = 6
    let nuetralGearNo = 0
    let reverseGearNo = -1

    enum GearChange {
            case Up, Down, Reverse , neutral
    }

   mutating func changeGear(Action : GearChange) {
       if Action == GearChange.Up {
            if currentGear == maxGearNo{
                print("You are already on maximum gear No")
            } else {
                self.currentGear += 1
            }
       } else if Action == GearChange.Down {
           if currentGear == -1 {
               print("You are on minimum gear No")
           } else {
               self.currentGear -= 1
           }
       } else if Action == GearChange.Reverse {
           self.currentGear = reverseGearNo
       } else if Action == GearChange.neutral {
           self.currentGear = nuetralGearNo
       } else {
           print("Please change the gear properly")
       }
    }
}

var c = Car (model: "3gx2v", noOfSeats: 7, currentGear: 6)

c.changeGear(Action: .Reverse)

3      

Helo everybody

This is my first interaction here

Can you check my solution for checkpoint 6 :

struct Car {
    let carmodel = "Citroen"
    let numberOfSeats = 5
    var currentGear = 5
    }
struct ShiftGear {
    var gear = 5 {
        didSet {
            print("Gear is now \(gear)")
        }
    }
}
var citroen = Car(currentGear: 5)
print(citroen)
var shiftGear = ShiftGear()
shiftGear.gear += 0
shiftGear.gear -= 1
shiftGear.gear -= 1
shiftGear.gear -= 1
shiftGear.gear -= 1

Car(carmodel: "Citroen", numberOfSeats: 5, currentGear: 5)

Gear is now 5

Gear is now 4

Gear is now 3

Gear is now 2

Gear is now 1

3      

@deniz  

Hello good people!

This is my code, but I'm not 100% sure if I did it correct (I always have that feeling after completing a challenge and especially if I see that Paul's solution is different ). Any thoughts/feedback?

import Cocoa

struct Car {
    let model: String
    let seats: Int
    var currentGear = 0

    mutating func changeGears(gear: String) {
        if currentGear < 10 && gear == "up"{
                currentGear += 1
                print ("You are driving a \(model) with \(seats) seats and changing to gear \(currentGear).")
            }
        else if currentGear > 0 && gear == "down" {
                currentGear -= 1
                print ("You are driving a \(model) with \(seats) seats and changing to gear \(currentGear).")
            }
        else {
                print ("Invalid gear.")
        }
        }
}

var change = Car(model: "Toyota", seats: 6)

//Checking if the code is working//
change.changeGears(gear: "up")
change.changeGears(gear: "up")

change.changeGears(gear: "down")
change.changeGears(gear: "down")
change.changeGears(gear: "down")
change.changeGears(gear: "down")

3      

Tried to incorporate as much as I learned so far. There's much room for improvement I am sure. The do - try - catch bothers me a bit. Isn't there a more elegant solution?

struct Car {

    let model: String
    let numberOfSeats: Int

    let minGear = 1
    let maxGear = 10

    var currentGear: Int = 0 {
        didSet {
            print("Gear \(currentGear)")
        }
        willSet {
            if newValue > currentGear {
                print("shifting up")
            } else {
                print("shifting down")
            }
        }
    }

    enum gearChangingMethod {
        case up, down
    }

    enum shiftingError: Error {
        case minReached, maxReached
    }

    func validShift (to: Int) -> Bool {
        if to >= minGear && to <= maxGear {
            return true
        } else {
            return false
        }
    }

    mutating func shift (_ direction: gearChangingMethod) throws {
        switch direction {
        case .up:
            if validShift(to: currentGear + 1)  {
                currentGear += 1
            } else {
                throw shiftingError.maxReached
            }

        case .down:
            if validShift(to: currentGear - 1)  {
                currentGear -= 1
            } else {
                throw shiftingError.minReached
            }
        }
    }
}

var bentley = Car(model: "Azure", numberOfSeats: 4)

for _ in 1...100 {
    let shiftUp = Bool.random()
    if shiftUp {
        do {
            try bentley.shift(.up)
        } catch {
            print("Error! Can't shift up")
        }
    } else {
        do {
            try bentley.shift(.down)
        } catch {
            print("Error! Can't shift down")
        }
    }
}

3      

Hello all,

I thought Ill add my solution on checkpoint 6 as well. You're welcomed to give any feedback on this. Thank you and happy coding!


struct Car {

    // properties:
    let model: String // a car's model should not change (const)
    let seatCount: Int // a car's number of seat should not change (const)

    private(set) var currentGear = 0 // start in 0th gear and may change (var), read only 

    // methods:
    mutating func shiftGear(up: Bool) {
        if (up && currentGear >= 7) {
            print("This is it! Youve hit the max gear! Cant go any higher!")
        }

        else if (!up && currentGear <= 0 ) {
            print("This is the lowest! Youve stop doc! Cant go lower!")
        }

        else if up {
            print("Shift gear up by 1...")
            currentGear += 1
        }
        else {
            print("Shift gear down by 1...")
            currentGear -= 1
        }

        currentGear = min(max(currentGear, 0), 7) // limit gear range between 0 and 7
        print("Current gear: \(currentGear)\n\n")
    }
}

// TEST Code:
// create a new Car instance
var myCar = Car(model: "Honda civic", seatCount: 5)

print("Current gear \(myCar.currentGear)")
myCar.shiftGear(up: true) // try shifting gear up after 7th gear 
myCar.shiftGear(up: false) // try shifting gear down below 0

4      

https://www.hackingwithswift.com/forums/100-days-of-swiftui/checkpoint-6-changing-gears/10129 I done the Checkpoint 6 by myself but my code is ugly. Then I come here and reworked the code example from beginning of the post:

struct Vehicle {
    let brand: String
    let model:String
    let seats: Int
    private var currentGear = 1
    init(brand: String, model: String, seats: Int) {
        self.brand = brand
        self.model = model
        self.seats = seats
    }
    enum GearChange {
        case up, down, neutral, reverse
    }
    mutating func gearShift (_ g:GearChange) {
    switch g {
        case .up: currentGear += 1 
              if currentGear < 10 && currentGear > 1  {print("Gear is shifted to \(currentGear) and your \(brand) \(model) with \(seats) seats moving forward")}
              else { currentGear = 10 
              print("Khhhhhrrr max gear is 10")}
        case .down: currentGear -= 1 
        if currentGear > 1 {print("Gear is shifted to \(currentGear) and your \(brand) \(model) with \(seats) seats still moving forward")}
              else {print("Khhhhhrrr min gear is 1")
                  currentGear = 1
              }
        case .neutral: currentGear = 1
        print ("Your \(brand) \(model) with \(seats) seats has stopped because gear set to neutral")
        case .reverse: currentGear = -1 
        print("Your \(brand) \(model) with \(seats) seats rides back because gear set to reverse")
        }
    }
}

var car = Vehicle(brand: "Volkswagen", model:"T4", seats: 8)
car.gearShift(.up) // while not above 10 all working good
car.gearShift(.down) // while not less than 1 working good
car.gearShift(.neutral) // stops the car
car.gearShift(.reverse) // move car backward

3      

@Amir add yet another solution to this puzzle! Nice job!

If you were on my development team, we might ask you to take another look at your solution to answer this question:

It is safe to switch from 4th gear directly to reverse gear?
Is this a valid use case, or do you consider this an error condition?

How might you update your code to test this condition?

Also, can you share why the currentGear variable is private? There's a good reason. Why do you think it's private?

Keep Coding!

4      

I have a simple solution as well, just wanted to start interacting

struct Car {
    let model: String = "Toyota"
    let numberOfSeats: Int = 5
    var currentGear = 1 {
        didSet {
            print("You are in the gear \(currentGear)")
        }
    }

    mutating func changeGearUp() {
        if currentGear > 10 {
            print("You can't change the Gear UP")
        } else {
            currentGear += 1
        }
    }
    mutating func changeGearDown() {
        if currentGear <= 0 {
            print("You can't chagen the Ghear DOWN")
        } else {
            currentGear -= 1
        }
    }
}

var car = Car()
car.changeGearUp()
car.changeGearDown()

3      

@Obelix

@Amir add yet another solution to this puzzle! Nice job!

If you were on my development team, we might ask you to take another look at your solution to answer this question:

1) It is safe to switch from 4th gear directly to reverse gear? Is this a valid use case, or do you consider this an error condition?

2) How might you update your code to test this condition?

3) Also, can you share why the currentGear variable is private? There's a good reason. Why do you think it's private?

Hi! Sorry I had a long pause in learning because of some circumstances.

Answer to first question is: "It is not safe to switch from 4th gear to reverse, because it can break gearbox, so if it is an electronic switcher with touch control i will implement a step by step shifting to avoid this. But if we have other control system it will be error condition with warning like: 'This action can totally break your gearshift, please make shifts consistent one by one down to neutral before doing reverse'."

Here an updated code with answer to the second question:

struct Vehicle {
    let brand: String
    let model:String
    let seats: Int
     // new parameter for edgecases or error testing
    let shiftStep: Int
    private var currentGear = 1
    init(brand: String, model: String, seats: Int, shiftStep: Int) {
        self.brand = brand
        self.model = model
        self.seats = seats
        self.shiftStep = shiftStep
    }
    enum GearChange {
        case up, down, neutral, reverse
    }
    mutating func gearShift (_ g:GearChange) {
    switch g {
        case .up: currentGear += shiftStep 
              if shiftStep > 1 || shiftStep < 1 {
                  print ("It is an overshift warning current shiftStep is \(shiftStep), it may cause a gearbox break, please set shiftStep parameter of your \(brand) \(model) car to 1.")
              }
              else if currentGear < 10 && currentGear > 1  {
              print("Gear is shifted to \(currentGear) and your \(brand) \(model) with \(seats) seats moving forward")}
              else { currentGear = 10 
              print("Khhhhhrrr max gear is 10")}
        case .down: currentGear -= shiftStep 
          if shiftStep > 1 || shiftStep < 1  {
                  print ("It is an overshift warning current shiftStep is \(shiftStep), it may cause a gearbox break, please set shiftStep parameter of your \(brand) \(model) car to -1.")
              }
        else if currentGear > 1 {print("Gear is shifted to \(currentGear) and your \(brand) \(model) with \(seats) seats still moving forward")}
              else {print("Khhhhhrrr min gear is 1")
                  currentGear = 1
              }
        case .neutral: currentGear = 1
        print ("Your \(brand) \(model) with \(seats) seats has stopped because gear set to neutral")
        case .reverse: currentGear = -1 
        print("Your \(brand) \(model) with \(seats) seats rides back because gear set to reverse")
        }
    }
}

// here we can simulate overshift through shiftStep
var car = Vehicle(brand: "Volkswagen", model:"T4", seats: 8, shiftStep: 2)
// if shiftStep parameter set to greater than 1 or lower than 1, we can see a warning about gearbox break, it is an explicit parameter for any edgecases with gear shifting
car.gearShift(.up) // while not above 10 all working good
car.gearShift(.down) // while not less than 1 working good
car.gearShift(.neutral) // stops the car
car.gearShift(.reverse) // move car backward

And to the 3rd question I can answer: Because of the private variable parameter can guard the variable from unnecessary changes outside of struct's function, it is absolutely important for states like the account balance or something like this.

Thank 'u for your attention to my soltion, sorry for my poor English.

3      

@kp9z  

I am not sure why most solution, make an assumption that we can only change 1 gear at a time. I have try to drive from Neutural to 2 or even 4 gear before. Also, if we limit the input, I don't think we need to validate it? or am I missing something?

enum CarGear: Int {
    case Reverse = -1
    case Park = 0
    case First = 1
    case Second = 2
    case Third = 3
    case Fourth = 4
}
struct Car {
    let model: String
    let numSeats: Int = 4
    private(set) var currentGear: CarGear = .Park // need some control over what gear to put in

    mutating func changeGear(_ newGear: CarGear) {

        currentGear = newGear
        print("changing to \(currentGear)")

        }

}

var car = Car(model: "ford")

car.numSeats
car.currentGear

car.changeGear(.First)

3      

Been coding for alot of years but still fairly new to Swift & SwiftUI. I think I coverd all the bases and allow for other number of gears instead of default 10 if one wants to. I do my checks in the Switch statement since it is one simple check. Then default and return if they try an invalid shift. Use private(set) on curGear so only mutating func can change it.

struct Car {
    let model: String
    let numOfSeats: Int
    let topGear: Int
    private(set) var curGear: Int = 1

    init(model: String, numOfSeats: Int, topGear: Int = 10) {
        self.model = model
        self.numOfSeats = numOfSeats
        self.topGear = topGear
    }

    enum shifts {
        case up, down
    }

    mutating func changeGear(shift: shifts) {
        switch shift {
        case .up where curGear < topGear:
                curGear += 1
        case .down where curGear > 2:
                curGear -= 1
        default:
            print("No shift allowed...")
            return

        }

        print("Current Gear \(curGear)")
    }
}

var myCar2 = Car(model: "Acura", numOfSeats: 5, topGear: 4)
print("My Second Car...")
myCar2.changeGear(shift: .up)
myCar2.changeGear(shift: .up)
myCar2.changeGear(shift: .up)
myCar2.changeGear(shift: .up)
myCar2.changeGear(shift: .down)

Output

  • My Second Car...
  • Current Gear 2
  • Current Gear 3
  • Current Gear 4
  • No shift allowed...
  • Current Gear 3

3      

@ScottThePilot brings a ship safely into port!

case .up where curGear < topGear:
        curGear += 1
case .down where curGear > 2:
        curGear -= 1  // spell out currentGear?  

Very clever use combining the case with a where clause. Over the years, this is the first use of this in the Checkpoint 6 solution. Nice!

You'll be answering forum questions in no time!

4      

Thank you sir...

I doubt I will be answering things but who knows...

I thought "where" was sort of the easy and efficeint way to add that one little check to an already efficient switch statement. Swift really is pretty cool language with lots of hidden gems like that...

3      

I've just started to learn how to code but I went into this trying to make the code as short as possible for example I saw many people us currentGear.up or something along those lines which I felt would be rather annoying if you wanted to switch lets say 2 or more gears at once, anyways heres my code let me know what you guys think!

struct Car {
    let carModel: String
    let numberOfSeats: Int
    private(set) var currentGear = 0

    mutating func changeGear(number: Int) -> Bool {
        if currentGear + number > 0 && currentGear + number < 11 {
            currentGear += number
            print("The current gear is \(currentGear)")
            return true
        } else {
            print("Error gear doesn't exist")
            return false
        }

    }
}

var porsche = Car(carModel: "911", numberOfSeats: 2)
porsche.changeGear(number: 4)

3      

How about my approach? I think it does cover all the points mentioned in the challenge. Too straight to the point?

struct Car {
    let model: String
    let numOfSeats: Int
    var currentGear: Int

    mutating func gearUp() {
        if self.currentGear <= 9 {
            self.currentGear += 1
        }
    }

    mutating func gearDown() {
        if self.currentGear >= 2 {
            self.currentGear -= 1
        }
    }
}

3      

I worked hard and made new solution for this challenge

//To check your knowledge, here’s a small task for you: create a struct to store information about a car, including its model, number of seats, and current gear, then add a method to change gears up or down. Have a think about variables and access control: what data should be a variable rather than a constant, and what data should be exposed publicly? Should the gear-changing method validate its input somehow?

struct myCar {
    // Full car properties
    private let model: String
    private let seatsNumber: Int
    private let gears = ["reverse", "neutral", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"]
    private var currentGear: Int = 1
    private var maxGear: Int

    // method to check car info, so I can keep all properties of my struct private written with let
    func carSummary() {
        print("My new car is \(model), it has a \(seatsNumber) seats, and its max gear is \(maxGear)")
    }

    // method to shift gears (up if parameter up is true, or down if parameter up is false)
    // every shift validates through conditions
   mutating func gearShift(up: Bool) {
        if up == true && currentGear <= maxGear {
            currentGear += 1
            print("You switched to \(gears[currentGear]) gear")
        } else if up == false && currentGear > 0 {
            currentGear -= 1
            print("You switched to \(gears[currentGear]) gear")
        } else if up == true && currentGear > maxGear {
            print("You can't shift gears up, cause max gear is \(maxGear)")
        } else if up == false && currentGear == 0 {
            print("You can't shift gears down, cause no gears lower than reverse")
        }
    }

    // custom initializator for private properties, current gear property not listed cause it has initial value
    init(model: String, seatsNumber: Int, maxGear: Int) {
        self.model = model
        self.seatsNumber = seatsNumber
        self.maxGear = maxGear

    }
}

//some code for checking is this struct and it's methods and properties done right
var newCar = myCar(model: "VW Golf", seatsNumber: 5, maxGear: 6)
newCar.gearShift(up: false)
newCar.gearShift(up: false)
for _ in 1...8 {
    newCar.gearShift(up: true)
}
newCar.carSummary()

Be free to use this solution for improving your code

3      

Nothing new here, but just another example of a newbie:

struct Car {
    let model: String
    let numOfSeats: Int
    private(set) var currentGear: Int = 1
    private let maxGear = 5

    mutating func gearUp(){
        if currentGear < maxGear {
            currentGear += 1
            print("You are in gear \(currentGear).")
        } else {
            print("You are in max gear!")
        }
    }

    mutating func gearDown(){
        if currentGear > 1 {
            currentGear -= 1
            print("You are in gear \(currentGear).")
        } else {
            print("You are in the lowest gear!")
        }

    }
}

var myCar = Car(model: "Corolla", numOfSeats: 4)
myCar.gearUp() //prints "You are in gear 2."
myCar.gearUp() //prints "You are in gear 3."
myCar.gearUp() //prints "You are in gear 4."
myCar.gearUp() //prints "You are in gear 5."
myCar.gearUp() //prints "You are in max gear."
myCar.gearDown()  //prints "You are in gear 4."

I don't want the driver to skips gears. :)

I like the use of enum in previous examples and putting the shift up and down code into one func. Putting in neutral and reverse is also a good idea.

Though my Corolla has a CVT so this gear thing is foreign concept. :) Also with EVs.

   

Here is my solution to this:

struct Car {

    let model: String
    let numberOfSeats: Int
    var gearNumber: Int

    init(model: String, numberOfSeats: Int, gearNumber: Int) {
        self.model = model
        self.numberOfSeats = numberOfSeats
        self.gearNumber = gearNumber
    }

    mutating func changeGearsUp(amount: Int) {
            gearNumber += amount
        if gearNumber > 10 {gearNumber = 10}
    }
    mutating func changeGearsDown(amount: Int) {
            gearNumber -= amount
        if gearNumber < 0 {gearNumber = 1}
    }
}

var carY = Car(model: "Y", numberOfSeats: 5, gearNumber: 1) {
    didSet {
        print(carY)
    }
}
carY.changeGearsUp(amount: 4)
carY.changeGearsUp(amount: 9)
carY.changeGearsDown(amount: 15) // Will not allow car to go below 0. If below 0 is attempted, it will set it to 1.

   

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, 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!

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.