/* * namegenerator.h by Andrew Mann * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include "log.h" #include "namegenerator.h" #define PHONICS_LIST "/this/data/phonics.xml" PhonicEntry::PhonicEntry() { phonic[0]=0x00; begin_probability=end_probability=middle_probability=0.0f; flags=0x00; }; PhonicEntry::PhonicEntry(char *ph,float b_p,float e_p,float m_p,unsigned int fl) { strncpy(phonic,ph,6); phonic[5]=0x00; begin_probability=b_p; end_probability=e_p; middle_probability=m_p; flags=fl; } PhonicEntry::~PhonicEntry() { } NameGenerator::NameGenerator( iDocumentNode* node ) { begin_total = 0; end_total = 0; prejoin_total = 0; nonprejoin_total = 0; csRef iter = node->GetNodes(); while ( iter->HasNext() ) { csRef phonic = iter->Next(); PhonicEntry* entry = new PhonicEntry; strncpy( entry->phonic, phonic->GetAttributeValue("spelling"), 6 ); entry->phonic[5] = 0x00; entry->begin_probability = phonic->GetAttributeValueAsFloat("beginner"); entry->end_probability = phonic->GetAttributeValueAsFloat("ender"); entry->middle_probability= phonic->GetAttributeValueAsFloat("middle"); csString temp( phonic->GetAttributeValue("prejoiner") ); if ( temp.GetAt(0)=='Y') entry->flags|=PHONIC_PREJOINER; temp = phonic->GetAttributeValue("postjoiner"); if (temp.GetAt(0)=='Y') entry->flags|=PHONIC_POSTJOINER; // Update the totals begin_total+=entry->begin_probability; end_total+=entry->end_probability; if (entry->flags & PHONIC_PREJOINER) prejoin_total+=entry->middle_probability; else nonprejoin_total+=entry->middle_probability; entries.Push( entry ); } randomgen = new csRandomGen; } NameGenerator::~NameGenerator() { delete randomgen; } void NameGenerator::GenerateName(csString &namebuffer,int length_low,int length_high) { unsigned int length; PhonicEntry *lastphonic=NULL; namebuffer.Clear(); length=randomgen->Get((length_high-length_low))+length_low; // Pick a beginning lastphonic=GetRandomBeginner(); namebuffer.Append(lastphonic->phonic); // Add phonics to the middle while within length while (namebuffer.Length() < length) { if (lastphonic->flags & PHONIC_POSTJOINER) lastphonic=GetRandomNonPreJoiner(); else lastphonic=GetRandomPreJoiner(); namebuffer.Append(lastphonic->phonic); } // Pick an ending lastphonic=GetRandomEnder(!(lastphonic->flags & PHONIC_POSTJOINER)); namebuffer.Append(lastphonic->phonic); namebuffer.Downcase(); } PhonicEntry *NameGenerator::GetRandomBeginner() { size_t i; float randval,currentsum; randval=randomgen->Get() * begin_total; size_t entry_count = entries.Length(); currentsum=0.0f; for (i=0;ibegin_probability) { currentsum+=entries[i]->begin_probability; if (randval < currentsum) return (entries[i]); } } // We'll return the last one here, though this shouldn't happen, rounding error? return (entries[entry_count-1]); } PhonicEntry *NameGenerator::GetRandomEnder(bool prejoiner) { size_t i; float randval,currentsum; size_t entry_count = entries.Length(); csTicks timeLimit=5000; csTicks tickBegin=csGetTicks(); while ((csGetTicks() - tickBegin) < timeLimit) { randval=randomgen->Get() * end_total; currentsum=0.0f; for (i=0;iend_probability) { currentsum+=entries[i]->end_probability; if (randval < currentsum) { if (((entries[i]->flags & PHONIC_PREJOINER) && prejoiner) || (!(entries[i]->flags & PHONIC_PREJOINER) && !prejoiner)) { // Found the requested type return (entries[i]); } else { // Didn't find the requested type, reroll break; } } } } } // We'll return the last one here, though this can't happen return (entries[entry_count-1]); } PhonicEntry *NameGenerator::GetRandomPreJoiner() { size_t i; float randval,currentsum; randval=randomgen->Get() * prejoin_total; size_t entry_count = entries.Length(); currentsum=0.0f; for (i=0;iflags & PHONIC_PREJOINER) && entries[i]->middle_probability) { currentsum+=entries[i]->middle_probability; if (randval < currentsum) return (entries[i]); } } // We'll return the last one here, though this shouldn't happen, rounding error? return (entries[entry_count-1]); } PhonicEntry *NameGenerator::GetRandomNonPreJoiner() { size_t i; float randval,currentsum; randval=randomgen->Get() * nonprejoin_total; size_t entry_count = entries.Length(); currentsum=0.0f; for (i=0;iflags & PHONIC_PREJOINER) && entries[i]->middle_probability) { currentsum+=entries[i]->middle_probability; if (randval < currentsum) return (entries[i]); } } // We'll return the last one here, though this shouldn't happen, rounding error? return (entries[entry_count-1]); } NameGenerationSystem::NameGenerationSystem() { int i; for (i=0;i vfs = CS_QUERY_REGISTRY( objectReg, iVFS ); csRef xml = csPtr(new csTinyDocumentSystem); csRef buff = vfs->ReadFile( PHONICS_LIST ); if ( !buff || !buff->GetSize() ) { Error2( "Could not load XML: %s", PHONICS_LIST ); return false; } csRef doc=xml->CreateDocument(); const char* error =doc->Parse(buff); if(error) { Error3( "Error parsing XML file %s: %s", PHONICS_LIST, error ); return false; } csRef root, familyName, femaleName, maleName; if((root=doc->GetRoot())&&(familyName = root->GetNode("FAMILY_NAME")) && (femaleName = root->GetNode("FEMALE_FIRST_NAME")) && (maleName = root->GetNode("MALE_FIRST_NAME"))) { generators[0] = new NameGenerator( femaleName ); generators[1] = new NameGenerator( maleName ); generators[2] = new NameGenerator( familyName ); return true; } else { Error2("Error parsing XML file: %s", PHONICS_LIST); return false; } } void NameGenerationSystem::GenerateName(int generator_type,csString &namebuffer,int length_low,int length_high) { if (generator_type>=0 && generator_typeGenerateName(namebuffer,length_low,length_high); }