Darts in Cairo: Complete Solution & Deep Dive Guide

Pyramids visible over buildings and street traffic

Cairo Darts Challenge: Master Conditional Logic from Zero to Hero

Master the Cairo Darts scoring challenge by calculating dart-to-center distance using the Pythagorean theorem. This guide dives deep into conditional logic with if-else statements, helping you assign points based on whether a dart lands within the inner, middle, or outer circles of the target board.

You’ve just started your journey into the Starknet ecosystem, and you're ready to build. You imagine creating complex decentralized applications, on-chain games, or sophisticated DeFi protocols. But before you can build a skyscraper, you must first master the foundation. Often, the core logic of any complex system boils down to a series of simple, verifiable rules.

This is where fundamental challenges, like scoring a game of Darts, become invaluable. It feels simple, but it’s the perfect sandbox to master essential Cairo concepts: numerical computation, conditional branching, and function structure. This guide will walk you through solving this problem, transforming abstract geometric rules into concrete, efficient, and provable Cairo code.


What is the Darts Scoring Problem?

The Darts challenge, a classic problem from the exclusive kodikra.com curriculum, simulates scoring in a simplified darts game. The goal is to write a function that takes the Cartesian coordinates (x, y) of a dart's landing spot and returns the correct number of points based on its distance from the center of the target (the origin at (0, 0)).

The scoring is determined by four concentric circles:

  • Inner Circle (Bullseye): If the dart lands within or on the circle with a radius of 1 unit, the player scores 10 points.
  • Middle Circle: If the dart lands outside the inner circle but within or on the circle with a radius of 5 units, the player scores 5 points.
  • Outer Circle: If the dart lands outside the middle circle but within or on the circle with a radius of 10 units, the player scores 1 point.
  • Outside the Target: If the dart lands anywhere outside the outer circle (radius > 10), the player scores 0 points.

Our task is to implement this logic in a Cairo function that is both correct and efficient.


Why Use Cairo for This Challenge?

At first glance, using a cutting-edge language like Cairo for a simple geometry problem might seem like overkill. However, this perspective misses the fundamental purpose of Cairo. Cairo is designed for creating provable programs, where the correctness of a computation can be mathematically verified without re-executing it.

This Darts problem, while simple, perfectly encapsulates the "input -> computation -> verifiable output" model that is central to Starknet smart contracts. By solving it, you are not just learning geometry; you are practicing the core skills needed for on-chain development:

  • Strong Typing and Precision: Cairo's type system, using types like felt252 and integers (u8, u32, etc.), forces you to be precise about your data. This is critical in blockchain environments where small errors can have significant financial consequences.
  • Computational Efficiency: On a decentralized network, every computation has a cost. Learning to optimize your logic, even at this small scale, builds good habits for writing gas-efficient smart contracts.
  • Verifiable Logic: The conditional logic you write in Cairo can be translated into a STARK proof. This means you can prove that a certain score was awarded for a given (x, y) coordinate without revealing the exact coordinates, a concept with powerful privacy implications.

Mastering these fundamentals through the kodikra learning path prepares you for building complex, secure, and efficient decentralized applications on Starknet.


How to Approach the Solution: Geometry and Optimization

The heart of this problem lies in calculating the distance of the dart's landing point (x, y) from the center of the board (0, 0). This is a classic application of the Pythagorean theorem.

The Pythagorean Theorem in Code

The theorem states that for a right-angled triangle, the square of the hypotenuse (the side opposite the right angle, which is our distance d) is equal to the sum of the squares of the other two sides (our coordinates x and y).

The formula is: d² = x² + y²

To find the actual distance d, you would take the square root: d = sqrt(x² + y²).

However, performing square root operations is computationally expensive and can introduce floating-point inaccuracies, which are complexities we want to avoid in smart contracts. Cairo's core library does not have a native square root function for felt252 for this very reason.

The Optimization: Comparing Squared Distances

A much more efficient and precise method is to work with squared distances directly. If d <= radius, it is mathematically equivalent to say that d² <= radius². This allows us to bypass the costly square root calculation entirely.

Our new comparison logic becomes:

  • Is x² + y² <= 1² (i.e., 1)? If yes, 10 points.
  • Is x² + y² <= 5² (i.e., 25)? If yes, 5 points.
  • Is x² + y² <= 10² (i.e., 100)? If yes, 1 point.
  • Otherwise, 0 points.

This approach is faster, uses only integer arithmetic, and is perfectly suited for the constraints of the Cairo VM.

Logical Flow Diagram

Here is a visual representation of our decision-making process.

    ● Start: Input (x, y)
    │
    ▼
  ┌──────────────────────┐
  │ Calculate d² = x² + y² │
  └──────────┬───────────┘
             │
             ▼
    ◆ Is d² <= 1?
   ╱             ╲
 Yes (10 pts)     No
  │               │
  ▼               ▼
 ● End       ◆ Is d² <= 25?
            ╱             ╲
          Yes (5 pts)      No
           │               │
           ▼               ▼
          ● End       ◆ Is d² <= 100?
                     ╱             ╲
                   Yes (1 pt)       No (0 pts)
                    │               │
                    ▼               ▼
                   ● End           ● End

Where the Code Comes Together: The Cairo Implementation

Now, let's translate our logic into a complete Cairo function. We will define a function named score that accepts two felt252 arguments, x and y, and returns a u8 representing the score.

The felt252 type is a "field element," the native integer type in Cairo, capable of holding large numbers. The score, however, will only be 0, 1, 5, or 10, so a u8 (an 8-bit unsigned integer, range 0-255) is the most appropriate and gas-efficient return type.

The Final Cairo Code

// This function calculates the score for a dart toss in a game.
// It takes the x and y coordinates of the dart's landing position
// as felt252 values and returns the score as a u8 integer.

fn score(x: felt252, y: felt252) -> u8 {
    // Calculate the square of the distance from the origin (0,0).
    // We use squared distance to avoid a costly square root operation.
    // This is a common optimization in computational geometry.
    // Since x and y can be negative, squaring them ensures a non-negative result.
    let distance_squared = x * x + y * y;

    // Now, we use a series of if-else if-else statements to check which
    // scoring circle the dart landed in. We must check from the smallest
    // radius (inner circle) to the largest (outer circle).

    // Inner Circle (Bullseye): radius = 1, squared radius = 1.
    // If the squared distance is less than or equal to 1, it's a bullseye.
    if distance_squared <= 1 {
        10_u8
    } 
    // Middle Circle: radius = 5, squared radius = 25.
    // If it's not in the bullseye, check if it's within the middle circle.
    else if distance_squared <= 25 {
        5_u8
    } 
    // Outer Circle: radius = 10, squared radius = 100.
    // If not in the middle circle, check the outer one.
    else if distance_squared <= 100 {
        1_u8
    } 
    // Outside all circles (a miss).
    // If none of the above conditions are met, the dart missed the board.
    else {
        0_u8
    }
}

Step-by-Step Code Walkthrough

  1. Function Signature: fn score(x: felt252, y: felt252) -> u8 declares a function named score. It takes two parameters, x and y, both of type felt252. It specifies that the function will return a value of type u8.
  2. Distance Calculation: let distance_squared = x * x + y * y; calculates the squared distance. We declare an immutable variable distance_squared and assign it the result of x² + y². This works correctly even if x or y are negative, as their squares will always be non-negative.
  3. Conditional Block (Bullseye): if distance_squared <= 1 checks if the dart is in the inner circle. The squared radius is 1*1 = 1. If this condition is true, the function immediately returns 10_u8. The _u8 suffix is a type cast, explicitly telling the compiler this is a u8 value.
  4. Conditional Block (Middle Circle): else if distance_squared <= 25 is only evaluated if the first condition was false. It checks against the squared radius of the middle circle (5*5 = 25). If true, it returns 5_u8.
  5. Conditional Block (Outer Circle): else if distance_squared <= 100 is the next check, for the outer circle's squared radius (10*10 = 100). If true, it returns 1_u8.
  6. Final Else Block (Miss): The final else block acts as a catch-all. If none of the previous conditions were met, the dart must be outside the target. The function returns 0_u8.

Data Flow Visualization

This diagram illustrates how data moves through our function from input to final output.

  ┌──────────────────┐
  │ Input: x, y      │
  │ (Type: felt252)  │
  └─────────┬────────┘
            │
            ▼
  ┌──────────────────┐
  │ Computation:     │
  │ d² = x*x + y*y   │
  └─────────┬────────┘
            │
            ▼
  ┌──────────────────┐
  │ Conditional Logic│
  │ (if-else chain)  │
  ├──────────────────┤
  │ d² <= 1   ⟶ 10   │
  │ d² <= 25  ⟶ 5    │
  │ d² <= 100 ⟶ 1    │
  │ else      ⟶ 0    │
  └─────────┬────────┘
            │
            ▼
  ┌──────────────────┐
  │ Output: score    │
  │ (Type: u8)       │
  └──────────────────┘

Evaluating Alternative Approaches and Best Practices

While the `if-else` chain is the most straightforward and readable solution for this problem, it's useful to consider the trade-offs involved. This critical thinking is key to becoming an expert developer.

Pros and Cons of the Squared Distance Method

