/** Updates the ranking of the karts. */ void ThreeStrikesBattle::updateKartRanks() { beginSetKartPositions(); // sort karts by their times then give each one its position. // in battle-mode, long time = good (meaning he survived longer) const unsigned int NUM_KARTS = getNumKarts(); int *karts_list = new int[NUM_KARTS]; for( unsigned int n = 0; n < NUM_KARTS; ++n ) karts_list[n] = n; bool sorted=false; do { sorted = true; for( unsigned int n = 0; n < NUM_KARTS-1; ++n ) { const int this_karts_time = m_karts[karts_list[n]]->hasFinishedRace() ? (int)m_karts[karts_list[n]]->getFinishTime() : (int)WorldStatus::getTime(); const int next_karts_time = m_karts[karts_list[n+1]]->hasFinishedRace() ? (int)m_karts[karts_list[n+1]]->getFinishTime() : (int)WorldStatus::getTime(); // Swap if next kart survived longer or has more lives bool swap = next_karts_time > this_karts_time || m_kart_info[karts_list[n+1]].m_lives > m_kart_info[karts_list[n]].m_lives; if(swap) { int tmp = karts_list[n+1]; karts_list[n+1] = karts_list[n]; karts_list[n] = tmp; sorted = false; break; } } // for n = 0; n < NUM_KARTS-1 } while(!sorted); for( unsigned int n = 0; n < NUM_KARTS; ++n ) { setKartPosition(karts_list[n], n+1); } delete [] karts_list; endSetKartPositions(); } // updateKartRank
/** Ends the race early and places still active player karts at the back. * The race immediately goes to the result stage, estimating the time for the * karts still in the race. Still active player karts get a penalty in time * as well as being placed at the back. Players that already finished keep * their position. * * End time for the punished players is calculated as follows * end_time = current_time + (estimated_time - current_time) * + (estimated_time_for_last - current_time) * = estimated_time + estimated_time_for_last - current_time * This will put them at the end at all times. The further you (and the last in * the race) are from the finish line, the harsher the punishment will be. */ void StandardRace::endRaceEarly() { const unsigned int kart_amount = (unsigned int)m_karts.size(); std::vector<int> active_players; // Required for debugging purposes beginSetKartPositions(); for (unsigned int i = 1; i <= kart_amount; i++) { int kartid = m_position_index[i-1]; AbstractKart* kart = m_karts[kartid]; if (kart->hasFinishedRace()) { // Have to do this to keep endSetKartPosition happy setKartPosition(kartid, kart->getPosition()); continue; } if (kart->getController()->isPlayerController()) { // Keep active players apart for now active_players.push_back(kartid); } else { // AI karts finish setKartPosition(kartid, i - (unsigned int) active_players.size()); kart->finishedRace(estimateFinishTimeForKart(kart)); } } // i <= kart_amount // Now make the active players finish for (unsigned int i = 0; i < active_players.size(); i++) { int kartid = active_players[i]; int position = getNumKarts() - (int) active_players.size() + 1 + i; setKartPosition(kartid, position); m_karts[kartid]->eliminate(); } // Finish the active players endSetKartPositions(); setPhase(RESULT_DISPLAY_PHASE); if (!isNetworkWorld() || NetworkConfig::get()->isServer()) terminateRace(); } // endRaceEarly
/** Find the position (rank) of every kart. ATM it uses a stable O(n^2) * algorithm by counting for each kart how many other karts are ahead of * it. */ void LinearWorld::updateRacePosition() { // Mostly for debugging: beginSetKartPositions(); const unsigned int kart_amount = (unsigned int) m_karts.size(); #ifdef DEBUG bool rank_changed = false; #endif // NOTE: if you do any changes to this loop, the next loop (see // DEBUG_KART_RANK below) needs to have the same changes applied // so that debug output is still correct!!!!!!!!!!! for (unsigned int i=0; i<kart_amount; i++) { AbstractKart* kart = m_karts[i]; // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) { // This is only necessary to support debugging inconsistencies // in kart position parameters. setKartPosition(i, kart->getPosition()); continue; } KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const unsigned int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; // Count karts ahead of the current kart, i.e. kart that are // already finished or have covered a larger overall distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { // don't compare a kart with itself and ignore eliminated karts if(j == my_id || m_karts[j]->isEliminated()) continue; // If the other kart has: // - finished the race (but this kart hasn't) // - or is ahead // - or has the same distance (very unlikely) but started earlier // it is ahead --> increase position if((!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) || m_kart_info[j].m_overall_distance > my_distance || (m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) ) { p++; } } //next kart #ifndef DEBUG setKartPosition(i, p); #else rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { Log::error("[LinearWorld]", "Same rank used twice!!"); Log::debug("[LinearWorld]", "Info used to decide ranking :"); for (unsigned int d=0; d<kart_amount; d++) { Log::debug("[LinearWorld]", "Kart %s has finished (%d), is at lap (%u)," "is at distance (%u), is eliminated(%d)", m_karts[d]->getIdent().c_str(), m_karts[d]->hasFinishedRace(), getLapForKart(d), m_kart_info[d].m_overall_distance, m_karts[d]->isEliminated()); } Log::debug("[LinearWorld]", "Who has each ranking so far :"); for (unsigned int d=0; d<i; d++) { Log::debug("[LinearWorld]", "%s has rank %d", m_karts[d]->getIdent().c_str(), m_karts[d]->getPosition()); } Log::debug("[LinearWorld]", " --> And %s is being set at rank %d", kart->getIdent().c_str(), p); history->Save(); assert(false); } #endif // Switch on faster music if not already done so, if the // first kart is doing its last lap. if(!m_faster_music_active && p == 1 && kart_info.m_race_lap == race_manager->getNumLaps() - 1 && useFastMusicNearEnd() ) { music_manager->switchToFastMusic(); m_faster_music_active=true; } } // for i<kart_amount // Define this to get a detailled analyses each time a race position // changes. #ifdef DEBUG #undef DEBUG_KART_RANK #ifdef DEBUG_KART_RANK if(rank_changed) { Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime()); for (unsigned int i=0; i<kart_amount; i++) { AbstractKart* kart = m_karts[i]; Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u," " progress %u, finished %d, eliminated %d, initial position %u.", kart->getIdent().c_str(), m_kart_info[i].m_race_lap, m_kart_info[i].m_overall_distance, kart->hasFinishedRace(), kart->isEliminated(), kart->getInitialPosition()); // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == my_id) continue; if(m_karts[j]->isEliminated()) { Log::debug("[LinearWorld]", " %u: %s because it is eliminated.", p, m_karts[j]->getIdent().c_str()); continue; } if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; Log::debug("[LinearWorld]", " %u: %s because it has finished the race.", p, m_karts[j]->getIdent().c_str()); continue; } if(m_kart_info[j].m_overall_distance > my_distance) { p++; Log::debug("[LinearWorld]", " %u: %s because it is ahead %u.", p, m_karts[j]->getIdent().c_str(), m_kart_info[j].m_overall_distance); continue; } if(m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition()) { p++; Log::debug("[LinearWorld]"," %u: %s has same distance, but started ahead %d", p, m_karts[j]->getIdent().c_str(), m_karts[j]->getInitialPosition()); } } // next kart j } // for i<kart_amount Log::debug("LinearWorld]", "-------------------------------------------"); } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition
/** Find the position (rank) of every kart */ void LinearWorld::updateRacePosition() { // Mostly for debugging: beginSetKartPositions(); const unsigned int kart_amount = m_karts.size(); #ifdef DEBUG bool rank_changed = false; #endif // NOTE: if you do any changes to this loop, the next loop (see // DEBUG_KART_RANK below) needs to have the same changes applied // so that debug output is still correct!!!!!!!!!!! for (unsigned int i=0; i<kart_amount; i++) { AbstractKart* kart = m_karts[i]; // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) { // This is only necessary to support debugging inconsistencies // in kart position parameters. setKartPosition(i, kart->getPosition()); continue; } KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const unsigned int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; // Count karts ahead of the current kart, i.e. kart that are // already finished or have covered a larger overall distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { // don't compare a kart with itself and ignore eliminated karts if(j == my_id || m_karts[j]->isEliminated()) continue; // If the other kart has: // - finished the race (but this kart hasn't) // - or is ahead // - or has the same distance (very unlikely) but started earlier // it is ahead --> increase position if((!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) || m_kart_info[j].m_overall_distance > my_distance || (m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) ) { p++; } } //next kart #ifndef DEBUG setKartPosition(i, p); #else rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { std::cerr << "ERROR, same rank used twice!!\n"; std::cerr << "Info used to decide ranking :\n"; for (unsigned int d=0; d<kart_amount; d++) { std::cerr << " kart " << m_karts[d]->getIdent() << " has finished(" << m_karts[d]->hasFinishedRace() << "), is at lap (" << getLapForKart(d) << "), is at distance(" << m_kart_info[d].m_overall_distance << "), is eliminated(" << m_karts[d]->isEliminated() << ")" << std::endl; } std::cerr << "Who has each ranking so far :\n"; for (unsigned int d=0; d<i; d++) { std::cerr << " " << m_karts[d]->getIdent() << " has rank " << m_karts[d]->getPosition() << std::endl; } std::cerr << " --> And " << kart->getIdent() << " is being set at rank " << p << std::endl; history->Save(); assert(false); } #endif // Switch on faster music if not already done so, if the // first kart is doing its last lap, and if the estimated // remaining time is less than 30 seconds. if(!m_faster_music_active && kart_info.m_race_lap == race_manager->getNumLaps()-1 && p==1 && useFastMusicNearEnd() && kart_info.m_estimated_finish > 0 && kart_info.m_estimated_finish - getTime() < 30.0f ) { music_manager->switchToFastMusic(); m_faster_music_active=true; } } // for i<kart_amount // Define this to get a detailled analyses each time a race position // changes. #ifdef DEBUG #undef DEBUG_KART_RANK #ifdef DEBUG_KART_RANK if(rank_changed) { std::cout << "Counting laps at "<<getTime()<<" seconds.\n"; for (unsigned int i=0; i<kart_amount; i++) { AbstractKart* kart = m_karts[i]; std::cout << "counting karts ahead of " << kart->getIdent() << " (laps " << m_kart_info[i].m_race_lap << ", progress " << m_kart_info[i].m_overall_distance << " finished " << kart->hasFinishedRace() << " eliminated " << kart->isEliminated() << " initial position "<< kart->getInitialPosition() << ").\n"; // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == my_id) continue; if(m_karts[j]->isEliminated()) { std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it is eliminated.\n"; continue; } if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it has finished the race.\n"; continue; } if(m_kart_info[j].m_overall_distance > my_distance) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it is ahead " << m_kart_info[j].m_overall_distance <<".\n"; continue; } if(m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " has same distance, but started ahead " << m_karts[j]->getInitialPosition()<<".\n"; } } // next kart j } // for i<kart_amount std::cout << "-------------------------------------------\n"; } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition
/** Find the position (rank) of every kart */ void LinearWorld::updateRacePosition() { // Mostly for debugging: beginSetKartPositions(); const unsigned int kart_amount = m_karts.size(); #ifdef DEBUG bool rank_changed = false; #endif // NOTE: if you do any changes to this loop, the next loop (see // DEBUG_KART_RANK below) needs to have the same changes applied // so that debug output is still correct!!!!!!!!!!! for (unsigned int i=0; i<kart_amount; i++) { Kart* kart = m_karts[i]; // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) { // This is only necessary to support debugging inconsistencies // in kart position parameters. setKartPosition(i, kart->getPosition()); continue; } KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const int my_laps = getLapForKart(my_id); const float my_progression = getDistanceDownTrackForKart(my_id); // Count karts ahead of the current kart, i.e. kart that are already finished, // have done more laps, or the same number of laps, but a greater distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == kart->getWorldKartId()) continue; // don't compare a kart with itself if(m_karts[j]->isEliminated()) continue; // dismiss eliminated karts if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; continue; } /* has done more or less lapses */ assert(j==m_karts[j]->getWorldKartId()); int other_laps = getLapForKart(j); if (other_laps != my_laps) { if(other_laps > my_laps) { p++; // Other kart has more lapses } continue; } // Now both karts have the same number of lapses. Test progression. // A kart is ahead if it's driven further, or driven the same // distance, but started further to the back. float other_progression = getDistanceDownTrackForKart(j); if(other_progression > my_progression || (other_progression == my_progression && m_karts[j]->getInitialPosition() > kart->getInitialPosition()) ) { p++; #if _DEBUG_PRINTS_LIKE_MAD_ std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has is further within the track (my progression is " << my_progression << ", his progression is " << other_progression << ")\n"; #endif } } //next kart #ifndef DEBUG setKartPosition(i, p); #else rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { std::cerr << "ERROR, same rank used twice!!\n"; std::cerr << "Info used to decide ranking :\n"; for (unsigned int d=0; d<kart_amount; d++) { std::cerr << " kart " << m_karts[d]->getIdent() << " has finished(" << m_karts[d]->hasFinishedRace() << "), is at lap (" << getLapForKart(d) << "), is at distance(" << getDistanceDownTrackForKart(d) << "), is eliminated(" << m_karts[d]->isEliminated() << ")" << std::endl; } std::cerr << "Who has each ranking so far :\n"; for (unsigned int d=0; d<i; d++) { std::cerr << " " << m_karts[d]->getIdent() << " has rank " << m_karts[d]->getPosition() << std::endl; } std::cerr << " --> And " << kart->getIdent() << " is being set at rank " << p << std::endl; history->Save(); assert(false); } #endif // Switch on faster music if not already done so, if the // first kart is doing its last lap, and if the estimated // remaining time is less than 30 seconds. if(!m_faster_music_active && kart_info.m_race_lap == race_manager->getNumLaps()-1 && p==1 && useFastMusicNearEnd() && kart_info.m_estimated_finish > 0 && kart_info.m_estimated_finish - getTime() < 30.0f ) { music_manager->switchToFastMusic(); m_faster_music_active=true; } } // for i<kart_amount // Define this to get a detailled analyses each time a race position // changes. #ifdef DEBUG #undef DEBUG_KART_RANK #ifdef DEBUG_KART_RANK if(rank_changed) { std::cout << "Counting laps at "<<getTime()<<" seconds.\n"; for (unsigned int i=0; i<kart_amount; i++) { Kart* kart = m_karts[i]; if(kart->isEliminated() || kart->hasFinishedRace()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const int my_laps = getLapForKart(my_id); const float my_progression = getDistanceDownTrackForKart(my_id); std::cout << "counting karts ahead of " << kart->getIdent() << " (laps "<<m_kart_info[i].m_race_lap<<", progress " << my_progression<<").\n"; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == kart->getWorldKartId()) continue; // don't compare a kart with itself if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has finished.\n"; continue; } int other_laps = getLapForKart(j); if (other_laps != my_laps) { if(other_laps > my_laps) { p++; // Other kart has more lapses std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has more laps than me.\n"; } continue; } float other_progression = getDistanceDownTrackForKart(j); if(other_progression > my_progression || (other_progression == my_progression && m_karts[j]->getInitialPosition() > kart->getInitialPosition()) ) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he is further within the track (my progression is " << my_progression << ", his progression is " << other_progression << ")\n"; } } //next kart } // for i<kart_amount std::cout << "-------------------------------------------\n"; } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition