From 0da7e2da1073d7bb8434cc3ccb1b4f8ae8a496d6 Mon Sep 17 00:00:00 2001 From: auria Date: Mon, 8 Mar 2010 18:39:05 +0000 Subject: [PATCH] Hopefully fixed bug about bogus kart rankings. 1) Made all karts be ranked at the same time, so there's less risk of mismatches 2) Found a precondition inside the sorting method, that was not documented in the doxygen comments, nor enforced with contracts... and sure enough someone somewhere called it without respecting that hidden precondition. Fixed the problem by removing the precondition (the new logic doesn't have the same precondition) git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4959 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/modes/linear_world.cpp | 161 ++++++++++++++++++++++++------------- src/modes/linear_world.hpp | 6 +- 2 files changed, 107 insertions(+), 60 deletions(-) diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index e24d4bba7..4a5952039 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -119,10 +119,7 @@ void LinearWorld::restartRace() // First all kart infos must be updated before the kart position can be // recomputed, since otherwise 'new' (initialised) valued will be compared // with old values. - for (unsigned int i=0; ihasFinishedRace() || m_karts[i]->isEliminated()) - continue; - updateRacePosition(m_karts[i], m_kart_info[i]); + if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated()) continue; + // During the last lap update the estimated finish time. // This is used to play the faster music, and by the AI - if(m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1) + if (m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1) + { m_kart_info[i].m_estimated_finish = estimateFinishTimeForKart(m_karts[i]); + } checkForWrongDirection(i); } + #ifdef DEBUG // FIXME: Debug output in case that the double position error // occurs again. It can most likely be removed. @@ -563,61 +565,106 @@ void LinearWorld::moveKartAfterRescue(Kart* kart, btRigidBody* body) } // moveKartAfterRescue //----------------------------------------------------------------------------- -/** Find the position (rank) of 'kart' and update it accordingly +/** Find the position (rank) of every kart */ -void LinearWorld::updateRacePosition ( Kart* kart, KartInfo& kart_info ) +void LinearWorld::updateRacePosition() { - int p = 1 ; - const unsigned int kart_amount = m_karts.size(); - const int my_id = kart->getWorldKartId(); - const int my_laps = getLapForKart(my_id); - const float my_progression = getDistanceDownTrackForKart(my_id); - 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 - // Count karts ahead of the current kart, i.e. kart that are already - // finished (the current kart k has not yet finished!!), have done more - // laps, or the same number of laps, but a greater distance. - if(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++; - } - } //next kart - kart->setPosition(p); +#ifdef DEBUG + bool rank_used[kart_amount+1]; + for (unsigned int n=0; n<=kart_amount; n++) rank_used[n] = 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 ) + for (unsigned int i=0; iswitchToFastMusic(); - m_faster_music_active=true; - } + Kart* kart = m_karts[i]; + 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); + 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 + + // 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. + 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++; + } + } //next kart + +#ifdef DEBUG + if (rank_used[p]) + { + std::cerr << "ERROR, same rank used twice!!\n"; + + std::cerr << "Info used to decide ranking :\n"; + for (unsigned int d=0; dgetIdent() << " 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 << "Used ranks:\n"; + for (unsigned int d=1; d<=kart_amount; d++) + { + std::cerr << " rank " << d << " used : " << rank_used[d] << std::endl; + } + + std::cerr << "Who has each ranking so far :\n"; + for (unsigned int d=0; dgetIdent() << " has rank " << m_karts[d]->getPosition() << std::endl; + } + + std::cerr << " --> And " << kart->getIdent() << " is being set at rank " << p << std::endl; + assert(false); + } + rank_used[p] = true; +#endif + + kart->setPosition(p); + + // 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 ) + { + sound_manager->switchToFastMusic(); + m_faster_music_active=true; + } + } + } // updateRacePosition //----------------------------------------------------------------------------- diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index eda4af27d..0fa7b09f5 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -63,11 +63,11 @@ protected: /** Linear races can trigger rescues for one additional reason : shortcuts. - * It may need to do some specific world before calling the generic Kart::forceRescue - */ + * It may need to do some specific world before calling the generic Kart::forceRescue + */ void rescueKartAfterShortcut(Kart* kart, KartInfo& kart_info); void checkForWrongDirection(unsigned int i); - void updateRacePosition(Kart* kart, KartInfo& kart_info ); + void updateRacePosition(); virtual float estimateFinishTimeForKart(Kart* kart); public: