|
#!/usr/bin/env python3 |
|
|
|
import argparse |
|
import doctest |
|
|
|
def float_range(start, end, steps): |
|
"""Similar to numpy.linspace(), but written in pure Python. |
|
|
|
Extreme cases: |
|
|
|
>>> list(float_range(-5, 5, 0)) |
|
[] |
|
>>> list(float_range(-5, 5, 1)) |
|
[-5.0] |
|
|
|
More useful cases: |
|
|
|
>>> list(float_range(-5, 5, 2)) |
|
[-5.0, 5.0] |
|
>>> list(float_range(-5, 5, 3)) |
|
[-5.0, 0.0, 5.0] |
|
>>> list(float_range(-5, 5, 5)) |
|
[-5.0, -2.5, 0.0, 2.5, 5.0] |
|
|
|
>>> list(float_range(0, 2, 5)) |
|
[0.0, 0.5, 1.0, 1.5, 2.0] |
|
>>> list(float_range(0, 3, 4)) |
|
[0.0, 1.0, 2.0, 3.0] |
|
|
|
Also in reverse order: |
|
|
|
>>> list(float_range(5, -5, 5)) |
|
[5.0, 2.5, 0.0, -2.5, -5.0] |
|
""" |
|
if steps <= 0: |
|
return |
|
if steps == 1: |
|
yield start * 1.0 |
|
return |
|
for i in range(steps): |
|
yield start + (end - start) * (i / (steps - 1)) |
|
|
|
|
|
def mandelbrot_0(c, iters): |
|
z = c |
|
nv = 0 |
|
for i in range(iters): |
|
if abs(z) > 2: |
|
break |
|
z = z * z + c |
|
nv += 1 |
|
return nv |
|
|
|
|
|
def calculate_mandelbrot(width, height, iters): |
|
for y in float_range(-1, 1, height): |
|
for x in float_range(-1.5, 0.5, width): |
|
c = mandelbrot_0(complex(x, y), iters) |
|
rgb = round(c / iters * (256 ** 3 - 1)) |
|
print('\033[48;2;{r};{g};{b}m '.format( |
|
r=round((rgb >> 16) & 0xFF), |
|
g=round((rgb >> 8) & 0xFF), |
|
b=round((rgb >> 0) & 0xFF), |
|
), end='') |
|
print('\033[m') |
|
|
|
|
|
def main(): |
|
parser = argparse.ArgumentParser( |
|
prog='Mandelbrot in the terminal', |
|
# Don't add `-h` and `--help`, because it conflicts with `--height`. |
|
add_help=False, |
|
) |
|
parser.add_argument('--help', action='help', help='Show this help message') |
|
parser.add_argument('-t', '--test', action='store_true', help='Run tests') |
|
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose test output') |
|
parser.add_argument('-w', '--width', type=int, default=80, help='Width, in number of characters') |
|
parser.add_argument('-h', '--height', type=int, default=25, help='Height, in number of lines') |
|
parser.add_argument('-i', '--iterations', type=int, default=5000, help='Height, in number of lines') |
|
args = parser.parse_args() |
|
|
|
if args.test: |
|
doctest.testmod(verbose=args.verbose) |
|
else: |
|
calculate_mandelbrot(args.width, args.height, args.iterations) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |