mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-28 13:46:06 -08:00
109
70_Poetry/csharp/Context.cs
Normal file
109
70_Poetry/csharp/Context.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
78
70_Poetry/csharp/Phrase.cs
Normal file
78
70_Poetry/csharp/Phrase.cs
Normal 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
32
70_Poetry/csharp/Poem.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
5
70_Poetry/csharp/Program.cs
Normal file
5
70_Poetry/csharp/Program.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
global using Games.Common.IO;
|
||||
global using Games.Common.Randomness;
|
||||
global using Poetry;
|
||||
|
||||
Poem.Compose(new ConsoleIO(), new RandomNumberGenerator());
|
||||
16
70_Poetry/csharp/Resources/Resource.cs
Normal file
16
70_Poetry/csharp/Resources/Resource.cs
Normal 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}'.");
|
||||
}
|
||||
5
70_Poetry/csharp/Resources/Title.txt
Normal file
5
70_Poetry/csharp/Resources/Title.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Poetry
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user