#include #include #include #include #include #include #include #include "colors.hpp" #include "perform.hpp" std::vector maxWeightMatching(const std::deque,unsigned long long> >& edgeWeights); template struct AlwaysTrue { bool operator()(const Type&) const {return true;} }; template struct Identity { Type operator()(const Type& type) const {return type;} }; class SchedulePenalties { const unsigned int numPlayers; const unsigned int numPairings; const bool byeFlag; std::vector > triangle; SchedulePenalties(const unsigned int numPlayers_) : numPlayers(numPlayers_), numPairings(numPlayers_/2), byeFlag(numPlayers_%2!=0), triangle(std::vector >(numPlayers_)) {} unsigned long long maxPenalty() const { unsigned long long result=0; for (unsigned int player1=0;player1 std::vector maxWeightMatching(const WeightModification& weightModification,const ByeCondition& byeCondition) const { std::deque,unsigned long long> > edgeWeights; for (unsigned int player1=1;player1player && byeCondition(player)) edgeWeights.push_back(std::make_pair(std::make_pair(player,numPlayers),weightModification(triangle[player][player])+1)); return ::maxWeightMatching(edgeWeights); } unsigned long long totalWeight(const std::vector& pairings) const { unsigned long long result=0; for (unsigned int player1=0;player1::max(); for (unsigned int player1=1;player1::max(); for (unsigned int player=0;playerplayer) { // bye allowed const unsigned long long byePenalty=triangle[player][player]; if (byePenalty==0) return; else offset=std::min(offset,byePenalty); } for (unsigned int player=0;playerplayer) // bye allowed triangle[player][player]-=offset; } friend std::vector bestSchedule( const std::vector& plays, const std::vector& losses, const std::vector >& orderedEncounters); }; template class ElementComparison { const std::vector& vector; const Type value; public: ElementComparison(const std::vector& vector_,Type value_) : vector(vector_), value(value_) {} bool operator()(unsigned int index) const {return Comparator()(vector[index],value);} }; std::vector bestSchedule( const std::vector& plays, const std::vector& losses, const std::vector >& orderedEncounters) { SchedulePenalties schedulePenalties(plays.size()); if (schedulePenalties.numPlayers==0) return std::vector(); std::vector > lossPlayerPairs; lossPlayerPairs.reserve(schedulePenalties.numPlayers); for (unsigned int player=0;player newRanks(schedulePenalties.numPlayers); unsigned int minLossDiff=std::numeric_limits::max(); unsigned int maxEqualLossDiff=0; unsigned int equalLossDiff=0; for (unsigned int newRank=0;newRank& lossPlayerPair=lossPlayerPairs[newRank]; newRanks[lossPlayerPair.second]=newRank; if (newRankmaxEqualLossDiff) maxEqualLossDiff=equalLossDiff; equalLossDiff=0; } unsigned int minPlays=std::numeric_limits::max(); unsigned int maxPlays=0; std::vector > lossDifferences(schedulePenalties.numPlayers); std::vector > unorderedEncounters(schedulePenalties.numPlayers); unsigned int minEncounters=std::numeric_limits::max(); unsigned int maxEncounters=0; const unsigned int maxEqualLossScore=maxEqualLossDiff*maxEqualLossDiff; for (int player1=schedulePenalties.numPlayers-1;player1>=0;--player1) { schedulePenalties.triangle[player1].reserve(player1); lossDifferences [player1].reserve(player1); unorderedEncounters [player1].reserve(player1); for (int player2=0;player2(), AlwaysTrue()))- schedulePenalties.totalWeight( schedulePenalties.maxWeightMatching( std::bind1st(std::minus(),schedulePenalties.maxPenalty()), AlwaysTrue()))+1; unsigned int playerCount=1; for (unsigned int player=previousPlayerWithBye+1;player(), AlwaysTrue()))- schedulePenalties.totalWeight( schedulePenalties.maxWeightMatching( std::bind1st(std::minus(),schedulePenalties.maxPenalty()), AlwaysTrue()))+1; bool pairingCompression=true; for (unsigned int player1=1;player1(), ElementComparison >(losses,earlierLossScore))); const unsigned long long lowerbound= schedulePenalties.totalWeight( schedulePenalties.maxWeightMatching( std::bind1st(std::minus(),schedulePenalties.maxPenalty()), ElementComparison >(losses,lossScore))); if (upperbound>=lowerbound) { const unsigned long long byePenalty=upperbound-lowerbound+1; bool possibleByeCompression=false; do { const unsigned int player=lossPlayerPairs[newRank].second; if (plays[player]==maxPlays) { unsigned long long& currentByePenalty=schedulePenalties.triangle[player][player]; if (currentByePenalty==0) possibleByeCompression=true; currentByePenalty+=byePenalty; } ++newRank; } while (newRank(), AlwaysTrue()))- schedulePenalties.totalWeight( schedulePenalties.maxWeightMatching( std::bind1st(std::minus(),schedulePenalties.maxPenalty()), AlwaysTrue()))+1; bool pairingCompression=true; for (unsigned int player1=1;player1(), ElementComparison >(plays,maxPlays))); const unsigned long long lowerbound= schedulePenalties.totalWeight( schedulePenalties.maxWeightMatching( std::bind1st(std::minus(),schedulePenalties.maxPenalty()), ElementComparison >(plays,maxPlays))); if (upperbound>=lowerbound) { const unsigned long long byePenalty=upperbound-lowerbound+1; for (unsigned int player=0;player(),schedulePenalties.maxPenalty()), AlwaysTrue()); } template struct greater_second { bool operator()(const std::pair& lhs,const std::pair& rhs) { return lhs.second>rhs.second; } }; std::vector ratingsToRanks( const std::vector& ratings, const std::vector& removed, const bool randomizeTies) { std::vector > playerRatingPairs; const unsigned int numPlayers=ratings.size(); for (unsigned int player=0;player()); std::vector rankToPlayer; for (std::vector >::const_iterator i=playerRatingPairs.begin(); i!=playerRatingPairs.end();++i) rankToPlayer.push_back(i->first); return rankToPlayer; } std::vector bestSchedule( unsigned int numLives, const long double virtualGameWeight, const bool randomizeSeeds, const std::vector& losses, const std::vector >& orderedEncounters, const std::vector >& ratedDefeats, std::vector& removed ) { std::vector performanceRatings=calculatePerformanceRatings(virtualGameWeight,ratedDefeats); const unsigned int numPlayers=losses.size(); unsigned int minLosses=std::numeric_limits::max(); for (unsigned int player=0;player=numLives) removed[player]=true; std::vector rankToPlayer=ratingsToRanks(performanceRatings,removed,randomizeSeeds); const unsigned int remainingPlayers=rankToPlayer.size(); std::vector playsByRank(remainingPlayers); std::vector lossesByRank; lossesByRank.reserve(remainingPlayers); std::vector > orderedEncountersByRank(remainingPlayers,std::vector(remainingPlayers)); for (unsigned int rank1=0;rank1 rankedPairings=bestSchedule(playsByRank,lossesByRank,orderedEncountersByRank); std::vector result(numPlayers,-1); for (unsigned int rank1=0;rank1>goldPlayer)) continue; if (!(ss>>silverPlayer)) abort(); colorHistory.addGame(goldPlayer,silverPlayer); } } std::ifstream ratingFile(argv[argc-4]); std::vector players; std::map playerToID; while (std::getline(ratingFile,line)) { if (line.empty()) continue; std::stringstream ss; ss<>player)) continue; playerToID.insert(make_pair(player,players.size())); players.push_back(player); } const unsigned int numPlayers=players.size(); std::vector removed(numPlayers); std::vector losses(numPlayers); std::vector > orderedEncounters(numPlayers,std::vector(numPlayers)), ratedDefeats(orderedEncounters); std::ifstream tournament(argv[argc-2]); while (std::getline(tournament,line)) { if (line.empty()) continue; std::stringstream ss; ss<>goldPlayer)) continue; if (playerToID.find(goldPlayer)==playerToID.end()) abort(); const unsigned int goldID=playerToID[goldPlayer]; if (!(ss>>silverPlayer)) { // player removed from tournament removed[goldID]=true; continue; } if (playerToID.find(silverPlayer)==playerToID.end()) abort(); const unsigned int silverID=playerToID[silverPlayer]; ++orderedEncounters[goldID][silverID]; colorHistory.addGame(goldPlayer,silverPlayer); std::string winner; if (!(ss>>winner)) { // double forfeit ++losses[goldID]; ++losses[silverID]; } else if (winner!=goldPlayer && winner!=silverPlayer) abort(); else { const unsigned int loserID=(winner==goldPlayer ? silverID : goldID); ++losses[loserID]; /*if (!(ss>>winner))*/ { // no dummy fourth word indicating forfeit (DISABLED) const unsigned int winnerID=playerToID[winner]; ++ratedDefeats[winnerID][loserID]; } } } long double virtualGameWeight; std::stringstream ss; ss<>virtualGameWeight; srand(time(0)); const std::vector pairings=bestSchedule( atoi(argv[argc-1]), // number of lives virtualGameWeight, atoi(argv[argc-5])!=0, // randomize seeds losses, orderedEncounters, ratedDefeats, removed ); for (int player1=0;player1(numPlayers);++player1) { const int player2=pairings[player1]; if (player1==player2) std::cout<0 || (color==0 && (rand()%2)==0)) { goldPlayer=players[player1]; silverPlayer=players[player2]; } else { silverPlayer=players[player1]; goldPlayer=players[player2]; } std::cout<