Feedback

C# - Schreibtischfeuerwerk

Veröffentlicht von am 31.12.2015
(1 Bewertungen)
Nicht ganz zum ernst nehmen, aber passend zum heutigen Tag.

Das lauffähige Programm gibt es hier: https://1drv.ms/f/s!At7rxWKLl2pvkddck6sbxeUvxnaySg
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();
        }
    }
}

4 Kommentare zum Snippet

Thomas Roskop schrieb am 01.01.2016:
Hallo,
kann das sein, dass dieser Code c# 6 nutzt?
Das hätte man nämlich erwähnen können.
Koopakiller schrieb am 01.01.2016:
Hallo Thomas,
ja, der Code nutzt ein paar Dinge von C# 6. Da diese Sprachversion mittlerweile auch schon wieder 6 Monate alt ist, hielt ich einen Hinweis darauf für nicht nötig. Sonst müsste man es ja praktisch bei jedem Snippet dazu schreiben welche Sprachversion man braucht.

Ansonsten kann man die wenigen Stellen an denen ich etwas von C# 6 nutzte auch schnell umbauen.
Patrick Semmler schrieb am 15.07.2017:
Hallo,

die Links (Screenshot) und lauffähiges Programm funktionieren nicht mehr...
Koopakiller schrieb am 18.07.2017:
Stimmt, danke für den Hinweis. Zumindest den Download-Link konnte ich korrigieren. Was mit den Bildern nicht klappt kann ich im Moment noch nicht sagen.
 

Logge dich ein, um hier zu kommentieren!