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

Matchmaker #3

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 6 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pallets/connectfour/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ frame-support = {default-features = false, version = '3.0.0', git = 'https://git
frame-system = {default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-05'}
frame-benchmarking = {default-features = false, version = '3.1.0', git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-05', optional = true}

# external pallets
pallet-matchmaker = {default-features = false, version = '0.1.0', git = 'https://github.com/JetonNetwork/pallet-jton-matchmaker.git'}

[dev-dependencies]
serde = '1.0.119'
sp-core = {default-features = false, version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', tag = 'monthly-2021-05'}
Expand All @@ -41,5 +44,6 @@ std = [
'frame-support/std',
'frame-system/std',
'frame-benchmarking/std',
'pallet-matchmaker/std',
]
try-runtime = ['frame-support/try-runtime']
2 changes: 1 addition & 1 deletion pallets/connectfour/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Benchmarking setup for pallet-template
//! Benchmarking setup for pallet-connect four

use super::*;

Expand Down
91 changes: 81 additions & 10 deletions pallets/connectfour/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use sp_runtime::{
use sp_std::vec::{
Vec
};
use pallet_matchmaker::MatchFunc;

use log::info;

// Re-export pallet items so that they can be accessed from the crate namespace.
Expand Down Expand Up @@ -69,6 +71,7 @@ pub struct BoardStruct<Hash, AccountId, BlockNumber, BoardState> {

const PLAYER_1: u8 = 1;
const PLAYER_2: u8 = 2;
const MAX_GAMES_PER_BLOCK: u8 = 10;
const MAX_BLOCKS_PER_TURN: u8 = 10;
const CLEANUP_BOARDS_AFTER: u8 = 20;

Expand All @@ -95,6 +98,9 @@ pub mod pallet {
type Scheduler: Named<Self::BlockNumber, Self::Proposal, Self::PalletsOrigin>;

type PalletsOrigin: From<frame_system::RawOrigin<Self::AccountId>>;

type MatchMaker: MatchFunc<Self::AccountId>;

// /// Weight information for extrinsics in this pallet.
//type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -194,6 +200,10 @@ pub mod pallet {
NotPlayerTurn,
/// There was an error while trying to execute something in the logic mod.
WrongLogic,
/// Unable to queue, make sure you're not already queued.
AlreadyQueued,
/// Extrinsic is limited to founder.
OnlyFounderAllowed,
}

// Pallet implements [`Hooks`] trait to define some logic to execute in some context.
Expand All @@ -206,7 +216,25 @@ pub mod pallet {
fn on_initialize(_: T::BlockNumber) -> Weight {
// Anything that needs to be done at the start of the block.
// We don't do anything here.
0

// initial weights
let mut tot_weights = 10_000;
for _i in 0..MAX_GAMES_PER_BLOCK {
// try to create a match till we reached max games or no more matches available
let result = T::MatchMaker::try_match();
// if result is not empty we have a valid match
if !result.is_empty() {
// Create new game
let _game_id = Self::create_game(result[0].clone(), result[1].clone());
// weights need to be adjusted
tot_weights = tot_weights + T::DbWeight::get().reads_writes(1,1);
continue;
}
break;
}

// return standard weigth for trying to fiond a match
return tot_weights
}

// `on_finalize` is executed at the end of block after all extrinsic are dispatched.
Expand Down Expand Up @@ -274,6 +302,40 @@ pub mod pallet {
}
}

/// Queue sender up for a game, ranking brackets
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
pub fn queue(origin: OriginFor<T>) -> DispatchResult {

let sender = ensure_signed(origin)?;

// Make sure player has no board open.
ensure!(!PlayerBoard::<T>::contains_key(&sender), Error::<T>::PlayerBoardExists);

let bracket: u8 = 0;
// Add player to queue, duplicate check is done in matchmaker.
if !T::MatchMaker::add_queue(sender, bracket) {
return Err(Error::<T>::AlreadyQueued)?
}

Ok(())
}

/// Empty all brackets, this is a founder only extrinsic.
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
pub fn empty_queue(origin: OriginFor<T>) -> DispatchResult {

let sender = ensure_signed(origin)?;

// Make sure sender is founder.
ensure!(sender == Self::founder_key().unwrap(), Error::<T>::OnlyFounderAllowed);

let bracket: u8 = 0;
// Empty queues
T::MatchMaker::empty_queue(bracket);

Ok(())
}

/// Create game for two players
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
pub fn new_game(origin: OriginFor<T>, opponent: T::AccountId) -> DispatchResult {
Expand All @@ -283,16 +345,16 @@ pub mod pallet {
// Don't allow playing against yourself.
ensure!(sender != opponent, Error::<T>::NoFakePlay);

// Don't allow queued player to create a game.
ensure!(!T::MatchMaker::is_queued(sender.clone()), Error::<T>::AlreadyQueued);
ensure!(!T::MatchMaker::is_queued(opponent.clone()), Error::<T>::AlreadyQueued);

// Make sure players have no board open.
ensure!(!PlayerBoard::<T>::contains_key(&sender), Error::<T>::PlayerBoardExists);
ensure!(!PlayerBoard::<T>::contains_key(&opponent), Error::<T>::PlayerBoardExists);

// Create new game
let board_id = Self::create_game(sender.clone(), opponent.clone());

// Add board to the players playing it.
<PlayerBoard<T>>::insert(sender, board_id);
<PlayerBoard<T>>::insert(opponent, board_id);
let _board_id = Self::create_game(sender.clone(), opponent.clone());

Ok(())
}
Expand Down Expand Up @@ -468,24 +530,34 @@ impl<T: Config> Pallet<T> {
red: T::AccountId,
blue: T::AccountId
) -> T::Hash {

// get a random hash as board id
let board_id = Self::generate_random_hash(b"create", red.clone());

// calculate plyer to start the first turn, with the first byte of the board_id random hash
let next_player = if board_id.as_ref()[0] < 128 { PLAYER_1 } else { PLAYER_2 };

// get current blocknumber
let block_number = <frame_system::Pallet<T>>::block_number();
// create a new empty bgame oard

// create a new empty game
let board = BoardStruct {
id: board_id,
red: red,
blue: blue,
red: red.clone(),
blue: blue.clone(),
board: [[0u8; 6]; 7],
last_turn: block_number,
next_player: next_player,
board_state: BoardState::Running,
};

// insert the new board into the storage
<Boards<T>>::insert(board_id, board);

// Add board to the players playing it.
<PlayerBoard<T>>::insert(red, board_id);
<PlayerBoard<T>>::insert(blue, board_id);

// emit event for a new board creation
// Emit an event.
Self::deposit_event(Event::NewBoard(board_id));
Expand Down Expand Up @@ -518,7 +590,6 @@ impl<T: Config> Pallet<T> {
Some(schedule_task_id)
}


}


14 changes: 14 additions & 0 deletions pallets/connectfour/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ frame_support::construct_runtime!(
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Scheduler: pallet_scheduler::{Pallet, Call, Storage, Config, Event<T>},
MatchMaker: pallet_matchmaker::{Pallet, Call, Storage, Event<T>},
ConnectFour: pallet_connectfour::{Pallet, Call, Config<T>, Storage, Event<T>},
}
);
Expand Down Expand Up @@ -81,12 +82,25 @@ impl pallet_scheduler::Config for Test {
type WeightInfo = ();
}

parameter_types! {
pub const AmountPlayers: u8 = 2;
pub const AmountBrackets: u8 = 3;
}

/// Used for matchmaking in pallets/connectfour.
impl pallet_matchmaker::Config for Test {
type Event = Event;
type AmountPlayers = AmountPlayers;
type AmountBrackets = AmountBrackets;
}

impl pallet_connectfour::Config for Test {
type Proposal = Call;
type Event = Event;
type Randomness = TestRandomness<Self>;
type Scheduler = Scheduler;
type PalletsOrigin = OriginCaller;
type MatchMaker = MatchMaker;
}

/// Build genesis storage according to the mock runtime.
Expand Down
64 changes: 64 additions & 0 deletions pallets/connectfour/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,68 @@ fn test_force_turn() {
assert!(!PlayerBoard::<Test>::contains_key(board.blue));
assert!(!BoardSchedules::<Test>::contains_key(board_id));
});
}

#[test]
fn test_matchmaker_game() {
new_test_ext().execute_with(|| {

let mut current_block:u64 = 100;

// start from block 100
run_to_block(current_block);

// queue up player 1
assert_ok!(ConnectFour::queue(Origin::signed(PLAYER_1 as u64)));

run_to_block(current_block + 1);
current_block = current_block + 1;

// try to queue again same player 1
assert_noop!(
ConnectFour::queue(Origin::signed(PLAYER_1 as u64)),
Error::<Test>::AlreadyQueued
);

// queue up player 2
assert_ok!(ConnectFour::queue(Origin::signed(PLAYER_2 as u64)));

assert!(!PlayerBoard::<Test>::contains_key(PLAYER_1 as u64));

run_to_block(current_block + 1);
current_block = current_block + 1;

assert!(PlayerBoard::<Test>::contains_key(PLAYER_1 as u64));

let board_id = PlayerBoard::<Test>::get(PLAYER_1 as u64);
let board = ConnectFour::boards(board_id);

assert_eq!(board.blue, PLAYER_2 as u64);

if board.next_player == PLAYER_1 {
assert_ok!(ConnectFour::play_turn(Origin::signed(PLAYER_1 as u64), 0));
let board = ConnectFour::boards(board_id);
assert!(board.board_state == BoardState::Running);
assert!(board.next_player == PLAYER_2);
assert_eq!(board.last_turn, current_block);

run_next_block();
current_block = current_block + 1;
}

assert_ok!(ConnectFour::play_turn(Origin::signed(PLAYER_2 as u64), 1));
let board = ConnectFour::boards(board_id);
assert_eq!(board.last_turn, current_block);
assert!(board.board_state == BoardState::Running);
assert!(board.next_player == PLAYER_1);

run_to_block(current_block + 10);
current_block = current_block + 10;

// check if force turn ended the game
let board = ConnectFour::boards(board_id);
assert_eq!(board.last_turn, current_block);
assert!(board.board_state == BoardState::Finished(board.blue));

});
}
11 changes: 10 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,17 @@ impl pallet_scheduler::Config for Runtime {
type WeightInfo = pallet_scheduler::weights::SubstrateWeight<Runtime>;
}

/// Used for test_module
parameter_types! {
pub const AmountPlayers: u8 = 2;
pub const AmountBrackets: u8 = 3;
}


/// Used for matchmaking in pallets/connectfour.
impl pallet_matchmaker::Config for Runtime {
type Event = Event;
type AmountPlayers = AmountPlayers;
type AmountBrackets = AmountBrackets;
}

/// Configure the pallet-connectfour in pallets/connectfour.
Expand All @@ -301,6 +309,7 @@ impl pallet_connectfour::Config for Runtime {
type Randomness = RandomnessCollectiveFlip;
type Scheduler = Scheduler;
type PalletsOrigin = OriginCaller;
type MatchMaker = MatchMaker;
//type WeightInfo = pallet_connectfour::weights::SubstrateWeight<Runtime>;
}

Expand Down