Skip to content

Instantly share code, notes, and snippets.

@savaged
Created February 24, 2023 08:46
Show Gist options
  • Save savaged/bea80a7a930777b7c45e9f07a897f616 to your computer and use it in GitHub Desktop.
Save savaged/bea80a7a930777b7c45e9f07a897f616 to your computer and use it in GitHub Desktop.
Fun C# Caesar Cipher command line tool in a functional programming style
using CaesarCipher;
if (args?.Length > 0)
Console.WriteLine(args[0].Rot13());
else
{
Console.WriteLine("Start typing (Return key to exit)");
PresentUntilReturnKey();
}
static void PresentUntilReturnKey(char output = '\0')
{
if (output != 0)
{
if (output == '\r') return;
Present(
output,
Console.Write,
Console.GetCursorPosition,
Console.SetCursorPosition);
}
PresentUntilReturnKey(Console.ReadKey().Rot13());
}
static void Present(
char output,
Action<string> writer,
Func<(int Left, int Top)> cursorPositionGetter,
Action<int, int> cursorPositionSetter) =>
KeyPressPresenter.Present(
output, writer, cursorPositionGetter, cursorPositionSetter);
internal class KeyPressPresenter
{
public static void Present(
char output,
Action<string> writer,
Func<(int Left, int Top)>? cursorPositionGetter = null,
Action<int, int>? cursorPositionSetter = null)
{
if (output == 127)
{
writer($"\b\b");
return;
}
if (cursorPositionGetter == null
|| cursorPositionSetter == null)
{
writer($"\b{output}");
return;
}
Write(output,
cursorPositionGetter(),
writer,
cursorPositionSetter);
}
private static void Write(
char output,
(int Left, int Top) origPos,
Action<string> writer,
Action<int, int> cursorPositionSetter)
{
SetPosition(cursorPositionSetter, origPos);
writer($"{output}");
ResetPosition(cursorPositionSetter, origPos);
}
private static void SetPosition(
Action<int, int> cursorPositionSetter,
(int Left, int Top) origPos)
{
try
{
cursorPositionSetter(origPos.Left - 1, origPos.Top + 1);
}
catch (ArgumentOutOfRangeException)
{
cursorPositionSetter(1, 1);
}
}
private static void ResetPosition(
Action<int, int> cursorPositionSetter,
(int Left, int Top) origPos)
{
cursorPositionSetter(origPos.Left, origPos.Top);
}
}
namespace CaesarCipher
{
public static class Extensions
{
public static char[] Rot13(this string self) =>
self.ToCharArray().Rot13();
public static char Rot13(this ConsoleKeyInfo self) =>
self.KeyChar.Rot13();
private static char[] Rot13(this IEnumerable<char> self) =>
self.Select(c => c.Rot13()).ToArray();
private static char Rot13(this char self) =>
self switch
{
>= 'a' and <= 'm' or >= 'A' and <= 'M' => (char)(self + 13),
>= 'n' and <= 'z' or >= 'N' and <= 'Z' => (char)(self - 13),
_ => self
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment