103
\$\begingroup\$

I always used a Mandelbrot image as the 'graphical' version of Hello World in any graphical application I got my hands on. Now it's your guys' turn.

  • Language must be capable of graphical output or drawing charts (saving files disallowed)
  • Render a square image or graph. The size at least 128 and at most 640 across*
  • The fractal coordinates range from approximately -2-2i to 2+2i
  • The pixels outside of the Mandelbrot set should be colored according to the number of iterations before the magnitude exceeds 2 (excluding* black & white)
  • Each iteration count must have a unique color*, and neighboring colors should preferably be easily distinguishable by the eye
  • The other pixels (presumably inside the Mandelbrot set) must be colored either black or white
  • At least 99 iterations
  • ASCII art not allowed

* unless limited by the platform, e.g. graphical calculator

Allowed:
Allowed
Disallowed:
Disallowed
(shrunken images)

Winning conditions:

Shortest version (size in bytes) for each language will get a mention in this post, ordered by size.
No answer will ever be 'accepted' with the button.

Leaderboard:

/* Configuration */

var QUESTION_ID = 23423; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 17419; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,<]*(?:<(?:[^\n>]*>[^\n<]*<\/[^\n>]*>)[^\n,<]*)*),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];
  
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });
    else console.log(body);
  });
  
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;
    
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    lang = jQuery('<a>'+lang+'</a>').text();
    
    languages[lang] = languages[lang] || {lang: a.language, lang_raw: lang, user: a.user, size: a.size, link: a.link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang_raw.toLowerCase() > b.lang_raw.toLowerCase()) return 1;
    if (a.lang_raw.toLowerCase() < b.lang_raw.toLowerCase()) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body {
  text-align: left !important;
  display: block !important;
}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.sstatic.net/Sites/codegolf/all.css?v=ffb5d0584c5f">
<div id="language-list">
  <h2>Shortest Solution by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

\$\endgroup\$
14
  • 9
    \$\begingroup\$ "Easily distinguished by the eye" is hard to make objective. ...Also, apart from your personal association of the two, the Mandelbrot set has nothing to do with Hello World, so it's best to omit that from the title unless you are deliberately trolling the search engines. \$\endgroup\$ Mar 7, 2014 at 21:50
  • 3
    \$\begingroup\$ I've seen a few people now mentioning that they render the Mandelbrot as a "Hello World". I've done that too, for something like 30 years. The Mandelbrot is the perfect "Hello World" because it shows both that you have pixel access to the display and gives a good feel for compute bound performance on the new platform. \$\endgroup\$
    – Roger Dahl
    Mar 9, 2014 at 2:00
  • 7
    \$\begingroup\$ Great idea to ask a question which requires a combination of mathematical and aesthetic sensitivities, then impose all the the design decisions in advance. \$\endgroup\$
    – jwg
    Mar 10, 2014 at 8:25
  • 3
    \$\begingroup\$ Anyone manages to make one in brainfuck WINS, I'd say :D \$\endgroup\$
    – MadTux
    Mar 10, 2014 at 18:45
  • 2
    \$\begingroup\$ Not mine and not golfed, but this code is a marvel of obfuscated python producing a mandelbrot fractal \$\endgroup\$
    – Aaron
    May 26, 2017 at 8:37

39 Answers 39

1
2
4
\$\begingroup\$

QBasic, QuickBasic, QB64 - 156 153

SCREEN 13
FOR J=0TO 191
B=J/48-2
FOR I=0TO 191
A=I/48-2
X=A
Y=B
C=0
DO
U=X*X
V=Y*Y
Y=2*X*Y+B
X=U-V+A
C=C+1
LOOP UNTIL C>247OR U+V>4
PSET(I,J),C
NEXT
NEXT

Standard DOS palette:

enter image description here

\$\endgroup\$
4
\$\begingroup\$

QBasic, 139 bytes

-1 c/o DLosc

SCREEN 13
FOR i=0TO 199
FOR j=0TO 199
x=0
y=0
FOR c=0TO 255
t=y*y
c=c-255*(x*x+t>4)
y=2*x*y+j/50-2
x=x*x-t+i/50-2
NEXT
PSET(i,j),c
NEXT j,i

Output:

It may be necessary to append a INPUT$(1) to prevent the window from closing until a key is pressed.


FreeBASIC, 139 bytes

Using FreeBASIC's SCREEN 16, we can generate a more detailed image at the same code length:

SCREEN 16
FOR i=0TO 383
FOR j=0TO 383
x=0
y=0
FOR c=0TO 255
t=y*y
c=c-255*(x*x+t>4)
y=2*x*y+j/96-2
x=x*x-t+i/96-2
NEXT
PSET(i,j),c
NEXT j,i

Compile as fbc -lang qb mandel.bas.

Higher resolutions are also available.

\$\endgroup\$
4
  • \$\begingroup\$ Please count newlines as a byte too \$\endgroup\$ Sep 27, 2017 at 14:32
  • \$\begingroup\$ @MarkJeronimus my mistake, I though I had. \$\endgroup\$
    – primo
    Sep 28, 2017 at 4:31
  • \$\begingroup\$ Modifying c to exit the FOR loop is really clever! You can save 2 bytes by using y*y directly instead of assigning to t, and one more byte by writing NEXT j,i instead of NEXT twice. (Not sure if that second one works in FreeBASIC.) \$\endgroup\$
    – DLosc
    Jun 3, 2021 at 19:59
  • \$\begingroup\$ The assignment to t is necessary, because the old value of y is used in the computation of x. Thanks for the multi-NEXT tip ;) \$\endgroup\$
    – primo
    Jun 4, 2021 at 11:49
3
\$\begingroup\$

Perl + GD, 264

$I=new GD::Image $s=499,$s;Z(0,0,0);Z(map rand 256,1..3)for
0..99;for$x(0..$s){for$y(0..$s){for($H=$K=$c=$t=0;$c++<99&&$H*$H+$K*$K<4;){sub
Z{$I->colorAllocate(@_)}($H,$K)=($H*$H-$K*$K+4*$x/$s-2,2*$H*$K+4*$y/$s-2)}use
GD;$I->setPixel($x,$y,$c<99&&$c)}}print $I->png

Mandelbrot fractal from Perl+GD

Golfed from this code

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Nominated: most ugly color scheme. \$\endgroup\$
    – meawoppl
    Mar 9, 2014 at 9:41
3
\$\begingroup\$

Tcl/Tk, 316

322 324 336 348 349 351 352 353 354 355

Now a shorter version using 3 letter #RGB shorthands style color triplets (instead of #RRGGBB triplets), which results in different colors.

And some more golfing.

