Master Cars Assemble in Cairo: Complete Learning Path

a city street filled with lots of tall buildings

Master Cars Assemble in Cairo: A Complete Learning Path

This comprehensive guide provides a complete walkthrough of the "Cars Assemble" module, a core part of the Kodikra Cairo curriculum. You will master fundamental Cairo concepts like functions, conditional logic using if-else and match statements, and working with numerical types to solve a practical production line problem.


The Challenge: Optimizing a Robotic Assembly Line

Imagine you're the lead engineer at a state-of-the-art, fully automated car factory. Your primary responsibility is to write the core logic for the central control system. This system monitors the production speed of assembly-line robots and needs to calculate the number of cars produced per hour, accounting for varying success rates at different speeds. A simple counter isn't enough; the system needs to be intelligent.

You've noticed that at lower speeds, the production is flawless, but as you ramp up the speed to meet demand, the error rate increases, and some cars are produced with defects. Your task is to model this behavior in code. This is a classic problem of conditional logic that every developer faces: how do you make a program behave differently based on a set of changing inputs? This module will equip you with the foundational Cairo skills to solve this and many similar problems you'll encounter in smart contract development.


What is the "Cars Assemble" Module?

The "Cars Assemble" module from the exclusive kodikra.com curriculum is a practical programming challenge designed to teach foundational concepts in the Cairo language. At its core, it simulates a car production line where the output rate is dependent on the operational speed, which is set on a scale from 0 to 10.

The rules of the simulation are straightforward:

  • Each speed setting (1-10) corresponds to a base production rate of 221 cars per hour.
  • However, the success rate changes with speed:
    • Speeds 1 to 4 have a 100% success rate.
    • Speeds 5 to 8 have a 90% success rate.
    • Speeds 9 and 10 have a 77% success rate.
  • A speed of 0 produces 0 cars.

Your goal is to write functions that take the speed as input and correctly calculate the number of successfully produced cars per hour and per minute. This requires translating these business rules into robust, efficient Cairo code.

    ● Start: Receive Speed (0-10)
    │
    ▼
  ┌──────────────────┐
  │ Is speed == 0?   │
  └─────────┬────────┘
            │
      Yes ──┤
            │
            ▼
        ┌───────────┐
        │ Return 0  │
        └───────────┘
            │
            └──────────────────────────► ● End
            │
       No ──┤
            │
            ▼
    ◆ Speed Range Check
   ╱         │         ╲
 1-4       5-8       9-10
  │         │          │
  ▼         ▼          ▼
[100% Rate] [90% Rate] [77% Rate]
  │         │          │
  └─────────┼──────────┘
            │
            ▼
  ┌──────────────────┐
  │ Calculate Output │
  └──────────────────┘
            │
            ▼
        ● End

Why This Module is a Cornerstone for Learning Cairo

While seemingly simple, this module is a perfect vehicle for understanding several non-negotiable Cairo programming concepts. It’s not just about cars; it’s about building the mental models required for developing complex decentralized applications on Starknet.

Mastering Conditional Logic

The heart of the problem lies in applying different logic based on the value of the speed input. Cairo, like other modern languages, provides powerful constructs for this. This module forces you to deeply understand and compare two primary methods: the classic if-else if-else chain and the more expressive match statement. You'll learn not just how they work, but when to choose one over the other for clarity, safety, and performance.

Understanding Numerical Types

Cairo is a strongly typed language with a unique emphasis on field elements (felt252) but also provides standard integer types like u8, u32, and u256. This module requires you to handle numbers representing speed, production counts, and percentages. You'll learn the importance of choosing the right data type, how to perform arithmetic operations, and how to handle potential issues like type casting and floating-point emulation (since Cairo does not have native floats).

Building Reusable Functions

The problem is broken down into logical units: one function to calculate the hourly rate and another to calculate the minute rate. This structure teaches the importance of modularity and the Single Responsibility Principle. You will write clean, testable functions with clear inputs and outputs, a skill that is paramount for writing auditable and maintainable smart contracts.


How to Solve the "Cars Assemble" Challenge in Cairo

