#ifndef CHAMPIONSHIP_H #define CHAMPIONSHIP_H #include #include #include #include template class Championship { public: class Match { friend class MatchIterator; Competitor* first; Competitor* second; long firstScore; long secondScore; public: Match(Competitor* first = nullptr, Competitor* second = nullptr, long firstScore = -1, long secondScore = -1) : first(first) , second(second) , firstScore(firstScore) , secondScore(secondScore) { } std::ostream& print(std::ostream& out) const { return out << std::setw(20) << *first << std::setw(4) << firstScore << std::setw(4) << secondScore << " " << *second; } void inventScores(long max) { firstScore = rand() % max; secondScore = rand() % max; } friend inline std::ostream& operator<<(std::ostream& out, const Match& match) { return match.print(out); } inline bool isFinished() const { return firstScore != -1 && secondScore != -1; } void updateCompetitorScores() { if ( firstScore > secondScore ) (*first) += 2; else if ( secondScore > firstScore ) (*second) += 2; else { (*first) += 1; (*second) += 1; } } }; enum class State { notStarted, started, knockout }; class MatchIterator { typename std::vector::iterator itr; public: MatchIterator(const typename std::vector::iterator& itr) : itr(itr) { } inline MatchIterator& operator++() { ++itr; return *this; } inline Match& operator*() { return *itr; } inline const Match& operator*() const { return *itr; } inline bool operator==(const MatchIterator& other) const { return itr == other.itr; } inline bool operator!=(const MatchIterator& other) const { return itr != other.itr; } void setScores(long first, long second) { itr->firstScore = first; itr->secondScore = second; } inline void inventScores() { itr->inventScores(); } }; protected: std::vector competitors; size_t groupCount = 1; std::vector matches; State state = State::notStarted; public: inline void addCompetitor(const Competitor& competitor) { competitors.push_back(competitor); } inline Championship& operator<<(const Competitor& competitor) { addCompetitor(competitor); return *this; } inline void setGroupCount(size_t groupCount) { if (groupCount > 0 ) this->groupCount = groupCount; } bool makeGroups() { if ( competitors.size() < groupCount || competitors.size() % groupCount || groupCount % 2 != 0 ) return false; std::random_shuffle(competitors.begin(), competitors.end()); return true; } std::ostream& printGroups(std::ostream& out, bool withPoints = false) const { size_t groupSize = competitors.size() / groupCount, competitor = 0; for ( size_t group = 0; group < groupCount; ++group ) { out << "\nGroup " << char('A' + group) << ":\n"; for ( size_t i = 0; i < groupSize; ++i ) if ( withPoints ) { out << " "; competitors[competitor++].printWithPoints(out) << std::endl; } else out << " " << competitors[competitor++] << std::endl; } return out; } void update() { switch ( state ) { case State::notStarted: permuteGroups(); state = State::started; break; case State::started: if ( areGroupMatchesComplete() ) { mixGroups(); state = State::knockout; } break; default: break; } } void permuteGroups() { size_t groupSize = competitors.size() / groupCount; for ( size_t group = 0; group < groupCount; ++group ) for ( size_t i = 0; i < groupSize - 1; ++i ) for ( size_t j = i + 1; j < groupSize; ++j ) matches.push_back( Match(& competitors[group * groupSize + i], & competitors[group * groupSize + j]) ); } std::ostream& printMatches(std::ostream& out) const { for ( size_t i = 0; i < matches.size(); ++i ) out << matches[i] << std::endl; return out; } friend inline std::ostream& operator<<(std::ostream& out, const Championship& championship) { championship.printGroups(out); return championship.printMatches(out); } inline MatchIterator beginMatch() { return MatchIterator(matches.begin()); } inline MatchIterator endMatch() { return MatchIterator(matches.end()); } inline MatchIterator firstUnfinishedMatch() { for ( MatchIterator itr = matches.begin(); itr != matches.end(); ++itr ) if ( ! itr->isFinished() ) return itr; return matches.end(); } bool areGroupMatchesComplete() // const { for ( MatchIterator itr = beginMatch(); itr != endMatch(); ++itr ) if ( ! (*itr).isFinished() ) return false; return true; } void mixGroups() { updateCompetitorScores(); sortCompetitorsInGroups(); addMatchesBetweenGroups(); } void updateCompetitorScores() { for ( MatchIterator itr = beginMatch(); itr != endMatch(); ++itr ) (*itr).updateCompetitorScores(); } void sortCompetitorsInGroups() { size_t groupSize = competitors.size() / groupCount; for ( size_t group = 0; group < groupCount; ++group ) std::sort(competitors.begin() + group * groupSize, competitors.begin() + (group + 1) * groupSize, std::greater()); } void addMatchesBetweenGroups() { size_t groupSize = competitors.size() / groupCount; for ( size_t group = 0; group < groupCount; group += 2 ) for ( size_t competitor = 0; competitor < groupSize / 2; ++competitor ) matches.push_back( Match(& competitors[group * groupSize + competitor], & competitors[(group + 1) * groupSize + competitor]) ); } }; #endif // CHAMPIONSHIP_H