Merge pull request #817 from drewjcooper/csharp-70-poetry

C# 70 poetry
This commit is contained in:
Jeff Atwood
2022-10-12 16:46:05 -07:00
committed by GitHub
8 changed files with 265 additions and 3 deletions

109
70_Poetry/csharp/Context.cs Normal file
View File

@@ -0,0 +1,109 @@
namespace Poetry;
internal class Context
{
private readonly IReadWrite _io;
private readonly IRandom _random;
private int _phraseNumber;
private int _groupNumber;
private bool _skipComma;
private int _lineCount;
private bool _useGroup2;
private bool _atStartOfLine = true;
public Context(IReadWrite io, IRandom random)
{
_io = io;
_random = random;
}
public int PhraseNumber => Math.Max(_phraseNumber - 1, 0);
public int GroupNumber
{
get
{
var value = _useGroup2 ? 2 : _groupNumber;
_useGroup2 = false;
return Math.Max(value - 1, 0);
}
}
public int PhraseCount { get; set; }
public bool GroupNumberIsValid => _groupNumber < 5;
public void WritePhrase()
{
Phrase.GetPhrase(this).Write(_io, this);
_atStartOfLine = false;
}
public void MaybeWriteComma()
{
if (!_skipComma && _random.NextFloat() <= 0.19F && PhraseCount != 0)
{
_io.Write(",");
PhraseCount = 2;
}
_skipComma = false;
}
public void WriteSpaceOrNewLine()
{
if (_random.NextFloat() <= 0.65F)
{
_io.Write(" ");
PhraseCount += 1;
}
else
{
EndLine();
PhraseCount = 0;
}
}
public void Update(IRandom random)
{
_phraseNumber = random.Next(1, 6);
_groupNumber += 1;
_lineCount += 1;
}
public void MaybeIndent()
{
if (PhraseCount == 0 && _groupNumber % 2 == 0)
{
_io.Write(" ");
}
}
public void ResetGroup()
{
_groupNumber = 0;
EndLine();
}
public bool MaybeCompleteStanza()
{
if (_lineCount > 20)
{
_io.WriteLine();
PhraseCount = _lineCount = 0;
_useGroup2 = true;
return true;
}
return false;
}
internal string MaybeCapitalise(string text) =>
_atStartOfLine ? (char.ToUpper(text[0]) + text[1..]) : text;
public void SkipNextComma() => _skipComma = true;
public void EndLine()
{
_io.WriteLine();
_atStartOfLine = true;
}
}

View File

@@ -0,0 +1,78 @@
namespace Poetry;
internal class Phrase
{
private readonly static Phrase[][] _phrases = new Phrase[][]
{
new Phrase[]
{
new("midnight dreary"),
new("fiery eyes"),
new("bird or fiend"),
new("thing of evil"),
new("prophet")
},
new Phrase[]
{
new("beguiling me", ctx => ctx.PhraseCount = 2),
new("thrilled me"),
new("still sitting....", ctx => ctx.SkipNextComma()),
new("never flitting", ctx => ctx.PhraseCount = 2),
new("burned")
},
new Phrase[]
{
new("and my soul"),
new("darkness there"),
new("shall be lifted"),
new("quoth the raven"),
new(ctx => ctx.PhraseCount != 0, "sign of parting")
},
new Phrase[]
{
new("nothing more"),
new("yet again"),
new("slowly creeping"),
new("...evermore"),
new("nevermore")
}
};
private readonly Predicate<Context> _condition;
private readonly string _text;
private readonly Action<Context> _update;
private Phrase(Predicate<Context> condition, string text)
: this(condition, text, _ => { })
{
}
private Phrase(string text, Action<Context> update)
: this(_ => true, text, update)
{
}
private Phrase(string text)
: this(_ => true, text, _ => { })
{
}
private Phrase(Predicate<Context> condition, string text, Action<Context> update)
{
_condition = condition;
_text = text;
_update = update;
}
public static Phrase GetPhrase(Context context) => _phrases[context.GroupNumber][context.PhraseNumber];
public void Write(IReadWrite io, Context context)
{
if (_condition.Invoke(context))
{
io.Write(context.MaybeCapitalise(_text));
}
_update.Invoke(context);
}
}

32
70_Poetry/csharp/Poem.cs Normal file
View File

@@ -0,0 +1,32 @@
using static Poetry.Resources.Resource;
namespace Poetry;
internal class Poem
{
internal static void Compose(IReadWrite io, IRandom random)
{
io.Write(Streams.Title);
var context = new Context(io, random);
while (true)
{
context.WritePhrase();
context.MaybeWriteComma();
context.WriteSpaceOrNewLine();
while (true)
{
context.Update(random);
context.MaybeIndent();
if (context.GroupNumberIsValid) { break; }
context.ResetGroup();
if (context.MaybeCompleteStanza()) { break; }
}
}
}
}

View File

@@ -6,4 +6,12 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Resources/*.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\00_Common\dotnet\Games.Common\Games.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,5 @@
global using Games.Common.IO;
global using Games.Common.Randomness;
global using Poetry;
Poem.Compose(new ConsoleIO(), new RandomNumberGenerator());

View File

@@ -0,0 +1,16 @@
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Poetry.Resources;
internal static class Resource
{
internal static class Streams
{
public static Stream Title => GetStream();
}
private static Stream GetStream([CallerMemberName] string? name = null) =>
Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt")
?? throw new Exception($"Could not find embedded resource stream '{name}'.");
}

View File

@@ -0,0 +1,5 @@
Poetry
Creative Computing Morristown, New Jersey

View File

@@ -1,3 +1,8 @@
5 Y=RND(-1)
6 REM FOR X = 1 TO 100
7 REM PRINT RND(1);","
8 REM NEXT X
9 REM GOTO 999
10 PRINT TAB(30);"POETRY"
20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
30 PRINT:PRINT:PRINT
@@ -26,17 +31,21 @@
133 PRINT "SLOWLY CREEPING";:GOTO 210
134 PRINT "...EVERMORE";:GOTO 210
135 PRINT "NEVERMORE";
210 IF U=0 OR RND(1)>.19 THEN 212
210 GOSUB 500 : IF U=0 OR X>.19 THEN 212
211 PRINT ",";:U=2
212 IF RND(1)>.65 THEN 214
212 GOSUB 500 : IF X>.65 THEN 214
213 PRINT " ";:U=U+1:GOTO 215
214 PRINT : U=0
215 I=INT(INT(10*RND(1))/2)+1
215 GOSUB 500 : I=INT(INT(10*X)/2)+1
220 J=J+1 : K=K+1
225 REM PRINT "I=";I;"; J=";J;"; K=";K;"; U=";U
230 IF U>0 OR INT(J/2)<>J/2 THEN 240
235 PRINT " ";
240 ON J GOTO 90,110,120,130,250
250 J=0 : PRINT : IF K>20 THEN 270
260 GOTO 215
270 PRINT : U=0 : K=0 : GOTO 110
500 X = RND(1)
505 REM PRINT "#";X;"#"
510 RETURN
999 END