From 25463bc029899593c6c15ceb3a7655c9cca375e8 Mon Sep 17 00:00:00 2001 From: Mmeso Love Date: Wed, 30 Apr 2025 20:24:52 +0100 Subject: [PATCH 1/4] added helper's experience --- .../src/helpers/experience_utils.cairo | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo diff --git a/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo b/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo new file mode 100644 index 0000000..611e39e --- /dev/null +++ b/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo @@ -0,0 +1,55 @@ +#[starknet::interface] +trait IExperienceCalculator { + fn calculate_experience(ref self: TContractState, level: u32) -> u32; + fn check_level_up(ref self: TContractState, current_level: u32, current_exp: u32) -> bool; + fn calculate_remaining_exp(ref self: TContractState, current_level: u32, current_exp: u32) -> u32; +} + +#[starknet::contract] +mod ExperienceCalculator { + use starknet::ContractAddress; + use zeroable::Zeroable; + use traits::TryInto; + use integer::{U256TryIntoFelt252, U256FromFelt252}; + + #[storage] + struct Storage { + base_exp: u32, + exp_multiplier: u32, + } + + #[constructor] + fn constructor(ref self: ContractState, base_exp: u32, exp_multiplier: u32) { + self.base_exp.write(base_exp); + self.exp_multiplier.write(exp_multiplier); + } + + #[external(v0)] + impl ExperienceCalculatorImpl of super::IExperienceCalculator { + fn calculate_experience(ref self: ContractState, level: u32) -> u32 { + let base_exp: felt252 = self.base_exp.read().into(); + let exp_multiplier: felt252 = self.exp_multiplier.read().into(); + let level_felt: felt252 = level.into(); + + // Calculate: base_exp * (level * exp_multiplier) + let result = base_exp * (level_felt * exp_multiplier); + + // Convert back to u32 + result.try_into().unwrap() + } + + fn check_level_up(ref self: ContractState, current_level: u32, current_exp: u32) -> bool { + let required_exp = self.calculate_experience(current_level); + current_exp >= required_exp + } + + fn calculate_remaining_exp(ref self: ContractState, current_level: u32, current_exp: u32) -> u32 { + let required_exp = self.calculate_experience(current_level); + if current_exp >= required_exp { + 0 + } else { + required_exp - current_exp + } + } + } +} \ No newline at end of file From 85a222e46510cda7fc103f887c65ceee5d462019 Mon Sep 17 00:00:00 2001 From: Mmeso Love Date: Fri, 2 May 2025 12:50:16 +0100 Subject: [PATCH 2/4] added files --- .../src/helpers/experience_utils.cairo | 198 +++++++++++++----- .../src/tests/test.experience_utils.cairo | 90 ++++++++ client/src/experinece_utils.cairo | 55 +++++ 3 files changed, 296 insertions(+), 47 deletions(-) create mode 100644 backend/dojo_examples/combat_game/src/tests/test.experience_utils.cairo create mode 100644 client/src/experinece_utils.cairo diff --git a/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo b/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo index 611e39e..4cdc549 100644 --- a/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo +++ b/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo @@ -1,55 +1,159 @@ -#[starknet::interface] -trait IExperienceCalculator { - fn calculate_experience(ref self: TContractState, level: u32) -> u32; - fn check_level_up(ref self: TContractState, current_level: u32, current_exp: u32) -> bool; - fn calculate_remaining_exp(ref self: TContractState, current_level: u32, current_exp: u32) -> u32; -} - -#[starknet::contract] -mod ExperienceCalculator { - use starknet::ContractAddress; - use zeroable::Zeroable; - use traits::TryInto; - use integer::{U256TryIntoFelt252, U256FromFelt252}; +use core::traits::Into; - #[storage] - struct Storage { - base_exp: u32, - exp_multiplier: u32, +#[generate_trait] +pub impl ExperienceCalculator of ExperienceCalculatorTrait { + + fn calculate_exp_needed_for_level(level: u8) -> u16 { + let level_u16: u16 = level.into(); + level_u16 * level_u16 * 10 } - - #[constructor] - fn constructor(ref self: ContractState, base_exp: u32, exp_multiplier: u32) { - self.base_exp.write(base_exp); - self.exp_multiplier.write(exp_multiplier); + + fn should_level_up(current_level: u8, current_exp: u16) -> bool { + let exp_needed = Self::calculate_exp_needed_for_level(current_level); + current_exp >= exp_needed } - - #[external(v0)] - impl ExperienceCalculatorImpl of super::IExperienceCalculator { - fn calculate_experience(ref self: ContractState, level: u32) -> u32 { - let base_exp: felt252 = self.base_exp.read().into(); - let exp_multiplier: felt252 = self.exp_multiplier.read().into(); - let level_felt: felt252 = level.into(); - - // Calculate: base_exp * (level * exp_multiplier) - let result = base_exp * (level_felt * exp_multiplier); - - // Convert back to u32 - result.try_into().unwrap() + + fn remaining_exp_after_level_up(current_level: u8, current_exp: u16) -> u16 { + let exp_needed = Self::calculate_exp_needed_for_level(current_level); + if current_exp >= exp_needed { + current_exp - exp_needed + } else { + current_exp } + } +} - fn check_level_up(ref self: ContractState, current_level: u32, current_exp: u32) -> bool { - let required_exp = self.calculate_experience(current_level); - current_exp >= required_exp - } +#[cfg(test)] +mod experience_calculator_tests { + use super::{ExperienceCalculator}; - fn calculate_remaining_exp(ref self: ContractState, current_level: u32, current_exp: u32) -> u32 { - let required_exp = self.calculate_experience(current_level); - if current_exp >= required_exp { - 0 - } else { - required_exp - current_exp - } + #[test] + #[available_gas(1000000)] + fn test_calculate_exp_needed_for_level() { + // Test values for different levels to verify the formula level² × 10 + + // Level 1: 1² × 10 = 10 + let exp_level_1 = ExperienceCalculator::calculate_exp_needed_for_level(1); + assert(exp_level_1 == 10, 'Level 1 should need 10 exp'); + + // Level 2: 2² × 10 = 40 + let exp_level_2 = ExperienceCalculator::calculate_exp_needed_for_level(2); + assert(exp_level_2 == 40, 'Level 2 should need 40 exp'); + + // Level 5: 5² × 10 = 250 + let exp_level_5 = ExperienceCalculator::calculate_exp_needed_for_level(5); + assert(exp_level_5 == 250, 'Level 5 should need 250 exp'); + + // Level 10: 10² × 10 = 1000 + let exp_level_10 = ExperienceCalculator::calculate_exp_needed_for_level(10); + assert(exp_level_10 == 1000, 'Level 10 should need 1000 exp'); + + // Level 20: 20² × 10 = 4000 + let exp_level_20 = ExperienceCalculator::calculate_exp_needed_for_level(20); + assert(exp_level_20 == 4000, 'Level 20 should need 4000 exp'); + } + + #[test] + #[available_gas(1000000)] + fn test_should_level_up() { + // Level 1 (needs 10 exp) + + // 9 exp: should not level up + let should_level_up_1_9 = ExperienceCalculator::should_level_up(1, 9); + assert(!should_level_up_1_9, 'Level 1 with 9 exp not level up'); + + // 10 exp: should level up + let should_level_up_1_10 = ExperienceCalculator::should_level_up(1, 10); + assert(should_level_up_1_10, 'Level 1 with 10 exp level up'); + + // 15 exp: should level up + let should_level_up_1_15 = ExperienceCalculator::should_level_up(1, 15); + assert(should_level_up_1_15, 'Level 1 with 15 exp level up'); + + // Level 5 (needs 250 exp) + + // 249 exp: should not level up + let should_level_up_5_249 = ExperienceCalculator::should_level_up(5, 249); + assert(!should_level_up_5_249, 'Level 5 249 exp not level up'); + + // 250 exp: should level up + let should_level_up_5_250 = ExperienceCalculator::should_level_up(5, 250); + assert(should_level_up_5_250, 'Level 5 with 250 exp level up'); + + // 300 exp: should level up + let should_level_up_5_300 = ExperienceCalculator::should_level_up(5, 300); + assert(should_level_up_5_300, 'Level 5 with 300 exp level up'); + } + + #[test] + #[available_gas(1000000)] + fn test_remaining_exp_after_level_up() { + // Level 1 (needs 10 exp) + + // 9 exp: should remain at 9 (no level up) + let remaining_1_9 = ExperienceCalculator::remaining_exp_after_level_up(1, 9); + assert(remaining_1_9 == 9, 'Level 1 with 9 exp keep 9'); + + // 10 exp: should remain at 0 (level up) + let remaining_1_10 = ExperienceCalculator::remaining_exp_after_level_up(1, 10); + assert(remaining_1_10 == 0, 'Level 1 with 10 exp 0 remaining'); + + // 15 exp: should remain at 5 (level up) + let remaining_1_15 = ExperienceCalculator::remaining_exp_after_level_up(1, 15); + assert(remaining_1_15 == 5, 'Level 1 with 15 exp 5 remaining'); + + // Level 5 (needs 250 exp) + + // 300 exp: should remain at 50 (level up) + let remaining_5_300 = ExperienceCalculator::remaining_exp_after_level_up(5, 300); + assert(remaining_5_300 == 50, 'Level 5 300 exp 50 remaining'); + } + + #[test] + #[available_gas(1000000)] + fn test_multiple_level_ups_simulation() { + // Simulate a scenario where a beast levels up multiple times + + // Beast level 1 with 0 initial exp + let mut current_level = 1_u8; + let mut current_exp = 0_u16; + + // Earned 20 exp + current_exp += 20; + + // Validate if it should level up + let should_level = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(should_level, 'Level up after more 20 exp'); + + // Level up and update remaining exp + if should_level { + current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); + current_level += 1; + } + + // Verify final values + assert(current_level == 2, 'Should now be level 2'); + assert(current_exp == 10, 'Should have 10 exp remaining'); + + // Earned 50 more exp + current_exp += 50; + + // Validate if it should level up again + let should_level_again = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(should_level_again, 'Level up 60 exp at level 2'); + + // Level up again + if should_level_again { + current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); + current_level += 1; } + + // Verify final values + assert(current_level == 3, 'Should now be level 3'); + assert(current_exp == 20, 'Should have 20 exp remaining'); + + // Should not level up to level 4 yet + let not_enough_for_level4 = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(!not_enough_for_level4, 'Should not reach level 4 yet'); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/backend/dojo_examples/combat_game/src/tests/test.experience_utils.cairo b/backend/dojo_examples/combat_game/src/tests/test.experience_utils.cairo new file mode 100644 index 0000000..52d1ca0 --- /dev/null +++ b/backend/dojo_examples/combat_game/src/tests/test.experience_utils.cairo @@ -0,0 +1,90 @@ +use core::debug::PrintTrait; +use core::traits::Into; +use core::test::test_utils::assert_eq; + +use combat_game::helpers::experience_utils::{ExperienceCalculator, ExperienceCalculatorTrait, ExperienceCalculatorImpl}; + +#[test] +fn test_calculate_exp_needed_for_level() { + // Test level 1 + let exp_needed = ExperienceCalculatorImpl::calculate_exp_needed_for_level(1); + assert_eq(exp_needed, 10, 'Level 1 should need 10 exp'); + + // Test level 2 + let exp_needed = ExperienceCalculatorImpl::calculate_exp_needed_for_level(2); + assert_eq(exp_needed, 40, 'Level 2 should need 40 exp'); + + // Test level 5 + let exp_needed = ExperienceCalculatorImpl::calculate_exp_needed_for_level(5); + assert_eq(exp_needed, 250, 'Level 5 should need 250 exp'); + + // Test level 10 + let exp_needed = ExperienceCalculatorImpl::calculate_exp_needed_for_level(10); + assert_eq(exp_needed, 1000, 'Level 10 should need 1000 exp'); + + // Test level 20 + let exp_needed = ExperienceCalculatorImpl::calculate_exp_needed_for_level(20); + assert_eq(exp_needed, 4000, 'Level 20 should need 4000 exp'); +} + +#[test] +fn test_should_level_up() { + // Test level 1 with enough exp + let should_level = ExperienceCalculatorImpl::should_level_up(1, 10); + assert_eq(should_level, true, 'Should level up with exact exp needed'); + + // Test level 1 with not enough exp + let should_level = ExperienceCalculatorImpl::should_level_up(1, 9); + assert_eq(should_level, false, 'Should not level up with insufficient exp'); + + // Test level 2 with more than enough exp + let should_level = ExperienceCalculatorImpl::should_level_up(2, 50); + assert_eq(should_level, true, 'Should level up with excess exp'); + + // Test level 5 with exact exp needed + let should_level = ExperienceCalculatorImpl::should_level_up(5, 250); + assert_eq(should_level, true, 'Should level up with exact exp needed'); +} + +#[test] +fn test_remaining_exp_after_level_up() { + // Test level 1 with exact exp needed + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(1, 10); + assert_eq(remaining, 0, 'Should have 0 exp remaining after level up'); + + // Test level 1 with excess exp + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(1, 15); + assert_eq(remaining, 5, 'Should have 5 exp remaining after level up'); + + // Test level 2 with not enough exp + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(2, 30); + assert_eq(remaining, 30, 'Should keep current exp if not enough for level up'); + + // Test level 5 with excess exp + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(5, 300); + assert_eq(remaining, 50, 'Should have 50 exp remaining after level up'); +} + +#[test] +fn test_multiple_sequential_level_ups() { + let mut current_level: u8 = 1; + let mut current_exp: u16 = 100; + + // First level up + let should_level = ExperienceCalculatorImpl::should_level_up(current_level, current_exp); + assert_eq(should_level, true, 'Should level up first time'); + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(current_level, current_exp); + current_exp = remaining; + current_level += 1; + + // Second level up + let should_level = ExperienceCalculatorImpl::should_level_up(current_level, current_exp); + assert_eq(should_level, true, 'Should level up second time'); + let remaining = ExperienceCalculatorImpl::remaining_exp_after_level_up(current_level, current_exp); + current_exp = remaining; + current_level += 1; + + // Check final state + assert_eq(current_level, 3, 'Should be level 3 after two level ups'); + assert_eq(current_exp, 20, 'Should have 20 exp remaining after two level ups'); +} \ No newline at end of file diff --git a/client/src/experinece_utils.cairo b/client/src/experinece_utils.cairo new file mode 100644 index 0000000..611e39e --- /dev/null +++ b/client/src/experinece_utils.cairo @@ -0,0 +1,55 @@ +#[starknet::interface] +trait IExperienceCalculator { + fn calculate_experience(ref self: TContractState, level: u32) -> u32; + fn check_level_up(ref self: TContractState, current_level: u32, current_exp: u32) -> bool; + fn calculate_remaining_exp(ref self: TContractState, current_level: u32, current_exp: u32) -> u32; +} + +#[starknet::contract] +mod ExperienceCalculator { + use starknet::ContractAddress; + use zeroable::Zeroable; + use traits::TryInto; + use integer::{U256TryIntoFelt252, U256FromFelt252}; + + #[storage] + struct Storage { + base_exp: u32, + exp_multiplier: u32, + } + + #[constructor] + fn constructor(ref self: ContractState, base_exp: u32, exp_multiplier: u32) { + self.base_exp.write(base_exp); + self.exp_multiplier.write(exp_multiplier); + } + + #[external(v0)] + impl ExperienceCalculatorImpl of super::IExperienceCalculator { + fn calculate_experience(ref self: ContractState, level: u32) -> u32 { + let base_exp: felt252 = self.base_exp.read().into(); + let exp_multiplier: felt252 = self.exp_multiplier.read().into(); + let level_felt: felt252 = level.into(); + + // Calculate: base_exp * (level * exp_multiplier) + let result = base_exp * (level_felt * exp_multiplier); + + // Convert back to u32 + result.try_into().unwrap() + } + + fn check_level_up(ref self: ContractState, current_level: u32, current_exp: u32) -> bool { + let required_exp = self.calculate_experience(current_level); + current_exp >= required_exp + } + + fn calculate_remaining_exp(ref self: ContractState, current_level: u32, current_exp: u32) -> u32 { + let required_exp = self.calculate_experience(current_level); + if current_exp >= required_exp { + 0 + } else { + required_exp - current_exp + } + } + } +} \ No newline at end of file From e3c8729a4358535dcb92cb2c68a4dc924c5aa435 Mon Sep 17 00:00:00 2001 From: Mmeso Love Date: Mon, 5 May 2025 07:12:36 +0100 Subject: [PATCH 3/4] deleted file --- .../src/helpers/experience_utils.cairo | 159 ------------------ client/src/experinece_utils.cairo | 55 ------ 2 files changed, 214 deletions(-) delete mode 100644 backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo delete mode 100644 client/src/experinece_utils.cairo diff --git a/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo b/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo deleted file mode 100644 index 4cdc549..0000000 --- a/backend/dojo_examples/combat_game/src/helpers/experience_utils.cairo +++ /dev/null @@ -1,159 +0,0 @@ -use core::traits::Into; - -#[generate_trait] -pub impl ExperienceCalculator of ExperienceCalculatorTrait { - - fn calculate_exp_needed_for_level(level: u8) -> u16 { - let level_u16: u16 = level.into(); - level_u16 * level_u16 * 10 - } - - fn should_level_up(current_level: u8, current_exp: u16) -> bool { - let exp_needed = Self::calculate_exp_needed_for_level(current_level); - current_exp >= exp_needed - } - - fn remaining_exp_after_level_up(current_level: u8, current_exp: u16) -> u16 { - let exp_needed = Self::calculate_exp_needed_for_level(current_level); - if current_exp >= exp_needed { - current_exp - exp_needed - } else { - current_exp - } - } -} - -#[cfg(test)] -mod experience_calculator_tests { - use super::{ExperienceCalculator}; - - #[test] - #[available_gas(1000000)] - fn test_calculate_exp_needed_for_level() { - // Test values for different levels to verify the formula level² × 10 - - // Level 1: 1² × 10 = 10 - let exp_level_1 = ExperienceCalculator::calculate_exp_needed_for_level(1); - assert(exp_level_1 == 10, 'Level 1 should need 10 exp'); - - // Level 2: 2² × 10 = 40 - let exp_level_2 = ExperienceCalculator::calculate_exp_needed_for_level(2); - assert(exp_level_2 == 40, 'Level 2 should need 40 exp'); - - // Level 5: 5² × 10 = 250 - let exp_level_5 = ExperienceCalculator::calculate_exp_needed_for_level(5); - assert(exp_level_5 == 250, 'Level 5 should need 250 exp'); - - // Level 10: 10² × 10 = 1000 - let exp_level_10 = ExperienceCalculator::calculate_exp_needed_for_level(10); - assert(exp_level_10 == 1000, 'Level 10 should need 1000 exp'); - - // Level 20: 20² × 10 = 4000 - let exp_level_20 = ExperienceCalculator::calculate_exp_needed_for_level(20); - assert(exp_level_20 == 4000, 'Level 20 should need 4000 exp'); - } - - #[test] - #[available_gas(1000000)] - fn test_should_level_up() { - // Level 1 (needs 10 exp) - - // 9 exp: should not level up - let should_level_up_1_9 = ExperienceCalculator::should_level_up(1, 9); - assert(!should_level_up_1_9, 'Level 1 with 9 exp not level up'); - - // 10 exp: should level up - let should_level_up_1_10 = ExperienceCalculator::should_level_up(1, 10); - assert(should_level_up_1_10, 'Level 1 with 10 exp level up'); - - // 15 exp: should level up - let should_level_up_1_15 = ExperienceCalculator::should_level_up(1, 15); - assert(should_level_up_1_15, 'Level 1 with 15 exp level up'); - - // Level 5 (needs 250 exp) - - // 249 exp: should not level up - let should_level_up_5_249 = ExperienceCalculator::should_level_up(5, 249); - assert(!should_level_up_5_249, 'Level 5 249 exp not level up'); - - // 250 exp: should level up - let should_level_up_5_250 = ExperienceCalculator::should_level_up(5, 250); - assert(should_level_up_5_250, 'Level 5 with 250 exp level up'); - - // 300 exp: should level up - let should_level_up_5_300 = ExperienceCalculator::should_level_up(5, 300); - assert(should_level_up_5_300, 'Level 5 with 300 exp level up'); - } - - #[test] - #[available_gas(1000000)] - fn test_remaining_exp_after_level_up() { - // Level 1 (needs 10 exp) - - // 9 exp: should remain at 9 (no level up) - let remaining_1_9 = ExperienceCalculator::remaining_exp_after_level_up(1, 9); - assert(remaining_1_9 == 9, 'Level 1 with 9 exp keep 9'); - - // 10 exp: should remain at 0 (level up) - let remaining_1_10 = ExperienceCalculator::remaining_exp_after_level_up(1, 10); - assert(remaining_1_10 == 0, 'Level 1 with 10 exp 0 remaining'); - - // 15 exp: should remain at 5 (level up) - let remaining_1_15 = ExperienceCalculator::remaining_exp_after_level_up(1, 15); - assert(remaining_1_15 == 5, 'Level 1 with 15 exp 5 remaining'); - - // Level 5 (needs 250 exp) - - // 300 exp: should remain at 50 (level up) - let remaining_5_300 = ExperienceCalculator::remaining_exp_after_level_up(5, 300); - assert(remaining_5_300 == 50, 'Level 5 300 exp 50 remaining'); - } - - #[test] - #[available_gas(1000000)] - fn test_multiple_level_ups_simulation() { - // Simulate a scenario where a beast levels up multiple times - - // Beast level 1 with 0 initial exp - let mut current_level = 1_u8; - let mut current_exp = 0_u16; - - // Earned 20 exp - current_exp += 20; - - // Validate if it should level up - let should_level = ExperienceCalculator::should_level_up(current_level, current_exp); - assert(should_level, 'Level up after more 20 exp'); - - // Level up and update remaining exp - if should_level { - current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); - current_level += 1; - } - - // Verify final values - assert(current_level == 2, 'Should now be level 2'); - assert(current_exp == 10, 'Should have 10 exp remaining'); - - // Earned 50 more exp - current_exp += 50; - - // Validate if it should level up again - let should_level_again = ExperienceCalculator::should_level_up(current_level, current_exp); - assert(should_level_again, 'Level up 60 exp at level 2'); - - // Level up again - if should_level_again { - current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); - current_level += 1; - } - - // Verify final values - assert(current_level == 3, 'Should now be level 3'); - assert(current_exp == 20, 'Should have 20 exp remaining'); - - // Should not level up to level 4 yet - let not_enough_for_level4 = ExperienceCalculator::should_level_up(current_level, current_exp); - assert(!not_enough_for_level4, 'Should not reach level 4 yet'); - } -} \ No newline at end of file diff --git a/client/src/experinece_utils.cairo b/client/src/experinece_utils.cairo deleted file mode 100644 index 611e39e..0000000 --- a/client/src/experinece_utils.cairo +++ /dev/null @@ -1,55 +0,0 @@ -#[starknet::interface] -trait IExperienceCalculator { - fn calculate_experience(ref self: TContractState, level: u32) -> u32; - fn check_level_up(ref self: TContractState, current_level: u32, current_exp: u32) -> bool; - fn calculate_remaining_exp(ref self: TContractState, current_level: u32, current_exp: u32) -> u32; -} - -#[starknet::contract] -mod ExperienceCalculator { - use starknet::ContractAddress; - use zeroable::Zeroable; - use traits::TryInto; - use integer::{U256TryIntoFelt252, U256FromFelt252}; - - #[storage] - struct Storage { - base_exp: u32, - exp_multiplier: u32, - } - - #[constructor] - fn constructor(ref self: ContractState, base_exp: u32, exp_multiplier: u32) { - self.base_exp.write(base_exp); - self.exp_multiplier.write(exp_multiplier); - } - - #[external(v0)] - impl ExperienceCalculatorImpl of super::IExperienceCalculator { - fn calculate_experience(ref self: ContractState, level: u32) -> u32 { - let base_exp: felt252 = self.base_exp.read().into(); - let exp_multiplier: felt252 = self.exp_multiplier.read().into(); - let level_felt: felt252 = level.into(); - - // Calculate: base_exp * (level * exp_multiplier) - let result = base_exp * (level_felt * exp_multiplier); - - // Convert back to u32 - result.try_into().unwrap() - } - - fn check_level_up(ref self: ContractState, current_level: u32, current_exp: u32) -> bool { - let required_exp = self.calculate_experience(current_level); - current_exp >= required_exp - } - - fn calculate_remaining_exp(ref self: ContractState, current_level: u32, current_exp: u32) -> u32 { - let required_exp = self.calculate_experience(current_level); - if current_exp >= required_exp { - 0 - } else { - required_exp - current_exp - } - } - } -} \ No newline at end of file From 6b7f9bdb0131755e54992d4e6cff953c99e6ff68 Mon Sep 17 00:00:00 2001 From: Mmeso Love Date: Tue, 6 May 2025 00:40:49 +0100 Subject: [PATCH 4/4] added file --- .../src/helpers/Experience_utils.cairo | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 backend/dojo_examples/combat_game/src/helpers/Experience_utils.cairo diff --git a/backend/dojo_examples/combat_game/src/helpers/Experience_utils.cairo b/backend/dojo_examples/combat_game/src/helpers/Experience_utils.cairo new file mode 100644 index 0000000..4cdc549 --- /dev/null +++ b/backend/dojo_examples/combat_game/src/helpers/Experience_utils.cairo @@ -0,0 +1,159 @@ +use core::traits::Into; + +#[generate_trait] +pub impl ExperienceCalculator of ExperienceCalculatorTrait { + + fn calculate_exp_needed_for_level(level: u8) -> u16 { + let level_u16: u16 = level.into(); + level_u16 * level_u16 * 10 + } + + fn should_level_up(current_level: u8, current_exp: u16) -> bool { + let exp_needed = Self::calculate_exp_needed_for_level(current_level); + current_exp >= exp_needed + } + + fn remaining_exp_after_level_up(current_level: u8, current_exp: u16) -> u16 { + let exp_needed = Self::calculate_exp_needed_for_level(current_level); + if current_exp >= exp_needed { + current_exp - exp_needed + } else { + current_exp + } + } +} + +#[cfg(test)] +mod experience_calculator_tests { + use super::{ExperienceCalculator}; + + #[test] + #[available_gas(1000000)] + fn test_calculate_exp_needed_for_level() { + // Test values for different levels to verify the formula level² × 10 + + // Level 1: 1² × 10 = 10 + let exp_level_1 = ExperienceCalculator::calculate_exp_needed_for_level(1); + assert(exp_level_1 == 10, 'Level 1 should need 10 exp'); + + // Level 2: 2² × 10 = 40 + let exp_level_2 = ExperienceCalculator::calculate_exp_needed_for_level(2); + assert(exp_level_2 == 40, 'Level 2 should need 40 exp'); + + // Level 5: 5² × 10 = 250 + let exp_level_5 = ExperienceCalculator::calculate_exp_needed_for_level(5); + assert(exp_level_5 == 250, 'Level 5 should need 250 exp'); + + // Level 10: 10² × 10 = 1000 + let exp_level_10 = ExperienceCalculator::calculate_exp_needed_for_level(10); + assert(exp_level_10 == 1000, 'Level 10 should need 1000 exp'); + + // Level 20: 20² × 10 = 4000 + let exp_level_20 = ExperienceCalculator::calculate_exp_needed_for_level(20); + assert(exp_level_20 == 4000, 'Level 20 should need 4000 exp'); + } + + #[test] + #[available_gas(1000000)] + fn test_should_level_up() { + // Level 1 (needs 10 exp) + + // 9 exp: should not level up + let should_level_up_1_9 = ExperienceCalculator::should_level_up(1, 9); + assert(!should_level_up_1_9, 'Level 1 with 9 exp not level up'); + + // 10 exp: should level up + let should_level_up_1_10 = ExperienceCalculator::should_level_up(1, 10); + assert(should_level_up_1_10, 'Level 1 with 10 exp level up'); + + // 15 exp: should level up + let should_level_up_1_15 = ExperienceCalculator::should_level_up(1, 15); + assert(should_level_up_1_15, 'Level 1 with 15 exp level up'); + + // Level 5 (needs 250 exp) + + // 249 exp: should not level up + let should_level_up_5_249 = ExperienceCalculator::should_level_up(5, 249); + assert(!should_level_up_5_249, 'Level 5 249 exp not level up'); + + // 250 exp: should level up + let should_level_up_5_250 = ExperienceCalculator::should_level_up(5, 250); + assert(should_level_up_5_250, 'Level 5 with 250 exp level up'); + + // 300 exp: should level up + let should_level_up_5_300 = ExperienceCalculator::should_level_up(5, 300); + assert(should_level_up_5_300, 'Level 5 with 300 exp level up'); + } + + #[test] + #[available_gas(1000000)] + fn test_remaining_exp_after_level_up() { + // Level 1 (needs 10 exp) + + // 9 exp: should remain at 9 (no level up) + let remaining_1_9 = ExperienceCalculator::remaining_exp_after_level_up(1, 9); + assert(remaining_1_9 == 9, 'Level 1 with 9 exp keep 9'); + + // 10 exp: should remain at 0 (level up) + let remaining_1_10 = ExperienceCalculator::remaining_exp_after_level_up(1, 10); + assert(remaining_1_10 == 0, 'Level 1 with 10 exp 0 remaining'); + + // 15 exp: should remain at 5 (level up) + let remaining_1_15 = ExperienceCalculator::remaining_exp_after_level_up(1, 15); + assert(remaining_1_15 == 5, 'Level 1 with 15 exp 5 remaining'); + + // Level 5 (needs 250 exp) + + // 300 exp: should remain at 50 (level up) + let remaining_5_300 = ExperienceCalculator::remaining_exp_after_level_up(5, 300); + assert(remaining_5_300 == 50, 'Level 5 300 exp 50 remaining'); + } + + #[test] + #[available_gas(1000000)] + fn test_multiple_level_ups_simulation() { + // Simulate a scenario where a beast levels up multiple times + + // Beast level 1 with 0 initial exp + let mut current_level = 1_u8; + let mut current_exp = 0_u16; + + // Earned 20 exp + current_exp += 20; + + // Validate if it should level up + let should_level = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(should_level, 'Level up after more 20 exp'); + + // Level up and update remaining exp + if should_level { + current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); + current_level += 1; + } + + // Verify final values + assert(current_level == 2, 'Should now be level 2'); + assert(current_exp == 10, 'Should have 10 exp remaining'); + + // Earned 50 more exp + current_exp += 50; + + // Validate if it should level up again + let should_level_again = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(should_level_again, 'Level up 60 exp at level 2'); + + // Level up again + if should_level_again { + current_exp = ExperienceCalculator::remaining_exp_after_level_up(current_level, current_exp); + current_level += 1; + } + + // Verify final values + assert(current_level == 3, 'Should now be level 3'); + assert(current_exp == 20, 'Should have 20 exp remaining'); + + // Should not level up to level 4 yet + let not_enough_for_level4 = ExperienceCalculator::should_level_up(current_level, current_exp); + assert(!not_enough_for_level4, 'Should not reach level 4 yet'); + } +} \ No newline at end of file