Aspect Squared Distance (Our Method) Actual Distance (Square Root)
Performance Highly efficient. Uses only multiplication and addition, which are fast operations in the Cairo VM. Computationally expensive. Requires a complex square root algorithm, which would consume significantly more gas.
Precision Perfectly precise. Works entirely with integers (felt252), avoiding any rounding or floating-point errors. Prone to precision issues. Square roots of non-perfect squares are irrational, requiring approximation and potential for errors.
Cairo Compatibility Ideal. Leverages Cairo's native arithmetic on field elements directly. Poor. Requires implementing or importing a complex math library for square roots, which is non-standard for felt252.
Readability Very readable once the concept is understood. The logic directly maps to the problem's constraints. Slightly more intuitive at first glance as it uses the direct distance formula, but the implementation complexity hides the logic.

Future-Proofing Your Logic

As Cairo evolves, new language features might offer different ways to structure this logic. For instance, future versions might enhance pattern matching capabilities that could be used as an alternative to `if-else` chains for certain problems. However, for a series of range checks like this, the `if-else` structure remains the gold standard for clarity and efficiency. It is a fundamental pattern you will use throughout your Cairo development career.

The core takeaway is to always think about the computational environment. On a blockchain like Starknet, every operation matters. Choosing an algorithm that avoids complex math like square roots is a crucial optimization skill.


Frequently Asked Questions (FAQ)

Why not use floating-point numbers in Cairo for this?

Cairo, like many blockchain-focused languages, does not have native floating-point types. This is intentional. Floating-point arithmetic can lead to non-deterministic results and rounding errors, which are unacceptable in a consensus-driven system where every node must arrive at the exact same result. All calculations are done with integers or field elements to ensure absolute precision and verifiability.

What exactly is felt252 and why is it used for coordinates?

felt252 stands for "field element of 252 bits." It is the primitive data type in Cairo. It represents a number in a large finite field, which is a core concept in the cryptography behind STARK proofs. For practical purposes, you can think of it as a very large integer. We use it for coordinates because it's the most natural and efficient type for general-purpose computation in Cairo.

How could this Darts logic be used in a real Starknet smart contract?

This logic is a building block for on-chain games. Imagine a decentralized game where a player submits a transaction with a "randomly" generated coordinate. The smart contract, using this exact score function, could verifiably calculate the points and award tokens or NFTs to the player's wallet. The provability of Cairo ensures the player cannot cheat the scoring logic.

How do I test this Cairo code?

You would use the Starknet toolchain, specifically Scarb. You would place this function in a Cairo library file and then write a corresponding test file with a #[test] attribute. Inside the test, you would call the score function with various coordinates (e.g., score(0, 0), score(4, 4), score(10, 10)) and use the assert! macro to verify that it returns the expected scores.

Why is the order of checks (inner circle first) important?

The order is crucial for correctness. If you checked for the outer circle first (distance_squared <= 100), a bullseye toss (e.g., at (0,0)) would satisfy this condition and incorrectly return 1 point. By checking from the smallest radius to the largest, we ensure that a point is categorized by the most specific (and highest-scoring) circle it falls into.

What are common pitfalls when working with coordinates in Cairo?

A common pitfall is forgetting about potential integer overflows if you are not using felt252. If you were using a fixed-size integer like u64, calculating x*x could exceed the maximum value if x is large. Using felt252 largely mitigates this for typical use cases due to its massive size, but it's always important to be mindful of the range of your inputs.

Is there a way to solve this without an if-else chain?

While `if-else` is the most idiomatic solution, you could theoretically use boolean logic and arithmetic. For example: `let is_bullseye = distance_squared <= 1; let score = is_bullseye * 10; ...`. However, this often becomes much less readable and less efficient than a simple, short-circuiting `if-else` chain. For this specific problem, the `if-else` structure is superior.


Conclusion: From Geometry to Verifiable Computation

You have successfully translated a real-world problem into efficient, provable Cairo code. By solving the Darts challenge, you've done more than just score a game; you've practiced fundamental skills essential for any Starknet developer. You learned how to apply the Pythagorean theorem, optimized it by using squared distances to avoid costly operations, and implemented the logic using Cairo's clear and concise conditional statements.

This exercise from the kodikra.com curriculum demonstrates how core programming principles are the bedrock of advanced blockchain development. The patterns you've mastered here—precise data types, computational optimization, and clear logical flow—will appear again and again as you build more complex systems.

Ready to tackle the next challenge? Continue your journey by exploring the full Cairo 2 Learning Path, where you'll build upon these skills to create even more powerful applications. For a deeper dive into the language itself, be sure to consult our comprehensive Cairo language guide.

Disclaimer: The code and explanations in this article are based on Cairo v2.6.3 and the Starknet toolchain as of the current date. The Cairo language and its ecosystem are under active development, and syntax or best practices may evolve.


Published by Kodikra — Your trusted Cairo learning resource.