From 254696011dc01a5f5519e5097a7979bf71e6d59d Mon Sep 17 00:00:00 2001 From: Ajidokwu Sabo Date: Sat, 12 Jul 2025 22:34:27 +0100 Subject: [PATCH 1/2] feat: fixed properties manipulation --- src/interfaces/IActions.cairo | 1 + src/model/property_model.cairo | 71 ++++- src/systems/actions.cairo | 495 ++++++++++++++++++++------------- src/tests/test_world.cairo | 197 +++++++++++-- 4 files changed, 548 insertions(+), 216 deletions(-) diff --git a/src/interfaces/IActions.cairo b/src/interfaces/IActions.cairo index 1f61f27..dd9d5ec 100644 --- a/src/interfaces/IActions.cairo +++ b/src/interfaces/IActions.cairo @@ -26,6 +26,7 @@ pub trait IActions { ) -> u256; fn join_game(ref self: T, player_symbol: PlayerSymbol, game_id: u256); fn start_game(ref self: T, game_id: u256) -> bool; + fn finish_turn(ref self: T, game: Game) -> Game; // Game state retrieval fn retrieve_game(self: @T, game_id: u256) -> Game; diff --git a/src/model/property_model.cairo b/src/model/property_model.cairo index b9d0a4c..44bd328 100644 --- a/src/model/property_model.cairo +++ b/src/model/property_model.cairo @@ -72,7 +72,11 @@ pub trait PropertyTrait { group_id: u8, owner: ContractAddress, ) -> Property; - fn get_rent_amount(self: @Property) -> u256; + fn get_rent_amount( + self: @Property, owner_railroads: u8, owner_utilities: u8, dice_rolled: u256, + ) -> u256; + fn calculate_utility_rent(self: @Property, no_of_utilities: u8, dice_rolled: u256) -> u256; + fn calculate_railway_rent(self: @Property, no_of_railways: u8) -> u256; fn mortgage(ref self: Property, owner: ContractAddress); fn lift_mortgage(ref self: Property, owner: ContractAddress); fn upgrade_property(ref self: Property, player: ContractAddress, upgrade_level: u8) -> bool; @@ -121,23 +125,68 @@ impl PropertyImpl of PropertyTrait { development: 0, } } - - fn get_rent_amount(self: @Property) -> u256 { + fn get_rent_amount( + self: @Property, owner_railroads: u8, owner_utilities: u8, dice_rolled: u256, + ) -> u256 { if *self.is_mortgaged { return 0; } - match *self.property_level { - 0 => *self.rent_site_only, - 1 => *self.rent_one_house, - 2 => *self.rent_two_houses, - 3 => *self.rent_three_houses, - 4 => *self.rent_four_houses, - 5 => *self.rent_hotel, - _ => *self.rent_site_only // default fallback + match *self.property_type { + PropertyType::Property => { + match *self.development { + 0 => *self.rent_site_only, + 1 => *self.rent_one_house, + 2 => *self.rent_two_houses, + 3 => *self.rent_three_houses, + 4 => *self.rent_four_houses, + 5 => *self.rent_hotel, + _ => *self.rent_site_only, + } + }, + PropertyType::RailRoad => { + match owner_railroads { + 0 => 0, + 1 => 25, + 2 => 50, + 3 => 100, + 4 => 200, + _ => 0, + } + }, + PropertyType::Utility => { + match owner_utilities { + 0 => 0, + 1 => 4 * dice_rolled, + 2 => 10 * dice_rolled, + _ => 0, + } + }, + _ => 0, + } + } + + + fn calculate_utility_rent(self: @Property, no_of_utilities: u8, dice_rolled: u256) -> u256 { + match no_of_utilities { + 0 => 0, + 1 => 4 * dice_rolled, + 2 => 10 * dice_rolled, + _ => 0, + } + } + fn calculate_railway_rent(self: @Property, no_of_railways: u8) -> u256 { + match no_of_railways { + 0 => 0, + 1 => 25, + 2 => 50, + 3 => 100, + 4 => 200, + _ => 0, } } + fn mortgage(ref self: Property, owner: ContractAddress) { self.is_mortgaged = true; } diff --git a/src/systems/actions.cairo b/src/systems/actions.cairo index 0d57fc6..f96d1be 100644 --- a/src/systems/actions.cairo +++ b/src/systems/actions.cairo @@ -424,54 +424,37 @@ pub mod actions { let mut world = self.world_default(); let caller = get_caller_address(); - // Load players let mut player: GamePlayer = world.read_model((caller, property.game_id)); let mut owner: GamePlayer = world.read_model((property.owner, property.game_id)); // Validate game let mut game: Game = world.read_model(property.game_id); - assert(game.status == GameStatus::Ongoing, 'Game has not started yet'); + assert(game.status == GameStatus::Ongoing, 'Game not started'); - // Ensure property is owned and valid + // Basic checks let zero_address: ContractAddress = contract_address_const::<0>(); - assert(property.owner != zero_address, 'Property is unowned'); - assert(property.owner != caller, 'You cannot pay rent to yourself'); + assert(property.owner != zero_address, 'Property unowned'); + assert(property.owner != caller, 'Cannot pay rent to yourself'); assert(player.position == property.id, 'Not on property'); - assert(!property.is_mortgaged, 'No rent on mortgaged properties'); - - let mut rent_amount = 0; - - match property.property_type { - PropertyType::Property => { rent_amount = property.get_rent_amount(); }, - PropertyType::Utility => { - // Utilities rent depends on number owned and dice roll - if player.no_of_utilities == 2 { - rent_amount = 10 * player.dice_rolled.into(); - } else if player.no_of_utilities == 1 { - rent_amount = 4 * player.dice_rolled.into(); - } - }, - PropertyType::RailRoad => { - // Assuming rent increases by number of railroads owned - // e.g. rent = 25 * number of railroads owned - rent_amount = 25 * player.no_of_railways.into(); - }, - _ => { - rent_amount = 0; // No rent for other types - }, - } + assert(!property.is_mortgaged, 'No rent on mortgaged'); + + // Get dynamic counts + let railroads = self.count_owner_railroads(property.owner, property.game_id); + let utilities = self.count_owner_utilities(property.owner, property.game_id); + + // Calculate rent + let rent_amount = property + .get_rent_amount(railroads, utilities, player.dice_rolled.into()); - // Check player can pay rent - assert(player.balance >= rent_amount, 'Insufficient rent funds'); + assert(player.balance >= rent_amount, 'Insufficient funds'); // Transfer rent player.balance -= rent_amount; owner.balance += rent_amount; - // Finish turn + // Finish turn and persist game = self.finish_turn(game); - // Persist changes world.write_model(@game); world.write_model(@player); world.write_model(@owner); @@ -493,6 +476,8 @@ pub mod actions { // Move player game_player = GamePlayerTrait::move(game_player, steps); + game_player.dice_rolled = steps; + if game_player.position > 40 { game_player.position = ((game_player.position - 1) % 40) + 1; game_player.balance += 200; @@ -534,6 +519,12 @@ pub mod actions { player.properties_owned.append(property.id); // Increment section or special counters + if property.property_type == PropertyType::RailRoad { + player.no_of_railways += 1; + } + if property.property_type == PropertyType::Utility { + player.no_of_utilities += 1; + } match property.group_id { 0 => {}, 1 => player.no_section1 += 1, @@ -544,15 +535,7 @@ pub mod actions { 6 => player.no_section6 += 1, 7 => player.no_section7 += 1, 8 => player.no_section8 += 1, - _ => { - // Handle special types by property names (or you could use a dedicated - // enum/type) - if property.property_type == PropertyType::RailRoad { - player.no_of_railways += 1; - } else if property.property_type == PropertyType::Utility { - player.no_of_utilities += 1; - } - }, + _ => {}, } // Finish turn @@ -571,23 +554,63 @@ pub mod actions { fn buy_house_or_hotel(ref self: ContractState, mut property: Property) -> bool { let mut world = self.world_default(); let caller = get_caller_address(); + let mut player: GamePlayer = world.read_model((caller, property.game_id)); - let contract_address = get_contract_address(); + assert(property.owner == caller, 'Only the owner can develop'); + assert(!property.is_mortgaged, 'Property is mortgaged'); + assert(property.development < 5, 'Maximum development reached'); + + // ✅ Check owns full set + let owns_entire_group = match property.group_id { + 0 => false, + 1 => player.no_section1 == 2, + 2 => player.no_section2 == 3, + 3 => player.no_section3 == 3, + 4 => player.no_section4 == 3, + 5 => player.no_section5 == 3, + 6 => player.no_section6 == 3, + 7 => player.no_section7 == 3, + 8 => player.no_section8 == 2, + _ => false, + }; + assert!(owns_entire_group, "Must own all properties in the group to build"); - assert(property.owner == caller, 'Only the owner '); - assert(property.is_mortgaged == false, 'Cannot develop'); - assert(property.development < 5, 'Maximum development '); + // ✅ Enforce even building + let group_properties: Array = self + .get_properties_by_group(property.group_id, property.game_id); + + let mut i = 0; + while i < group_properties.len() { + let prop = group_properties[i]; + if *prop.id != property.id { + assert!( + *prop.development >= property.development, + "Must build evenly: other properties are under-developed", + ); + } + i += 1; + }; + // ✅ Passed checks, build let cost: u256 = property.cost_of_house; - // self.transfer_from(caller, contract_address, property.game_id, cost); + assert(player.balance >= cost, 'Insufficient balance'); + + player.balance -= cost; + property.development += 1; - property.development += 1; // Increases to 5 (hotel) max + if property.development < 5 { + player.total_houses_owned += 1; + } else { + player.total_hotels_owned += 1; + } world.write_model(@property); + world.write_model(@player); true } + // fn offer_trade( // ref self: ContractState, // game_id: u256, @@ -722,18 +745,9 @@ pub mod actions { }; stat } - } - - #[generate_trait] - impl InternalImpl of InternalTrait { - /// Use the default namespace "dojo_starter". This function is handy since the ByteArray - /// can't be const. - fn world_default(self: @ContractState) -> dojo::world::WorldStorage { - self.world(@"blockopoly") - } - fn finish_turn(ref self: ContractState, mut game: Game) -> Game { + let mut world = self.world_default(); let caller = get_caller_address(); let mut index = 0; let mut current_index = 0; @@ -751,8 +765,18 @@ pub mod actions { let next_index = (current_index + 1) % players_len; game.next_player = *game.game_players.at(next_index); + world.write_model(@game); game } + } + + #[generate_trait] + impl InternalImpl of InternalTrait { + /// Use the default namespace "dojo_starter". This function is handy since the ByteArray + /// can't be const. + fn world_default(self: @ContractState) -> dojo::world::WorldStorage { + self.world(@"blockopoly") + } fn generate_chance_deck(ref self: ContractState) -> Array { let mut deck: Array = array![]; @@ -778,6 +802,38 @@ pub mod actions { deck } + // Count how many railroads the owner has + fn count_owner_railroads( + ref self: ContractState, owner: ContractAddress, game_id: u256, + ) -> u8 { + let mut count = 0; + let mut i = 1; + while i < 41_u32 { + let prop: Property = self.world_default().read_model((i, game_id)); + if prop.owner == owner && prop.property_type == PropertyType::RailRoad { + count += 1; + } + i += 1; + }; + count + } + + // Count how many utilities the owner has + fn count_owner_utilities( + ref self: ContractState, owner: ContractAddress, game_id: u256, + ) -> u8 { + let mut count = 0; + let mut i = 1; + while i < 41_u32 { + let prop: Property = self.world_default().read_model((i, game_id)); + if prop.owner == owner && prop.property_type == PropertyType::Utility { + count += 1; + } + i += 1; + }; + count + } + fn generate_chance_indices(ref self: ContractState) -> Array { let mut indices: Array = array![]; @@ -961,6 +1017,23 @@ pub mod actions { (game, player) } + fn get_properties_by_group( + ref self: ContractState, group_id: u8, game_id: u256, + ) -> Array { + let mut world = self.world_default(); + let mut group_properties: Array = array![]; + + let mut i = 0; // defaults to felt252 + while i < 41_u32 { + let prop: Property = world.read_model((i, game_id)); + if prop.group_id == group_id { + group_properties.append(prop); + } + i += 1; + }; + + group_properties + } fn process_community_chest_card( @@ -1009,7 +1082,7 @@ pub mod actions { let houses = player.total_houses_owned; let hotels = player.total_hotels_owned; let cost = (40 * houses) + (115 * hotels); - // player.balance -= cost; + player.balance -= cost.into(); } else if card == "Won second prize in beauty contest - Collect $10" { player.balance += 10; } else if card == "You inherit $100" { @@ -1049,6 +1122,7 @@ pub mod actions { let mut world = self.world_default(); let contract_address = get_contract_address(); let bank: GamePlayer = world.read_model((contract_address, game_id)); + self .generate_properties( 1, @@ -1071,24 +1145,6 @@ pub mod actions { .generate_properties( 2, game_id, - 'Community Chest', - 0, - PropertyType::Property, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - false, - 0, - bank.address, - ); - self - .generate_properties( - 3, - game_id, 'Axone Avenue', 60, PropertyType::Property, @@ -1105,11 +1161,11 @@ pub mod actions { ); self .generate_properties( - 4, + 3, game_id, - 'Income Tax', - 200, - PropertyType::Property, + 'Community Chest', + 0, + PropertyType::CommunityChest, 0, 0, 0, @@ -1121,13 +1177,31 @@ pub mod actions { 0, bank.address, ); + self + .generate_properties( + 4, + game_id, + 'Onlydust Avenue', + 60, + PropertyType::Property, + 4, + 20, + 60, + 180, + 320, + 450, + 50, + false, + 1, + bank.address, + ); self .generate_properties( 5, game_id, 'IPFS Railroad', 200, - PropertyType::Property, + PropertyType::RailRoad, 25, 50, 100, @@ -1143,18 +1217,18 @@ pub mod actions { .generate_properties( 6, game_id, - 'Onlydust Avenue', - 60, + 'ZkSync Lane', + 100, PropertyType::Property, - 4, - 20, - 60, - 180, - 320, - 450, + 6, + 30, + 90, + 270, + 400, + 550, 50, false, - 1, + 2, bank.address, ); self @@ -1163,7 +1237,7 @@ pub mod actions { game_id, 'Chance', 0, - PropertyType::Property, + PropertyType::Chance, 0, 0, 0, @@ -1179,7 +1253,7 @@ pub mod actions { .generate_properties( 8, game_id, - 'ZkSync Lane', + 'Starknet Lane', 100, PropertyType::Property, 6, @@ -1197,15 +1271,15 @@ pub mod actions { .generate_properties( 9, game_id, - 'Starknet Lane', - 100, + 'Linea Lane', + 120, PropertyType::Property, - 6, - 30, - 90, - 270, - 400, - 550, + 8, + 40, + 100, + 300, + 450, + 600, 50, false, 2, @@ -1217,7 +1291,7 @@ pub mod actions { game_id, 'Visiting Jail', 0, - PropertyType::Property, + PropertyType::VisitingJail, 0, 0, 0, @@ -1229,22 +1303,23 @@ pub mod actions { 0, bank.address, ); + self .generate_properties( 11, game_id, - 'Linea Lane', - 120, + 'Arbitrium Avenue', + 140, PropertyType::Property, - 8, - 40, - 100, - 300, - 450, - 600, + 10, 50, + 150, + 450, + 625, + 750, + 100, false, - 2, + 3, bank.address, ); self @@ -1253,7 +1328,7 @@ pub mod actions { game_id, 'Chainlink Power Plant', 150, - PropertyType::Property, + PropertyType::Utility, 0, 0, 0, @@ -1269,7 +1344,7 @@ pub mod actions { .generate_properties( 13, game_id, - 'Arbitrium Avenue', + 'Optimistic Avenue', 140, PropertyType::Property, 10, @@ -1289,7 +1364,7 @@ pub mod actions { game_id, 'Community Chest', 0, - PropertyType::Property, + PropertyType::CommunityChest, 0, 0, 0, @@ -1305,27 +1380,9 @@ pub mod actions { .generate_properties( 15, game_id, - 'Optimistic Avenue', - 140, - PropertyType::Property, - 10, - 50, - 150, - 450, - 625, - 750, - 100, - false, - 3, - bank.address, - ); - self - .generate_properties( - 16, - game_id, 'Pinata Railroad', 200, - PropertyType::Property, + PropertyType::RailRoad, 25, 50, 100, @@ -1339,7 +1396,7 @@ pub mod actions { ); self .generate_properties( - 17, + 16, game_id, 'Base Avenue', 160, @@ -1355,6 +1412,24 @@ pub mod actions { 3, bank.address, ); + self + .generate_properties( + 17, + game_id, + 'Chance', + 0, + PropertyType::Chance, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + false, + 0, + bank.address, + ); self .generate_properties( 18, @@ -1377,24 +1452,6 @@ pub mod actions { .generate_properties( 19, game_id, - 'Chance', - 0, - PropertyType::Property, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - false, - 0, - bank.address, - ); - self - .generate_properties( - 20, - game_id, 'Polkadot Lane', 180, PropertyType::Property, @@ -1411,11 +1468,11 @@ pub mod actions { ); self .generate_properties( - 21, + 20, game_id, 'Free Parking', 0, - PropertyType::Property, + PropertyType::FreeParking, 0, 0, 0, @@ -1427,9 +1484,10 @@ pub mod actions { 0, bank.address, ); + self .generate_properties( - 22, + 21, game_id, 'Near Lane', 200, @@ -1447,11 +1505,11 @@ pub mod actions { ); self .generate_properties( - 23, + 22, game_id, 'Community Chest', 0, - PropertyType::Property, + PropertyType::CommunityChest, 0, 0, 0, @@ -1465,7 +1523,7 @@ pub mod actions { ); self .generate_properties( - 24, + 23, game_id, 'Uniswap Avenue', 220, @@ -1481,13 +1539,31 @@ pub mod actions { 5, bank.address, ); + self + .generate_properties( + 24, + game_id, + 'MakerDAO Avenue', + 220, + PropertyType::Property, + 18, + 90, + 250, + 700, + 875, + 1050, + 150, + false, + 5, + bank.address, + ); self .generate_properties( 25, game_id, 'OpenZeppelin Railroad', 200, - PropertyType::Property, + PropertyType::RailRoad, 25, 50, 100, @@ -1503,24 +1579,6 @@ pub mod actions { .generate_properties( 26, game_id, - 'MakerDAO Avenue', - 220, - PropertyType::Property, - 18, - 90, - 250, - 700, - 875, - 1050, - 150, - false, - 5, - bank.address, - ); - self - .generate_properties( - 27, - game_id, 'Aave Avenue', 240, PropertyType::Property, @@ -1537,11 +1595,11 @@ pub mod actions { ); self .generate_properties( - 28, + 27, game_id, 'Graph Water Works', 150, - PropertyType::Property, + PropertyType::Utility, 0, 0, 0, @@ -1555,7 +1613,7 @@ pub mod actions { ); self .generate_properties( - 29, + 28, game_id, 'Lisk Lane', 260, @@ -1571,13 +1629,31 @@ pub mod actions { 6, bank.address, ); + self + .generate_properties( + 29, + game_id, + 'Chance', + 0, + PropertyType::Chance, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + false, + 0, + bank.address, + ); self .generate_properties( 30, game_id, 'Go To Jail', 0, - PropertyType::Property, + PropertyType::Jail, 0, 0, 0, @@ -1589,6 +1665,7 @@ pub mod actions { 0, bank.address, ); + self .generate_properties( 31, @@ -1631,7 +1708,7 @@ pub mod actions { game_id, 'Community Chest', 0, - PropertyType::Property, + PropertyType::CommunityChest, 0, 0, 0, @@ -1667,7 +1744,7 @@ pub mod actions { game_id, 'Cartridge Railroad', 200, - PropertyType::Property, + PropertyType::RailRoad, 25, 50, 100, @@ -1685,7 +1762,7 @@ pub mod actions { game_id, 'Chance', 0, - PropertyType::Property, + PropertyType::Chance, 0, 0, 0, @@ -1721,7 +1798,7 @@ pub mod actions { game_id, 'Luxury Tax', 100, - PropertyType::Property, + PropertyType::Tax, 0, 0, 0, @@ -1771,6 +1848,7 @@ pub mod actions { ); } + fn try_join_symbol( ref self: ContractState, mut game: Game, @@ -1877,9 +1955,51 @@ pub mod actions { property.cost_of_property, ); } else if property.owner != caller { - // Property is owned by someone else - println!("This property '{}' is owned by {:?}.", property.name, property.owner); - println!("Player {:?} needs to pay rent of {}", caller, property.rent_site_only); + // Property owned by someone else, calculate rent dynamically + let owner_railroads = self.count_owner_railroads(property.owner, property.game_id); + let owner_utilities = self.count_owner_utilities(property.owner, property.game_id); + + let rent_amount = property + .get_rent_amount(owner_railroads, owner_utilities, player.dice_rolled.into()); + + match property.property_type { + PropertyType::RailRoad => { + println!( + "This railroad '{}' is owned by {:?}. Player {:?} must pay rent: {}.", + property.name, + property.owner, + caller, + rent_amount, + ); + }, + PropertyType::Utility => { + println!( + "This utility '{}' is owned by {:?}. Player {:?} must pay rent: {}.", + property.name, + property.owner, + caller, + rent_amount, + ); + }, + PropertyType::Property => { + println!( + "This property '{}' is owned by {:?}. Player {:?} must pay rent: {}.", + property.name, + property.owner, + caller, + rent_amount, + ); + }, + _ => { + println!( + "This space '{}' is owned by {:?}. Player {:?} may owe rent: {}.", + property.name, + property.owner, + caller, + rent_amount, + ); + }, + } } else { // Property owned by caller println!("Player {:?} landed on their own property '{}'.", caller, property.name); @@ -1889,6 +2009,7 @@ pub mod actions { } } + #[generate_trait] impl PlayerGameBalanceImpl of IPlayerGameBalance { fn check_if_player_is_capable_of_trans( diff --git a/src/tests/test_world.cairo b/src/tests/test_world.cairo index 22efb2d..442b89a 100644 --- a/src/tests/test_world.cairo +++ b/src/tests/test_world.cairo @@ -860,7 +860,9 @@ mod tests { testing::set_contract_address(caller_2); actions_system.move_player(1, 5); - let ppt1 = actions_system.get_property(5, 1); + let ppt1 = actions_system.get_property(4, 1); + + testing::set_contract_address(caller_2); actions_system.pay_rent(ppt1); let aji = actions_system.retrieve_game_player(caller_1, 1); @@ -1002,6 +1004,133 @@ mod tests { assert(ppt11.is_mortgaged, 'morgage failed') } + #[test] + fn test_buy_houses_in_and_hotel_game() { + let caller_1 = contract_address_const::<'aji'>(); + let caller_2 = contract_address_const::<'collins'>(); + let caller_3 = contract_address_const::<'jerry'>(); + let caller_4 = contract_address_const::<'aliyu'>(); + let username = 'Ajidokwu'; + let username_1 = 'Collins'; + let username_2 = 'Jerry'; + let username_3 = 'Aliyu'; + + let ndef = namespace_def(); + let mut world = spawn_test_world([ndef].span()); + world.sync_perms_and_inits(contract_defs()); + + let (contract_address, _) = world.dns(@"actions").unwrap(); + let actions_system = IActionsDispatcher { contract_address }; + + testing::set_contract_address(caller_2); + actions_system.register_new_player(username_1); + + testing::set_contract_address(caller_1); + actions_system.register_new_player(username); + + testing::set_contract_address(caller_3); + actions_system.register_new_player(username_2); + + testing::set_contract_address(caller_4); + actions_system.register_new_player(username_3); + + testing::set_contract_address(caller_1); + actions_system.create_new_game(GameType::PublicGame, PlayerSymbol::Hat, 4); + + testing::set_contract_address(caller_2); + actions_system.join_game(PlayerSymbol::Dog, 1); + + testing::set_contract_address(caller_3); + actions_system.join_game(PlayerSymbol::Car, 1); + + testing::set_contract_address(caller_4); + actions_system.join_game(PlayerSymbol::Iron, 1); + + testing::set_contract_address(caller_1); + let started = actions_system.start_game(1); + assert(started, 'Game start fail'); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 2); + let mut property = actions_system.get_property(2, 1); + actions_system.buy_property(property); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 12); + + let mut game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_3); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_4); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_1); + actions_system.move_player(1, 2); + property = actions_system.get_property(4, 1); + actions_system.buy_property(property); + + testing::set_contract_address(caller_2); + actions_system.move_player(1, 12); + + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_3); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_4); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_1); + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + let success = actions_system.buy_house_or_hotel(property); + assert(success, 'house failed'); + property = actions_system.get_property(4, 1); + assert(property.development == 5, 'dev correct'); + + let aji = actions_system.retrieve_game_player(caller_1, 1); + + assert(aji.total_hotels_owned == 2, 'house count error'); + assert(aji.total_houses_owned == 8, 'house count error'); + } #[test] fn test_play_game() { @@ -1050,31 +1179,63 @@ mod tests { assert(started, 'Game start fail'); testing::set_contract_address(caller_1); - actions_system.move_player(1, 5); - let ppt = actions_system.get_property(5, 1); - actions_system.buy_property(ppt); + actions_system.move_player(1, 2); + let mut property = actions_system.get_property(2, 1); + actions_system.buy_property(property); - let ppt1 = actions_system.get_property(5, 1); - actions_system.mortgage_property(ppt1); + testing::set_contract_address(caller_2); + actions_system.move_player(1, 12); - let ppt11 = actions_system.get_property(5, 1); + let mut game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); - let aji = actions_system.retrieve_game_player(caller_1, 1); - assert(aji.balance == 1400, 'morgage inbursement failed'); - assert(ppt11.is_mortgaged, 'morgage failed'); + testing::set_contract_address(caller_3); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); - let ppt2 = actions_system.get_property(5, 1); - actions_system.unmortgage_property(ppt2); + testing::set_contract_address(caller_4); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); - let ppt21 = actions_system.get_property(5, 1); + testing::set_contract_address(caller_1); + actions_system.move_player(1, 2); + property = actions_system.get_property(4, 1); + actions_system.buy_property(property); - let aji1 = actions_system.retrieve_game_player(caller_1, 1); + testing::set_contract_address(caller_2); + actions_system.move_player(1, 12); - assert(aji1.balance == 1290, 'morgage inbursement failed'); - assert(!ppt21.is_mortgaged, 'morgage failed'); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); - assert(ppt11.is_mortgaged, 'morgage failed') - // testing::set_contract_address(caller_3); + testing::set_contract_address(caller_3); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_4); + actions_system.move_player(1, 8); + game = actions_system.retrieve_game(1); + actions_system.finish_turn(game); + + testing::set_contract_address(caller_1); + property = actions_system.get_property(4, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(2, 1); + actions_system.buy_house_or_hotel(property); + + property = actions_system.get_property(4, 1); + let success = actions_system.buy_house_or_hotel(property); + + assert(success, 'house failed'); + // let aji = actions_system.retrieve_game_player(caller_1, 1); + // property = actions_system.get_property(4, 1); + // println!("no of total_houses_owned :{}", aji.total_houses_owned); + // println!("no of property :{}", property.development); + // testing::set_contract_address(caller_3); // actions_system.move_player(1, 5); // testing::set_contract_address(caller_4); // actions_system.move_player(1, 5); From 727695f317c8cb0fb251c34b578b0ca67dd62308 Mon Sep 17 00:00:00 2001 From: Ajidokwu Sabo Date: Sat, 12 Jul 2025 22:36:55 +0100 Subject: [PATCH 2/2] feat: fixed properties manipulation --- src/tests/test_world.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/test_world.cairo b/src/tests/test_world.cairo index 442b89a..4169030 100644 --- a/src/tests/test_world.cairo +++ b/src/tests/test_world.cairo @@ -860,7 +860,7 @@ mod tests { testing::set_contract_address(caller_2); actions_system.move_player(1, 5); - let ppt1 = actions_system.get_property(4, 1); + let ppt1 = actions_system.get_property(5, 1); testing::set_contract_address(caller_2); actions_system.pay_rent(ppt1);