Let's break down the implementation step-by-step, from setting up the project to writing the final, optimized logic. This is where theory meets practice.

Step 1: Project Setup with Scarb

First, ensure you have the Cairo toolchain installed. We use Scarb, the official Cairo package manager, to create and manage our project. Open your terminal and run the following command:

scarb new cars_assemble
cd cars_assemble

This command creates a new directory named cars_assemble with the standard Cairo project structure, including a src/lib.cairo file where we'll write our logic and a Scarb.toml file for project configuration.

Step 2: Defining the Core Function with `if-else`

Let's start by implementing the production_rate_per_hour function using a traditional if-else structure. Open src/lib.cairo and add the following code. We'll use u8 for the speed since it's a small number (0-10), which is more memory-efficient and safer than a general-purpose felt252 for this specific domain.

fn production_rate_per_hour(speed: u8) -> u32 {
    let base_rate: u32 = 221;
    let total_cars: u32 = base_rate * (speed as u32);

    if speed >= 1 && speed <= 4 {
        // 100% success rate, so we return the total cars
        return total_cars;
    } else if speed >= 5 && speed <= 8 {
        // 90% success rate. We perform fixed-point arithmetic.
        // (total_cars * 90) / 100
        return (total_cars * 9) / 10;
    } else if speed == 9 || speed == 10 {
        // 77% success rate
        // (total_cars * 77) / 100
        return (total_cars * 77) / 100;
    } else {
        // Speed is 0 or an invalid value outside 1-10
        return 0;
    }
}

In this code, we first calculate the theoretical maximum number of cars. Then, we use an if-else if-else chain to check the speed and apply the corresponding success rate. Notice the use of (speed as u32) to cast the u8 speed to a u32 for multiplication. Since Cairo lacks floating-point numbers, we simulate percentage calculations using integer arithmetic (e.g., multiplying by 90 and dividing by 100).

Step 3: Refactoring with the `match` Statement

The if-else chain works, but Cairo's match statement often provides a more readable and safer alternative, especially when dealing with ranges or enumerated values. The compiler can also check match statements for exhaustiveness, ensuring you've handled all possible cases.

Here is the same logic implemented with a match statement:

fn production_rate_per_hour_match(speed: u8) -> u32 {
    let base_rate: u32 = 221;
    let total_cars: u32 = base_rate * (speed as u32);

    match speed {
        0 => 0,
        1..=4 => total_cars, // 100% rate
        5..=8 => (total_cars * 9) / 10, // 90% rate
        9..=10 => (total_cars * 77) / 100, // 77% rate
        _ => 0, // Catch-all for any other u8 value, though our logic is 0-10
    }
}

This version is arguably cleaner. The `..=` syntax creates an inclusive range, making the logic for each tier immediately obvious. The underscore `_` is a wildcard pattern that acts as a default case, which is crucial for handling any unexpected values and satisfying the compiler's exhaustiveness check.

Pros and Cons: `if-else` vs. `match`

Choosing between these two constructs is a key architectural decision. Here's a breakdown to guide your choice:

Aspect if-else if-else match Statement
Readability Can become nested and hard to follow with many conditions (the "arrow anti-pattern"). Generally flatter and more declarative, especially for multiple distinct cases or ranges. Easier to scan visually.
Safety The programmer is responsible for handling all cases. It's easy to miss a condition. The Cairo compiler enforces exhaustiveness. It will throw an error if you don't handle every possible value of the matched type, preventing bugs.
Flexibility Can handle complex boolean expressions (e.g., if x > 5 && y < 10) more directly in a single condition. Excels at pattern matching on a single variable's value, ranges, and struct destructuring. Complex boolean logic might require nested matches or `if` guards inside match arms.
Use Case Best for simple binary choices or conditions involving multiple unrelated variables. Ideal for state machines, checking enum variants, or applying logic based on ranges of a single variable, as in our "Cars Assemble" example.

Step 4: Calculating Items per Minute

The second part of the challenge is to create a function that calculates the working items produced per minute. This is a great example of function composition, where we reuse the logic we've already built.

fn working_items_per_minute(speed: u8) -> u32 {
    let hourly_rate = production_rate_per_hour_match(speed: speed);
    // There are 60 minutes in an hour
    return hourly_rate / 60;
}

