using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Koopakiller.Apps.Desktop.Schreibtischfeuerwerk
{
class Program
{
static Random rnd = new Random();
static void Intro()
{
Console.WriteLine("Maximieren Sie ggf. das Konsolenfenster und drücken Sie anschließend Enter.");
Console.ReadKey();
}
static void PrintCurrentYear()
{
PrintYear(DateTime.Now.AddDays(-1).Year);
}
static void PrintYear(int year)
{
var size = (int)Math.Min((Console.WindowWidth - 6) / (int)(Math.Log10(year) + 1) - 2, Console.WindowHeight / 3 - 3);
var digits = year.ToString().ToCharArray();
var paddingHorz = (Console.WindowWidth - 4 * (size + 2) - 1) / 2;
for (int i = 0; i < digits.Length; ++i)
{
ConsoleHelper.WriteDigit(3, paddingHorz + i * (size + 2), digits[i] - '0', size);
}
}
static void PrintCredits()
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine();
var s = $"Wir wünschen euch ein frohes neues Jahr";
Console.WriteLine($"{new string(' ', (Console.WindowWidth - s.Length) / 2)}{s}");
PrintYear(DateTime.Now.AddDays(-1).Year + 1);
}
static RocketBase CreateSingleRingRocket(int startStep)
{
var c1 = ConsoleHelper.RandomColor(ConsoleColor.DarkGray);
var c2 = ConsoleHelper.RandomColor(ConsoleColor.DarkGray, c1);
return new SingleRingRocket()
{
BaseLine = Console.LargestWindowHeight,
Radius = rnd.Next(2, 10),
Color1 = c1,
Color2 = c2,
Height = rnd.Next(25, Console.WindowHeight - 4),
LeftPosition = rnd.Next(0, Console.WindowWidth - 4),
StartStep = startStep,
};
}
static RocketBase CreateDoubleRingRocket(int startStep)
{
var c1 = ConsoleHelper.RandomColor(ConsoleColor.DarkGray);
var c2 = ConsoleHelper.RandomColor(ConsoleColor.DarkGray, c1);
var r1 = rnd.Next(2, 8);
var r2 = rnd.Next(r1 + 1, 12);
return new DoubleRingRocket()
{
BaseLine = Console.LargestWindowHeight,
RadiusA = r1,
RadiusB = r2,
Color1 = c1,
Color2 = c2,
Height = rnd.Next(25, Console.WindowHeight - 4),
LeftPosition = rnd.Next(0, Console.WindowWidth - 4),
StartStep = startStep,
};
}
static RocketBase CreateConicalRocket(int startStep)
{
return new ConicalRocket()
{
HasShortSparks = rnd.Next(2) == 0,
BaseLine = Console.LargestWindowHeight,
Length = rnd.Next(4, 9),
Color = ConsoleHelper.RandomColor(ConsoleColor.DarkGray),
Height = rnd.Next(25, Console.WindowHeight - 4),
LeftPosition = rnd.Next(0, Console.WindowWidth - 4),
StartStep = startStep,
};
}
static RocketBase CreateFlareRocket(int startStep)
{
return new FlareRocket()
{
BaseLine = Console.LargestWindowHeight,
Duration = rnd.Next(20, 30),
Color = ConsoleHelper.RandomColor(ConsoleColor.DarkGray, ConsoleColor.Black, ConsoleColor.DarkMagenta, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.DarkRed, ConsoleColor.DarkCyan),
Height = rnd.Next(25, Console.WindowHeight - 4),
LeftPosition = rnd.Next(0, Console.WindowWidth - 4),
StartStep = startStep,
HorizontalDirection = (HorizontalDirection)rnd.Next(2),
};
}
static RocketBase CreateTracerRocket(int startStep)
{
return new TracerRocket()
{
BaseLine = Console.LargestWindowHeight,
Color = ConsoleHelper.RandomColor(ConsoleColor.DarkGray, ConsoleColor.Black, ConsoleColor.DarkMagenta, ConsoleColor.DarkBlue, ConsoleColor.DarkGreen, ConsoleColor.DarkRed, ConsoleColor.DarkCyan),
Height = rnd.Next(25, Console.WindowHeight - 4),
LeftPosition = rnd.Next(0, Console.WindowWidth - 4),
StartStep = startStep,
LaunchAngle = (TracerRocketLaunchAngle)rnd.Next(3),
};
}
static void Rockets(int newRocketPropability, int sleepTime, TimeSpan runningTime)
{
if (newRocketPropability <= 0)
{
throw new ArgumentOutOfRangeException(nameof(newRocketPropability));
}
var creators = new Func<int, RocketBase>[] {
CreateSingleRingRocket,
CreateDoubleRingRocket,
CreateConicalRocket,
CreateFlareRocket ,
CreateTracerRocket
};
var items = new List<RocketBase>();
for (int i = 0; i < 5; ++i)
{
items.Add(creators[rnd.Next(creators.Length)](0));
}
var end = DateTime.Now + runningTime;
for (int i = 0; end > DateTime.Now; ++i)
{
if (rnd.Next(newRocketPropability) == 0)
{
items.Add(creators[rnd.Next(creators.Length)](i));
}
for (int j = 0; j < items.Count; ++j)
{
if (items[j].Print(i))
{
items.RemoveAt(j--);
}
}
ConsoleBuffer.WriteBufferToConsole();
Thread.Sleep(sleepTime);
}
}
static void Main(string[] args)
{
Console.Title = "Schreibtischfeuerwerk";
Console.WindowWidth = Console.LargestWindowWidth - 4;
Console.WindowHeight = Console.LargestWindowHeight - 4;
Intro();
Console.Clear();
PrintCurrentYear();
ConsoleBuffer.InitBuffer();
Rockets(5, 80, TimeSpan.FromSeconds(30));
PrintCredits();
Thread.Sleep(5000);
Rockets(1, 5, TimeSpan.FromDays(364));
}
}
public abstract class RocketBase
{
public int Height { get; set; }
public int BaseLine { get; set; }
public int LeftPosition { get; set; }
public int StartStep { get; set; }
public abstract bool Print(int step);
protected static Random Random = new Random();
}
public abstract class CircularRocket : RocketBase
{
protected void PrintCircle(int leftCenter, int topCenter, int radius, ConsoleColor foreground, params char[] chars)
{
if (chars.Length == 1)
{
chars = Enumerable.Repeat(chars[0], 8).ToArray();
}
if (chars.Length != 8)
{
throw new ArgumentOutOfRangeException(nameof(chars), "chars.Length == 8");
}
var s2 = (int)(radius * 1.4);
ConsoleBuffer.WriteCharToBuffer(chars[0], leftCenter + s2, topCenter, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[1], leftCenter + radius, topCenter + radius, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[2], leftCenter, topCenter + s2, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[3], leftCenter - radius, topCenter + radius, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[4], leftCenter - s2, topCenter, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[5], leftCenter - radius, topCenter - radius, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[6], leftCenter, topCenter - s2, foreground);
ConsoleBuffer.WriteCharToBuffer(chars[7], leftCenter + radius, topCenter - radius, foreground);
}
}
public class SingleRingRocket : CircularRocket
{
public int Radius { get; set; }
public ConsoleColor Color1 { get; set; }
public ConsoleColor Color2 { get; set; }
public override bool Print(int step)
{
step -= StartStep;
if (step < 0) throw new ArgumentOutOfRangeException(nameof(step), "stept must be >=0");
if (step <= Height)
{
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - step, ConsoleColor.Yellow);
}
else if (step == this.Height + 1)
{
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition, this.BaseLine - this.Height, ConsoleColor.White);
}
else if (step <= this.Radius + this.Height + 1)
{
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, step - this.Height + 1, ConsoleColor.Gray, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step <= this.Radius + this.Height + 1 + 10)
{
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, this.Radius + 3, step % 2 == 0 ? this.Color1 : this.Color2, '*');
}
else
{
return true;
}
return false;
}
}
public class DoubleRingRocket : CircularRocket
{
public int RadiusA { get; set; }
public int RadiusB { get; set; }
public ConsoleColor Color1 { get; set; }
public ConsoleColor Color2 { get; set; }
public override bool Print(int step)
{
step -= StartStep;
if (step < 0) throw new ArgumentOutOfRangeException(nameof(step), "stept must be >=0");
if (step <= Height)
{
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - step, ConsoleColor.Yellow);
}
else if (step == this.Height + 1)
{
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition, this.BaseLine - this.Height, ConsoleColor.White);
}
else if (step <= this.RadiusB + this.Height + 1)
{
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, step - this.Height + 1, ConsoleColor.Gray, '-', '\\', '|', '/', '-', '\\', '|', '/');
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, (int)((step - this.Height + 1) / (double)this.RadiusB * this.RadiusA), ConsoleColor.Gray, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step <= this.RadiusB + this.Height + 1 + 10)
{
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, this.RadiusB + 3, step % 2 == 0 ? this.Color1 : this.Color2, '*');
PrintCircle(this.LeftPosition, this.BaseLine - this.Height, (int)((this.RadiusB + 3) / (double)this.RadiusB * this.RadiusA), step % 2 != 0 ? this.Color1 : this.Color2, '*');
}
else
{
return true;
}
return false;
}
}
public class ConicalRocket : RocketBase
{
public ConsoleColor Color { get; set; }
public int Length { get; set; }
public bool HasShortSparks { get; set; }
public override bool Print(int step)
{
step -= StartStep;
if (step < 0) throw new ArgumentOutOfRangeException(nameof(step), "stept must be >=0");
if (step < Height)
{
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - step, ConsoleColor.Yellow);
}
else if (step == Height)
{
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition, this.BaseLine - step, ConsoleColor.White);
}
else if (step <= Height + Length)
{
if (HasShortSparks)
{
ConsoleBuffer.WriteCharToBuffer('/', this.LeftPosition + (step - this.Height), this.BaseLine - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('\\', this.LeftPosition - (step - this.Height), this.BaseLine - step, this.Color);
}
else
{
for (int i = Height + 1; i <= step; ++i)
{
ConsoleBuffer.WriteCharToBuffer('/', this.LeftPosition + (i - this.Height), this.BaseLine - i, this.Color);
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - i, this.Color);
ConsoleBuffer.WriteCharToBuffer('\\', this.LeftPosition - (i - this.Height), this.BaseLine - i, this.Color);
}
}
}
else
{
return true;
}
return false;
}
}
public class FlareRocket : CircularRocket
{
public HorizontalDirection HorizontalDirection { get; set; }
public ConsoleColor Color { get; set; }
public int Duration { get; set; }
private void PrintFlare(int leftCenter, int topCenter, int radius, ConsoleColor foreground, params char[] chars)
{
PrintCircle(leftCenter, topCenter, radius, foreground, chars);
ConsoleBuffer.WriteCharToBuffer('*', leftCenter, topCenter, foreground);
}
public override bool Print(int step)
{
step -= StartStep;
if (step < Height)
{
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine - step, ConsoleColor.Yellow);
}
else if (step == Height)
{
PrintFlare(this.LeftPosition, this.BaseLine - this.Height, 1, this.Color, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step == Height + 1)
{
PrintFlare(this.HorizontalDirection == HorizontalDirection.Left ? this.LeftPosition - 1 : this.LeftPosition + 1, this.BaseLine - this.Height - 1, 1, this.Color, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step == Height + 2)
{
PrintFlare(this.HorizontalDirection == HorizontalDirection.Left ? this.LeftPosition - 2 : this.LeftPosition + 2, this.BaseLine - this.Height - 1, 1, this.Color, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step <= Height + Duration + 2)
{
PrintFlare(this.HorizontalDirection == HorizontalDirection.Left ? this.LeftPosition - 3 : this.LeftPosition + 3, this.BaseLine - this.Height - 1 + (step - Height - 2), 1, this.Color, '-', '\\', '|', '/', '-', '\\', '|', '/');
}
else if (step <= Height + Height + 2)
{
ConsoleBuffer.WriteCharToBuffer('*', this.HorizontalDirection == HorizontalDirection.Left ? this.LeftPosition - 3 : this.LeftPosition + 3, this.BaseLine - this.Height - 1 + (step - Height - 2), this.Color);
}
else
{
return true;
}
return false;
}
}
public class TracerRocket : RocketBase
{
public ConsoleColor Color { get; set; }
public TracerRocketLaunchAngle LaunchAngle { get; internal set; }
public override bool Print(int step)
{
step -= StartStep;
if (step <= this.BaseLine + 5)
{
switch (LaunchAngle)
{
case TracerRocketLaunchAngle.TopRight:
for (int i = 0; i < 5; ++i)
{
ConsoleBuffer.WriteCharToBuffer('/', this.LeftPosition - i + step, this.BaseLine + i - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('/', this.LeftPosition - i + step, this.BaseLine + i + 1 - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('/', this.LeftPosition - i + 1 + step, this.BaseLine + i + 1 - step, this.Color);
}
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition + step + 1, this.BaseLine - step, this.Color);
break;
case TracerRocketLaunchAngle.TopLeft:
for (int i = 0; i < 5; ++i)
{
ConsoleBuffer.WriteCharToBuffer('\\', this.LeftPosition + i - step, this.BaseLine + i - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('\\', this.LeftPosition + i - step, this.BaseLine + i + 1 - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('\\', this.LeftPosition + i - 1 - step, this.BaseLine + i + 1 - step, this.Color);
}
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition - step - 1, this.BaseLine - step, this.Color);
break;
case TracerRocketLaunchAngle.Top:
for (int i = 0; i < 5; ++i)
{
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition - 1, this.BaseLine + i + 1 - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition, this.BaseLine + i + 1 - step, this.Color);
ConsoleBuffer.WriteCharToBuffer('|', this.LeftPosition + 1, this.BaseLine + i + 1 - step, this.Color);
}
ConsoleBuffer.WriteCharToBuffer('█', this.LeftPosition, this.BaseLine - step, this.Color);
break;
}
}
else
{
return true;
}
return false;
}
}
public enum HorizontalDirection
{
Left,
Right,
}
public enum TracerRocketLaunchAngle
{
TopLeft,
TopRight,
Top,
}
public static class ConsoleBuffer
{
static ConsolePosition[,] buffer, lastBuffer;
static int w, h;
public static void InitBuffer()
{
w = Console.WindowWidth;
h = Console.WindowHeight;
buffer = new ConsolePosition[w, h];
if (lastBuffer == null)
{
lastBuffer = buffer;
}
}
public static void WriteCharToBuffer(char chr, int left, int top, ConsoleColor foreground)
{
if (left < 0 || left >= w || top < 0 || top >= h)
{
return;
}
buffer[left, top] = new ConsolePosition(chr, foreground);
}
public static void WriteBufferToConsole()
{
if (lastBuffer.GetLength(0) != buffer.GetLength(0) || lastBuffer.GetLength(1) != buffer.GetLength(1))
{
lastBuffer = null;
}
for (int y = 0; y < h; ++y)
{
Console.CursorTop = y;
for (int x = 0; x < w; ++x)
{
if (lastBuffer == null || buffer[x, y].Char != '\0' || lastBuffer[x, y].Char != '\0')
{
Console.CursorLeft = x;
Console.ForegroundColor = buffer[x, y].Foreground;
Console.Write(buffer[x, y].Char.ToString());
}
}
}
lastBuffer = buffer;
InitBuffer();
}
}
public class ConsoleHelper
{
static Random rnd = new Random();
public static ConsoleColor RandomColor(params ConsoleColor[] excluded)
{
ConsoleColor result;
do
{
result = (ConsoleColor)rnd.Next(0, 16);
} while (excluded != null && excluded.Contains(result));
return result;
}
public static void WriteDigit(int top, int left, int digit, int size)
{
if (digit < 0 || digit > 9)
{
throw new ArgumentOutOfRangeException(nameof(digit));
}
if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || digit == 8 || digit == 9)
{
PrintHorizontalLine(top, left, size);
}
if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
{
PrintVerticalLine(top, left, size);
}
if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || digit == 8 || digit == 9)
{
PrintVerticalLine(top, left + size - 1, size);
}
if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
{
PrintHorizontalLine(top + size - 1, left, size);
}
if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
{
PrintVerticalLine(top + size - 1, left, size);
}
if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 7 || digit == 8 || digit == 9)
{
PrintVerticalLine(top + size - 1, left + size - 1, size);
}
if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
{
PrintHorizontalLine(top + 2 * (size - 1), left, size);
}
}
public static void PrintHorizontalLine(int top, int left, int length)
{
Console.CursorTop = top;
Console.CursorLeft = left;
Console.Write(new string('█', length));
}
public static void PrintVerticalLine(int top, int left, int length)
{
for (int i = 0; i < length; ++i)
{
Console.CursorTop = top + i;
Console.CursorLeft = left;
Console.Write("█");
}
}
}
struct ConsolePosition
{
public ConsolePosition(char chr, ConsoleColor foreground)
{
this.Char = chr;
this.Foreground = foreground;
}
public char Char { get; set; }
public ConsoleColor Foreground { get; set; }
public override string ToString()
{
return this.Char.ToString();
}
}
}