diff --git a/onchain/src/contracts/lyricsflip.cairo b/onchain/src/contracts/lyricsflip.cairo index 94a2f980..266fcb56 100644 --- a/onchain/src/contracts/lyricsflip.cairo +++ b/onchain/src/contracts/lyricsflip.cairo @@ -4,7 +4,8 @@ pub mod LyricsFlip { use core::poseidon::PoseidonTrait; use lyricsflip::interfaces::lyricsflip::{ILyricsFlip}; use lyricsflip::utils::errors::Errors; - use lyricsflip::utils::types::{Answer, Card, Entropy, Genre, Round}; + + use lyricsflip::utils::types::{Card, Entropy, Genre, Round, Answer, PlayerStats}; use openzeppelin::introspection::src5::SRC5Component; use openzeppelin_access::accesscontrol::{AccessControlComponent}; use openzeppelin_access::ownable::OwnableComponent; @@ -47,6 +48,7 @@ pub mod LyricsFlip { >, // round_id -> player_index -> player_address round_players_count: Map, round_cards: Map>, // round_id -> vec + player_stats: Map, // player_address -> PlayerStats round_ready_players: Map< u64, Map >, // round_id -> player_address -> is_ready @@ -218,6 +220,33 @@ pub mod LyricsFlip { let is_ready = self.round_ready_players.entry(round_id).entry(caller_address).read(); assert(!is_ready, Errors::ALREADY_READY); + let round_players_count = self.round_players_count.entry(round_id).read(); + let mut round_players = array![]; + let mut idx = 0; + while (idx < round_players_count) { + round_players.append(self.round_players.entry(round_id).entry(idx).read()); + idx += 1; + }; + + let mut index = 0_u32; + let mut i = 0_u256; + while (i < round_players_count) { + let curr_player: ContractAddress = *round_players.at(index); + let curr_player_stat = self.player_stats.entry(curr_player).read(); + let new_total_rounds = curr_player_stat.total_rounds + 1; + let new_stats = PlayerStats { + total_rounds: new_total_rounds, + rounds_won: curr_player_stat.rounds_won, + current_streak: curr_player_stat.current_streak, + max_streak: curr_player_stat.max_streak + }; + + self.player_stats.entry(curr_player).write(new_stats); + index += 1; + i += 1; + }; + + //TODO: call the next_card function to get the first QuestionCard // mark player as ready self.round_ready_players.entry(round_id).entry(caller_address).write(true); @@ -373,6 +402,10 @@ pub mod LyricsFlip { cards.span() } + fn get_player_stat(self: @ContractState, player: ContractAddress) -> PlayerStats { + self.player_stats.entry(player).read() + } + // TODO fn submit_answer(self: @ContractState, answer: Answer) -> bool { false diff --git a/onchain/src/interfaces/lyricsflip.cairo b/onchain/src/interfaces/lyricsflip.cairo index 9edc4a6b..b6030e1e 100644 --- a/onchain/src/interfaces/lyricsflip.cairo +++ b/onchain/src/interfaces/lyricsflip.cairo @@ -1,4 +1,5 @@ -use lyricsflip::utils::types::{Answer, Card, Genre, Round}; +use lyricsflip::utils::types::{Card, Genre, Round, Answer, PlayerStats}; + use starknet::ContractAddress; #[starknet::interface] @@ -25,6 +26,8 @@ pub trait ILyricsFlip { ref self: TContractState, recipient: ContractAddress, role: felt252, is_enable: bool, ); + fn get_player_stat(self: @TContractState, player: ContractAddress) -> PlayerStats; + //TODO fn submit_answer(self: @TContractState, answer: Answer) -> bool; } diff --git a/onchain/src/tests/test_lyricsflip.cairo b/onchain/src/tests/test_lyricsflip.cairo index e7edebd3..486ee3bc 100644 --- a/onchain/src/tests/test_lyricsflip.cairo +++ b/onchain/src/tests/test_lyricsflip.cairo @@ -25,6 +25,10 @@ fn PLAYER_2() -> ContractAddress { 'PLAYER_2'.try_into().unwrap() } +fn PLAYER_3() -> ContractAddress { + 'PLAYER_3'.try_into().unwrap() +} + const ADMIN_ROLE: felt252 = selector!("ADMIN_ROLE"); const INVALID_ROLE: felt252 = selector!("INVALID_ROLE"); @@ -1007,3 +1011,76 @@ fn test_next_card_should_panic_with_completed_round() { lyricsflip.next_card(round_id); stop_cheat_caller_address(lyricsflip.contract_address); } + + +#[test] +fn test_start_round_updates_player_stats() { + let lyricsflip = deploy(); + + start_cheat_caller_address(lyricsflip.contract_address, OWNER()); + lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true); + stop_cheat_caller_address(lyricsflip.contract_address); + + start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS()); + for i in 0 + ..10_u64 { + let card = Card { + card_id: i.into(), + genre: Genre::HipHop, + artist: 'Bob Marley', + title: "", + year: 2000, + lyrics: "Lorem Ipsum", + }; + lyricsflip.add_card(card); + }; + + let valid_cards_per_round = 5; + lyricsflip.set_cards_per_round(valid_cards_per_round); + stop_cheat_caller_address(lyricsflip.contract_address); + + let seed = 1; + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); + let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), seed); + + stop_cheat_caller_address(lyricsflip.contract_address); + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_3()); + + lyricsflip.join_round(round_id); + + stop_cheat_caller_address(lyricsflip.contract_address); + + let player_one_stats = lyricsflip.get_player_stat(PLAYER_1()); + let player_two_stats = lyricsflip.get_player_stat(PLAYER_2()); + let player_three_stats = lyricsflip.get_player_stat(PLAYER_3()); + + assert(player_one_stats.total_rounds == 0, 'total rounds not zero'); + assert(player_two_stats.total_rounds == 0, 'total rounds not zero'); + assert(player_three_stats.total_rounds == 0, 'total rounds not zero'); + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); + lyricsflip.start_round(round_id); + stop_cheat_caller_address(lyricsflip.contract_address); + + let curr_player_stats = lyricsflip.get_player_stat(PLAYER_1()); + let curr_player_two_stats = lyricsflip.get_player_stat(PLAYER_2()); + let curr_player_three_stats = lyricsflip.get_player_stat(PLAYER_3()); + + assert(curr_player_stats.total_rounds == 1, 'Player stats not updated'); + assert(curr_player_two_stats.total_rounds == 0, 'Player two stats updated'); + assert(curr_player_three_stats.total_rounds == 1, 'Player three stats not updated'); + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_2()); + + let round_two_id = lyricsflip.create_round(Option::Some(Genre::HipHop), seed); + + lyricsflip.start_round(round_two_id); + + stop_cheat_caller_address(lyricsflip.contract_address); + + let new_player_two_stats = lyricsflip.get_player_stat(PLAYER_2()); + + assert(new_player_two_stats.total_rounds == 1, 'Player two stats not updated'); +} diff --git a/onchain/src/utils/types.cairo b/onchain/src/utils/types.cairo index af8bea10..0e483df1 100644 --- a/onchain/src/utils/types.cairo +++ b/onchain/src/utils/types.cairo @@ -10,6 +10,14 @@ pub struct Card { pub lyrics: ByteArray, } +#[derive(Drop, Serde, starknet::Store)] +pub struct PlayerStats { + pub total_rounds: u64, + pub rounds_won: u64, + pub current_streak: u64, + pub max_streak: u64, +} + #[derive(Drop, Copy, Serde, PartialEq, starknet::Store)] pub enum Genre { HipHop,