# Three Numbers Are Not a Player.

Look at this line:

```rust
attack(enemy_health, 5, 2)
```

Three values. Two belong to the player. One belongs to the enemy.

Nothing in the code says which is which.

In this article, we are going to fix that by grouping those values into two new Rust types: a `Player` and an `Enemy`.

By the end, our code will start describing the things that actually exist in our game instead of asking us to remember what those numbers represent.

* * *

## Our starting point

You only need four small functions to follow along:

```rust
fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(
    health: u32,
    damage: u32,
) -> u32 {
    health.saturating_sub(damage)
}

fn is_defeated(health: u32) -> bool {
    health == 0
}

fn attack(
    health: u32,
    base_damage: u32,
    bonus_damage: u32,
) -> u32 {
    let damage =
        click_damage(base_damage, bonus_damage);

    health_after_hit(health, damage)
}
```

Our combat loop currently looks like this:

```rust
fn main() {
    let mut enemy_health = 20;

    while !is_defeated(enemy_health) {
        enemy_health =
            attack(enemy_health, 5, 2);

        println!(
            "Enemy health: {enemy_health}"
        );
    }

    println!("Enemy defeated!");
}
```

This code works.

The problem is not what it does.

The problem is what it says.

* * *

## Three numbers with three different meanings

Look at the attack again:

```rust
attack(enemy_health, 5, 2)
```

The first value represents the enemy.

The other two belong to the player.

But nothing in the function call makes those relationships clear.

Someone reading this code has to remember:

```text
enemy_health → the enemy's current health
5            → the player's base damage
2            → the player's bonus damage
```

That is manageable today.

It will become harder when our player also has:

*   a level
    
*   experience
    
*   gold
    
*   upgrade levels
    
*   passive damage
    

The enemy will need more information too:

*   a name
    
*   maximum health
    
*   gold rewards
    
*   experience rewards
    
Passing every single value as an individual number just isn't going to scale.

We need a way to tell Rust which values belong together.

* * *

## Give the player some shape

Rust lets us create our own types with `struct`.