rename set s
grid [canvas .c -w 640 -he 640]
.c cr i 320 320 -i [s p [image c photo -w 640 -h 640]]
time {incr x
s y 0
time {incr y
s a 0
s b 0
s n 0
while \$n<99 {s A [expr $a*$a-$b*$b+$x[s f *4/639.-2]]
if [s b [expr 2*$a*$b+$y$f]]*$b+[s a $A]*$a>4 break
incr n}
$p p [format #%03x [expr $n*41]] -t $x $y} 640} 640

fractal


Tcl/Tk, 325

331 333 345 357 358 360 361 362 364 365

I think I would win if the criterium was beauty!

rename set s
grid [canvas .c -w 640 -he 640]
.c cr i 320 320 -i [s p [image c photo -w 640 -h 640]]
time {incr x
s y 0
time {incr y
s a 0
s b 0
s n 0
while \$n<99 {s A [expr $a*$a-$b*$b+$x[s f *4/639.-2]]
if [s b [expr 2*$a*$b+$y$f]]*$b+[s a $A]*$a>4 break
incr n}
$p p [format #%06x [expr $n*16777215/99]] -t $x $y} 640} 640

Presentation:

fractal

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice. You can reduce a few characters (down to 380, I think) by adding rename set s at the top and then replacing all the set by s \$\endgroup\$
    – user7795
    Apr 4, 2017 at 0:00
3
\$\begingroup\$

Python 3, 290 Bytes

from PIL import Image
import numpy as n
s=640;d=n.zeros((s,s,3),dtype=n.uint8)
for k in range(s*s):
    r=4/s*(k%s)-2;i=2-4/s*(k//s);z=c=complex(r,i)
    for i in range(50,9950,100):
        if abs(z)>2:
            d[k//s,k%s]=[i*5,i*9,i*7];break
        z=z*z+c
Image.fromarray(d).show()

mandelbrot

\$\endgroup\$
3
\$\begingroup\$

GLSL, 146 bytes

void mainImage( out vec4 o, vec2 C ) {o -= o; vec2 z;
for(;o.z++<99.^^length(z)>2.;)z=mat2(z.rg,-z.g,z)*z+C/99.-2.;o=mod(vec4(o.z)/vec4(4,2,6,0),1.19);}


https://www.shadertoy.com/view/sly3RW

enter image description here

\$\endgroup\$
4
  • \$\begingroup\$ no unique color for you \$\endgroup\$
    – Max
    Nov 18, 2021 at 11:28
  • \$\begingroup\$ For some reason I see 95% animated noise and 5% Mandelbrot \$\endgroup\$ Nov 18, 2021 at 13:51
  • \$\begingroup\$ Changing the final statement to o=vec4(mod(o.z/2.,2.),mod(o.z,2.),mod(o.z/4.,2.),0) might make it colorful (my theory at least) \$\endgroup\$ Nov 18, 2021 at 13:53
  • \$\begingroup\$ You're right :) Thanks, updated it to fit the rules now. But +25 bytes \$\endgroup\$
    – Max
    Nov 18, 2021 at 14:10
2
\$\begingroup\$

Julia

Well, better late than never:

function mandelbrot(x0,y0,side,N=800,L=55,R=3.)
    m = [0 for i=1:N,j=1:N]
    delta = side/N
    for i=1:N, j=1:N
        c = x0+delta*i+(y0+delta*j)*im
        z, h = 0+0*im, 0
        while (h<L) && (abs(z)<R)
            z = z^2+c
            h+=1
        end
        m[j,i]=h
    end
    return m
end
n=2.6
m = mandelbrot(-n/1.3,-n/2, n)
using Winston, Color
imagesc(m)
title("Mandelbrot Set")

Colormap Mod. :

function RGB_cm()
    colormap = [RGB(0,0,0) for t=1:255*5]
    rgb = [255,0,0]
    for t in 0:(255*5-1)
    c = [0, 0, 0]
    i = ifloor(t/255)
    c[(i+3)%3!=0?(i+3)%3:3] = (-1)^i
    rgb+=c
    colormap[t+1] = RGB(rgb[1],rgb[2],rgb[3])
    end
    colormap[(end-25):end] = RGB(0,0,0)
    return colormap
end
c = RGB_cm()
Winston.colormap(c)

Output:

Mandelbrot Set

\$\endgroup\$
3
  • \$\begingroup\$ Should I byte-count only the first program or both? \$\endgroup\$ Mar 29, 2014 at 10:10
  • \$\begingroup\$ I think both, because without the color map mod the image would not satisfy the rules. \$\endgroup\$
    – CCP
    Mar 29, 2014 at 15:35
  • 2
    \$\begingroup\$ I'm sure you can save much on whitespace. \$\endgroup\$ Sep 25, 2017 at 17:15
2
\$\begingroup\$

SmileBASIC, 126 bytes

X=RNDF()*4-2Y=RNDF()*4-2@N
N=N+16I=X+S*S-T*T
T=Y+S*T*2S=I
IF N<#L&&S*S+T*T<4GOTO@N
GPSET X*50+99,Y*50+99,RGB(99XOR N,N,N)EXEC.

enter image description here

\$\endgroup\$
3
  • \$\begingroup\$ Nice use of randoms to save on loops \$\endgroup\$ Feb 19, 2017 at 9:07
  • \$\begingroup\$ Should make it 240x240, but I guess that would be longer. \$\endgroup\$
    – snail_
    Mar 20, 2017 at 12:28
  • \$\begingroup\$ Code golf is about what you can get away with, not what you should do. \$\endgroup\$
    – 12Me21
    Jun 17, 2017 at 15:28
2
\$\begingroup\$

JavaScript (pixel shader), 88 bytes

m=(x,y,A=0,B=0,n=99)=>n--&&A*A+B*B<4?m(x,y,A*A-B*B+x,2*A*B+y,n):`hsl(${n*7} 99%${n/2}%)`

A pixel shader function that takes x and y between [-2, -2] and [2, 2] and returns CSS <color> (HSL).

mandelbrot

m=(x,y,A=0,B=0,n=99)=>n--&&A*A+B*B<4?m(x,y,A*A-B*B+x,2*A*B+y,n):`hsl(${n*7} 99%${n/2}%)`

const size = 512;
const scale = 4;
const ratio = scale / size;

const canvas = document.getElementById('canvas');
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');

let x, y;
for (x = 0; x < size; x++) for (y = 0; y < size; y++) {
  ctx.fillStyle = m((x - size / 2) * ratio, (y - size / 2) * ratio);
  ctx.fillRect(x, y, 1, 1);
}
<canvas id="canvas"/>

Ungolfed and Explained

m = (
  x,    // Re(c)
  y,    // Im(c)
  A=0,  // Re(z[i])
  B=0,  // Im(z[i])
  n=99  // 99 - i
) =>
  n-- && // if haven't reached max depth
  A * A + B * B < 4 ? // and |z| < 2
    m( // recurse
      x,
      y,
      A * A - B * B + x, // Re(z[i] ^ 2 + c)
      2 * A * B + y,     // Im(z[i] ^ 2 + c)
      n
    ) : // else return HSL colour
    `hsl(${n * 7} 99% ${n / 2}%)` // n * 7 always unique in mod 360
\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.