This function is simple and elegant. It calls our previously defined production_rate_per_hour_match function to get the hourly production and then divides the result by 60. This promotes code reuse and separates concerns, making the codebase easier to maintain and test.

Step 5: Writing Tests

In smart contract development, testing is not optional. Cairo has a built-in testing framework. We can add tests to our src/lib.cairo file to verify our logic.

#[cfg(test)]
mod tests {
    use super::{production_rate_per_hour_match, working_items_per_minute};

    #[test]
    fn test_production_rate_at_speed_6() {
        // Speed 6: 221 * 6 = 1326 cars/hour theoretical
        // Success rate: 90%
        // 1326 * 0.9 = 1193.4. Integer division gives 1193.
        assert(production_rate_per_hour_match(6) == 1193, 'Rate at speed 6 failed');
    }

    #[test]
    fn test_production_rate_at_speed_10() {
        // Speed 10: 221 * 10 = 2210 cars/hour theoretical
        // Success rate: 77%
        // 2210 * 0.77 = 1701.7. Integer division gives 1701.
        assert(production_rate_per_hour_match(10) == 1701, 'Rate at speed 10 failed');
    }

    #[test]
    fn test_items_per_minute_at_speed_5() {
        // Speed 5: 221 * 5 = 1105. Rate is 90%. (1105 * 9)/10 = 994.
        // 994 / 60 = 16.56. Integer division gives 16.
        assert(working_items_per_minute(5) == 16, 'Items per minute failed');
    }
}

To run these tests, simply execute the following command in your terminal:

scarb test

Scarb will compile your code and run any function annotated with #[test]. If all assertions pass, you'll see a successful output, confirming your logic is correct.


The Kodikra Learning Path for "Cars Assemble"

The kodikra.com curriculum structures this module as a progressive learning path. Each exercise builds upon the last, solidifying your understanding before introducing new complexity. This ensures you build a robust mental model of Cairo's features.

    ● Module Start
    │
    ▼
  ┌───────────────────────────┐
  │ Exercise 1:               │
  │ Calculate Production Rate │
  │ (Core `match` logic)      │
  └────────────┬──────────────┘
               │
               ▼
  ┌───────────────────────────┐
  │ Exercise 2:               │
  │ Calculate Working Items   │
  │ (Function composition)    │
  └────────────┬──────────────┘
               │
               ▼
  ┌───────────────────────────┐
  │ Exercise 3: (Advanced)    │
  │ Calculate Production Cost │
  │ (Structs & more complex   │
  │  arithmetic)              │
  └────────────┬──────────────┘
               │
               ▼
           ● Module Complete

1. Foundational Logic: Calculate Production Rate

This is the first and most critical step. The goal is to implement the `production_rate_per_hour` function. You are encouraged to first try with an `if-else` block and then refactor it using a `match` statement to fully appreciate the differences in syntax and safety. This exercise hammers home conditional logic and basic arithmetic in Cairo.

Focus: fn, u8, u32, match, ranges (`..=`), return values.

Ready to build the core engine? Learn calculate_production_rate step by step.

2. Abstraction and Reuse: Calculate Working Items

