' Fractal: Mandelbrot set with integer math, Julia set variation
#COMPILE EXE
#DIM ALL

FUNCTION MandelbrotIter(BYVAL cx AS DOUBLE, BYVAL cy AS DOUBLE, BYVAL maxIter AS LONG) AS LONG
    LOCAL zx  AS DOUBLE
    LOCAL zy  AS DOUBLE
    LOCAL zx2  AS DOUBLE
    LOCAL zy2  AS DOUBLE
    LOCAL tmp  AS DOUBLE
    LOCAL iter AS LONG
    zx = 0.0: zy = 0.0: iter = 0
    DO WHILE iter < maxIter
        zx2 = zx * zx: zy2 = zy * zy
        IF zx2 + zy2 > 4.0 THEN EXIT LOOP
        tmp = zx2 - zy2 + cx
        zy = 2.0 * zx * zy + cy
        zx = tmp
        INCR iter
    LOOP
    FUNCTION = iter
END FUNCTION

FUNCTION JuliaIter(BYVAL zx AS DOUBLE, BYVAL zy AS DOUBLE, BYVAL cx AS DOUBLE, BYVAL cy AS DOUBLE, BYVAL maxIter AS LONG) AS LONG
    LOCAL zx2  AS DOUBLE
    LOCAL zy2  AS DOUBLE
    LOCAL tmp  AS DOUBLE
    LOCAL iter AS LONG
    iter = 0
    DO WHILE iter < maxIter
        zx2 = zx * zx: zy2 = zy * zy
        IF zx2 + zy2 > 4.0 THEN EXIT LOOP
        tmp = zx2 - zy2 + cx
        zy = 2.0 * zx * zy + cy
        zx = tmp
        INCR iter
    LOOP
    FUNCTION = iter
END FUNCTION

SUB MandelbrotASCII(BYVAL width AS LONG, BYVAL height AS LONG, BYVAL maxIter AS LONG)
    LOCAL x  AS LONG
    LOCAL y  AS LONG
    LOCAL iter  AS LONG
    LOCAL cx  AS DOUBLE
    LOCAL cy  AS DOUBLE
    LOCAL xMin  AS DOUBLE
    LOCAL xMax  AS DOUBLE
    LOCAL yMin  AS DOUBLE
    LOCAL yMax  AS DOUBLE
    LOCAL stepX  AS DOUBLE
    LOCAL stepY  AS DOUBLE
    LOCAL line AS STRING
    xMin = -2.0: xMax = 1.0: yMin = -1.2: yMax = 1.2
    stepX = (xMax - xMin) / width
    stepY = (yMax - yMin) / height
    FOR y = 0 TO height - 1
        cy = yMin + y * stepY
        line = ""
        FOR x = 0 TO width - 1
            cx = xMin + x * stepX
            iter = MandelbrotIter(cx, cy, maxIter)
            IF iter >= maxIter THEN
                line = line + "#"
            ELSEIF iter > 20 THEN
                line = line + "*"
            ELSEIF iter > 5 THEN
                line = line + "."
            ELSE
                line = line + " "
            END IF
        NEXT x
        PRINT line
    NEXT y
END SUB

SUB JuliaASCII(BYVAL width AS LONG, BYVAL height AS LONG, BYVAL cx AS DOUBLE, BYVAL cy AS DOUBLE, BYVAL maxIter AS LONG)
    LOCAL x  AS LONG
    LOCAL y  AS LONG
    LOCAL iter  AS LONG
    LOCAL zx  AS DOUBLE
    LOCAL zy  AS DOUBLE
    LOCAL xMin  AS DOUBLE
    LOCAL xMax  AS DOUBLE
    LOCAL yMin  AS DOUBLE
    LOCAL yMax  AS DOUBLE
    LOCAL stepX  AS DOUBLE
    LOCAL stepY  AS DOUBLE
    LOCAL line AS STRING
    xMin = -1.5: xMax = 1.5: yMin = -1.5: yMax = 1.5
    stepX = (xMax - xMin) / width
    stepY = (yMax - yMin) / height
    FOR y = 0 TO height - 1
        zy = yMin + y * stepY
        line = ""
        FOR x = 0 TO width - 1
            zx = xMin + x * stepX
            iter = JuliaIter(zx, zy, cx, cy, maxIter)
            IF iter >= maxIter THEN
                line = line + "#"
            ELSEIF iter > 30 THEN
                line = line + "O"
            ELSEIF iter > 10 THEN
                line = line + "."
            ELSE
                line = line + " "
            END IF
        NEXT x
        PRINT line
    NEXT y
END SUB

FUNCTION BurningShipIter(BYVAL cx AS DOUBLE, BYVAL cy AS DOUBLE, BYVAL maxIter AS LONG) AS LONG
    LOCAL zx  AS DOUBLE
    LOCAL zy  AS DOUBLE
    LOCAL zx2  AS DOUBLE
    LOCAL zy2  AS DOUBLE
    LOCAL tmp  AS DOUBLE
    LOCAL iter AS LONG
    zx = 0.0: zy = 0.0: iter = 0
    DO WHILE iter < maxIter
        zx2 = zx * zx: zy2 = zy * zy
        IF zx2 + zy2 > 4.0 THEN EXIT LOOP
        tmp = zx2 - zy2 + cx
        zy = ABS(2.0 * zx * zy) + cy
        zx = tmp
        INCR iter
    LOOP
    FUNCTION = iter
END FUNCTION

FUNCTION PBMAIN() AS LONG
    LOCAL width  AS LONG
    LOCAL height  AS LONG
    LOCAL maxIter  AS LONG
    PRINT "=== Fractal Demo ==="
    PRINT
    width = 60: height = 20: maxIter = 50
    PRINT "Mandelbrot set (ASCII art " + FORMAT$(width) + "x" + FORMAT$(height) + "):"
    CALL MandelbrotASCII(width, height, maxIter)
    PRINT
    PRINT "Julia set (c = -0.7 + 0.27i):"
    CALL JuliaASCII(60, 16, -0.7, 0.27, 40)
    PRINT
    PRINT "Burning Ship sample:"
    PRINT "  Mandelbrot at (0,0):"; MandelbrotIter(0.0, 0.0, 100); " iterations"
    PRINT "  Mandelbrot at (-1,0):"; MandelbrotIter(-1.0, 0.0, 100); " iterations"
    PRINT "  Mandelbrot at (0.5,0.5):"; MandelbrotIter(0.5, 0.5, 100); " iterations"
    PRINT "  Julia at (0.3,-0.5) c=(-0.7,0.27):"; JuliaIter(0.3, -0.5, -0.7, 0.27, 100)
    PRINT
    PRINT "Fractal demo complete."
    FUNCTION = 0
END FUNCTION
