2020-12-22 03:13:43 +00:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
2020-03-11 15:18:36 +00:00
|
|
|
|
using System.Collections.Generic;
|
2021-03-11 11:18:21 +00:00
|
|
|
|
using System.Linq;
|
2026-09-14 17:39:12 +02:00
|
|
|
|
using static CultMath.math;
|
|
|
|
|
|
using Random = CultMath.Random;
|
2020-03-11 15:18:36 +00:00
|
|
|
|
|
|
|
|
|
|
//Generates random names based on the statistical weight of letter sequences
|
|
|
|
|
|
//in a collection of sample names
|
|
|
|
|
|
public class MarkovNameGenerator
|
|
|
|
|
|
{
|
2021-03-10 09:18:07 +00:00
|
|
|
|
private Dictionary<string, List<char>> _chains = new Dictionary<string, List<char>>();
|
|
|
|
|
|
private List<string> _samples = new List<string>();
|
|
|
|
|
|
private static List<string> _used = new List<string>();
|
|
|
|
|
|
private int _order;
|
|
|
|
|
|
private int _minLength;
|
|
|
|
|
|
private int _maxLength;
|
|
|
|
|
|
private Random _random;
|
2021-03-12 05:12:01 +00:00
|
|
|
|
|
2021-04-22 02:53:06 +01:00
|
|
|
|
public MarkovNameGenerator(ref Random random, IEnumerable<string> sampleNames, NameGeneratorSettings settings)
|
2021-03-12 05:12:01 +00:00
|
|
|
|
{
|
|
|
|
|
|
var names = new HashSet<string>();
|
2021-03-15 11:40:46 +00:00
|
|
|
|
foreach (var line in sampleNames)
|
2021-03-12 05:12:01 +00:00
|
|
|
|
{
|
|
|
|
|
|
foreach(var word in line.ToUpperInvariant().Split(' ', ',', '.', '"'))
|
|
|
|
|
|
if (word.Length >= settings.NameGeneratorMinLength && !names.Contains(word))
|
|
|
|
|
|
names.Add(word);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_random = random;
|
|
|
|
|
|
|
|
|
|
|
|
_order = max(1, settings.NameGeneratorOrder);
|
|
|
|
|
|
_minLength = max(1, settings.NameGeneratorMinLength);
|
|
|
|
|
|
_maxLength = settings.NameGeneratorMaxLength;
|
|
|
|
|
|
|
|
|
|
|
|
Initialize(names);
|
|
|
|
|
|
}
|
2021-03-10 09:18:07 +00:00
|
|
|
|
|
|
|
|
|
|
public MarkovNameGenerator(ref Random random, IEnumerable<string> sampleNames, int order, int minLength, int maxLength)
|
2020-03-11 15:18:36 +00:00
|
|
|
|
{
|
2021-03-10 09:18:07 +00:00
|
|
|
|
_random = random;
|
2020-03-11 15:18:36 +00:00
|
|
|
|
|
2021-03-12 05:12:01 +00:00
|
|
|
|
_order = max(1, order);
|
|
|
|
|
|
_minLength = max(1, minLength);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
_maxLength = maxLength;
|
2021-03-12 05:12:01 +00:00
|
|
|
|
|
|
|
|
|
|
Initialize(sampleNames);
|
|
|
|
|
|
}
|
2020-03-11 15:18:36 +00:00
|
|
|
|
|
2021-03-12 05:12:01 +00:00
|
|
|
|
private void Initialize(IEnumerable<string> sampleNames)
|
|
|
|
|
|
{
|
2020-03-11 15:18:36 +00:00
|
|
|
|
//split comma delimited lines
|
|
|
|
|
|
foreach (string line in sampleNames)
|
|
|
|
|
|
{
|
2021-03-11 11:18:21 +00:00
|
|
|
|
string[] tokens = line.Split(' ','\'','(',')');
|
2020-03-11 15:18:36 +00:00
|
|
|
|
foreach (string word in tokens)
|
|
|
|
|
|
{
|
2021-03-10 09:18:07 +00:00
|
|
|
|
string upper = word.Trim().ToLowerInvariant();
|
2021-03-12 05:12:01 +00:00
|
|
|
|
if (upper.Length < _order + 1)
|
2020-03-11 15:18:36 +00:00
|
|
|
|
continue;
|
|
|
|
|
|
_samples.Add(upper + '|'); // Add end character
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Build chains
|
|
|
|
|
|
foreach (string word in _samples)
|
|
|
|
|
|
{
|
2021-03-12 05:12:01 +00:00
|
|
|
|
for (int letter = 0; letter < word.Length - _order; letter++)
|
2020-03-11 15:18:36 +00:00
|
|
|
|
{
|
2021-03-12 05:12:01 +00:00
|
|
|
|
string token = word.Substring(letter, _order);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
List<char> entry = null;
|
|
|
|
|
|
if (_chains.ContainsKey(token))
|
|
|
|
|
|
entry = _chains[token];
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
entry = new List<char>();
|
|
|
|
|
|
_chains[token] = entry;
|
|
|
|
|
|
}
|
2021-03-12 05:12:01 +00:00
|
|
|
|
entry.Add(word[letter + _order]);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Get the next random name
|
|
|
|
|
|
public string NextName
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
string s = "";
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
2021-03-10 09:18:07 +00:00
|
|
|
|
int n = _random.NextInt(0,_samples.Count);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
//int nameLength = _samples[n].Length;
|
|
|
|
|
|
s = _samples[n].Substring(0, _order);//get a random token at the start of a sample word
|
|
|
|
|
|
while (true)//(s.Length < nameLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
string token = s.Substring(s.Length - _order, _order);
|
|
|
|
|
|
char c = GetLetter(token);
|
|
|
|
|
|
if (c != '?' && c != '|')
|
|
|
|
|
|
s += c;//GetLetter(token);
|
|
|
|
|
|
else
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-03-12 05:12:01 +00:00
|
|
|
|
s = s.Substring(0, 1).ToUpper() + s.Substring(1);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
while (_used.Contains(s) || s.Length < _minLength || s.Length > _maxLength);
|
|
|
|
|
|
_used.Add(s);
|
2021-03-12 05:12:01 +00:00
|
|
|
|
return s;
|
2020-03-11 15:18:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Reset the used names
|
|
|
|
|
|
public void Reset()
|
|
|
|
|
|
{
|
|
|
|
|
|
_used.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Get a random letter from the chain
|
|
|
|
|
|
private char GetLetter(string token)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_chains.ContainsKey(token))
|
|
|
|
|
|
return '?';
|
|
|
|
|
|
List<char> letters = _chains[token];
|
2021-03-10 09:18:07 +00:00
|
|
|
|
int n = _random.NextInt(0,letters.Count);
|
2020-03-11 15:18:36 +00:00
|
|
|
|
return letters[n];
|
|
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
}
|