41
\$\begingroup\$

Here’s the picture of the first published picture of the Mandelbrot set.

Use the fewest bytes possible to write a program or function that outputs the following.

the Mandelbrot set

A trailing new line is permitted. Character * cannot be replaced by any other character.

Useful information: Center is \$(-0.75, 0)\$, \$\Delta x = 0.035\$, and \$\Delta y = 1.66\Delta x\$. Iteration count is 250.

As text (for checking):

                                                     *              
                                                   ****             
                                                  ******            
                                                   *****            
                                              * *********           
                                         *** ****************       
                                           ******************** **  
                                        *************************   
                                       **************************** 
                                     *******************************
                                     ****************************** 
                        * *****     ********************************
                       ***********  ********************************
                      ************* ******************************* 
                  ** ************** ******************************  
****************************************************************    
                  ** ************** ******************************  
                      ************* ******************************* 
                       ***********  ********************************
                        * *****     ********************************
                                     ****************************** 
                                     *******************************
                                       **************************** 
                                        *************************   
                                           ******************** **  
                                         *** ****************       
                                              * *********           
                                                   *****            
                                                  ******            
                                                   ****             
                                                     *              

Thanks @Sisyphus for providing the parameters.

\$\endgroup\$
  • 6
    \$\begingroup\$ Is there a text form of the image we can use to check our output? \$\endgroup\$ – xnor Jan 13 at 4:25
  • 4
    \$\begingroup\$ Just edited a text version in. Hopefully my quick image processing script got it correct. \$\endgroup\$ – Sisyphus Jan 13 at 4:41
  • 11
    \$\begingroup\$ Also relevant. Center is \$(-0.75, 0)\$, \$\Delta x = 0.035\$, and \$\Delta y = 1.66\Delta x\$. Iteration count is 250. \$\endgroup\$ – Sisyphus Jan 13 at 5:00
  • 2
    \$\begingroup\$ Do we have to print the spaces at the end? \$\endgroup\$ – Command Master Jan 13 at 13:25
  • 4
    \$\begingroup\$ Interesting side effect of printing *s is that half of the programs will necessarily contain the answer to life, the universe and everything. It's often used as a sample value in programs, but here it's actually relevant. \$\endgroup\$ – Darrel Hoffman Jan 13 at 15:36

11 Answers 11

20
\$\begingroup\$

Ruby 2.5, 98 bytes

-15.upto(15){|y|68.times{|x|z=0;250.times{z=0.035*x-1.9751+y/17.21i+z*z};putc z.abs<2?42:32};puts}

Try it online!

Very straightforward implementation, with a little bit of trickery to allow using times instead of upto in the inner loop.

Unfortunately, loop merging is two bytes longer, although it may help in other languages:

-1034.upto(1104){|x|z=0;250.times{z=x%69*0.035-2.0101+x/69/17.21i+z*z};putc x%69>0?z.abs<2?42:32:10}
\$\endgroup\$
  • 2
    \$\begingroup\$ Note that the 8th row (and its counterpart in the lower part) is one * shorter than expected. \$\endgroup\$ – Arnauld Jan 13 at 13:44
  • 2
    \$\begingroup\$ This can be fixed by using 1.9751. \$\endgroup\$ – Arnauld Jan 13 at 14:08
  • 1
    \$\begingroup\$ @Arnauld Aha, did I neatly avoided a floating-point error when porting this to Charcoal by golfing .035*x-1.975 to .035*(x-85)+1 (well it's golfier in Charcoal at least)? \$\endgroup\$ – Neil Jan 13 at 15:15
  • 1
    \$\begingroup\$ @Arnauld Good catch. Fixed. \$\endgroup\$ – Sisyphus Jan 13 at 21:25
10
\$\begingroup\$

MATL, 45 bytes

Some numerical constants have been taken from Sisyphus' answer

Thanks to @Arnauld for a correction!

O8W:"U-1.9751:.035:.4-15:15!17.21j/++]|2<42*c

Try it online!

How it works

O                  % Push 0
8W                 % Push 2^8, that is, 256
:                  % Range. Gives [1 2 ... 256]
"                  % For each. This iterates 256 times
  U                %   Square, element-wise
  -1.9751:.035:.4  %   Push range from -1.9751 to 0.4 (actually to 0.37) with step 0.035
  -15:15           %   Push range from -15 to 15 (with step 1)
  !                %   Transpose into a column vector
  17.21j/          %   Divide by 17.21j, element-wise
  +                %   Add with broadcast. Gives the complex grid
  +                %   Add element-wise to result from previous iteration
]                  % End
|                  % Absolute value, element-wise
2<                 % Less than 2? Element-wise
42*                % Multiply by 42 (ASCII code of '*'), element-wise
c                  % Convert to char (char 0 is displayed as space). Implicit display

