Skip to content

Commit

Permalink
Implement the attack logic keep-starknet-strange#26
Browse files Browse the repository at this point in the history
I have implemented the beginning of the contract as well as the attack logic tests but the implementation of the attack requires the modification of the component file as well as the implementation of the card deck system in order to verify the lenght of the players' hand.
  • Loading branch information
WhoIsNac committed Aug 14, 2023
1 parent 544de5f commit 34508cf
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 80 deletions.
3 changes: 3 additions & 0 deletions contracts/src/systems.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ mod attack;
mod end_turn;
mod place_card;
mod create_game;
mod create_card;

use attack::attack_system;
use end_turn::end_turn_system;
use place_card::place_card_system;
use create_game::create_game_system;

use create_card::create_card_system;

69 changes: 68 additions & 1 deletion contracts/src/systems/attack.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,74 @@
#[system]
mod attack_system {
use dojo::world::Context;
use traits::Into;
use option::Option;
use tsubasa::components::{Game, Energy, Card};
use tsubasa::components::Roles;
use tsubasa::events::{EndTurn};
use array::ArrayTrait;
use debug::PrintTrait;

fn execute(ctx: Context, player: u8) {}
fn execute(ctx: Context, game_id: felt252, token_id_player1: u256, token_id_player2: u256) {
let game = get!(ctx.world, game_id, Game);
let card_player1 = get!(ctx.world, token_id_player1, Card);
let card_player2 = get!(ctx.world, token_id_player2, Card);

set!(
ctx.world, Card {
token_id: token_id_player1,
dribble: card_player1.dribble,
current_dribble: card_player1.current_dribble,
defense: card_player1.defense,
current_defense: card_player1.current_defense,
cost: card_player1.cost,
role: card_player1.role,
is_captain: card_player1.is_captain,
}
);

//We set a value as boolean replacement to match the Roles
let mut value = 0;
match card_player1.role {
Roles::Goalkeeper => 'Goalkeeper'.print(),
Roles::Defender => 'Defender'.print(),
Roles::Midfielder => 'Midfielder'.print(),
Roles::Attacker => value = 1,
}

if value == 1 {
//If the card_player1 can dribble the current card_player2
if card_player1.dribble > card_player2.defense {
set!(
ctx.world, Card {
token_id: token_id_player1,
dribble: card_player1.dribble,
current_dribble: card_player1.current_dribble,
defense: card_player1.defense,
current_defense: card_player1.current_defense - card_player2.dribble,
cost: card_player1.cost,
role: card_player1.role,
is_captain: card_player1.is_captain
}
);
// TO-DO : Add an remove card_player2 function
} else {
//If the Attacker didn't pass the card_player2 => end of the turn
let game = get!(ctx.world, game_id, Game);

set!(
ctx.world, Game {
game_id,
player1: game.player1,
player2: game.player2,
player1_score: game.player1_score,
player2_score: game.player2_score,
turn: game.turn + 1,
outcome: game.outcome
}
);
}
}
}
}

34 changes: 34 additions & 0 deletions contracts/src/systems/create_card.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#[system]
mod create_card_system {
use traits::Into;
use dojo::world::Context;
use starknet::ContractAddress;
use tsubasa::events::{GameCreated};
use tsubasa::components::{Game, Energy, Card};
use option::Option;
use array::{ArrayTrait};
use tsubasa::components::Roles;


fn execute(ctx: Context, token_id: u256, role: felt252) {
let mut value = Roles::Attacker;
match role {
0 => value = Roles::Attacker,
_ => value = Roles::Midfielder,
}

set!(
ctx.world, Card {
token_id: token_id,
dribble: 11,
current_dribble: 0,
defense: 10,
current_defense: 0,
cost: 0,
role: value,
is_captain: false
}
);
//emit!(ctx.world, GameCreated { game_id, player1, player2 })
}
}
1 change: 1 addition & 0 deletions contracts/src/tests.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod attack;
mod create_game;
mod create_card;
mod end_turn;
mod place_card;
mod utils;
66 changes: 57 additions & 9 deletions contracts/src/tests/attack.cairo
Original file line number Diff line number Diff line change
@@ -1,24 +1,72 @@
use core::traits::{Into, Default};
use array::ArrayTrait;
use traits::{Into, Default};
use option::{Option, OptionTrait};
use serde::Serde;
use array::ArrayTrait;

use dojo::world::IWorldDispatcherTrait;

use tsubasa::systems::place_card_system;
use tsubasa::systems::attack_system;
use tsubasa::components::{Game, Energy, Card};
use tsubasa::components::Roles;
use tsubasa::systems::{
create_game_system, attack_system, end_turn_system, place_card_system, create_card_system,
};

use tsubasa::tests::utils::spawn_world;


