#!/usr/bin/perl
use strict;

use Math::Complex;

# Set options
our $output_axes = 0;	# Choose whether to output axes (still broken)
our $gradient = 1;		# Choose an ASCII gradient (values 0-3 are valid)

# Set window
my $width = 3;				# Set width of view. Height is auto-set to keep square units
(my $x, my $y) = (-1,0);	# Set the center of view.

##############################
##	Change nothing below
##	this point unless you know
##	you know what you're doing
##############################

# Set ascii gradient
my @gradients = (
	' .:coCO8@',
	' .:oO8@',
	' ~:;!>+=icjtJY56SXDQKHNWM',
	' .:+j6bHM',
	);
our @ascii_table = split '', $gradients[$gradient];

# Set constants
my $max_iterations = 50/$width;
#TODO: Find a better value.

# Set terminal size
my $s_width = 80;
my $s_height = 24;

# Calculate window values
my $height = $s_height*($width/$s_width)*2;
my $x_offset = ($width/2)-$x;
my $y_offset = ($height/2)+$y;

# Main program starts here
for (map {-1*((($_/$s_height)*$height)-$y_offset)} (0..$s_height)){	# Iterate rows
	my $complex = $_;
	for (map {((($_/$s_width)*$width)-$x_offset)} (0..$s_width)){	# Iterate columns
		my $real = $_;
		print mandel($real,$complex,$max_iterations);				# Call mandel() function
	}
	print "\n";
}

# NOTE: the map statements simply map a set of values corresponding to the coordinates of
#	each character in the output to the numbers corresponding to the chosen window to $_. 
#	It's ugly, but it does the job.

sub mandel{
	my $a = Math::Complex->make(shift,shift);
	if ($output_axes){	#TODO: Fix this
		return '*' if (abs($a)==0);
		return '|' if (Re($a)==0);
		return '-' if (Im($a)==0);
	}
	
	my $max_iterations = shift;
	my $conv;
	
	do {$conv+=.5} until $max_iterations/$conv <= scalar @ascii_table;
	
	my $iterations=0;
	my @z;
	for (1..$max_iterations){
		last if abs($z[$iterations])>=2;
		$iterations++;
		$z[$iterations] = $z[$iterations-1]**2+$a;
	}
	return $ascii_table[int $iterations/$conv];
}
