khanat-opennel-code/code/ryzom/server/src/frontend_service/selection_generator.cpp

191 lines
4.4 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "selection_generator.h"
//#include <sstream>
using namespace std;
/*
* Recursive function that generate the levels for CP2CGenerator
* The output looks like the following:
* 0 1 0 2 0 1 0 3 0 1 0 2 0 1 0 4 0 1 0 2 0 1 0 3 0 1 0 2 0 1 0
* (every level has twice occurences as its lower level)
*/
void CP2CGenerator::generateLevels( vector<TSelectionLevel>::iterator& iter, TSelectionLevel level )
{
if ( level == 0 )
{
*iter= 0;
++iter;
}
else
{
generateLevels( iter, level-1 );
*iter = level;
++iter;
generateLevels( iter, level-1 );
}
}
/*
* Power of 2
*/
uint32 pow2( uint32 n )
{
uint32 res = 1;
res <<= n;
return res;
}
/*
* Constructor
*/
CP2CGenerator::CP2CGenerator( TSelectionLevel ceiling ) :
_CurrentLevelIndex(0), _Ceiling(ceiling), _NbLevels(0), _CurrentLowRank(0)
{
// Generate levels
_Ceiling = std::max( ceiling, (TSelectionLevel)1 );
nldebug( "P2CGenerator: Generating levels..." );
_LevelSequence.resize( pow2(_Ceiling+1)-1 );
vector<TSelectionLevel>::iterator iter = _LevelSequence.begin();
generateLevels( iter, _Ceiling );
_LevelSequence.pop_back(); // avoid the last zero
}
/*
* Initialization of a selection cycle
*/
void CP2CGenerator::init( TSelectionLevel nblevels )
{
_CurrentLevelIndex = 0;
_NbLevels = nblevels;
_CurrentLowRank = 0;
}
/*
* Change the number of levels without restarting the cycle
*/
void CP2CGenerator::changeNbLevels( TSelectionLevel nblevels )
{
if ( nblevels < _LevelSequence[_CurrentLevelIndex] )
{
// The number of levels has been reduced to lower than the current level
init( nblevels );
}
else
{
_NbLevels = nblevels;
}
}
/*
* Return the next level to select
*/
ISelectionGenerator::TSelectionLevel CP2CGenerator::getNext()
{
// Get next generated level
TSelectionLevel level = _LevelSequence[_CurrentLevelIndex];
_CurrentLevelIndex = (_CurrentLevelIndex + 1) % _LevelSequence.size();
if ( level < _Ceiling )
{
// Case of power of 2
return level;
}
else
{
// Equitable case beyond ceiling
nlassertex( _NbLevels >= _Ceiling, ("%u %u", _NbLevels, _Ceiling) );
uint32 rank = _CurrentLowRank;
_CurrentLowRank = (_CurrentLowRank + 1 ) % ( _NbLevels - _Ceiling + 1 );
return level + rank;
}
}
/*
* Initialization of a selection cycle
*/
void CScoringGenerator::init( TSelectionLevel nblevels )
{
// Do not set the scores to 0, they remain the same from one cycle to the next one
changeNbLevels( nblevels );
// TODO: handle possibility of score overflow
}
/*
* Change the number of levels without restarting the cycle
*/
void CScoringGenerator::changeNbLevels( TSelectionLevel nblevels )
{
// Adjust vector size, and reset all scores to 0 if one level was added
if ( nblevels > _LevelScores.size() )
{
fill( _LevelScores.begin(), _LevelScores.end(), 0 );
}
_LevelScores.resize( nblevels, 0 );
}
/*
* Return the next level to select
*/
ISelectionGenerator::TSelectionLevel CScoringGenerator::getNext()
{
nlassert( ! _LevelScores.empty() );
// Return the index of the smallest score and add index+1 to the min score
TLevelScores::iterator iminscore = min_element( _LevelScores.begin(), _LevelScores.end() );
uint32 index = (uint32)(iminscore - _LevelScores.begin());
(*iminscore) += (index + 1);
//printScores();
return index;
}
/*
* Display the scores (debugging)
*/
void CScoringGenerator::printScores()
{
// stringstream ss;
string str;
vector<uint32>::iterator ils;
for ( ils=_LevelScores.begin(); ils!=_LevelScores.end(); ++ils )
{
//ss << " " << (int)(*ils);
str += " " + NLMISC::toString((*ils));
}
nlinfo( "SCOG: Scores: %s", str.c_str() );
}