Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #644 from Dugy/master
Unit name generator using context-free grammar
- Loading branch information
Showing
9 changed files
with
377 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
Copyright (C) 2016 by Ján Dugáček | ||
Part of the Battle for Wesnoth Project http://www.wesnoth.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; either version 2 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. | ||
See the COPYING file for more details. | ||
*/ | ||
|
||
/** | ||
* @file | ||
* Algorithm to generate names using a context-free grammar, which allows more control | ||
* than the usual Markov chain generator | ||
*/ | ||
|
||
#include "context_free_grammar_generator.hpp" | ||
#include "../log.hpp" | ||
#include "../random_new.hpp" | ||
|
||
context_free_grammar_generator::context_free_grammar_generator() : | ||
initialized_(false) | ||
{ | ||
|
||
} | ||
|
||
context_free_grammar_generator::~context_free_grammar_generator() | ||
{ | ||
|
||
} | ||
|
||
bool context_free_grammar_generator::constructFromString(const std::string &source) { | ||
const char* reading = source.c_str(); | ||
nonterminal* current = nullptr; | ||
std::vector<std::string>* filled = nullptr; | ||
std::string buf; | ||
|
||
while (*reading != 0) { | ||
if (*reading == '=') { | ||
current = &nonterminals_[buf]; | ||
current->possibilities_.push_back(std::vector<std::string>()); | ||
filled = ¤t->possibilities_.back(); | ||
buf.clear(); | ||
} else if (*reading == '\n') { | ||
if (filled) filled->push_back(buf); | ||
filled = nullptr; | ||
current = nullptr; | ||
buf.clear(); | ||
} else if (*reading == '|') { | ||
if (!filled || !current) { | ||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced | symbol"; | ||
return false; | ||
} | ||
filled->push_back(buf); | ||
current->possibilities_.push_back(std::vector<std::string>()); | ||
filled = ¤t->possibilities_.back(); | ||
buf.clear(); | ||
} else if (*reading == '\\' && reading[1] == 'n') { | ||
reading++; | ||
buf.push_back('\n'); | ||
} else if (*reading == '\\' && reading[1] == 't') { | ||
reading++; | ||
buf.push_back('\t'); | ||
} else { | ||
if (*reading == '{') { | ||
if (!filled) { | ||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol"; | ||
return false; | ||
} | ||
filled->push_back(buf); | ||
buf.clear(); | ||
} | ||
if (*reading == '}') { | ||
if (!filled) { | ||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol"; | ||
return false; | ||
} | ||
filled->push_back(buf); | ||
buf.clear(); | ||
} else buf.push_back(*reading); | ||
} | ||
reading++; | ||
} | ||
if (filled) filled->push_back(buf); | ||
|
||
initialized_ = true; | ||
return true; | ||
} | ||
|
||
std::string context_free_grammar_generator::print_nonterminal(const std::string& name, uint32_t* seed, short seed_pos) const { | ||
std::string result; | ||
std::map<std::string, nonterminal>::const_iterator found = nonterminals_.find(name); | ||
if (found == nonterminals_.end()) { | ||
lg::wml_error() << "[context_free_grammar_generator] Warning: needed nonterminal " << name << " not defined"; | ||
return "!" + name; | ||
} | ||
const context_free_grammar_generator::nonterminal& got = found->second; | ||
unsigned int picked = seed[seed_pos++] % got.possibilities_.size(); | ||
if (seed_pos >= seed_size) seed_pos = 0; | ||
if (picked == got.last_) { | ||
picked = seed[seed_pos++] % got.possibilities_.size(); | ||
if (seed_pos >= seed_size) seed_pos = 0; | ||
} | ||
const_cast<unsigned int&>(got.last_) = picked; /* The variable last_ can change, the rest must stay const */ | ||
const std::vector<std::string>& used = got.possibilities_[picked]; | ||
for (unsigned int i = 0; i < used.size(); i++) { | ||
if (used[i][0] == '{') result += print_nonterminal(used[i].substr(1), seed, seed_pos); | ||
else result += used[i]; | ||
} | ||
return result; | ||
} | ||
|
||
std::string context_free_grammar_generator::generate() const { | ||
uint32_t seed[seed_size]; | ||
for (unsigned short int i = 0; i < seed_size; i++) { | ||
seed[i] = random_new::generator->next_random(); | ||
} | ||
return print_nonterminal("main", seed, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
Copyright (C) 2016 by Ján Dugáček | ||
Part of the Battle for Wesnoth Project http://www.wesnoth.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; either version 2 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. | ||
See the COPYING file for more details. | ||
*/ | ||
|
||
#ifndef CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED | ||
#define CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED | ||
|
||
#include <string> | ||
#include <map> | ||
#include <list> | ||
#include <vector> | ||
|
||
class context_free_grammar_generator | ||
{ | ||
private: | ||
|
||
struct nonterminal { | ||
nonterminal() : last_(1) {} | ||
std::vector<std::vector<std::string> > possibilities_; | ||
unsigned int last_; | ||
}; | ||
|
||
std::map<std::string, nonterminal> nonterminals_; | ||
bool initialized_; | ||
std::string print_nonterminal(const std::string& name, uint32_t* seed, short int seed_pos) const; | ||
static const short unsigned int seed_size = 20; | ||
|
||
public: | ||
/** Default constructor */ | ||
context_free_grammar_generator(); | ||
|
||
/** Initialisation | ||
* @param source the definition of the context-free grammar to use | ||
* @returns if the operation was successful | ||
*/ | ||
bool constructFromString(const std::string& source); | ||
|
||
/** Generates a possible word in the grammar set before | ||
* @returns the word | ||
*/ | ||
std::string generate() const; | ||
|
||
~context_free_grammar_generator(); | ||
|
||
/** Checks if the object is initialized | ||
* @returns if it is initialized | ||
*/ | ||
bool is_initialized() const {return initialized_; } | ||
}; | ||
|
||
#endif |