Skip to content

Commit d329003

Browse files
committed
✨ Add round limit
1 parent 149ca79 commit d329003

14 files changed

+116
-48
lines changed

src/models/game.cairo

+22-7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct Game {
2626
price: u256,
2727
clock: u64,
2828
penalty: u64,
29+
limit: u32,
2930
}
3031

3132
#[derive(Drop, PartialEq)]
@@ -62,7 +63,18 @@ impl GameImpl of GameTrait {
6263
assert(host != 0, errors::GAME_INVALID_HOST);
6364

6465
// [Return] Default game
65-
Game { id, host, over: false, seed: 0, player_count: 0, nonce: 0, price, clock: 0, penalty }
66+
Game {
67+
id,
68+
host,
69+
over: false,
70+
seed: 0,
71+
player_count: 0,
72+
nonce: 0,
73+
price,
74+
clock: 0,
75+
penalty,
76+
limit: 0
77+
}
6678
}
6779

6880
#[inline(always)]
@@ -160,7 +172,7 @@ impl GameImpl of GameTrait {
160172
self.host = host;
161173
}
162174

163-
fn start(ref self: Game, time: u64, mut players: Array<felt252>) {
175+
fn start(ref self: Game, time: u64, round_count: u32, mut players: Array<felt252>) {
164176
// [Check] Game is valid
165177
self.assert_exists();
166178
self.assert_not_over();
@@ -178,6 +190,7 @@ impl GameImpl of GameTrait {
178190
};
179191
self.seed = state.finalize();
180192
self.clock = time;
193+
self.limit = self.player_count.into() * round_count * TURN_COUNT;
181194
}
182195

183196
#[inline(always)]
@@ -308,7 +321,8 @@ impl ZeroableGame of core::Zeroable<Game> {
308321
nonce: 0,
309322
price: 0,
310323
clock: 0,
311-
penalty: 0
324+
penalty: 0,
325+
limit: 0,
312326
}
313327
}
314328

@@ -345,6 +359,7 @@ mod tests {
345359
const HOST: felt252 = 'HOST';
346360
const PLAYER: felt252 = 'PLAYER';
347361
const TIME: u64 = 1337;
362+
const ROUND_COUNT: u32 = 100;
348363

349364
#[test]
350365
#[available_gas(100_000)]
@@ -491,7 +506,7 @@ mod tests {
491506
game.join();
492507
};
493508
let players = array![HOST, PLAYER];
494-
game.start(TIME, players);
509+
game.start(TIME, ROUND_COUNT, players);
495510
assert(game.seed != 0, 'Game: wrong seed');
496511
}
497512

@@ -502,7 +517,7 @@ mod tests {
502517
let mut game = GameTrait::new(ID, HOST, PRICE, PENALTY);
503518
game.player_count = 0;
504519
let players = array![HOST, PLAYER];
505-
game.start(TIME, players);
520+
game.start(TIME, ROUND_COUNT, players);
506521
}
507522

508523
#[test]
@@ -512,7 +527,7 @@ mod tests {
512527
let mut game = GameTrait::new(ID, HOST, PRICE, PENALTY);
513528
game.over = true;
514529
let players = array![HOST, PLAYER];
515-
game.start(TIME, players);
530+
game.start(TIME, ROUND_COUNT, players);
516531
}
517532

518533
#[test]
@@ -522,7 +537,7 @@ mod tests {
522537
let mut game = GameTrait::new(ID, HOST, PRICE, PENALTY);
523538
game.seed = 1;
524539
let players = array![HOST, PLAYER];
525-
game.start(TIME, players);
540+
game.start(TIME, ROUND_COUNT, players);
526541
}
527542

528543
#[test]

src/models/player.cairo

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Core imports
2+
3+
use core::zeroable::Zeroable;
4+
15
// Starknet imports
26

37
use starknet::ContractAddress;
@@ -71,7 +75,7 @@ impl PlayerAssert of AssertTrait {
7175
}
7276
}
7377

74-
impl ZeroablePlayer of core::Zeroable<Player> {
78+
impl ZeroablePlayer of Zeroable<Player> {
7579
#[inline(always)]
7680
fn zero() -> Player {
7781
Player {

src/store.cairo

+24-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
1111
// Components imports
1212

1313
use zconqueror::models::game::{Game, GameTrait};
14-
use zconqueror::models::player::{Player, PlayerTrait};
14+
use zconqueror::models::player::{Player, PlayerTrait, ZeroablePlayer};
1515
use zconqueror::models::tile::Tile;
16+
use zconqueror::types::map::{Map, MapTrait};
1617

1718
// Internal imports
1819

@@ -108,6 +109,28 @@ impl StoreImpl of StoreTrait {
108109
rank - 1
109110
}
110111

112+
fn get_last_unranked_player(ref self: Store, game: Game, ref map: Map) -> Option<Player> {
113+
let mut index = game.player_count;
114+
let mut score = 0;
115+
let mut last: Player = ZeroablePlayer::zero();
116+
loop {
117+
if index == 0 {
118+
break;
119+
};
120+
index -= 1;
121+
let player = self.player(game, index.into());
122+
let player_score = map.player_score(player.index);
123+
if player.rank == 0 && (player_score < score || score == 0) {
124+
last = player;
125+
};
126+
};
127+
if last.is_zero() {
128+
Option::None
129+
} else {
130+
Option::Some(last)
131+
}
132+
}
133+
111134
fn tile(ref self: Store, game: Game, id: u8) -> Tile {
112135
let tile_key = (game.id, id);
113136
get!(self.world, tile_key.into(), (Tile))

src/systems/host.cairo

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ trait IHost<TContractState> {
2222
fn delete(self: @TContractState, world: IWorldDispatcher, game_id: u32);
2323
fn kick(self: @TContractState, world: IWorldDispatcher, game_id: u32, index: u32);
2424
fn transfer(self: @TContractState, world: IWorldDispatcher, game_id: u32, index: u32);
25-
fn start(self: @TContractState, world: IWorldDispatcher, game_id: u32);
25+
fn start(self: @TContractState, world: IWorldDispatcher, game_id: u32, round_count: u32);
2626
fn claim(self: @TContractState, world: IWorldDispatcher, game_id: u32);
2727
}
2828

@@ -275,7 +275,7 @@ mod host {
275275
store.set_player(player);
276276
}
277277

278-
fn start(self: @ContractState, world: IWorldDispatcher, game_id: u32,) {
278+
fn start(self: @ContractState, world: IWorldDispatcher, game_id: u32, round_count: u32) {
279279
// [Setup] Datastore
280280
let mut store: Store = StoreTrait::new(world);
281281

@@ -296,7 +296,7 @@ mod host {
296296

297297
// [Effect] Update Game
298298
let time = get_block_timestamp();
299-
game.start(time, addresses);
299+
game.start(time, round_count, addresses);
300300
store.set_game(game);
301301

302302
// [Effect] Update Tiles

src/systems/play.cairo

+21-4
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ mod play {
278278
battle.attacker_troops = attacker_troops;
279279
battle.defender_troops = defender_troops;
280280
battle.tx_hash = get_tx_info().unbox().transaction_hash;
281-
emit!(world, battle);
281+
emit!(world, (Event::Battle(battle)));
282282
},
283283
Option::None => { break; },
284284
};
@@ -565,9 +565,26 @@ mod play {
565565
) {
566566
// [Compute] Update next player to not dead player
567567
let tiles = store.tiles(game).span();
568-
let mut map = MapTrait::from_tiles(game.player_count.into(), tiles);
569-
let rank = store.get_next_rank(game);
568+
let mut map: Map = MapTrait::from_tiles(game.player_count.into(), tiles);
569+
570+
// [Check] Game reached the last round
571+
if game.limit == game.nonce {
572+
// [Effect] Rank every remaining players
573+
loop {
574+
let last_unranked = store.get_last_unranked_player(game, ref map);
575+
match last_unranked {
576+
Option::Some(mut player) => {
577+
let rank = store.get_next_rank(game);
578+
player.rank(rank);
579+
store.set_player(player);
580+
},
581+
Option::None => { break; },
582+
};
583+
};
584+
return;
585+
};
570586

587+
let rank = store.get_next_rank(game);
571588
loop {
572589
let mut next_player = store.current_player(game);
573590
// [Check] Next player is the current player or next rank is 1, means game is over
@@ -591,7 +608,7 @@ mod play {
591608
let player_score = map.player_score(next_player.index);
592609
if 0 == player_score.into() {
593610
// [Effect] Update player
594-
next_player.rank(store.get_next_rank(game));
611+
next_player.rank(rank);
595612
store.set_player(next_player);
596613
// [Effect] Move to next player
597614
game.pass();

src/tests/attack.cairo

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const PRICE: u256 = 1_000_000_000_000_000_000;
2929
const PENALTY: u64 = 60;
3030
const PLAYER_COUNT: u8 = 2;
3131
const PLAYER_INDEX: u32 = 0;
32+
const ROUND_COUNT: u32 = 10;
3233

3334
#[test]
3435
#[available_gas(1_000_000_000)]
@@ -42,7 +43,7 @@ fn test_attack() {
4243
set_contract_address(PLAYER());
4344
systems.host.join(world, game_id, PLAYER_NAME);
4445
set_contract_address(HOST());
45-
systems.host.start(world, game_id);
46+
systems.host.start(world, game_id, ROUND_COUNT);
4647

4748
// [Compute] Attacker tile
4849
let game: Game = store.game(game_id);
@@ -98,7 +99,7 @@ fn test_attack_revert_invalid_player() {
9899
set_contract_address(PLAYER());
99100
systems.host.join(world, game_id, PLAYER_NAME);
100101
set_contract_address(HOST());
101-
systems.host.start(world, game_id);
102+
systems.host.start(world, game_id, ROUND_COUNT);
102103

103104
// [Compute] Tile army and player available supply
104105
let game: Game = store.game(game_id);
@@ -140,7 +141,7 @@ fn test_attack_revert_invalid_owner() {
140141
set_contract_address(PLAYER());
141142
systems.host.join(world, game_id, PLAYER_NAME);
142143
set_contract_address(HOST());
143-
systems.host.start(world, game_id);
144+
systems.host.start(world, game_id, ROUND_COUNT);
144145

145146
// [Compute] Tile army and player available supply
146147
let game: Game = store.game(game_id);

src/tests/banish.cairo

+5-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const PRICE: u256 = 1_000_000_000_000_000_000;
3030
const PENALTY: u64 = 60;
3131
const PLAYER_COUNT: u8 = 2;
3232
const PLAYER_INDEX: u32 = 0;
33+
const ROUND_COUNT: u32 = 10;
3334

3435
#[test]
3536
#[available_gas(1_000_000_000)]
@@ -44,7 +45,7 @@ fn test_banish_2_players() {
4445
set_contract_address(PLAYER());
4546
systems.host.join(world, game_id, PLAYER_NAME);
4647
set_contract_address(HOST());
47-
systems.host.start(world, game_id);
48+
systems.host.start(world, game_id, ROUND_COUNT);
4849

4950
// [Banish]
5051
set_contract_address(PLAYER());
@@ -72,7 +73,7 @@ fn test_banish_3_players() {
7273
set_contract_address(ANYONE());
7374
systems.host.join(world, game_id, ANYONE_NAME);
7475
set_contract_address(HOST());
75-
systems.host.start(world, game_id);
76+
systems.host.start(world, game_id, ROUND_COUNT);
7677

7778
// [Banish]
7879
set_contract_address(PLAYER());
@@ -120,7 +121,7 @@ fn test_banish_revert_invalid_condition() {
120121
set_contract_address(PLAYER());
121122
systems.host.join(world, game_id, PLAYER_NAME);
122123
set_contract_address(HOST());
123-
systems.host.start(world, game_id);
124+
systems.host.start(world, game_id, ROUND_COUNT);
124125

125126
// [Banish]
126127
set_contract_address(PLAYER());
@@ -143,7 +144,7 @@ fn test_banish_revert_game_is_over() {
143144
set_contract_address(PLAYER());
144145
systems.host.join(world, game_id, PLAYER_NAME);
145146
set_contract_address(HOST());
146-
systems.host.start(world, game_id);
147+
systems.host.start(world, game_id, ROUND_COUNT);
147148

148149
// [Banish]
149150
set_contract_address(PLAYER());

src/tests/defend.cairo

+6-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const PRICE: u256 = 1_000_000_000_000_000_000;
2929
const PENALTY: u64 = 60;
3030
const PLAYER_COUNT: u8 = 2;
3131
const PLAYER_INDEX: u32 = 0;
32+
const ROUND_COUNT: u32 = 10;
3233

3334
#[test]
3435
#[available_gas(1_000_000_000)]
@@ -42,7 +43,7 @@ fn test_defend_win() {
4243
set_contract_address(PLAYER());
4344
systems.host.join(world, game_id, PLAYER_NAME);
4445
set_contract_address(HOST());
45-
systems.host.start(world, game_id);
46+
systems.host.start(world, game_id, ROUND_COUNT);
4647

4748
// [Compute] Attacker tile
4849
let game: Game = store.game(game_id);
@@ -122,7 +123,7 @@ fn test_defend_lose() {
122123
set_contract_address(PLAYER());
123124
systems.host.join(world, game_id, PLAYER_NAME);
124125
set_contract_address(HOST());
125-
systems.host.start(world, game_id);
126+
systems.host.start(world, game_id, ROUND_COUNT);
126127

127128
// [Compute] Attacker tile
128129
let game: Game = store.game(game_id);
@@ -204,7 +205,7 @@ fn test_defend_revert_invalid_order() {
204205
set_contract_address(PLAYER());
205206
systems.host.join(world, game_id, PLAYER_NAME);
206207
set_contract_address(HOST());
207-
systems.host.start(world, game_id);
208+
systems.host.start(world, game_id, ROUND_COUNT);
208209

209210
// [Compute] Attacker tile
210211
let game: Game = store.game(game_id);
@@ -265,7 +266,7 @@ fn test_defend_revert_invalid_player() {
265266
set_contract_address(PLAYER());
266267
systems.host.join(world, game_id, PLAYER_NAME);
267268
set_contract_address(HOST());
268-
systems.host.start(world, game_id);
269+
systems.host.start(world, game_id, ROUND_COUNT);
269270

270271
// [Compute] Tile army and player available supply
271272
let game: Game = store.game(game_id);
@@ -307,7 +308,7 @@ fn test_defend_revert_invalid_owner() {
307308
set_contract_address(PLAYER());
308309
systems.host.join(world, game_id, PLAYER_NAME);
309310
set_contract_address(HOST());
310-
systems.host.start(world, game_id);
311+
systems.host.start(world, game_id, ROUND_COUNT);
311312

312313
// [Compute] Tile army and player available supply
313314
let game: Game = store.game(game_id);

src/tests/emote.cairo

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const PENALTY: u64 = 60;
3030
const PLAYER_COUNT: u8 = 2;
3131
const PLAYER_INDEX: u32 = 0;
3232
const EMOTE_INDEX: u8 = 12;
33+
const ROUND_COUNT: u32 = 10;
3334

3435

3536
#[test]
@@ -44,7 +45,7 @@ fn test_emote_valid_player() {
4445
set_contract_address(PLAYER());
4546
systems.host.join(world, game_id, PLAYER_NAME);
4647
set_contract_address(HOST());
47-
systems.host.start(world, game_id);
48+
systems.host.start(world, game_id, ROUND_COUNT);
4849

4950
// [Emote]
5051
let game: Game = store.game(game_id);
@@ -69,7 +70,7 @@ fn test_emote_revert_invalid_player() {
6970
set_contract_address(PLAYER());
7071
systems.host.join(world, game_id, PLAYER_NAME);
7172
set_contract_address(HOST());
72-
systems.host.start(world, game_id);
73+
systems.host.start(world, game_id, ROUND_COUNT);
7374

7475
// [Emote]
7576
let game: Game = store.game(game_id);

0 commit comments

Comments
 (0)