Add this near the top of `main.rs`:

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}
```

A **struct** is a type that groups related values together.

Our new type is called:

```text
Player
```

It contains two named values:

```text
base_damage
bonus_damage
```

The named values inside a struct are called **fields**.

Each field has a type. The colon syntax is the same as a function parameter—it connects the name to the type:

```rust
base_damage: u32
bonus_damage: u32
```

So every `Player` has a field named `base_damage` that contains a `u32`, and a field named `bonus_damage` that also contains a `u32`.

The struct definition describes the shape of a player.

It does not create one yet.

* * *

## Create a player

Now that Rust knows what a `Player` looks like, we can create one:

```rust
let player = Player {
    base_damage: 5,
    bonus_damage: 2,
};
```

This creates a value with a type of: `Player`.

The values line up with the fields from our definition:

```text
Player
├── base_damage: 5
└── bonus_damage: 2
```

We can access a field with a dot:

```rust
player.base_damage
```

That gives us the player's base damage.

We can do the same for bonus damage:

```rust
player.bonus_damage
```

Our attack call can now become:

```rust
attack(
    enemy_health,
    player.base_damage,
    player.bonus_damage,
)
```

That does happen to be longer than:

```rust
attack(enemy_health, 5, 2)
```

But it is also clearer.

We no longer have to remember what `5` and `2` represent.

The code tells us.

* * *

## Give the enemy some shape

Our enemy is still represented by one loose variable:

```rust
let mut enemy_health = 20;
```

Health is not the only thing an enemy needs.

Even giving it a name creates another related value.

Add another struct:

```rust
struct Enemy {
    name: String,
    health: u32,
}
```

Our new `Enemy` type contains two fields:

```text
Enemy
├── name
└── health
```

We already know the type of `health`:

```rust
health: u32
```

The name introduces a new type:

```rust
name: String
```

* * *

## Give the enemy a name

`String` is a Rust type for storing owned text.

That fits our enemy: it should keep its own name for as long as it exists.

We can create a `String` from text like this:

```rust
String::from("Training Slime")
```

For now, read that as:

> Create a `String` containing "Training Slime."

Our game only needs enough text to name an enemy.

Now we can create one:

```rust
let enemy = Enemy {
    name: String::from("Training Slime"),
    health: 20,
};
```

Rust now understands that the name and health belong to the same enemy.

* * *

## The enemy still needs to change

There is one problem with our new enemy:

```rust
let enemy = Enemy {
    name: String::from("Training Slime"),
    health: 20,
};
```

Combat changes health.

But `enemy` is immutable by default.

If we try to assign a new value to:

```rust
enemy.health
```

Rust will refuse to compile the program.

We have already solved this problem once.

The enemy needs to be mutable:

```rust
let mut enemy = Enemy {
    name: String::from("Training Slime"),
    health: 20,
};
```

The `mut` applies to the `enemy` value, which allows us to change its fields:

```rust
enemy.health = 13;
```

We are not adding mutability everywhere.

The player does not need to change yet:

```rust
let player = Player {
```

The enemy does:

```rust
let mut enemy = Enemy {
```

Once again, the game tells us which values need to be mutable.

* * *

## Put the player and enemy into combat

We can now update `main()`:

```rust
fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    while !is_defeated(enemy.health) {
        enemy.health = attack(
            enemy.health,
            player.base_damage,
            player.bonus_damage,
        );

        println!(
            "{} health: {}",
            enemy.name,
            enemy.health
        );
    }

    println!("{} defeated!", enemy.name);
}
```

There is one small change in our `println!()` calls.

The `{}` placeholders are filled from left to right by the values that follow the format string:

```rust
println!(
    "{} health: {}",
    enemy.name,
    enemy.health
);
```

The first `{}` displays `enemy.name`.

The second displays `enemy.health`.

Run the game:

```bash
cargo run
```

You should see:

```text
Training Slime health: 13
Training Slime health: 6
Training Slime health: 0
Training Slime defeated!
```

The combat still works.

But the code now contains an actual player and enemy.

* * *

## Notice what the structs made visible

Before, our game looked like this:

```rust
let mut enemy_health = 20;

enemy_health =
    attack(enemy_health, 5, 2);
```

Now it looks like this:

```rust
let player = Player {
    base_damage: 5,
    bonus_damage: 2,
};

let mut enemy = Enemy {
    name: String::from("Training Slime"),
    health: 20,
};

enemy.health = attack(
    enemy.health,
    player.base_damage,
    player.bonus_damage,
);
```

The behavior is the same.

The meaning is not.

Before:

```text
20
5
2
```

Now:

```text
Player
├── base_damage
└── bonus_damage

Enemy
├── name
└── health
```

We gave related values names and grouped them into types.

Rust can now help us keep player data with the player and enemy data with the enemy.

* * *

## The behavior did not change

Notice what we did not touch:

```rust
click_damage()
```

still calculates damage.

```rust
health_after_hit()
```

still reduces health.

```rust
is_defeated()
```

still checks for defeat.

```rust
attack()
```

still combines the smaller rules.

We changed how the application organizes its data.

We did not rewrite the behavior we already trust.

Run the tests:

```bash
cargo test
```

All four should still pass.

No new combat rule was added in this article, so we do not need to invent a new behavior test just to prove that a struct can hold the values we typed into it.

The compiler checks that our struct fields exist and contain the expected types.

Our existing tests continue checking the game rules.

* * *

## The complete program

At this point, `src/main.rs` should look like this:

```rust
struct Player {
    base_damage: u32,
    bonus_damage: u32,
}

struct Enemy {
    name: String,
    health: u32,
}

fn click_damage(base: u32, bonus: u32) -> u32 {
    base.saturating_add(bonus)
}

fn health_after_hit(
    health: u32,
    damage: u32,
) -> u32 {
    health.saturating_sub(damage)
}

fn is_defeated(health: u32) -> bool {
    health == 0
}

fn attack(
    health: u32,
    base_damage: u32,
    bonus_damage: u32,
) -> u32 {
    let damage =
        click_damage(base_damage, bonus_damage);

    health_after_hit(health, damage)
}

fn main() {
    let player = Player {
        base_damage: 5,
        bonus_damage: 2,
    };

    let mut enemy = Enemy {
        name: String::from("Training Slime"),
        health: 20,
    };

    while !is_defeated(enemy.health) {
        enemy.health = attack(
            enemy.health,
            player.base_damage,
            player.bonus_damage,
        );

        println!(
            "{} health: {}",
            enemy.name,
            enemy.health
        );
    }

    println!("{} defeated!", enemy.name);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn click_damage_adds_base_and_bonus() {
        assert_eq!(click_damage(3, 4), 7);
    }

    #[test]
    fn health_never_drops_below_zero() {
        assert_eq!(
            health_after_hit(3, 10),
            0
        );
    }

    #[test]
    fn zero_health_is_defeated() {
        assert!(is_defeated(0));
        assert!(!is_defeated(1));
    }

    #[test]
    fn attack_reduces_enemy_health() {
        assert_eq!(attack(10, 5, 2), 3);
    }
}
```

Run both:

```bash
cargo run
cargo test
```

The game should defeat the Training Slime, and all four tests should pass.

* * *

## What we learned

Along the way, we encountered:

*   `struct`
    
*   custom Rust types
    
*   struct fields
    
*   creating struct values
    
*   field access with `.`
    
*   `String`
    
*   mutable struct values
    

You do not need to memorize all of that yet.

The important change is what happened to our data.

We started with:

```text
enemy_health
5
2
```

We turned those values into:

```text
Player
Enemy
```

Our program now has a vocabulary that matches the game we are building.

* * *

## There is still something awkward

We solved one problem.

But look at our attack again:

```rust
enemy.health = attack(
    enemy.health,
    player.base_damage,
    player.bonus_damage,
);
```

We created a `Player`.

We created an `Enemy`.

Then, the moment they need to interact, we pull them apart into individual fields.

`attack()` does not accept a player.

It does not accept an enemy.

It still accepts three numbers and returns another number that we manually assign back to the enemy.

What we really want to express is:

```text
player attacks enemy
```

That means our attack needs to:

```text
read the player
change the enemy
leave both available for the next attack
```

Rust has a way to let a function temporarily use values without taking them away from the code that already owns them.

That is called **borrowing**.

Next, we will let our player attack an enemy without consuming either one.

**Small function. Bigger game.**
