C# :: Aufgabe #265 :: Lösung #1

2 Lösungen Lösungen öffentlich
#265

Das Zahnstochermuster und die Sequenz der Anzahl freier Spitzen im Muster

Fortgeschrittener - C# von hollst - 01.10.2019 um 18:15 Uhr
Man kann sogar mit Zahnstochern Mathematik bzw. Informatik betreiben!

Ein Zahnstochermuster wird schrittweise erzeugt: Im ersten Schritt legt man einen Zahnstocher
beliebig und flach auf eine 2D-Fläche ab. Ohne besondere Einschränkungen seien angenommen, dass jeder Zahnstocher
genau die Länge 1 (eins) hat und das erste Exemplar senkrecht und mittig in einem (X, Y)-Koordinatensystem
liegt. Das Muster hat nach dem ersten Schritt zwei freie Spitzen bei (1/2, 0) und (-1/2, 0).
Im zweite Schritt werden senkrecht zum ersten Zahnstocher auf die zwei freien Spitzen jeweils ein weiterer Zahnstocher gelegt,
danach haben wir vier freie Spitzen (siehe Bild step_2). Auf diese Weise wird schrittweise fortgefahren.
Die Sequenz der Anzahl freier Spitzen im Muster beginnt so:

Schritt........: 1..2..3..4..5....6..7..8..9..10 11 12 13 14 15 16 17 18 19 ...
freie Spitzen: 2..4..4..4..8..12, 8, 4, 8, 12, 12, 16, 28, 32, 16, 4, 8, 12, 12 ...

Sie steigt zunächst an bis 12 (Schritt 6), um danach auf 4 abzufallen (Schritt 8). Dieses Auf und Ab
zieht sich stetig fort (bis in alle Ewigkeit, was noch zu beweisen wäre [jedoch nicht von uns]).
Die Entwicklung des Zahnstochermusters hat fraktalen Charakter. Anhand von Bild step_10_14_17 soll dies belegt sein.

Die Programmieraufgabe bestehe darin, die Musterentwicklung bis zum Schritt 100 "interaktiv" darzustellen (Bild step_100)
und auch die Anzahl freier Zahnstocherspitzen jeweils anzugeben.

Viel Spaß!
#1
1x
vote_ok
von eulerscheZhl (5230 Punkte) - 03.11.2019 um 06:31 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

class Program
{
    public static void Main(string[] args)
    {
        Fractal fractal = new Fractal();
        for (int i = 1; i <= 100; i++)
        {
            fractal.Expand();
            Bitmap bmp = fractal.Draw();
            bmp.Save("step_" + i + ".png");
            bmp.Dispose();
        }
    }
}

class Toothpick : IEquatable<Toothpick>
{
    public Point End1 { get; private set; }
    public Point End2 { get; private set; }

    public Toothpick(Point end1, Point end2)
    {
        this.End1 = end1;
        this.End2 = end2;
    }

    public bool Equals(Toothpick pick)
    {
        return this.End1 == pick.End1 && this.End2 == pick.End2 ||
            this.End1 == pick.End2 && this.End2 == pick.End1;
    }

    public override int GetHashCode()
    {
        return End1.GetHashCode() ^ End2.GetHashCode();
    }

    public IEnumerable<Toothpick> Expand()
    {
        Point center = new Point((End1.X + End2.X) / 2, (End1.Y + End2.Y) / 2);
        int dx = (End1.X - End2.X) / 2;
        int dy = (End1.Y - End2.Y) / 2;
        yield return new Toothpick(new Point(End1.X + dy, End1.Y + dx), new Point(End1.X - dy, End1.Y - dx));
        yield return new Toothpick(new Point(End2.X + dy, End2.Y + dx), new Point(End2.X - dy, End2.Y - dx));
    }
}

class Fractal
{
    public HashSet<Toothpick> Toothpicks { get; private set; } = new HashSet<Toothpick>();
    private List<Toothpick> border = new List<Toothpick>();
    public Fractal()
    {
        border.Add(new Toothpick(new Point(1, 0), new Point(-1, 0)));
    }

    public void Expand()
    {
        Toothpicks.UnionWith(border);
        List<Toothpick> newBorder = new List<Toothpick>();
        foreach (Toothpick pick in border)
        {
            foreach (Toothpick next in pick.Expand())
            {
                if (!Toothpicks.Contains(next))
                {
                    Toothpick partner = newBorder.FirstOrDefault(p => p.Equals(next));
                    if (partner == null) newBorder.Add(next);
                    else newBorder.Remove(partner);
                }
            }
        }
        border = newBorder;
    }

    private Point TransformPoint(Point p, int xMin, int yMin, int factor)
    {
        return new Point(factor * (p.X - xMin + 1), factor * (p.Y - yMin + 1));
    }

    public Bitmap Draw()
    {
        List<Point> points = border.SelectMany(b => new[] { b.End1, b.End2 }).ToList();
        int xMin = points.Min(p => p.X);
        int xMax = points.Max(p => p.X);
        int yMin = points.Min(p => p.Y);
        int yMax = points.Max(p => p.Y);
        int factor = 10;

        Bitmap bmp = new Bitmap(factor * (xMax - xMin + 2), factor * (yMax - yMin + 2));
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.Clear(Color.White);
            foreach (Toothpick pick in Toothpicks)
                g.DrawLine(Pens.Black, TransformPoint(pick.End1, xMin, yMin, factor), TransformPoint(pick.End2, xMin, yMin, factor));
            foreach (Toothpick pick in border)
                g.DrawLine(Pens.Blue, TransformPoint(pick.End1, xMin, yMin, factor), TransformPoint(pick.End2, xMin, yMin, factor));
        }
        return bmp;
    }
}

Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben