Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding the model and system tournament blueprint #96

Merged
merged 4 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod systems {
mod spawn;
mod world_setup;
mod bag;
mod tournament;
}

mod models {
Expand All @@ -26,6 +27,7 @@ mod models {
mod achievement_rarity;
mod achievement_type;
mod achievements;
mod tournament;
}

mod tests {
Expand Down
70 changes: 70 additions & 0 deletions src/models/tournament.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use super::player::Player;

#[derive(Serde, Copy, Drop, Introspect, PartialEq, Debug)]
pub enum TournamentStatus {
Pending,
Ongoing,
Completed,
}


#[derive(Drop, Serde)]
#[dojo::model]
pub struct Tournament {
#[key]
pub tournament_id: u32,
pub name: felt252,
pub status: TournamentStatus,
pub entry_fee: u32,
pub max_participants: u32,
pub current_participants: Array<Player>,
pub prize_pool: u32,
Comment on lines +18 to +21

This comment was marked as spam.

}


#[cfg(test)]
mod tests {
use bytebeasts::{
models::{tournament::Tournament, tournament::TournamentStatus, player::Player}
};


#[test]
fn test_tournament_initialization() {
let mut players = ArrayTrait::new();

let player_ash = Player {
player_id: 1,
player_name: 'Ash',
beast_1: 1, // Beast 1 assigned
beast_2: 0, // No beast assigned
beast_3: 0, // No beast assigned
beast_4: 0, // No beast assigned
potions: 1
};
players.append(player_ash);

let tournament = Tournament {
tournament_id: 1,
name: 'gersonwashere',
status: TournamentStatus::Pending,
entry_fee: 1,
max_participants: 2,
current_participants: players,
prize_pool: 1,
};

assert_eq!(tournament.tournament_id, 1, "Tournament ID should be 1");
assert_eq!(tournament.name, 'gersonwashere', "Tournament name should be gersonwashere");
assert_eq!(
tournament.status, TournamentStatus::Pending, "Tournament status should be pending"
);
assert_eq!(tournament.entry_fee, 1, "Tournament entry fee should be 1");
assert_eq!(tournament.max_participants, 2, "Tournament max participants should be 2");
assert_eq!(
tournament.current_participants.len(), 1, "Tournament current participants should be 1"
);
assert_eq!(tournament.prize_pool, 1, "Tournament prize pool should be 1");
}
}

89 changes: 89 additions & 0 deletions src/systems/tournament.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
use bytebeasts::{models::{player::Player, tournament::Tournament, tournament::TournamentStatus},};

#[dojo::interface]
trait ITournamentAction {
fn create_tournament(
ref world: IWorldDispatcher,
tournament_id: u32,
name: felt252,
status: TournamentStatus,
entry_fee: u32,
max_participants: u32,
current_participants: Array<Player>,
prize_pool: u32
);
fn register_player(ref world: IWorldDispatcher, tournament_id: u32, new_player: Player);
fn start_tournament(ref world: IWorldDispatcher, tournament_id: u32);
// fn complete_tournament(ref world: IWorldDispatcher, tournament_id: u32, player_id: u32);
fn get_tournament(world: @IWorldDispatcher, tournament_id: u32) -> Tournament;

This comment was marked as spam.

}


#[dojo::contract]
mod tournament_system {
use super::ITournamentAction;
use bytebeasts::{
models::{player::Player, tournament::Tournament, tournament::TournamentStatus},
};

#[abi(embed_v0)]
impl TournamentActionImpl of ITournamentAction<ContractState> {
fn create_tournament(
ref world: IWorldDispatcher,
tournament_id: u32,
name: felt252,
status: TournamentStatus,
entry_fee: u32,
max_participants: u32,
current_participants: Array<Player>,
prize_pool: u32
) {
let tournament = Tournament {
tournament_id: tournament_id,
name: name,
status: status,
entry_fee: entry_fee,
max_participants: max_participants,
current_participants: current_participants,
prize_pool: prize_pool
};
set!(world, (tournament))
}
Comment on lines +32 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add validation for tournament ID uniqueness.

The create_tournament method should verify that the tournament_id doesn't already exist to prevent overwriting existing tournaments.

Add this validation before creating the tournament:

         prize_pool: u32
     ) {
+        let existing = get!(world, tournament_id, (Tournament));
+        assert!(existing.tournament_id == 0, "Tournament ID already exists");
         let tournament = Tournament {

Committable suggestion skipped: line range outside the PR's diff.


fn register_player(ref world: IWorldDispatcher, tournament_id: u32, new_player: Player) {
let mut tournament = get!(world, tournament_id, (Tournament));

assert!(tournament.status == TournamentStatus::Pending, "Tournament not open for registration");

assert!(
tournament.current_participants.len() < tournament.max_participants.try_into().unwrap(),
"Tournament is full"
);
Comment on lines +59 to +62
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix potential integer overflow in length comparison.

The current comparison between len() and max_participants involves unsafe type conversion.

Consider this safer approach:

-        assert!(
-            tournament.current_participants.len() < tournament.max_participants.try_into().unwrap(), 
-            "Tournament is full"
-        );
+        let current_count: u32 = tournament.current_participants.len().try_into().unwrap();
+        assert!(current_count < tournament.max_participants, "Tournament is full");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert!(
tournament.current_participants.len() < tournament.max_participants.try_into().unwrap(),
"Tournament is full"
);
let current_count: u32 = tournament.current_participants.len().try_into().unwrap();
assert!(current_count < tournament.max_participants, "Tournament is full");


tournament.current_participants.append(new_player);

set!(world, (tournament));
}
Comment on lines +54 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add player validation and entry fee handling.

The register_player method needs additional validations:

  1. Check for duplicate players
  2. Handle entry fee payment

Consider adding these validations:

     fn register_player(ref world: IWorldDispatcher, tournament_id: u32, new_player: Player) {
         let mut tournament = get!(world, tournament_id, (Tournament));
     
         assert!(tournament.status == TournamentStatus::Pending, "Tournament not open for registration");
     
         assert!(
             tournament.current_participants.len() < tournament.max_participants.try_into().unwrap(), 
             "Tournament is full"
         );

+        // Check for duplicate players
+        let mut i = 0;
+        loop {
+            if i >= tournament.current_participants.len() {
+                break;
+            }
+            assert!(
+                tournament.current_participants[i].player_id != new_player.player_id,
+                "Player already registered"
+            );
+            i += 1;
+        };
+
+        // TODO: Handle entry fee payment
+        // This would require integration with a payment system
+        // assert!(payment_received == tournament.entry_fee, "Entry fee not paid");

         tournament.current_participants.append(new_player);

Committable suggestion skipped: line range outside the PR's diff.


fn start_tournament(ref world: IWorldDispatcher, tournament_id: u32) {
let mut tournament = get!(world, tournament_id, (Tournament));

assert!(tournament.status == TournamentStatus::Pending, "Tournament not pending");

assert!(
tournament.current_participants.len() >= 2,
"Not enough participants to start"
);

tournament.status = TournamentStatus::Ongoing;

set!(world, (tournament));
}

fn get_tournament(world: @IWorldDispatcher, tournament_id: u32) -> Tournament {

This comment was marked as spam.

let tournament_from_world = get!(world, tournament_id, (Tournament));
tournament_from_world
}
Comment on lines +84 to +87
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for non-existent tournament.

The get_tournament method should handle the case when the tournament doesn't exist.

Add error handling:

     fn get_tournament(world: @IWorldDispatcher, tournament_id: u32) -> Tournament {
         let tournament_from_world = get!(world, tournament_id, (Tournament));
+        assert!(tournament_from_world.tournament_id != 0, "Tournament not found");
         tournament_from_world
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn get_tournament(world: @IWorldDispatcher, tournament_id: u32) -> Tournament {
let tournament_from_world = get!(world, tournament_id, (Tournament));
tournament_from_world
}
fn get_tournament(world: @IWorldDispatcher, tournament_id: u32) -> Tournament {
let tournament_from_world = get!(world, tournament_id, (Tournament));
assert!(tournament_from_world.tournament_id != 0, "Tournament not found");
tournament_from_world
}

}
}
Loading