Optimize. This brings the ALL_COURSES sort time down. I didn't check the time

spent in this code in release, but in debug this brings the time spent building
musicwheel items in ALL_COURSES sort mode from 30 seconds with my 1600+
songs in about 80 groups down to 12 seconds. Release is down to 6 seconds,
but I don't know where it was to start. This time would increase nearly
exponentially with the number of songs and groups.
This commit is contained in:
Thad Ward
2005-10-30 21:07:50 +00:00
parent 3c11c86ea9
commit df136da381
+53 -56
View File
@@ -512,6 +512,33 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
/* Set to true if CourseDifficulty is able to change something. */ /* Set to true if CourseDifficulty is able to change something. */
bool bCourseDifficultyIsSignificant = (cd == DIFFICULTY_MEDIUM); bool bCourseDifficultyIsSignificant = (cd == DIFFICULTY_MEDIUM);
// get a list of all songs that are 1 stage long
vector<Song*> vpAllPossibleSongs;
SONGMAN->GetSongs(vpAllPossibleSongs, 1);
// remove locked and tutorial songs from the list
FOREACH( Song*, vpAllPossibleSongs, song )
{
// Ignore locked songs when choosing randomly
// TODO: Move Course initialization after UNLOCKMAN is created
if( UNLOCKMAN && UNLOCKMAN->SongIsLocked(*song) )
{
vector<Song*>::iterator eraseme = song;
song--;
vpAllPossibleSongs.erase( eraseme );
continue;
}
// Ignore boring tutorial songs
if( (*song)->IsTutorial() )
{
vector<Song*>::iterator eraseme = song;
song--;
vpAllPossibleSongs.erase( eraseme );
continue;
}
}
// Resolve each entry to a Song and Steps. // Resolve each entry to a Song and Steps.
FOREACH_CONST( CourseEntry, entries, e ) FOREACH_CONST( CourseEntry, entries, e )
{ {
@@ -524,77 +551,41 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
// Start with all songs // Start with all songs
vector<Song*> vpPossibleSongs; vector<Song*> vpPossibleSongs;
vector<Steps*> vpPossibleSteps;
if( e->pSong ) if( e->pSong )
{ {
// Choose an exact song // Choose an exact song, if we have matching steps and all
vpPossibleSongs.push_back( e->pSong ); e->pSong->GetSteps( vpPossibleSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
if( ( !e->sSongGroup.empty() && (*song)->m_sGroupName == e->sSongGroup ) && !vpPossibleSteps.empty() )
{
pResolvedSong = e->pSong;
} }
else else
{ {
vpPossibleSongs = SONGMAN->GetAllSongs();
FOREACH( Song*, vpPossibleSongs, song )
{
// Ignore locked songs when choosing randomly
// TODO: Move Course initialization after UNLOCKMAN is created
if( UNLOCKMAN && UNLOCKMAN->SongIsLocked(*song) )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue;
}
// Ignore boring tutorial songs
if( (*song)->IsTutorial() )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue;
}
// Don't allow long songs
if( SONGMAN->GetNumStagesForSong(*song) > 1 )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
} }
} }
} else
{
// copy over any songs that match our group filter, if one is set, and match our
// Filter out all songs that don't have matching steps // steps filter.
// At the same time, create a list of matching song/steps. FOREACH( Song*, vpAllPossibleSongs, song )
typedef vector<Steps*> StepsVector;
map<Song*,StepsVector> mapSongToSteps;
FOREACH( Song*, vpPossibleSongs, song )
{ {
// Apply song group filter
if( !e->sSongGroup.empty() && (*song)->m_sGroupName != e->sSongGroup ) if( !e->sSongGroup.empty() && (*song)->m_sGroupName != e->sSongGroup )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
}
vector<Steps*> vpMatchingSteps; vector<Steps*> vpMatchingSteps;
(*song)->GetSteps( vpMatchingSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter ); (*song)->GetSteps( vpMatchingSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
if( vpMatchingSteps.empty() ) if( vpMatchingSteps.empty() )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
vpPossibleSongs.push_back( *song );
} }
mapSongToSteps[*song] = vpMatchingSteps; // if there are no songs to choose from, abort now
} if( vpPossibleSongs.empty() )
continue;
// TODO: Move Course initialization after PROFILEMAN is created // TODO: Move Course initialization after PROFILEMAN is created
switch( e->songSort ) switch( e->songSort )
@@ -623,12 +614,18 @@ bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail )
if( e->iChooseIndex < int(vpPossibleSongs.size()) ) if( e->iChooseIndex < int(vpPossibleSongs.size()) )
{ {
pResolvedSong = vpPossibleSongs[e->iChooseIndex]; pResolvedSong = vpPossibleSongs[e->iChooseIndex];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong]; pResolvedSong->GetSteps( vpPossibleSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
ASSERT( !vpPossibleSteps.empty() ); // if no steps are playable, this shouldn't be a possible song }
random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd ); else
pResolvedSteps = vpPossibleSteps[0]; {
continue;
}
} }
ASSERT( !vpPossibleSteps.empty() ); // if no steps are playable, this shouldn't be a possible song
if( vpPossibleSteps.size() > 1 ) // no reason to randomize if there's only one set of possible steps
random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd );
pResolvedSteps = vpPossibleSteps[0];
if( pResolvedSong == NULL || pResolvedSteps == NULL ) if( pResolvedSong == NULL || pResolvedSteps == NULL )
continue; // this song entry isn't playable. Skip. continue; // this song entry isn't playable. Skip.