Properly sequence matches when there are more than two players in the tournament
This commit is contained in:
parent
30874697cc
commit
f078fed4fd
4 changed files with 91 additions and 20 deletions
|
|
@ -89,7 +89,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
void pack_impl(std::ostream& stream) const;
|
||||
void unpack_impl(std::istream& stream);
|
||||
void on_initiate_match(database& db, const vector<account_id_type>& players);
|
||||
void on_initiate_match(database& db);
|
||||
void on_game_complete(database& db, const game_object& game);
|
||||
game_id_type start_next_game(database& db, match_id_type match_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,8 @@ namespace graphene { namespace chain {
|
|||
struct initiate_match
|
||||
{
|
||||
database& db;
|
||||
vector<account_id_type> players;
|
||||
initiate_match(database& db, const vector<account_id_type>& players) :
|
||||
db(db), players(players)
|
||||
initiate_match(database& db) :
|
||||
db(db)
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -80,7 +79,6 @@ namespace graphene { namespace chain {
|
|||
fc_ilog(fc::logger::get("tournament"),
|
||||
"Match ${id} is now in progress",
|
||||
("id", match.id));
|
||||
match.players = event.players;
|
||||
match.number_of_wins.resize(match.players.size());
|
||||
match.start_time = event.db.head_block_time();
|
||||
|
||||
|
|
@ -96,6 +94,24 @@ namespace graphene { namespace chain {
|
|||
"Match ${id} is complete",
|
||||
("id", match.id));
|
||||
|
||||
std::map<account_id_type, unsigned> scores_by_player;
|
||||
for (const flat_set<account_id_type>& game_winners : match.game_winners)
|
||||
for (const account_id_type& account_id : game_winners)
|
||||
++scores_by_player[account_id];
|
||||
|
||||
optional<account_id_type> high_scoring_account;
|
||||
unsigned high_score = 0;
|
||||
for (const auto& value : scores_by_player)
|
||||
if (value.second > high_score)
|
||||
{
|
||||
high_score = value.second;
|
||||
high_scoring_account = value.first;
|
||||
}
|
||||
|
||||
if (high_scoring_account)
|
||||
match.match_winners.insert(*high_scoring_account);
|
||||
|
||||
match.end_time = event.db.head_block_time();
|
||||
const tournament_object& tournament_obj = match.tournament_id(event.db);
|
||||
event.db.modify(tournament_obj, [&](tournament_object& tournament) {
|
||||
tournament.on_match_completed(event.db, match);
|
||||
|
|
@ -108,11 +124,13 @@ namespace graphene { namespace chain {
|
|||
fc_ilog(fc::logger::get("tournament"),
|
||||
"Match ${id} is complete, it was a buy",
|
||||
("id", match));
|
||||
match.players = event.players;
|
||||
match.number_of_wins.resize(match.players.size());
|
||||
boost::copy(event.players, std::inserter(match.match_winners, match.match_winners.end()));
|
||||
boost::copy(match.players, std::inserter(match.match_winners, match.match_winners.end()));
|
||||
match.start_time = event.db.head_block_time();
|
||||
match.end_time = event.db.head_block_time();
|
||||
// NOTE: when the match is a buy, we don't send a match completed event to
|
||||
// the tournament_obj, because it is already in the middle of handling
|
||||
// an event; it will figure out that the match has completed on its own.
|
||||
}
|
||||
};
|
||||
typedef waiting_on_previous_matches initial_state;
|
||||
|
|
@ -137,7 +155,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
bool match_is_a_buy(const initiate_match& event)
|
||||
{
|
||||
return event.players.size() < 2;
|
||||
return match_obj->players.size() < 2;
|
||||
}
|
||||
|
||||
void record_completed_game(const game_complete& event)
|
||||
|
|
@ -294,9 +312,9 @@ namespace graphene { namespace chain {
|
|||
ia >> my->state_machine;
|
||||
}
|
||||
|
||||
void match_object::on_initiate_match(database& db, const vector<account_id_type>& players)
|
||||
void match_object::on_initiate_match(database& db)
|
||||
{
|
||||
my->state_machine.process_event(initiate_match(db, players));
|
||||
my->state_machine.process_event(initiate_match(db));
|
||||
}
|
||||
|
||||
void match_object::on_game_complete(database& db, const game_object& game)
|
||||
|
|
|
|||
|
|
@ -172,7 +172,8 @@ namespace graphene { namespace chain {
|
|||
if (paired_players[2 * i + 1] != account_id_type())
|
||||
players.emplace_back(paired_players[2 * i + 1]);
|
||||
event.db.modify(matches[i](event.db), [&](match_object& match) {
|
||||
match.on_initiate_match(event.db, players);
|
||||
match.players = players;
|
||||
match.on_initiate_match(event.db);
|
||||
});
|
||||
}
|
||||
event.db.modify(tournament_details_obj, [&](tournament_details_object& tournament_details_obj){
|
||||
|
|
@ -181,11 +182,50 @@ namespace graphene { namespace chain {
|
|||
}
|
||||
void on_entry(const match_completed& event, tournament_state_machine_& fsm)
|
||||
{
|
||||
tournament_object& tournament = *fsm.tournament_obj;
|
||||
fc_ilog(fc::logger::get("tournament"),
|
||||
"Tournament ${id} is still in progress, maybe should start a new match here",
|
||||
("id", fsm.tournament_obj->id));
|
||||
"Match ${match_id} in tournament tournament ${tournament_id} is still in progress",
|
||||
("match_id", event.match.id)("tournament_id", tournament.id));
|
||||
|
||||
// this wasn't the final match that just finished, so figure out if we can start the next match.
|
||||
// The next match can start if both this match and the previous match have completed
|
||||
const tournament_details_object& tournament_details_obj = fsm.tournament_obj->tournament_details_id(event.db);
|
||||
unsigned num_matches = tournament_details_obj.matches.size();
|
||||
auto this_match_iter = std::find(tournament_details_obj.matches.begin(), tournament_details_obj.matches.end(), event.match.id);
|
||||
assert(this_match_iter != tournament_details_obj.matches.end());
|
||||
unsigned this_match_index = std::distance(tournament_details_obj.matches.begin(), this_match_iter);
|
||||
// TODO: we currently create all matches at startup, so they are numbered sequentially. We could get the index
|
||||
// by subtracting match.id as long as this behavior doesn't change
|
||||
|
||||
unsigned next_round_match_index = (this_match_index + num_matches + 1) / 2;
|
||||
assert(next_round_match_index < num_matches);
|
||||
const match_object& next_round_match = tournament_details_obj.matches[next_round_match_index](event.db);
|
||||
|
||||
// each match will have two players, match.players[0] and match.players[1].
|
||||
// for consistency, we want to feed the winner of this match into the correct
|
||||
// slot in the next match
|
||||
unsigned winner_index_in_next_match = (this_match_index + num_matches + 1) % 2;
|
||||
unsigned other_match_index = num_matches - ((num_matches - next_round_match_index) * 2 + winner_index_in_next_match);
|
||||
const match_object& other_match = tournament_details_obj.matches[other_match_index](event.db);
|
||||
|
||||
// the winners of the matches event.match and other_match will play in next_round_match
|
||||
|
||||
assert(event.match.match_winners.size() <= 1);
|
||||
|
||||
event.db.modify(next_round_match, [&](match_object& next_match_obj) {
|
||||
if (!event.match.match_winners.empty()) // if there is a winner
|
||||
{
|
||||
if (winner_index_in_next_match == 0)
|
||||
next_match_obj.players.insert(next_match_obj.players.begin(), *event.match.match_winners.begin());
|
||||
else
|
||||
next_match_obj.players.push_back(*event.match.match_winners.begin());
|
||||
}
|
||||
if (other_match.get_state() == match_state::match_complete)
|
||||
next_match_obj.on_initiate_match(event.db);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
struct registration_period_expired : public msm::front::state<>
|
||||
{
|
||||
void on_entry(const registration_deadline_passed& event, tournament_state_machine_& fsm)
|
||||
|
|
|
|||
|
|
@ -2525,16 +2525,29 @@ public:
|
|||
unsigned match_number = player_number / 2;
|
||||
unsigned player_in_match = player_number % 2;
|
||||
|
||||
match_object match = _remote_db->get_objects({tournament_details.matches[match_number]})[0].as<match_object>();
|
||||
std::string player_name;
|
||||
if (round != num_rounds &&
|
||||
!match.players.empty())
|
||||
if (round == num_rounds)
|
||||
{
|
||||
if (player_in_match < match.players.size())
|
||||
player_name = get_account(match.players[player_in_match]).name;
|
||||
else
|
||||
player_name = "[bye]";
|
||||
match_object match = get_object<match_object>(tournament_details.matches[num_matches - 1]);
|
||||
if (match.get_state() == match_state::match_complete &&
|
||||
!match.match_winners.empty())
|
||||
{
|
||||
assert(match.match_winners.size() == 1);
|
||||
player_name = get_account(*match.match_winners.begin()).name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match_object match = get_object<match_object>(tournament_details.matches[match_number]);
|
||||
if (!match.players.empty())
|
||||
{
|
||||
if (player_in_match < match.players.size())
|
||||
player_name = get_account(match.players[player_in_match]).name;
|
||||
else
|
||||
player_name = "[bye]";
|
||||
}
|
||||
}
|
||||
|
||||
ss << "__";
|
||||
ss << std::setfill('_') << std::setw(10) << player_name.substr(0,10);
|
||||
ss << "__";
|
||||
|
|
|
|||
Loading…
Reference in a new issue