From 6d17f3e0be8f43a869565eaf9bb62dc8f2e3c347 Mon Sep 17 00:00:00 2001 From: Asher <141028690+No-bodyq@users.noreply.github.com> Date: Sat, 22 Feb 2025 14:31:59 +0100 Subject: [PATCH 1/4] feat: Implement player peformance tracking --- onchain/src/contracts/lyricsflip.cairo | 33 ++++++++++++++++++++++++- onchain/src/interfaces/lyricsflip.cairo | 4 ++- onchain/src/utils/types.cairo | 8 ++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/onchain/src/contracts/lyricsflip.cairo b/onchain/src/contracts/lyricsflip.cairo index 09d116b4..7a9d8dcc 100644 --- a/onchain/src/contracts/lyricsflip.cairo +++ b/onchain/src/contracts/lyricsflip.cairo @@ -4,7 +4,7 @@ pub mod LyricsFlip { use core::poseidon::PoseidonTrait; use lyricsflip::interfaces::lyricsflip::{ILyricsFlip}; use lyricsflip::utils::errors::Errors; - use lyricsflip::utils::types::{Card, Entropy, Genre, Round, Answer}; + 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 +47,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 #[substorage(v0)] ownable: OwnableComponent::Storage, #[substorage(v0)] @@ -204,6 +205,32 @@ pub mod LyricsFlip { round.start_time.write(start_time); round.is_started.write(true); + 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 self @@ -334,6 +361,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 fa8c33c4..17b60c80 100644 --- a/onchain/src/interfaces/lyricsflip.cairo +++ b/onchain/src/interfaces/lyricsflip.cairo @@ -1,4 +1,4 @@ -use lyricsflip::utils::types::{Card, Genre, Round, Answer}; +use lyricsflip::utils::types::{Card, Genre, Round, Answer, PlayerStats}; use starknet::ContractAddress; #[starknet::interface] @@ -25,6 +25,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/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, From 6e4284f81966504536758c57809c1580b32ed585 Mon Sep 17 00:00:00 2001 From: Asher <141028690+No-bodyq@users.noreply.github.com> Date: Sat, 22 Feb 2025 14:43:09 +0100 Subject: [PATCH 2/4] add test --- onchain/src/tests/test_lyricsflip.cairo | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/onchain/src/tests/test_lyricsflip.cairo b/onchain/src/tests/test_lyricsflip.cairo index 8f211395..d1870f0f 100644 --- a/onchain/src/tests/test_lyricsflip.cairo +++ b/onchain/src/tests/test_lyricsflip.cairo @@ -949,3 +949,52 @@ 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_block_timestamp_global(1736593692); + + 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); + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); + let seed = 1; + let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), seed); + + let player_stats = lyricsflip.get_player_stat(PLAYER_1()); + + assert(player_stats.total_rounds == 0, 'total rounds not zero'); + lyricsflip.start_round(round_id); + + stop_cheat_caller_address(lyricsflip.contract_address); + + let round = lyricsflip.get_round(round_id); + + let player_stats = lyricsflip.get_player_stat(PLAYER_1()); + + assert(player_stats.total_rounds == 1, 'Player stats not updated'); + + stop_cheat_block_timestamp_global(); +} From b6843f619edaa2bc3694197e587983353c7f55e9 Mon Sep 17 00:00:00 2001 From: Asher <141028690+No-bodyq@users.noreply.github.com> Date: Sun, 23 Feb 2025 13:30:24 +0100 Subject: [PATCH 3/4] fix test --- onchain/src/tests/test_lyricsflip.cairo | 48 +++++++++++++++++++------ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/onchain/src/tests/test_lyricsflip.cairo b/onchain/src/tests/test_lyricsflip.cairo index e01aa0b9..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"); @@ -1013,8 +1017,6 @@ fn test_next_card_should_panic_with_completed_round() { fn test_start_round_updates_player_stats() { let lyricsflip = deploy(); - start_cheat_block_timestamp_global(1736593692); - start_cheat_caller_address(lyricsflip.contract_address, OWNER()); lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true); stop_cheat_caller_address(lyricsflip.contract_address); @@ -1037,22 +1039,48 @@ fn test_start_round_updates_player_stats() { lyricsflip.set_cards_per_round(valid_cards_per_round); stop_cheat_caller_address(lyricsflip.contract_address); - start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); let seed = 1; + + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), seed); - let player_stats = lyricsflip.get_player_stat(PLAYER_1()); + stop_cheat_caller_address(lyricsflip.contract_address); - assert(player_stats.total_rounds == 0, 'total rounds not zero'); - lyricsflip.start_round(round_id); + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_3()); + + lyricsflip.join_round(round_id); stop_cheat_caller_address(lyricsflip.contract_address); - let round = lyricsflip.get_round(round_id); + 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()); - let player_stats = lyricsflip.get_player_stat(PLAYER_1()); + 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'); - assert(player_stats.total_rounds == 1, 'Player stats not updated'); + start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1()); + lyricsflip.start_round(round_id); + stop_cheat_caller_address(lyricsflip.contract_address); - stop_cheat_block_timestamp_global(); + 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'); } From 11ef4fc8e299c9099101eb41732c1a28185a7057 Mon Sep 17 00:00:00 2001 From: Asher <141028690+No-bodyq@users.noreply.github.com> Date: Sun, 23 Feb 2025 13:32:39 +0100 Subject: [PATCH 4/4] fmt --- onchain/src/contracts/lyricsflip.cairo | 2 -- 1 file changed, 2 deletions(-) diff --git a/onchain/src/contracts/lyricsflip.cairo b/onchain/src/contracts/lyricsflip.cairo index 41d308ef..266fcb56 100644 --- a/onchain/src/contracts/lyricsflip.cairo +++ b/onchain/src/contracts/lyricsflip.cairo @@ -48,7 +48,6 @@ 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 @@ -221,7 +220,6 @@ 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;