Skip to content

Instantly share code, notes, and snippets.

@RobThree
Last active October 14, 2022 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RobThree/3f8f768514d04e7d306c7e43fe2522ce to your computer and use it in GitHub Desktop.
Save RobThree/3f8f768514d04e7d306c7e43fe2522ce to your computer and use it in GitHub Desktop.
Random animated string (see https://www.reddit.com/r/programming/y13q8x )
// Use chars from input value with custom iterations
WriteAnimatedString("Hello world", 50);
Console.WriteLine();
// Use printable ASCII chars with left-to-right effect
var chars = Enumerable.Range(32, 127).Select(c => (char)c);
WriteAnimatedString("I learned something new today!", animationStyle: AnimationStyle.LeftToRight, chars: chars);
Console.WriteLine();
static void WriteAnimatedString(
string value,
int maxiterations = 200,
TimeSpan? sleep = null,
AnimationStyle animationStyle = AnimationStyle.Random,
IEnumerable<char>? chars = null)
{
// Input validation
ArgumentNullException.ThrowIfNull(value, nameof(value));
if (maxiterations <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxiterations));
}
if (sleep < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(sleep));
}
// Initialization and setup
var rng = new Random(42); // Random number generator with fixed seed so animations are deterministic
var currentchars = value.Select(c => ' ').ToArray(); // Initialize a char array of same length as input with spaces
var counters = Enumerable.Range(0, value.Length) // Initialize letter counters
.Select(i => animationStyle switch
{
AnimationStyle.SingleShot => maxiterations, // All counters same value
AnimationStyle.LeftToRight => (int)Math.Ceiling((i + 1) * (maxiterations / (double)value.Length)), // Ascending counters
AnimationStyle.RightToLeft => (int)Math.Ceiling(maxiterations - (i * (maxiterations / (double)value.Length))), // Descending counters
AnimationStyle.Random or _ => rng.Next(maxiterations) // Random counters
}).ToArray();
var rndchars = (chars ?? value.Select(c => c))
.Distinct().ToArray(); // Initialize available chars (when none specified, use inputstring as source)
sleep ??= TimeSpan.FromMilliseconds(10); // Default sleep to 10 ms is not specified
var (cp_left, cp_top) = Console.GetCursorPosition(); // Get cursor position before we do anything
// Go time!
Console.CursorVisible = false; // Hide cursor
while (!currentchars.SequenceEqual(value)) // Keep going until currentchars equals input value
{
Console.SetCursorPosition(cp_left, cp_top); // Return cursor to position where we first found it at
Thread.Sleep(sleep.Value); // Slow down 'animation'
for (var i = 0; i < value.Length; i++) // Randomize string by iterating each letter
{
currentchars[i] = --counters[i] <= 0 // Decrease counter, then when at 0 or less...
? value[i] // ...pick actual letter from string
: rndchars[rng.Next(rndchars.Length)]; // ...else pick random letter
}
Console.Write(currentchars, 0, currentchars.Length); // Output string
}
Console.CursorVisible = true; // Show cursor
}
public enum AnimationStyle
{
Random = 0,
SingleShot = 1,
LeftToRight = 2,
RightToLeft = 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment