/** 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
//----------------------------------------------------------------------------- void LinearWorld::getKartsDisplayInfo( std::vector<RaceGUIBase::KartIconDisplayInfo> *info) { int laps_of_leader = -1; float time_of_leader = -1; // Find the best time for the lap. We can't simply use // the time of the kart at position 1, since the kart // might have been overtaken by now const unsigned int kart_amount = getNumKarts(); for(unsigned int i = 0; i < kart_amount ; i++) { RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i]; AbstractKart* kart = m_karts[i]; // reset color rank_info.m_color = video::SColor(255, 255, 255, 255); rank_info.lap = -1; if(kart->isEliminated()) continue; const float lap_time = getTimeAtLapForKart(kart->getWorldKartId()); const int current_lap = getLapForKart( kart->getWorldKartId() ); rank_info.lap = current_lap; if(current_lap > laps_of_leader) { // more laps than current leader --> new leader and // new time computation laps_of_leader = current_lap; time_of_leader = lap_time; } else if(current_lap == laps_of_leader) { // Same number of laps as leader: use fastest time time_of_leader=std::min(time_of_leader,lap_time); } } // we now know the best time of the lap. fill the remaining bits of info for(unsigned int i = 0; i < kart_amount ; i++) { RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i]; KartInfo& kart_info = m_kart_info[i]; AbstractKart* kart = m_karts[i]; const int position = kart->getPosition(); // Don't compare times when crossing the start line first if(laps_of_leader>0 && (getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f || rank_info.lap != laps_of_leader) && raceHasLaps()) { // Display for 5 seconds std::string str; if(position == 1) { str = " " + StringUtils::timeToString( getTimeAtLapForKart(kart->getWorldKartId()) ); } else { float timeBehind; timeBehind = (kart_info.m_race_lap==laps_of_leader ? getTimeAtLapForKart(kart->getWorldKartId()) : getTime()) - time_of_leader; str = "+" + StringUtils::timeToString(timeBehind); } rank_info.m_text = irr::core::stringw(str.c_str()); } else { rank_info.m_text = ""; } int numLaps = race_manager->getNumLaps(); if(kart_info.m_race_lap>=numLaps) { // kart is finished, display in green rank_info.m_color.setGreen(0); rank_info.m_color.setBlue(0); } else if(kart_info.m_race_lap>=0 && numLaps>1) { int col = (int)(255*(1.0f-(float)kart_info.m_race_lap /((float)numLaps-1.0f) )); rank_info.m_color.setBlue(col); rank_info.m_color.setGreen(col); } } // next kart } // getKartsDisplayInfo
/** 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