//+------------------------------------------------------------------
//|
//| Projekt              : Kapitel1 - Das erste echte Programm
//|
//| Projektbeschreibung  : Demonstration der Mandelbrot Menge in C
//|                      : mit der Ausgabe als ASCII-Art
//|                      :
//| Versionsnummer       : V1.00
//| Lauffähig unter      : Alle Systeme / Compiler ab ANSI-C 2011
//|
//| Autor                : Salomo Sokoll - ss@salomo-sokoll.de
//| Programmierung mit C und C++ ohne ideologischen Ballast
//| https://salomo-sokoll.de/Buch/C_CPP/index.html
//|
//+------------------------------------------------------------------

// Einbinden aller benötigten Header-Dateien (.h)
#include "stdio.h"          // Standard-Input-Output (Funktionen aus dem C-Standard)
#include "math.h"           // Mathematische Funktionen und Konstanten
#include "complex.h"        // Datentyp fuer Komplexe Zahlen

//+------------------------------------------------------------------------
//! Einsprung in das Programm, die main() Funktion muss in einem C Programm
//! immer existieren.
//+------------------------------------------------------------------------
//! Argumente :
//! Es werden keine Argumente übernommen
//!
//+------------------------------------------------------------------------
//! Rückgabewert :
//! \return int             - Fehlercode (0 für alles OK, kein Fehler)
//!
//+------------------------------------------------------------------------
int main( )
{
    // *
    // ** Anlegen und initialisieren aller benötigten Startwerte
    // ** für die Mandelbrot Menge als Konstanten
    // *

    // Minimale Koordinaten (links/oben) Real- und Imaginaer Teil
    const double complex K_Min = CMPLX( -1, -1.5 );

    // Maximale Koordinaten (rechts/unten) Real- und Imaginaer Teil
    const double complex K_Max = CMPLX( 2, 1.5 );

    // Maximale Anzahl der Iterationen für einen Punkt
    const int8_t Max_Iterationen = 32;

    // Spalten (Breite) in der Ausgabe
    const int32_t Spalten = 78;

    // Zeilen (Hoehe) in der Ausgabe
    const int32_t Zeilen  = 22;

    // *
    // ** Anlegen und initialisieren aller benötigten Variablen
    // ** für die Berechnung der Mandelbrot Menge
    // *
    double   Schritte_Spalte;    // Schrittweite der Koordinaten in den Spalten
    double   Schritte_Zeile;     // Schrittweite der Koordinaten in den Zeilen

    int32_t  Cx;                 // Zählvariabe für die Spalten, zum Durchlaufen des Realteil
    int32_t  Cy;                 // Zählvariabe für die Zeilen, zum Duchlaufen des Imaginaerteil

    // Berechne die Schrittweite für die Spalten (Vom Realteil aus K_Max bis K_Min)
    Schritte_Spalte = fabs( creal( K_Max ) - creal( K_Min ) ) / Spalten;

    // Berechne die Schrittweite für die Zeilen (Vom Imaginaerteil aus K_Max bis K_Min)
    Schritte_Zeile = fabs( cimag( K_Max ) - cimag( K_Min ) ) / Zeilen;

    // *
    // * Durchlaufen wird die Funktion: Z = Z^2 - C
    // * Wobei Z und C komplexe Zahlen sind
    // *
    double complex   Z;              // Komplexe Zahl für Z
    double complex   C;              // Komplexe Zahl für C (Der aktuell zu berechnende Punkt)

    // *
    // * Initialisiere die Koordinate fuer den aktuellen Punkt (Die Komplexe Zahl C)
    // * Gestartet wird links/oben
    // * Der Real Teil entspricht Cx (Spalten)
    // * Der Imaginaere Teil entspricht Cy (Zeilen)
    // *
    C =  CMPLX( creal( K_Min ), cimag( K_Max ) );

    // Durchlauf der Zeilen von oben nach unten (Entspricht dem Imaginaer Teil)
    for( Cy = 0; Cy < Zeilen; Cy++ )
    {

        // Durchlauf der Spalten von links nach rechts (Entspricht dem Rrealen Teil)

        // Zuruecksetzen der Spalte
        C = CMPLX( creal( K_Min ), cimag( C ) );

        for( Cx = 0; Cx < Spalten; Cx++ )
        {
            // *
            // * Berechne den aktuellen Punkt
            // *

            // Der Startwert von Z ist 0
            Z = CMPLX( 0, 0 );

            // Anzahl der Interationen für den aktuellen Punkt
            // Setze den Startwert der Iterationen auf 0
            int8_t Iterationen = 0;

            // *
            // * Durchlaufen wird die Funktion: Z = Z^2 - C
            // * Wobei Z und C komplexe Zahlen sind
            // *
            // * Abbruchkriterien:
            // * - Maximale Anzahl der Iterationen ist erreicht
            // * - Z >= 4
            // *

            do
            {
                // Berechne den aktuellen Punkt
                Z=( Z * Z ) - C;

                // Erhoehe den Iterationszaehler
                Iterationen++;
            }
            while ( // Fertig?
                ( Iterationen < Max_Iterationen ) &&
                ( ( creal( Z ) + cimag( Z ) ) < 4 )
                );

            // Erhoehe den Real Teil von C um einen Schritt
            C = CMPLX( creal( C + Schritte_Spalte ), cimag( C ) );

            // Bestimme die "Farbe" des Punktes als ACSII-Art
            if ( Iterationen == Max_Iterationen )
            {
                // Wenn die Maximale Iteration erreicht wurde
                // ein Leerzeichen ausgeben
                printf( " " );
            }
            else
            {
                // Sonst die Anzahl der Iterationen in ein Zeichen umsetzen, beginned ab
                // dem ASCII-Code 48 (Code fuer die "0")
                // Iteration hat mindestens den Wert 1, deshalb wird in der printf() Anweisung
                // der Wert 47 als Startwert angegeben, dieser entspricht dem Slash-Zeichen (/)
                // Bei der Maximalen Anzahl von 32 Iterationen sind folgende Zeichen moeglich:
                // 0123456789:;<=>?@ABCDEFGHIJKLMNOP
                printf( "%c", '/' + Iterationen );
            }

        }

        // Neue Zeile
        // Achtung: Windows Benutzer müssen eventuell "\r\n" Schreiben. MS-DOS nutzt <Carrige Return> und <Newline> als Zeilenende.
        printf( "\n" );

        // Erniedrige den Imaginaeren Teil von C um einen Schritt
        // Da die Grafik von oben nach unten aufgebaut wird
        C = CMPLX( creal( C ), cimag( C ) - Schritte_Zeile );

    }

    return( 0 );
}

