Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

(Golf) Mandelbrot Fractal

by {NULE} (Hermit)
on May 08, 2002 at 15:28 UTC ( [id://165069] : perlmeditation . print w/replies, xml ) Need Help??

Good day, monks,

A friend of mine sent me a link to a discussion of obfuscating code in C. In this particular discussion the programmer attacked a simple terminal application which produced a Mandelbrot fractal. It's a rather impressive bit of C coding (to a less than adept C coder), but I thought it would be fun to attack in Perl. (Note: I can't get the C code to compile on gcc, but I didn't try very hard.)

The C code example is 189 characters (my count with removed whitespace). I consider this more a golf than obfuscation since obfuscation implies a deliberate attempt to mislead the reader. The intent here was merely to make it as small as possible, and in the process it became difficult to read.

My code in Perl is 164 characters (less the shebang and newlines). This is my first official golf, so I'm sure someone out there will outdo me. I'd love to see it, and it might be fun to let the author of the C article see what madness we come up with.

#! /usr/bin/perl for(0..39){$i=-1+$_*.05;for(0..59){$r=$j=-2.3+$_*.05; $z=$i;$b=" ";for(0..255){$m=$r*$r;$n=$z*$z;if($m+$n>4) {$b="+";last}$z=2*$r*$z+$i;$r=$m-$n+$j}print$b}print"\n"}
This outputs a 60 column by 40 row graph of ' ' and '+' which gives a decent presentation of the Mandelbrot fractal. Read the original article for more information. It was tested on Solaris 2.8 with Perl 5.005_3 and 5.6.1, but should run anywhere.

Good luck!

__END__ Output should be this: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++ ++ +++++++++++ +++++++++++++++++++++++++++++++++++ +++++++ ++++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ ++++++++ ++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++ +++++ +++++++++++++++++++++++++++++++++ ++++++ +++++++++++++++++++++++ + +++++ ++++++ +++++++++++++++++++++++ ++ ++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++ + + +++++++ ++++++ ++++++++ ++++++++++++++++++++ + + +++++++ ++++++++++++++++++++++ + ++++++ ++++++++++++++++++++++ + ++++++ +++++++++++++++++++++++ ++ ++++++ +++++++++++++++++++++++ + +++++ ++++++ +++++++++++++++++++++++++++++++++ ++++++ +++++++++++++++++++++++++++++++++ +++++ ++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ ++++++++ ++++++++++++++++++++++++++++++++++++ +++++++ +++++++++++++++++++++++++++++++++++ +++++++ ++++++++++++++++++++++++++++++++++++ ++ +++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Replies are listed 'Best First'.
Re: (Golf) Mandelbrot Fractal
by japhy (Canon) on May 08, 2002 at 16:30 UTC
    I cut it down to 153:
    map{$i=$_*.05-1;map{$r=$j=$_*.05-2.3;$z=$i;$b=$";for (a..iv){$m=$r*$r;$n=$z*$z;$b="+",last if$m+$n>4;$z =2*$r*$z+$i;$r=$m-$n+$j}print$b}0..59;print$/}0..39
    I think the for(a..iv) trick is a nice stroke-shaver.

    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

      I'm sure there's more to come off, but I've worked it down to the following. Which seems to come in at 148 strokes using.
      -l map{$i=$_*.05-1;print map{$r=$j=$_*.05-2.3;$z=$i;$b=$";map{$m=$r*$r +;$n=$z*$z;$b='+'if$m+$n>4;$z=2*$r*$z+$i;$r=$m-$n+$j}a..iv;$b}0..59}0. +.39
        Application of YuckFoo's and my strategies gets us 134. There is an ever so slight change in the output due to the fudge factor introduced by YuckFoo's test change, switch back to the ()+() for 136 and no change in output.

        perl -l

        map{$i=$_/20-1;print map{$r=$j=$_/20-2.3;$z=$i;$b=$";map{$b='+'if $m=$r*$r,($n=$z*$z)>4;$z=2*$r*$z+$i;$r=$m-$n+$j}a..z;$b}0..59}0..39

        perl -pew "s/\b;([mnst])/'$1/g"

        And, sticking with the principle that we must iterate as many times as the original and that the output must look the same I've stolen a few ideas from other code and come up with
        -l map{$i=$_/20-1;print map{$r=$;=$_/20;$z=$i;$b=$";($m=$r*$r)+($n=$z* +$z)>4?$b='+':($z=2*$r*$z+$i,$r=$m-$n+$;)for a..iv;$b}-46..13}0..39
        Which wc tells me is 136 chars long (counting 3 for "-l\n" in the same fashion as the crowd). Having tried all the shorter solutions I've seen so far in this thread, I've not found one that actually works, but this one does.
      149 baby!
      map{$i=$_*.05-1;map{$r=$j=$_*.05-2.3;$z=$i;$b=$";for(a..iv){$m=$r*$r;$ +n=$z*$z; $m+$n>4?$b="+":($z=2*$r*$z+$i,$r=$m-$n+$j)}print$b}0..59;print$/}0..39

      148 for a tie

      map{$i=$_*.05-1;map{$r=$j=$_*.05-2.3;$z=$i;$b=$";for(a..iv){($m=$r*$r) ++ ($n=$z*$z)>4?$b="+":($z=2*$r*$z+$i,$r=$m-$n+$j)}print$b}0..59;print$/} +0..39

      Meanwhile, in the chatterbox...
      demerphq $i=$_*.05-1; could be written as $i=$_/2-1; couldnt it?
      belg4mit no, it's not .5
      belg4mit although /20 works ;-)

      146! @ Wed May 8 14:42:11 EDT 2002

      map{$i=$_/20-1;map{$r=$j=$_/20-2.3;$z=$i;$b=$";for(a..iv){($m=$r*$r)+ ($n=$z*$z)>4?$b="+":($z=2*$r*$z+$i,$r=$m-$n+$j)}print$b}0..59;print$/} +0..39

      perl -pew "s/\b;([mnst])/'$1/g"

        In a wild attempt to redeem myself I get 142:

        UPDATE:Removed single line version cause it screws up some peoples screen layout.

        Or a little better formatted
        map{$i=$_/20-1;map{$r=$j=$_/20-2.3;$z=$i;$b=$";($m=$r*$r)+($n=$z*$z)>4 +? $b="+":($z=2*$r*$z+$i,$r=$m-$n+$j)for a..iv;print$b}0..59;print$/}0..3 +9

        Yves / DeMerphq
        Writing a good benchmark isnt as easy as it might look.

Re: (Golf) Mandelbrot Fractal
by {NULE} (Hermit) on May 08, 2002 at 16:07 UTC
    This probably isn't fair without some clearer code to start with. This is based off the authors original C code.
    #! /usr/local/bin/perl -w use strict; my $fVRR = -2.3; my $fVRI = -1.0; my $fMaL = 0.05; for (my $i = 0; $i < 40; $i++) { my $fCI = $fVRI + $i * $fMaL; for (my $j = 0; $j < 60; $j++) { my $fCR = $fVRR + $j * $fMaL; my $fZR = $fCR; my $fZI = $fCI; my $bI = 1; for (0..255) { my $fZRS = $fZR * $fZR; my $fZIS = $fZI * $fZI; if ($fZRS + $fZIS > 4) { $bI = 0; last; } $fZI = 2 * $fZR * $fZI + $fCI; $fZR = $fZRS - $fZIS + $fCR; } print $bI?" ":"+"; } print "\n"; }
Re: (Golf) Mandelbrot Fractal
by tadman (Prior) on May 08, 2002 at 21:19 UTC
    Based on some musings in a deeper thread, a slight modification brings it to 131:
    map{$i=$_/20-1;map{$r=$j=$_/20-2.3;$z=$i;($m=$r*$r,$n=$z*$z,$z=2*$r*$z+$i,$r=$m-$n+$j)for a..z;print$m<4?$":"+"}0..59;print$/}0..39
    Update: With a bit of hackery then at 130:
    map{$i=$_/20-1;map{$r=$j=$_/20-2.3;$z=$i;($n=$z*$z,$z=2*$r*$z+$i,$r=($m=$r*$r)-$n+$j)for a..z;print$m<4?$":"+"}0..59;print$/}0..39
    As a note, using 'X' instead of '+' would save 2 characters.

    If a slight readjustment of the newlines isn't invalid, you get 126:
    print map{$i=$_/20-1;$/,map{$r=$j=$_/20-2.3;$z=$i;($n=$z*$z,$z=2*$r*$z+$i,$r=($m=$r*$r)-$n+$j)for a..z;$m<4?$":"+"}0..59}0..39
      -l map{$i=$_/20-1;print map{$r=$;=$_/20-2.3;$z=$i;$n=$z*$z,$m=$r*$r,$z +=2*$r*$z+$i,$r=$m-$n+$;for a..z;$m<4?$":"+"}0..59}0..39
      Update: 123
      -l map{$i=$_/20,print map{$r=$;=$_/20;$z=$i;$n=$z*$z,$m=$r*$r,$z=2*$r* +$z+$i,$r=$m-$n+$;for a..z;$m<4?$":"+"}-46..13}-20..19
        With some bending of the rules(?), we get a little more detail, and 117 chars

        perl -Mconstant=Z,20 -l map{$i=$_/Z,print map{$r=$;=$_/Z;$z=$i;$n=$z*$z,$m=$r*$r,$z=2*$r*$z+$i +,$r=$m-$n+$;for a..z;$m<4?$":"+"}-46..Z}-19..Z

        116 @ Wed May 8 19:50:10 EDT 2002

        map{$i=$_/Z,print map{$r=$;=$_/Z;$z=$i;$n=$z*$z,$z=2*$r*$z+$i,$r=($m=$ +r*$r)-$n+$;for a..z;$m<4?$":"+"}-46..Z}-19..Z

        BTW, I like the use of $; :-)

        UPDATE: Changed outside range from -20..Z to -19..Z to eliminate extra lines of +.

        perl -pew "s/\b;([mnst])/'$1/g"

        That use of $; is very clever, as it parses correctly and allows you to omit the brackets for the for. Combining this with other modifications yields 122 chars of obfuscated goodness:
        print map{$i=$_/20;$/,map{$r=$;=$_/20;$z=$i;$n=$z*$z,$z=2*$r*$z+$i,$r=($m=$r*$r)-$n+$;for a..z;$m<4?$":"+"}-46..13}-20..19
        Further savings if you choose 'X' instead of '+':
        print map{$i=$_/20;$/,map{$r=$;=$_/20;$z=$i;$n=$z*$z,$z=2*$r*$z+$i,$r=($m=$r*$r)-$n+$;for a..z;$m<4?$":X}-46..13}-20..19
        Here is the original C code, just for comparison, at 182 characters:
        void main(){double O,x,o,I,l,i;char _;for(l=-1;l<1;l+=.05,putc ;i<.7;i+=.05,putchar(_?'?':':'),O=i,x=l,o=I=(_=1)--)for(;++_&& );x=2*O*x+l,O=o-I+i);}
        C allows for shorter variable names, and Perl still comes out ahead. Crazy.
Re: (Golf) Mandelbrot Fractal
by YuckFoo (Abbot) on May 08, 2002 at 21:08 UTC
    Just because I spent way too much time and managed to get under 150, to 147

    for($x=-1;$x<1;$x+=.05){for($y=-2.3;$y<.7;$y+=.05){$i=$y;$j=$x;$k=99; while($j<4&&--$k){($i,$j)=($i*$i-$j*$j+$y,2*$i*$j+$x)}print$k?'+':' '} +print$/}


Re: (Golf) Mandelbrot Fractal
by {NULE} (Hermit) on May 10, 2002 at 12:57 UTC
    Hi again, my good monks,

    I'm pleased by the enthusiastic response to this post. The author of the original article was forwarded this node, although I'm not aware if he has commented on it. It looks like we could get down to about the mid 130's without changing the algorithm at all, and the low 120's with minor changes that are still in the spirit of thing. (Sorry belg4mit, that constant thing is cheating. {g})

    I learned plenty too, which is the whole reason for golfing. I'm kicking myself for not seeing the dumb optimizations in the simple mathematics (being a mathematician by training, you'd think I would have spotted that - but I was too focused on improving the Perl and didn't think about the algorithm enough).

    Anyway, thanks for all the responses,