#[test]
#[available_gas(30000000)]
fn test_attack() {
let caller = starknet::contract_address_const::<0x0>();
fn test_attack_turn() {
let player1 = starknet::contract_address_const::<0x1>();
let player2 = starknet::contract_address_const::<0x2>();

// use player1 address
starknet::testing::set_contract_address(player1);

let world = spawn_world();

let mut place_card_calldata: Array = Default::default();
0_u256.serialize(ref place_card_calldata);
//Create Game Part
let mut create_game_calldata: Array<felt252> = ArrayTrait::new();
create_game_calldata.append(player2.into());

world.execute('create_game_system', create_game_calldata);
let expected_game_id = pedersen(player1.into(), player2.into());
let game_id = pedersen(player1.into(), player2.into());
let game = get!(world, expected_game_id, Game);

assert(game.game_id == expected_game_id, 'invalid game_id');
assert(game.player1 == player1, 'invalid player 1');
assert(game.player2 == player2, 'invalid player 2');
assert(game.player1_score == 0, 'invalid player 1 score');
assert(game.player2_score == 0, 'invalid player 2 score');
assert(game.outcome.is_none(), 'invalid outcome');

// let place_card_calldata = array![0, 0]; // u256 { low: 0, high: 0 }
let mut place_card_calldata: Array<felt252> = ArrayTrait::new();
place_card_calldata.append(0);
place_card_calldata.append(0);
world.execute('place_card_system', place_card_calldata);

let attack_calldata = array![0];
//Create Card For test prupose
let mut create_card_calldata: Array<felt252> = ArrayTrait::new();
create_card_calldata.append(1);
create_card_calldata.append(0);
world.execute('create_card_system', create_card_calldata);

let mut create_card_calldata_player2: Array<felt252> = ArrayTrait::new();
create_card_calldata_player2.append(2);
create_card_calldata_player2.append(0);
world.execute('create_card_system', create_card_calldata_player2);

//Attack logic test part
let mut attack_calldata: Array<felt252> = ArrayTrait::new();
attack_calldata.append(game.game_id);
attack_calldata.append(1);
attack_calldata.append(2);
world.execute('attack_system', attack_calldata);

let card_player1 = get!(world, 1, Card);
let card_player2 = get!(world, 2, Card);
let expected_remaining_defense = card_player1.dribble - card_player2.defense;
assert(card_player1.defense != expected_remaining_defense, 'invalid Attack logic execution');
}
35 changes: 35 additions & 0 deletions contracts/src/tests/create_card.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use core::traits::{Into, Default};
use array::ArrayTrait;
use serde::Serde;
use option::{Option, OptionTrait};

use dojo::world::IWorldDispatcherTrait;

use tsubasa::components::{Game, Energy, Card};
use tsubasa::tests::utils::spawn_world;
use tsubasa::systems::create_card_system;

#[test]
#[available_gas(30000000)]
fn test_create_card() {
let player1 = starknet::contract_address_const::<0x1>();
let player2 = starknet::contract_address_const::<0x2>();

let world = spawn_world();

//Create Card For test prupose
let mut create_card_calldata: Array<felt252> = ArrayTrait::new();
create_card_calldata.append(1);
create_card_calldata.append(4);
world.execute('create_card_system', create_card_calldata);

let mut create_card_calldata_player2: Array<felt252> = ArrayTrait::new();
create_card_calldata_player2.append(2);
create_card_calldata_player2.append(4);
world.execute('create_card_system', create_card_calldata_player2);

let card_player1 = get!(world, 1, Card);
let card_player2 = get!(world, 1, Card);

assert(card_player1.dribble > card_player2.defense, 'invalid Attack logic execution');
}
70 changes: 0 additions & 70 deletions contracts/src/tests/end_turn.cairo
Original file line number Diff line number Diff line change
@@ -1,70 +0,0 @@
use traits::{Into, Default};
use option::{Option, OptionTrait};
use serde::Serde;
use array::ArrayTrait;

use dojo::world::IWorldDispatcherTrait;

use tsubasa::components::{Game, Energy};
use tsubasa::systems::{create_game_system, attack_system, end_turn_system, place_card_system};

use tsubasa::tests::utils::spawn_world;

#[test]
#[available_gas(30000000)]
fn test_end_turn() {
let player1 = starknet::contract_address_const::<0x1>();
let player2 = starknet::contract_address_const::<0x2>();

// use player1 address
starknet::testing::set_contract_address(player1);

let world = spawn_world();

let game_id = pedersen(player1.into(), player2.into());

// let create_game_calldata: Array<felt252> = array![player2.into()];
let mut create_game_calldata: Array<felt252> = ArrayTrait::new();
create_game_calldata.append(player2.into());
world.execute('create_game_system', create_game_calldata);

// let place_card_calldata = array![0, 0]; // u256 { low: 0, high: 0 }
let mut place_card_calldata: Array<felt252> = ArrayTrait::new();
place_card_calldata.append(0);
place_card_calldata.append(0);
world.execute('place_card_system', place_card_calldata);

// let attack_calldata = array![0];
let mut attack_calldata: Array<felt252> = ArrayTrait::new();
attack_calldata.append(0);
world.execute('attack_system', attack_calldata);

// let end_turn_calldata = array![game_id];
let mut end_turn_calldata: Array<felt252> = ArrayTrait::new();
end_turn_calldata.append(game_id);
world.execute('end_turn_system', end_turn_calldata);

let game = get!(world, game_id, Game);

let expected_game = Game {
game_id,
player1,
player2,
player1_score: 0,
player2_score: 0,
turn: 1,
outcome: Option::None
};

assert(game.game_id == expected_game.game_id, 'invalid game_id');
assert(game.player1_score == expected_game.player1_score, 'Wrong player1 score');
assert(game.player2_score == expected_game.player2_score, 'Wrong player2 score');
assert(game.turn == expected_game.turn, 'Wrong turn value');
// Check that option is None
assert(game.outcome.is_none(), 'Wrong outcome value');

let expected_energy = Energy { game_id, player: player1, remaining: 2 };
let player_energy = get!(world, (expected_energy.game_id, expected_energy.player), Energy);
// Check that player energy is correclty incremented at the end of each turn.
assert(player_energy.remaining == expected_energy.remaining, 'Wrong player energy value');
}

0 comments on commit 34508cf

Please sign in to comment.