Building on your completed first exercise, this task requires you to create the `working_items_per_minute` function. The key lesson here is not to repeat code. Instead, you should call your existing `production_rate_per_hour` function from within the new one. This teaches function composition and the DRY (Don't Repeat Yourself) principle, which are vital for writing clean code.

Focus: Function composition, integer division, code modularity.

Ready to make your code more efficient? Learn calculate_working_items step by step.

3. Advanced Application: Calculate Production Cost

In this more advanced, conceptual exercise, you would extend the logic to calculate the total production cost. This could involve defining a `struct` to hold cost parameters (e.g., cost per item, fixed hourly cost) and passing it to a new function. This challenges you to think about data structures and more complex calculations, mirroring real-world smart contract logic where you might calculate transaction fees or staking rewards based on various tiers.

Focus: `struct`, passing complex types to functions, advanced arithmetic.

Want to tackle a more complex challenge? Learn calculate_production_cost step by step.


Common Pitfalls and Future-Proofing Your Code

As you work through this module, you might encounter a few common issues. Being aware of them will help you write better, more resilient Cairo code.

  • Type Mismatches: A frequent error is trying to perform an operation between a felt252 and a u32 without explicit casting. Remember to use the as keyword (e.g., my_u8 as u32) when necessary. The compiler is your friend here; it will tell you exactly where the types don't match.
  • Integer Division Precision: When calculating percentages or rates, remember that division on integers in Cairo (like in most languages) truncates the decimal part. 10 / 3 is 3, not 3.33. For higher precision, use fixed-point arithmetic by multiplying by a large factor (e.g., 1000) first, doing all your calculations, and then dividing by that factor at the very end.
  • Forgetting the Match Wildcard: When using a match statement on a type like u8, it's easy to specify your expected ranges (0-10) and forget that a u8 can hold values up to 255. The compiler will force you to handle all possibilities. Always include a wildcard arm (_ => ...) to handle unexpected cases gracefully.

Technology Trend Predictions (Next 1-2 Years)

The Cairo language and Starknet ecosystem are evolving rapidly. Expect to see more advanced compiler optimizations related to match statements, potentially making them even more gas-efficient than complex if-else chains. Furthermore, as Cairo matures, more sophisticated data structures and libraries for handling fixed-point math will likely become standard, simplifying percentage and financial calculations in your smart contracts.


Frequently Asked Questions (FAQ)

Why use `u8` for speed instead of the default `felt252`?

While felt252 is the native field element in Starknet, for values that have a known, small, non-negative range (like a speed of 0-10), using a specific unsigned integer type like u8 (0-255) is better practice. It acts as a form of documentation, clearly stating the expected range of the input, and can lead to safer code by preventing underflow and leveraging type-specific optimizations.

What is `#[cfg(test)]` and `mod tests`?

This is Cairo's way of conditionally compiling code. The #[cfg(test)] attribute tells the compiler to only include the following module (mod tests) when you are running tests (i.e., with scarb test). This keeps your test code separate from your production logic and ensures it isn't deployed as part of your final smart contract, saving space and gas.

Can I use floating-point numbers like `f64` in Cairo?

No, Cairo 1.0 and later versions do not have native floating-point types. This is intentional for determinism, which is critical for blockchains. All calculations must be done with integers. To handle decimals, you must use fixed-point arithmetic, which involves scaling numbers by a power of 10, performing integer calculations, and then scaling them back down.

What happens if I provide a speed of 11 to my function?

In our match implementation, a speed of 11 (or any value greater than 10) would be caught by the wildcard arm: _ => 0. The function would safely return 0. In the if-else version, it would fall through all conditions and hit the final else { return 0; } block, also returning 0. This demonstrates the importance of having a default or fallback case.

Is the order of arms in a `match` statement important?

Yes, the `match` statement evaluates arms sequentially from top to bottom. It will execute the code for the first pattern that matches the value. For non-overlapping patterns like ours (0, 1..=4, 5..=8), the order doesn't change the logic. However, if you had overlapping patterns, the order would be critical.


Conclusion: Your First Step to Cairo Mastery

The "Cars Assemble" module is far more than a simple coding exercise; it's a foundational pillar in your journey to becoming a proficient Cairo developer. By completing this challenge, you have not only learned how to translate business logic into code but have also gained hands-on experience with Cairo's essential features: functions, types, and powerful conditional control flow. The choice between an if-else chain and a match statement is one you will make countless times, and now you have the context to make an informed decision based on readability, safety, and maintainability.

You are now equipped to tackle more complex problems. Use this momentum to continue exploring the rich features of Cairo and the Starknet ecosystem. The principles of modularity and testing you've applied here will serve as the bedrock for every smart contract you build.

Ready to continue your journey? Explore the complete Cairo Learning Path on Kodikra and discover the next set of challenges waiting for you.

Disclaimer: All code snippets and best practices are based on Cairo v2.6.x and Scarb v2.6.x. The Cairo language is under active development, and syntax or features may change in future versions.


Published by Kodikra — Your trusted Cairo learning resource.