From 09c9b3c2b229eac3e5caafd17a3b90f82afae803 Mon Sep 17 00:00:00 2001 From: layagyasz Date: Mon, 22 Jul 2019 20:37:28 -0600 Subject: [PATCH] Initial commit --- .gitignore | 40 +++++++++++ Hauyne.sln | 17 +++++ Hauyne/Engine/Generated.cs | 58 +++++++++++++++ Hauyne/Engine/Generator.cs | 10 +++ Hauyne/Engine/MatchRule.cs | 75 ++++++++++++++++++++ Hauyne/Engine/PrintRule.cs | 45 ++++++++++++ Hauyne/Engine/ReplaceRule.cs | 36 ++++++++++ Hauyne/Engine/Set.cs | 114 ++++++++++++++++++++++++++++++ Hauyne/Engine/SingleGenerator.cs | 47 ++++++++++++ Hauyne/Engine/SumGenerator.cs | 49 +++++++++++++ Hauyne/Examples/Example.txt | 65 +++++++++++++++++ Hauyne/Hauyne.csproj | 72 +++++++++++++++++++ Hauyne/Language.cs | 101 ++++++++++++++++++++++++++ Hauyne/Parsing/Operator.cs | 24 +++++++ Hauyne/Parsing/ParseNode.cs | 108 ++++++++++++++++++++++++++++ Hauyne/Parsing/ParseTree.cs | 25 +++++++ Hauyne/Program.cs | 22 ++++++ Hauyne/Properties/AssemblyInfo.cs | 26 +++++++ Hauyne/Sound.cs | 76 ++++++++++++++++++++ Hauyne/SoundClass.cs | 22 ++++++ Hauyne/Word.cs | 19 +++++ 21 files changed, 1051 insertions(+) create mode 100644 .gitignore create mode 100644 Hauyne.sln create mode 100644 Hauyne/Engine/Generated.cs create mode 100644 Hauyne/Engine/Generator.cs create mode 100644 Hauyne/Engine/MatchRule.cs create mode 100644 Hauyne/Engine/PrintRule.cs create mode 100644 Hauyne/Engine/ReplaceRule.cs create mode 100644 Hauyne/Engine/Set.cs create mode 100644 Hauyne/Engine/SingleGenerator.cs create mode 100644 Hauyne/Engine/SumGenerator.cs create mode 100644 Hauyne/Examples/Example.txt create mode 100644 Hauyne/Hauyne.csproj create mode 100644 Hauyne/Language.cs create mode 100644 Hauyne/Parsing/Operator.cs create mode 100644 Hauyne/Parsing/ParseNode.cs create mode 100644 Hauyne/Parsing/ParseTree.cs create mode 100644 Hauyne/Program.cs create mode 100644 Hauyne/Properties/AssemblyInfo.cs create mode 100644 Hauyne/Sound.cs create mode 100644 Hauyne/SoundClass.cs create mode 100644 Hauyne/Word.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e82d27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/Hauyne.sln b/Hauyne.sln new file mode 100644 index 0000000..7d06099 --- /dev/null +++ b/Hauyne.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hauyne", "Hauyne\Hauyne.csproj", "{9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9}.Debug|x86.ActiveCfg = Debug|x86 + {9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9}.Debug|x86.Build.0 = Debug|x86 + {9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9}.Release|x86.ActiveCfg = Release|x86 + {9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/Hauyne/Engine/Generated.cs b/Hauyne/Engine/Generated.cs new file mode 100644 index 0000000..d1fa590 --- /dev/null +++ b/Hauyne/Engine/Generated.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; + +namespace Hauyne.Engine +{ + public class Generated : IEnumerable + { + protected List _Sounds = new List(); + + T Last { get { return _Sounds[_Sounds.Count - 1]; } } + T First { get { return _Sounds[0]; } } + public int Length { get { return _Sounds.Count; } } + + public IEnumerator GetEnumerator() { return _Sounds.GetEnumerator(); } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public T this[int Index] { get { return _Sounds[Index]; } } + + public Generated() { } + public Generated(T Initial) { _Sounds.Add(Initial); } + + + public void Combine(Generated Word) + { + if (Word != null) foreach (T S in Word._Sounds) _Sounds.Add(S); + } + + public void Remove(int Index, int Length) + { + _Sounds.RemoveRange(Index, Length); + } + + public void Insert(int Index, List Values) + { + for (int i = Values.Count - 1; i >= 0; --i) + { + _Sounds.Insert(Index, Values[i]); + } + } + + public void RemoveDoubles() + { + for (int i = 0; i < _Sounds.Count - 1; ++i) + { + if (_Sounds[i].Equals(_Sounds[i + 1])) _Sounds.RemoveAt(i); + } + } + + public override string ToString() + { + string R = ""; + foreach (T S in _Sounds) R += S.ToString(); + return R; + } + } +} diff --git a/Hauyne/Engine/Generator.cs b/Hauyne/Engine/Generator.cs new file mode 100644 index 0000000..ed02783 --- /dev/null +++ b/Hauyne/Engine/Generator.cs @@ -0,0 +1,10 @@ +using System; + +namespace Hauyne.Engine +{ + interface Generator + { + double Frequency { get; } + Generated Generate(Random Random); + } +} diff --git a/Hauyne/Engine/MatchRule.cs b/Hauyne/Engine/MatchRule.cs new file mode 100644 index 0000000..527150a --- /dev/null +++ b/Hauyne/Engine/MatchRule.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + class MatchRule where T : Generator + { + public static readonly Set StartGenerated = new Set(); + public static readonly Set EndGenerated = new Set(); + + List> _Sets = new List>(); + int _Length; + int _StartIndex = 0; + int _EndIndex = -1; + + public int Length { get { return _Length; } } + public int StartIndex { get { return _StartIndex; } } + public int EndIndex { get { return _EndIndex; } } + + public MatchRule(string Source, List> Operators, Dictionary> Generators) + { + string[] s = Source.Split(':'); + for (int i = 0; i < s.Length; ++i) + { + string S = s[i]; + if (S.Trim() == "$") + { + if (_Sets.Count == 0) + { + _Sets.Add(StartGenerated); + _StartIndex = 1; + } + else + { + _Sets.Add(EndGenerated); + _Length--; + } + } + else + { + if (S.Contains('(')) + { + _StartIndex = _Length; + S = S.Replace("(", ""); + } + if (S.Contains(')')) + { + _EndIndex = _Length; + S = S.Replace(")", ""); + } + _Sets.Add(Set.ParseSet(S, Operators, Generators)); + } + _Length++; + } + if (_EndIndex == -1) _EndIndex = _Length - 1; + _Length = _EndIndex - _StartIndex + 1; + } + + public bool Match(Generated CompareTo, int Index) + { + for (int i = -StartIndex; i + StartIndex < _Sets.Count; ++i) + { + if (Index + i < -1) return false; + else if (Index + i > CompareTo.Length) return false; + else if (Index + i == -1 && _Sets[i + StartIndex] != StartGenerated) return false; + else if (Index + i == CompareTo.Length && _Sets[i + StartIndex] != EndGenerated) return false; + else if (Index + i > -1 && Index + i < CompareTo.Length && !_Sets[i + StartIndex].Contains(CompareTo[Index + i])) return false; + } + return true; + } + } +} diff --git a/Hauyne/Engine/PrintRule.cs b/Hauyne/Engine/PrintRule.cs new file mode 100644 index 0000000..174b428 --- /dev/null +++ b/Hauyne/Engine/PrintRule.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Cardamom.Utilities; +using Cardamom.Serialization; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + internal class PrintRule where T : Generator + { + MatchRule _Match; + WeightedVector _Options = new WeightedVector(); + + public int Length { get { return _Match.Length; } } + + public PrintRule(ParseBlock Block, List> Operators, Dictionary> Generators) + { + string[] def = Block.String.Split(new string[] { "=>" }, StringSplitOptions.None); + _Match = new MatchRule(def[0], Operators, Generators); + string[] ops = def[1].Split(':'); + for (int i = 0; i < ops.Length; ++i) + { + if (ops[i].Contains('*')) + { + string[] d = ops[i].Split('*'); + _Options.Add(Convert.ToDouble(d[0], System.Globalization.CultureInfo.InvariantCulture), d[1].Trim()); + } + else + { + _Options.Add(1, ops[i].Trim()); + } + } + } + + public bool Match(Generated MatchIn, int Index) + { + return _Match.Match(MatchIn, Index); + } + + public string Get(double Index) { return _Options[Index]; } + } +} diff --git a/Hauyne/Engine/ReplaceRule.cs b/Hauyne/Engine/ReplaceRule.cs new file mode 100644 index 0000000..12fcd8e --- /dev/null +++ b/Hauyne/Engine/ReplaceRule.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +using Cardamom.Serialization; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + class ReplaceRule where T : Generator + { + MatchRule _Match; + SingleGenerator _Replacement; + + public ReplaceRule(ParseBlock Block, List> Operators, Dictionary> Generators) + { + string[] def = Block.String.Split(new string[] { "=>" }, StringSplitOptions.None); + _Match = new MatchRule(def[0], Operators, Generators); + _Replacement = new SingleGenerator(def[1], Operators, Generators); + } + + public void Replace(Random Random, Generated ReplaceIn, int Index) + { + if (_Match.Match(ReplaceIn, Index)) + { + ReplaceIn.Remove(Index, _Match.Length); + List New = new List(); + Generated R = _Replacement.Generate(Random); + foreach (T S in R) New.Add(S); + ReplaceIn.Insert(Index, New); + } + } + + + } +} diff --git a/Hauyne/Engine/Set.cs b/Hauyne/Engine/Set.cs new file mode 100644 index 0000000..7fe1e3d --- /dev/null +++ b/Hauyne/Engine/Set.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Cardamom.Utilities; +using Cardamom.Serialization; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + class Set : IEnumerable, Generator where T : Generator + { + HashSet _Elements = new HashSet(); + WeightedVector _Selector = new WeightedVector(); + + public double Frequency { get { return 1; } } + public IEnumerator GetEnumerator() { return _Elements.GetEnumerator(); } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public Set() { } + + public Set(string Source, List> Operators, Dictionary> Sets) + { + foreach (T V in ParseSet(Source, Operators, Sets)) Add(V, V.Frequency); + } + + public static Set ParseSet(string Source, List> Operators, Dictionary> Sets) + { + return new ParseTree(Source, Operators, Sets).Traverse(); + } + + public Set(ParseBlock Block, List> Operators, Dictionary> Sets, Dictionary Sounds) + { + foreach (string S in Block.String.Split(':')) + { + bool c = false; + foreach (Operator O in Operators) + { + if (S.Contains(O.Symbol)) { c = true; break; } + } + if (c) + { + foreach (T V in ParseSet(S, Operators, Sets)) Add(V, V.Frequency); + } + else + { + T s = Sounds[S.Trim()]; + Add(s, s.Frequency); + } + } + } + + public void Add(T Value, double Weight) + { + if (!_Elements.Contains(Value)) + { + _Elements.Add(Value); + _Selector.Add(Weight, Value); + } + } + + public bool Contains(T Value) { return _Elements.Contains(Value); } + + public Generated Generate(Random Random) + { + if (_Selector.Length > 0) return _Selector[Random.NextDouble()].Generate(Random); + else return null; + } + + public T Random(Random Random) + { + return _Selector[Random.NextDouble()]; + } + + public static Set operator +(Set s1, Set s2) + { + Set S = new Set(); + foreach (T V in s1) S.Add(V, V.Frequency); + foreach (T V in s2) S.Add(V, V.Frequency); + return S; + } + + public static Set operator *(Set s1, Set s2) + { + Set S = new Set(); + foreach (T V in s1) + { + if (s2.Contains(V)) S.Add(V, V.Frequency); + } + return S; + } + + public static Set operator -(Set s1, Set s2) + { + Set S = new Set(); + foreach (T V in s1) + { + if (!s2.Contains(V)) S.Add(V, V.Frequency); + } + return S; + } + + public override string ToString() + { + string R = "[Set]"; + foreach (T S in _Selector) R += S + " "; + return R; + } + } +} diff --git a/Hauyne/Engine/SingleGenerator.cs b/Hauyne/Engine/SingleGenerator.cs new file mode 100644 index 0000000..39f1701 --- /dev/null +++ b/Hauyne/Engine/SingleGenerator.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +using Cardamom.Utilities; +using Cardamom.Serialization; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + internal class SingleGenerator : Generator where T : Generator + { + WeightedVector> _Generators = new WeightedVector>(); + + public double Frequency { get { return 1; } } + + public SingleGenerator(ParseBlock Block, List> Operators, Dictionary> Generators) + : this(Block.String, Operators, Generators) { } + + public SingleGenerator(string Source, List> Operators, Dictionary> Generators) + { + string[] g = Source.Split('|'); + foreach (string G in g) + { + string[] d = G.Split('@'); + if (d.Length == 2) + { + double w = Convert.ToDouble(d[0], System.Globalization.CultureInfo.InvariantCulture); + _Generators.Add(w, new SumGenerator(d[1], Operators, Generators)); + } + else _Generators.Add(1, new SumGenerator(G, Operators, Generators)); + } + } + + public Generated Generate(Random Random) + { + return _Generators[Random.NextDouble()].Generate(Random); + } + + public override string ToString() + { + string R = "[SingleGenerator]"; + foreach (Generator G in _Generators) R += "\n" + G.ToString(); + return R + "\n[/Generator]"; + } + } +} diff --git a/Hauyne/Engine/SumGenerator.cs b/Hauyne/Engine/SumGenerator.cs new file mode 100644 index 0000000..aa0c592 --- /dev/null +++ b/Hauyne/Engine/SumGenerator.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Hauyne.Parsing; + +namespace Hauyne.Engine +{ + class SumGenerator : Generator where T : Generator + { + Generator[] _Generators; + + public double Frequency { get { return 1; } } + + public SumGenerator(string Source, List> Operators, Dictionary> Generators) + { + string[] g = Source.Split(':'); + _Generators = new Generator[g.Length]; + for (int i = 0; i < g.Length; ++i) + { + bool c = false; + foreach (Operator O in Operators) + { + if (g[i].Contains(O.Symbol)) { c = true; break; } + } + if (c) _Generators[i] = Set.ParseSet(g[i], Operators, Generators); + else _Generators[i] = Generators[g[i].ToLower().Trim()]; + } + } + + public Generated Generate(Random Random) + { + Generated Word = new Generated(); + for (int i = 0; i < _Generators.Length; ++i) + { + Generated w = _Generators[i].Generate(Random); + if (w != null) Word.Combine(w); + } + return Word; + } + + public override string ToString() + { + string R = "[SumGenerator]"; + foreach (Generator G in _Generators) R += "\n" + G.ToString(); + return R; + } + } +} diff --git a/Hauyne/Examples/Example.txt b/Hauyne/Examples/Example.txt new file mode 100644 index 0000000..36b28fb --- /dev/null +++ b/Hauyne/Examples/Example.txt @@ -0,0 +1,65 @@ +sound[]:sounds +{ + sound:p { Consonant : Plosive : Unvoiced : Bilabial } + sound:b { Consonant : Plosive : Voiced : Bilabial } + sound:.2 * f { Consonant : Fricative : Unvoiced : Labiodental } + sound:.4 * v { Consonant : Fricative : Voiced : Labiodental } + sound:s { Consonant : Fricative : Unvoiced : Alveolar } + sound:.4 * z { Consonant : Fricative : Voiced : Alveolar } + sound:t { Consonant : Plosive : Unvoiced : Alveolar } + sound:d { Consonant : Plosive : Voiced : Alveolar } + sound:k { Consonant : Plosive : Unvoiced : Velar } + sound:g { Consonant : Plosive : Voiced : Velar } + sound:m { Consonant : Voiced : Nasal : Bilabial } + sound:n { Consonant : Voiced : Nasal : Alveolar } + sound:l { Consonant } + sound:r { Consonant } + sound:j { Consonant : Palatal : Approximant } + sound:.4 * th { Consonant : Unvoiced : Dental : Fricative } + sound:.2 * sh { Consonant : Unvoiced : Postalveolar : Fricative } + sound:.2 * ch { Consonant : Unvoiced : Postalveolar : Affricative } + + sound:1.5 * a { Vowel : Front : Open : Unrounded } + sound:3 * e { Vowel : Front : MidOpen : Unrounded } + sound:i { Vowel : Front : Closed : Unrounded } + sound:o { Vowel : Open : Back : Rounded } + sound:.4 * u { Vowel : Closed : Back : Rounded } +} +generator[]:generators +{ + generator:lead { 16 @ Consonant | 1.5 @ Fricative - Voiced + Plosive - th - sh - Plosive * Alveolar: l | 1.5 @ Fricative - Voiced + Plosive - s : r | s : Nasal | 8 @ ~ } + generator:tail { 10 @ Consonant - j | 2 @ s : Unvoiced * Plosive | 2 @ Consonant - j | m : p | 2 @ n : Alveolar - n + Velar + Dental | 2 @ r + l : Consonant - j - r - l } + generator:syll { 6 @ lead : Vowel | lead : Vowel : tail } + generator:main { syll : syll | syll | syll : syll : syll } +} +replacer[]:replacers +{ + replacer:_ { $ : Vowel : $ => syll : syll } + replacer:_ { $ : Vowel : Vowel : $ => Vowel : Consonant : Vowel } + replacer:_ { Vowel : Vowel => Vowel : Consonant : Vowel | Vowel } + replacer:_ { Vowel : $ => Vowel : tail } +} +orthography[]:orthography +{ + orthography:_ { f => ph } + orthography:_ { $ : i => i } + orthography:_ { i : j => i } + orthography:_ { j : i => i } + orthography:_ { i => i : y } + orthography:_ { Vowel : (k) : $ => c : .5 * ch } + orthography:_ { Vowel : (k) => ck : .2 * c : .5 * ch } + orthography:_ { k => k : c : ch } + orthography:_ { Vowel : (ch) => .5 * ch : tch } + orthography:_ { j => y } + orthography:_ { Vowel : (l) : Vowel => l : ll } + orthography:_ { Vowel : (r) : Vowel => r : rr } + orthography:_ { Vowel : (l) : $ => l : ll } + orthography:_ { Vowel : (r) : $ => r : rr } + orthography:_ { Vowel : (p) : Vowel => p : pp } + orthography:_ { Vowel : (n) : Vowel => n : nn } + orthography:_ { Vowel : (m) : Vowel => m : mm } + orthography:_ { Vowel : (n) : $ => n : nn } + orthography:_ { Vowel : (m) : $ => m : mm } + orthography:_ { Vowel : (s) : Vowel => s : ss } + orthography:_ { Vowel : (s) : $ => s : ss } +} \ No newline at end of file diff --git a/Hauyne/Hauyne.csproj b/Hauyne/Hauyne.csproj new file mode 100644 index 0000000..a5bfb8f --- /dev/null +++ b/Hauyne/Hauyne.csproj @@ -0,0 +1,72 @@ + + + + Debug + x86 + {9B5BF73D-5F30-4C25-A5F0-B2162A4B0AC9} + Exe + Hauyne + Hauyne + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + x86 + + + true + bin\Release + prompt + 4 + true + x86 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + {A416D343-545A-40B0-9AE3-A5AAA9D47E79} + Cardamom + + + + \ No newline at end of file diff --git a/Hauyne/Language.cs b/Hauyne/Language.cs new file mode 100644 index 0000000..41994b9 --- /dev/null +++ b/Hauyne/Language.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; + +using Cardamom.Serialization; + +using Hauyne.Engine; +using Hauyne.Parsing; + +namespace Hauyne +{ + public class Language + { + private enum Attribute { SOUNDS, GENERATORS, REPLACERS, ORTHOGRAPHY }; + + static List> OPERATORS = new List>() + { + new Operator('+', 1, delegate(Generator s1, Generator s2) { return (Set)s1 + (Set)s2;}), + new Operator('-', 1, delegate(Generator s1, Generator s2) { return (Set)s1 - (Set)s2;}), + new Operator('*', 2, delegate(Generator s1, Generator s2) { return (Set)s1 * (Set)s2;}) + }; + + Dictionary> _Generators = new Dictionary>() { { "*", new Set() }, { "~", new Set() } }; + List> _Replacers; + List> _Printers; + + public Language(ParseBlock Block) + { + Block.AddParser("sound", + i => + { + var s = new Sound(i); + AddSound(s); + return s; + }); + Block.AddParser>("generator", + i => + { + var g = new SingleGenerator(i, OPERATORS, _Generators); + _Generators.Add(i.Name, g); + return g; + }); + Block.AddParser>("replacer", i => new ReplaceRule(i, OPERATORS, _Generators)); + Block.AddParser>("orthography", i => new PrintRule(i, OPERATORS, _Generators)); + + object[] attributes = Block.BreakToAttributes(typeof(Attribute)); + _Replacers = (List>)attributes[(int)Attribute.REPLACERS]; + _Printers = (List>)attributes[(int)Attribute.ORTHOGRAPHY]; + } + + public Language(string Path) : this(new ParseBlock(File.ReadAllText(Path))) { } + + public void AddSound(Sound Sound) + { + foreach (string I in Sound.Identifiers) + { + if (!_Generators.ContainsKey(I)) _Generators.Add(I, new Set()); + ((Set)_Generators[I]).Add(Sound, Sound.Frequency); + } + Set NS = new Set(); + NS.Add(Sound, Sound.Frequency); + _Generators.Add(Sound.Symbol, NS); + ((Set)_Generators["*"]).Add(Sound, Sound.Frequency); + } + + public Word Generate(string Generator, Random Random) + { + Word W = new Word(_Generators[Generator].Generate(Random), Random, _Printers); + W.RemoveDoubles(); + foreach (ReplaceRule R in _Replacers) + { + for (int i = 0; i <= W.Length; ++i) R.Replace(Random, W, i); + } + W.RemoveDoubles(); + MakePrintable(W, Random, _Printers); + return W; + } + + private void MakePrintable(Word Word, Random Random, List> Rules) + { + string R = ""; + for (int i = 0; i < Word.Length;) + { + bool Matched = false; + foreach (PrintRule Rule in Rules) + { + if (Rule.Match(Word, i)) + { + i += Rule.Length; + R += Rule.Get(Random.NextDouble()); + Matched = true; + break; + } + } + if (!Matched) R += Word[i++].ToString(); + } + Word.Orthography = R; + } + } +} diff --git a/Hauyne/Parsing/Operator.cs b/Hauyne/Parsing/Operator.cs new file mode 100644 index 0000000..4b590b9 --- /dev/null +++ b/Hauyne/Parsing/Operator.cs @@ -0,0 +1,24 @@ +using System; + +using Hauyne.Engine; + +namespace Hauyne.Parsing +{ + class Operator where T : Generator + { + char _Operator; + int _Priority; + Func, Generator, Generator> _Function; + + public char Symbol { get { return _Operator; } } + public int Priority { get { return _Priority; } } + public Func, Generator, Generator> Function { get { return _Function; } } + + public Operator(char Operator, int Priority, Func, Generator, Generator> Function) + { + _Operator = Operator; + _Priority = Priority; + _Function = Function; + } + } +} diff --git a/Hauyne/Parsing/ParseNode.cs b/Hauyne/Parsing/ParseNode.cs new file mode 100644 index 0000000..11dc529 --- /dev/null +++ b/Hauyne/Parsing/ParseNode.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; + +using Hauyne.Engine; + +namespace Hauyne.Parsing +{ + class ParseNode where T : Generator + { + Operator _Operator; + ParseNode _Parent; + ParseNode _Left; + ParseNode _Right; + Generator _Value; + + public ParseNode(string Source, List> Operators, Dictionary> Sets) + { + for (int i = 0; i < Source.Length; ++i) + { + for (int j = 0; j < Operators.Count; ++j) + { + if (Source[i] == Operators[j].Symbol) + { + string left = Source.Substring(0, i); + string right = Source.Substring(i + 1); + _Operator = Operators[j]; + _Left = new ParseNode(left, Sets); + _Right = new ParseNode(right, Operators, Sets); + return; + } + } + } + + _Value = Sets[Source.ToLower().Trim()]; + } + + private ParseNode(string Source, Dictionary> Sets) + { + _Value = Sets[Source.ToLower().Trim()]; + } + + public Generator Traverse() + { + if (_Left != null && _Right != null) + { + return _Operator.Function.Invoke(_Left.Traverse(), _Right.Traverse()); + } + else if (_Left == null && _Right != null) return _Right.Traverse(); + else if (_Left != null && _Right == null) return _Left.Traverse(); + else return _Value; + } + + private void ReplaceChild(ParseNode Old, ParseNode New) + { + if (Old == _Left) _Left = New; + else _Right = New; + } + + public void Rebalance() + { + if (_Right != null) + { + if (_Right._Operator != null && _Right._Operator.Priority <= _Operator.Priority) + { + RebalanceLeft(); + _Parent.Rebalance(); + } + else if (_Right._Operator != null) _Right.Rebalance(); + } + } + + private void RebalanceLeft() + { + ParseNode OldRight = _Right; + _Right = OldRight._Left; + if (_Parent != null) _Parent.ReplaceChild(this, _Right); + _Parent = OldRight; + _Parent._Left = this; + } + + private string ToStringAux(int Depth) + { + if (_Operator != null) + { + string R = "" + _Operator.Symbol; + string Left = _Left.ToStringAux(Depth + 1); + string Right = _Right.ToStringAux(Depth + 1); + return R.PadLeft(R.Length + Depth, '\t') + Depth + "\n" + Left + "\n" + Right; + } + else + { + string R = _Value.ToString(); + return R.PadLeft(R.Length + Depth, '\t'); + } + } + + public ParseNode GetRoot() + { + ParseNode Current = this; + while (Current._Parent != null) Current = Current._Parent; + return Current; + } + + public override string ToString() + { + return ToStringAux(0); + } + } +} diff --git a/Hauyne/Parsing/ParseTree.cs b/Hauyne/Parsing/ParseTree.cs new file mode 100644 index 0000000..b1400f1 --- /dev/null +++ b/Hauyne/Parsing/ParseTree.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +using Hauyne.Engine; + +namespace Hauyne.Parsing +{ + class ParseTree where T : Generator + { + ParseNode _Head; + + public ParseTree(string Source, List> Operators, Dictionary> Sets) + { + _Head = new ParseNode(Source, Operators, Sets); + _Head.Rebalance(); + _Head = _Head.GetRoot(); + } + + public Set Traverse() { return (Set)_Head.Traverse(); } + + public override string ToString() + { + return _Head.ToString(); + } + } +} diff --git a/Hauyne/Program.cs b/Hauyne/Program.cs new file mode 100644 index 0000000..03463db --- /dev/null +++ b/Hauyne/Program.cs @@ -0,0 +1,22 @@ +using System; + +namespace Hauyne +{ + class MainClass + { + public static void Main(string[] args) + { + string file = args[0]; + string generator = args[1]; + int number = Convert.ToInt32(args[2]); + + Random random = new Random(); + Language language = new Language(file); + for (int i = 0; i < number; ++i) + { + Word word = language.Generate(generator, random); + Console.WriteLine("{0} ({1})", word.Orthography, word); + } + } + } +} diff --git a/Hauyne/Properties/AssemblyInfo.cs b/Hauyne/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cb735fe --- /dev/null +++ b/Hauyne/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Hauyne")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/Hauyne/Sound.cs b/Hauyne/Sound.cs new file mode 100644 index 0000000..256e867 --- /dev/null +++ b/Hauyne/Sound.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Cardamom.Serialization; + +using Hauyne.Engine; + +namespace Hauyne +{ + public class Sound : Generator + { + string _Sound; + string[] _Identifiers; + double _Frequency; + double _Drop; + + public string Symbol { get { return _Sound; } } + public double Frequency { get { return _Frequency; } } + public double Drop { get { return _Drop; } } + public string[] Identifiers { get { return _Identifiers; } } + + public Sound(ParseBlock Block) + { + string[] head = Block.Name.Split('*'); + if (head.Length == 3) + { + _Sound = head[2].Trim(); + _Drop = Convert.ToDouble(head[1], System.Globalization.CultureInfo.InvariantCulture); + _Frequency = Convert.ToDouble(head[0], System.Globalization.CultureInfo.InvariantCulture); + } + else if (head.Length == 2) + { + _Sound = head[1].Trim(); + _Frequency = Convert.ToDouble(head[0], System.Globalization.CultureInfo.InvariantCulture); + } + else + { + _Sound = head[0]; + _Frequency = 1; + } + _Identifiers = Block.String.Split(':'); + for (int i = 0; i < _Identifiers.Length; ++i) _Identifiers[i] = _Identifiers[i].Trim().ToLower(); + } + + public bool HasIdentifier(string Identifier) { return _Identifiers.Contains(Identifier); } + + public Generated Generate(Random Random) + { + return new Generated(this); + } + + public bool MatchesClasses(IEnumerable Classes) + { + foreach (SoundClass C in Classes) + { + if (MatchesClass(C)) return true; + } + return false; + } + + public bool MatchesClass(SoundClass Class) + { + foreach (string I in Class.Identifiers) + { + if (!_Identifiers.Contains(I)) return false; + } + return true; + } + + public override string ToString() + { + return _Sound; + } + } +} diff --git a/Hauyne/SoundClass.cs b/Hauyne/SoundClass.cs new file mode 100644 index 0000000..ec5dc5f --- /dev/null +++ b/Hauyne/SoundClass.cs @@ -0,0 +1,22 @@ +using Cardamom.Serialization; + +namespace Hauyne +{ + public class SoundClass + { + private enum Attribute { FREQUENCY, IDENTIFIERS }; + + double _Frequency; + string[] _Identifiers; + + public double Frequency { get { return _Frequency; } set { _Frequency = value; } } + public string[] Identifiers { get { return _Identifiers; } set { _Identifiers = value; } } + + public SoundClass(ParseBlock Block) + { + object[] attributes = Block.BreakToAttributes(typeof(Attribute)); + _Frequency = (double)attributes[(int)Attribute.FREQUENCY]; + _Identifiers = (string[])attributes[(int)Attribute.IDENTIFIERS]; + } + } +} diff --git a/Hauyne/Word.cs b/Hauyne/Word.cs new file mode 100644 index 0000000..518e336 --- /dev/null +++ b/Hauyne/Word.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +using Hauyne.Engine; + +namespace Hauyne +{ + public class Word : Generated + { + string _Orthography; + + public string Orthography { get { return _Orthography; } internal set { _Orthography = value; } } + + internal Word(Generated Generated, Random Random, List> PrintRules) + { + foreach (Sound S in Generated) _Sounds.Add(S); + } + } +}