As a curious note, the program uses : with three different meanings:

  • Unary range function (: appplied to 256)
  • Ternary range literal (-1.9751:.035:.4)
  • Binary range literal (-15:15)
\$\endgroup\$
  • \$\begingroup\$ Sisyphus' answer is slightly off. You can use 1.9751 to fix it. \$\endgroup\$ – Arnauld Jan 13 at 14:30
  • \$\begingroup\$ @Arnauld Thank you! Corrected \$\endgroup\$ – Luis Mendo Jan 13 at 16:05
10
\$\begingroup\$

Wolfram Language (Mathematica), 86 85 bytes

-1 thanks to sanchez

Print@@@Array[If[Re@Nest[zz^2+.035#2+I.0581#,0,200]<2,"*"," "]&,8{4,9},-5{3,79/7}]

Try it online!

Uses the constants found by Sisyphus.

Mathematica does have such functions as MandelbrotSetIterationCount and MandelbrotSetMemberQ (which, with the default 1000 iterations, produces a slightly different image). Unfortunately, MandelbrotSetIterationCount's name is a bit too long, while setting the MaxIterations option for MandelbrotSetMemberQ makes it even more verbose.

\$\endgroup\$
  • 2
    \$\begingroup\$ if you use Grid@ instead of Print@@@ you can omit the second If-argument. ," ". and using Re instead of Abs saves one more. \$\endgroup\$ – sanchez Jan 14 at 1:07
  • 1
    \$\begingroup\$ @sanchez Grid formats output in the REPL, but not that of a script. Nice one with Re. \$\endgroup\$ – att Jan 14 at 1:15
  • 1
    \$\begingroup\$ Ah yes, the classic "Mathematica has a builtin for this, but it's too long" \$\endgroup\$ – Hello Goodbye Jan 15 at 18:12
9
\$\begingroup\$

05AB1E, 56 bytes

Feels very long.

67ÝƵú*Ž
@-тn/15D(Ÿт*Ž6À/δ‚εε₅FDnÆsP·‚y+DnO4›©#}„* ®è]øJ»

Try it online!

Since 05AB1E does not support complex numbers the computation is done in a more manual way, keeping complex numbers as pairs [a, b]:

$$(a+bi)^2 = (a^2-b^2) + 2abi$$

D        # duplicate the pair
 n       # square each part: [a^2, b^2]
  Æ      # reduce by subtraction: a^2-b^2
   s     # swap to copy
    P    # take the product: a*b
     ·   # double it: 2*a*b
      ‚  # pair both results: [a^2-b^2, 2*a*b]

$$|a+bi|>2 \Leftrightarrow \sqrt{a^2+b^2}>2 \Leftrightarrow a^2 + b^2 > 4$$

n        # square each part: [a^2, b^2]
 O       # take the sum: a^2+b^2
  4›     # is this larger than 4: a^2+b^2>4

Complete code commented:

67ÝƵú*Ž\n@-тn/          # generate the x coordinates: ([0..67]*350-19751)/10000
67Ý                     # push the range [0 .. 67]
   Ƶú*                  # multiply each value by 350
      Ž\n@-             # subtract 19751 from each
           тn/          # divide by 100**2

15D(Ÿт*Ž6À/             # generate the y coordinates: [15..-15]*100/1721
15D                     # push 15 twice
   (                    # negate one copy
    Ÿ                   # take the inclusive range [15 .. -15]
     т*                 # multiply each value by 100
       Ž6À/             # divide by 1721

δ‚                      # create a grid of all x-y pairs
  ε                     # map over each line:
   ε                    #  map over each pair:
    ₅F                } #  iterate 255 times 
                        #  (produces the same output as 250 iterations)
      DnÆsP·‚           #    square the current value
             y+         #    add the coordinate
               D        #    duplicate current value
                nO4›©   #    check if the magnitude is larger than 2
                     #  #    if this is the case, stop the loop
                        #    this is necessary because the program will actually crash if trying to continue with infinite values
    „* ®è               #  index with the last result of |z|>2 into the string "* "
 ]                      # close all loops
ø                       # transpose the grid
 J                      # join each line into a single string
  »                     # join lines by newlines
\$\endgroup\$
9
\$\begingroup\$

R, 151 138 bytes

Edit: -13 bytes thanks to Giuseppe

write(matrix(unlist(Map(rep,c(" ","*"),utf8ToInt("T `#^%^$Y  (S\" /Q3 !I8I;E>D=8  $$?6*!?5, >2! - =!_#")-31)),68)[,c(1:16,15:1)],1,68,,"")

Try it online!

Encodes the run lengths of s and *s for the top half as a text string, converts these to a matrix (together with itself reversed by row), and outputs using cat.

Bearing in mind that actually calculating the Mandelbrot set in R costs only 123 bytes, including full-colour graphic display, this might not be the golfiest solution... but the text encoding was fun anyway...

\$\endgroup\$
  • \$\begingroup\$ 138 bytes. You can probably reduce it further by encoding using unprintables and getting rid of the -31. \$\endgroup\$ – Giuseppe Jan 13 at 17:46
6
\$\begingroup\$

Perl 5, 127 bytes

say for@o='e1q4o6o5j119d31@bD12ZIZLVOUNI1155PG;2PF=1OC21>1N2p4'=~s/./($i++%2?'*':$")x(-48+ord$&)/ger=~/.{68}/g,reverse@o[0..14]

Try it online!

say                                        #prints each line + \n newline at end
for @o=                                    #for all lines, also saved in array @o
'e1q4o6o5j119d31@bD12ZIZLVOUNI1155PG;2PF=1OC21>1N2p4' #lengths for spaces and *s
=~ s/./ ($i++%2?'*':$") x (-48+ord$&) /ger #...decode into lengths and output
                                           #...space or * of each length
=~ /.{68}/g,                               #...partition lines on every 68th char
reverse@o[0..14]                           #add mirror of first 15 lines
\$\endgroup\$
6
\$\begingroup\$

Bubblegum, 97 bytes

Using zopfli --i 10000 --deflate -c mandlebrot.txt | xxd and no trailing spaces. Increasing iterations beyond 10000 doesn't seem to make a difference.

00000000: c595 a901 c040 0c80 7ca6 8866 ff01 2bb1  .....@..|..f..+.
00000010: 574c f0d0 debf 05a6 4850 3c88 e216 9105  WL......HP<.....
00000020: f869 829a f63b 5ab2 30c1 6f3f 81c4 06d2  .i...;Z.0.o?....
00000030: 23a5 e19a 9908 1124 4700 0933 a2f4 d618  #......$G..3....
00000040: 3afd 1ffa 545c ac49 df1d 619b f6c6 c1c1  :...T\.I..a.....
00000050: 15e4 ee0e eb97 a8b0 c114 4e5e a8d9 02f3  ..........N^....
00000060: 01                                       .

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Honestly so surprised there is no Bubblegum to brainfuck transpiler... \$\endgroup\$ – Jay Jan 19 at 23:03
6
\$\begingroup\$

Charcoal, 74 73 bytes

F¹⁶«F⁶⁸«≔⁰θ≔⁰ηFφ«≔⁺⊕×·⁰³⁵⁻κ⁸⁵⁻×θθ×ηηζ≔⁺∕ι¹⁷·²¹⊗×θηη≔ζ軧 *‹⁺×θθ×ηη⁴»⸿»‖O↑

Don't try it online! Link is to verbose version of code. Performs 1,000 iterations, so it's too slow for TIO. It can be made faster by halving the number of iterations, which costs a byte:

F¹⁶«F⁶⁸«≔⁰θ≔⁰ηF⊘φ«≔⁺⊕×·⁰³⁵⁻κ⁸⁵⁻×θθ×ηηζ≔⁺∕ι¹⁷·²¹⊗×θηη≔ζ軧 *‹⁺×θθ×ηη⁴»⸿»‖O↑

Try it online! Link is to verbose version of code.

Previous 74-byte compression-based version:

”}∧q÷W9r¤1αlIχ‽§heY⟧>℅ν⊞P ~E .Q×jn⁵\6⧴<¤< U#V‽↶³≧JJD‴>π v‹»λê= ↨∨|>zθ9”‖O↓

Try it online! Link is to verbose version of code. Explanation: Works by printing the top half as a compressed string literal and reflecting it.

I also tried printing the bottom half and reflecting, but this increased the byte count to 78 bytes. I also tried printing the reflection of the image and for the bottom half this reduced the byte count to 75 bytes but for the top half it actually increased it to 81 bytes.

I also tried using manual run length encoding but I couldn't even get it as low as 81 bytes.

Previous 75-byte even faster pure Charcoal calculation version (uses the original 250 iterations):

F¹⁶«F⁶⁸«≔⁰θ≔⁰ηF²⁵⁰«≔⁺⊕×·⁰³⁵⁻κ⁸⁵⁻×θθ×ηηζ≔⁺∕ι¹⁷·²¹⊗×θηη≔ζ軧 *‹⁺×θθ×ηη⁴»⸿»‖O↑

Try it online! Link is to verbose version of code.

If Python exponentiation worked on inf then it would have been only 73 bytes:

F¹⁶«F⁶⁸«≔E²¦⁰θF²⁵⁰UMθ⎇ν⁺∕ι¹⁷·²¹⊗×μ§θ⁰⁺⊕×·⁰³⁵⁻κ⁸⁵⁻Xμ²X§θ¹¦²§ *›⁴ΣXθ²»⸿»‖O↑

Don't try it online! Link is to verbose version of code.

With some hacky uses of PythonEvaluate to get around the fact that Charcoal doesn't support complex numbers I can do it in 67 bytes:

F¹⁶«F⁶⁸«≔⁰θF²⁵⁰≔⁺⁺∕ιY¹⁷·²¹⊕×·⁰³⁵⁻κ⁸⁵×θθθ≔⁺absθθ§ *∨№θn‹UVθ²»⸿»‖O↑

Try it online! Link is to verbose version of code. Would probably be 53 bytes if Charcoal had a native imaginary constant, perhaps something like this (not actual Charcoal code):

F¹⁶«F⁶⁸«≔⁰θF²⁵⁰≔⁺⁺∕ιY¹⁷·²¹⊕×·⁰³⁵⁻κ⁸⁵×θθθ§ *‹↔θ²»⸿»‖O↑
\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6),  128 ... 124  123 bytes

Based on the parameters used by @Sisyphus.

f=(k=2138)=>k?`
 *`[k--%69&&-~(g=X=>++n>>8?X*X+Y*Y<4:g(X*X-Y*Y-k%69*.035+.3699,Y=2*X*Y-(16+~(k/69))/17.21))(Y=n=0)]+f(k):''

Try it online!

Commented

f = (k = 2138) =>            // f is a recursive function taking a counter k
                             // which encodes: x = k mod 69
                             //                y = floor(k / 69) - 15
k ?                          // if k is not equal to 0:
  `\n *`[                    //   character lookup:
    k-- % 69 &&              //     append a linefeed if k mod 69 = 0
                             //     (decrement k afterwards)
    -~(                      //     otherwise use the result of ...
      g = X =>               //     ... the recursive function g which takes X
                             //     and also uses Y and an iteration counter n
      ++n >> 8 ?             //       increment n; if it's not equal to 256:
        X * X + Y * Y < 4    //         return true if X² + Y² is less than 4
      :                      //       else:
        g(                   //         do a recursive call to g with:
          X * X - Y * Y      //           the updated X:
          - k % 69 * .035    //             X² - Y² - x * 0.035 + 0.3699
          + .3699,           //       
          Y = 2 * X * Y      //           the updated Y:
          - (16 + ~(k / 69)) //             2XY + y / 17.21
          / 17.21            //       
        )                    //         end of recursive call
    )(Y = n = 0)             //     initial call to g with X = Y = n = 0
  ]                          //   end of character lookup
  + f(k)                     //   append the result of a recursive call
:                            // else:
  ''                         //   stop the recursion
\$\endgroup\$
  • \$\begingroup\$ Nice work! Kudos! \$\endgroup\$ – Jay Jan 13 at 14:38
6
\$\begingroup\$

Python 3, 218 217 200 191 bytes

lambda:a+['*'*64]+a[::-1]
D=2**31
a=[f'{y:68b}'.translate(' *'*25)for y in[4**7,30<<12,63<<12,31<<12,3143680,125828992,33554412,D//8-8,D//4-2,D-1,D-2,6082*D-1,16378*D-1,32766*D-2,458750*D-4]]

Try it online!

Terrible score, but I wanted to see how it would look with bitmasks in the style of a typical challenge

-1 thanks to @thedefault

-17 thanks to @xnor

-9 thanks to @benrg


Python 3, 165 bytes

lambda:a+["*"*64]+a[::-1];a=[''.join((i-31)%64*' *'[i-31>>6]for i in j)for j in b'T`@Rc@Qe@Rd@M` h@Hb o@Js a!@Gx@F{@D~@D}@7` d$\x7f@6j!\x7f@5l ~@1a m }'.split(b"@")]

Try it online!

Run-length encoded.

\$\endgroup\$
  • 6
    \$\begingroup\$ I think 16384 can be replaced by 4**7. \$\endgroup\$ – the default. Jan 13 at 12:05
  • 1
    \$\begingroup\$ Could this not also generate the Julia set? given a different range? Then the question is how to fix the input vectors, most interesting. Garbage in garbage out \$\endgroup\$ – Jay Jan 13 at 14:06
  • 2
    \$\begingroup\$ Extracting a constant: Try it online! \$\endgroup\$ – xnor Jan 14 at 0:36
  • 3
    \$\begingroup\$ f'{y:68b}'.translate(' *'*25) saves 9 bytes. \$\endgroup\$ – benrg Jan 15 at 5:42
  • 3
    \$\begingroup\$ Multiplying by D instead of 25 saves another byte at the cost of slightly increased RAM usage. \$\endgroup\$ – benrg Jan 15 at 5:49
3
\$\begingroup\$

Python 2.6, 128 bytes

print"x\xda\xbd\x94\xa1\x15\x001\x0c\x85|\xa7@\xb3\xff\x80'\xbf\x0e\xe2\xf0\xf0\xfa\xda4\x14|E\xd2\xe2i\x14)\xa2\xa8\x1eM\x9dv\xb7\x99\xeb@_\xf4\xc7\x0b\x81\xd6p\xf4Hl\x88\xaaK\x84\x88#G\x1c\xca\xbd\xa1xi<;\xfd\x0c\xfd*\xfe\x7f\x93>\x1d}LC\xe3\xff\x8f\x1b\xd6G\x88\xf0\xe7\x12\xad\xcb{T\xd1*R=\xf0\x03-<\x12|".decode("zip")

This is an ASCII-fied version of the program. The actual program is encoded in latin-1 and looks like:

00000000: 7072 696e 7422 78da bd94 a115 5c78 3030  print"x.....\x00
00000010: 310c 857c a740 b3ff 8027 bf0e e2f0 f0fa  1..|.@...'......
00000020: da34 147c 45d2 e269 1429 a2a8 1e4d 9d76  .4.|E..i.)...M.v
00000030: b799 eb40 5ff4 c70b 81d6 70f4 486c 88aa  ...@_.....p.Hl..
00000040: 4b84 8823 471c cabd a178 693c 3bfd 0cfd  K..#G....xi<;...
00000050: 2afe 7f93 3e1d 7d4c 43e3 ff8f 1bd6 4788  *...>.}LC.....G.
00000060: f0e7 12ad cb7b 54d1 2a52 3df0 032d 3c12  .....{T.*R=..-<.
00000070: 7c22 2e64 6563 6f64 6528 227a 6970 2229  |".decode("zip")

Since Python 2.7, the default encoding of a file is now ASCII instead of Latin-1, so you need to prepend the file with #coding=L1 for the smaller version to run.

Try it online!

This is quite a boring answer: I zipped the original image into a string S then run print S.decode('zip').

\$\endgroup\$
  • \$\begingroup\$ Ah, you are right, my apologies! \$\endgroup\$ – G. Sliepen Jan 16 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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