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
+82 -85
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,111 +551,81 @@ 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
{
continue;
}
} }
else else
{ {
vpPossibleSongs = SONGMAN->GetAllSongs(); // copy over any songs that match our group filter, if one is set, and match our
// steps filter.
FOREACH( Song*, vpPossibleSongs, song ) FOREACH( Song*, vpAllPossibleSongs, song )
{ {
// Ignore locked songs when choosing randomly if( !e->sSongGroup.empty() && (*song)->m_sGroupName != e->sSongGroup )
// TODO: Move Course initialization after UNLOCKMAN is created
if( UNLOCKMAN && UNLOCKMAN->SongIsLocked(*song) )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
}
// Ignore boring tutorial songs vector<Steps*> vpMatchingSteps;
if( (*song)->IsTutorial() ) (*song)->GetSteps( vpMatchingSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
{ if( vpMatchingSteps.empty() )
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
}
// Don't allow long songs vpPossibleSongs.push_back( *song );
if( SONGMAN->GetNumStagesForSong(*song) > 1 )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue;
}
} }
}
// if there are no songs to choose from, abort now
if( vpPossibleSongs.empty() )
continue;
// Filter out all songs that don't have matching steps // TODO: Move Course initialization after PROFILEMAN is created
// At the same time, create a list of matching song/steps. switch( e->songSort )
typedef vector<Steps*> StepsVector; {
map<Song*,StepsVector> mapSongToSteps; default:
FOREACH( Song*, vpPossibleSongs, song ) ASSERT(0);
{ case SongSort_Randomize:
// Apply song group filter random_shuffle( vpPossibleSongs.begin(), vpPossibleSongs.end(), rnd );
if( !e->sSongGroup.empty() && (*song)->m_sGroupName != e->sSongGroup ) break;
case SongSort_MostPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), true ); // descending
break;
case SongSort_FewestPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), false ); // ascending
break;
case SongSort_TopGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, true ); // descending
break;
case SongSort_LowestGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, false ); // ascending
break;
}
if( e->iChooseIndex < int(vpPossibleSongs.size()) )
{
pResolvedSong = vpPossibleSongs[e->iChooseIndex];
pResolvedSong->GetSteps( vpPossibleSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
}
else
{ {
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue; continue;
} }
vector<Steps*> vpMatchingSteps;
(*song)->GetSteps( vpMatchingSteps, st, e->baseDifficulty, e->iLowMeter, e->iHighMeter );
if( vpMatchingSteps.empty() )
{
vector<Song*>::iterator eraseme = song;
song--;
vpPossibleSongs.erase( eraseme );
continue;
}
mapSongToSteps[*song] = vpMatchingSteps;
} }
ASSERT( !vpPossibleSteps.empty() ); // if no steps are playable, this shouldn't be a possible song
// TODO: Move Course initialization after PROFILEMAN is created if( vpPossibleSteps.size() > 1 ) // no reason to randomize if there's only one set of possible steps
switch( e->songSort )
{
default:
ASSERT(0);
case SongSort_Randomize:
random_shuffle( vpPossibleSongs.begin(), vpPossibleSongs.end(), rnd );
break;
case SongSort_MostPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), true ); // descending
break;
case SongSort_FewestPlays:
if( PROFILEMAN )
SongUtil::SortSongPointerArrayByNumPlays( vpPossibleSongs, PROFILEMAN->GetMachineProfile(), false ); // ascending
break;
case SongSort_TopGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, true ); // descending
break;
case SongSort_LowestGrades:
SongUtil::SortSongPointerArrayByGrades( vpPossibleSongs, false ); // ascending
break;
}
if( e->iChooseIndex < int(vpPossibleSongs.size()) )
{
pResolvedSong = vpPossibleSongs[e->iChooseIndex];
vector<Steps*> &vpPossibleSteps = mapSongToSteps[pResolvedSong];
ASSERT( !vpPossibleSteps.empty() ); // if no steps are playable, this shouldn't be a possible song
random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd ); random_shuffle( vpPossibleSteps.begin(), vpPossibleSteps.end(), rnd );
pResolvedSteps = vpPossibleSteps[0]; 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.