Skip to content

Instantly share code, notes, and snippets.

@eglaysher
Last active February 23, 2020 20:26
Show Gist options
  • Save eglaysher/6e7e6bd0de4b4b26af7e8940d6704cb2 to your computer and use it in GitHub Desktop.
Save eglaysher/6e7e6bd0de4b4b26af7e8940d6704cb2 to your computer and use it in GitHub Desktop.
Fixed-point (not floating point!) Mandelbrot generator in Hoon.
:: Mandelbrot implementation inspired by the fixed-point version for
:: uBasic/4tH, and the floating point version for PureBasic from
:: https://rosettacode.org/wiki/Mandelbrot_set. This is pure fixed-point.
::
:: The trick is to use 10.000 as "floating" 1.0, and then do all math in terms
:: of that.
::
|%
++ left-edge -21.000
++ right-edge --15.000
++ top-edge --15.000
++ bottom-edge -15.000
::
++ max-iterations 254
::
+$ render-type [r=@ g=@ b=@]
::
++ to-si
|= x=@u
^- @si
(pro:si (sun:si x) --10.000)
::
++ add-fp
|= [a=@s b=@s]
(sum:si a b)
::
++ sub-fp
|= [a=@s b=@s]
(dif:si a b)
::
++ mul-fp
|= [a=@s b=@s]
(fra:si (pro:si (fra:si a --10) b) --1.000)
::
:: returns a fraction where when over=0, fp-fraction=0 and when over=under,
:: fp-fraction=--10.000
++ fraction-fp
|= [over=@s under=@s]
(fra:si (pro:si over --10.000) under)
--
::
=/ plasma-colors=(list render-type)
:: color map derived from matplotlib's
:~ [12 7 134] [16 7 135] [19 6 137] [21 6 138] [24 6 139]
[27 6 140] [29 6 141] [31 5 142] [33 5 143] [35 5 144]
[37 5 145] [39 5 146] [41 5 147] [43 5 148] [45 4 148]
[47 4 149] [49 4 150] [51 4 151] [52 4 152] [54 4 152]
[56 4 153] [58 4 154] [59 3 154] [61 3 155] [63 3 156]
[64 3 156] [66 3 157] [68 3 158] [69 3 158] [71 2 159]
[73 2 159] [74 2 160] [76 2 161] [78 2 161] [79 2 162]
[81 1 162] [82 1 163] [84 1 163] [86 1 163] [87 1 164]
[89 1 164] [90 0 165] [92 0 165] [94 0 165] [95 0 166]
[97 0 166] [98 0 166] [100 0 167] [101 0 167] [103 0 167]
[104 0 167] [106 0 167] [108 0 168] [109 0 168] [111 0 168]
[112 0 168] [114 0 168] [115 0 168] [117 0 168] [118 1 168]
[120 1 168] [121 1 168] [123 2 168] [124 2 167] [126 3 167]
[127 3 167] [129 4 167] [130 4 167] [132 5 166] [133 6 166]
[134 7 166] [136 7 165] [137 8 165] [139 9 164] [140 10 164]
[142 12 164] [143 13 163] [144 14 163] [146 15 162] [147 16 161]
[149 17 161] [150 18 160] [151 19 160] [153 20 159] [154 21 158]
[155 23 158] [157 24 157] [158 25 156] [159 26 155] [160 27 155]
[162 28 154] [163 29 153] [164 30 152] [165 31 151] [167 33 151]
[168 34 150] [169 35 149] [170 36 148] [172 37 147] [173 38 146]
[174 39 145] [175 40 144] [176 42 143] [177 43 143] [178 44 142]
[180 45 141] [181 46 140] [182 47 139] [183 48 138] [184 50 137]
[185 51 136] [186 52 135] [187 53 134] [188 54 133] [189 55 132]
[190 56 131] [191 57 130] [192 59 129] [193 60 128] [194 61 128]
[195 62 127] [196 63 126] [197 64 125] [198 65 124] [199 66 123]
[200 68 122] [201 69 121] [202 70 120] [203 71 119] [204 72 118]
[205 73 117] [206 74 117] [207 75 116] [208 77 115] [209 78 114]
[209 79 113] [210 80 112] [211 81 111] [212 82 110] [213 83 109]
[214 85 109] [215 86 108] [215 87 107] [216 88 106] [217 89 105]
[218 90 104] [219 91 103] [220 93 102] [220 94 102] [221 95 101]
[222 96 100] [223 97 99] [223 98 98] [224 100 97] [225 101 96]
[226 102 96] [227 103 95] [227 104 94] [228 106 93] [229 107 92]
[229 108 91] [230 109 90] [231 110 90] [232 112 89] [232 113 88]
[233 114 87] [234 115 86] [234 116 85] [235 118 84] [236 119 84]
[236 120 83] [237 121 82] [237 123 81] [238 124 80] [239 125 79]
[239 126 78] [240 128 77] [240 129 77] [241 130 76] [242 132 75]
[242 133 74] [243 134 73] [243 135 72] [244 137 71] [244 138 71]
[245 139 70] [245 141 69] [246 142 68] [246 143 67] [246 145 66]
[247 146 65] [247 147 65] [248 149 64] [248 150 63] [248 152 62]
[249 153 61] [249 154 60] [250 156 59] [250 157 58] [250 159 58]
[250 160 57] [251 162 56] [251 163 55] [251 164 54] [252 166 53]
[252 167 53] [252 169 52] [252 170 51] [252 172 50] [252 173 49]
[253 175 49] [253 176 48] [253 178 47] [253 179 46] [253 181 45]
[253 182 45] [253 184 44] [253 185 43] [253 187 43] [253 188 42]
[253 190 41] [253 192 41] [253 193 40] [253 195 40] [253 196 39]
[253 198 38] [252 199 38] [252 201 38] [252 203 37] [252 204 37]
[252 206 37] [251 208 36] [251 209 36] [251 211 36] [250 213 36]
[250 214 36] [250 216 36] [249 217 36] [249 219 36] [248 221 36]
[248 223 36] [247 224 36] [247 226 37] [246 228 37] [246 229 37]
[245 231 38] [245 233 38] [244 234 38] [243 236 38] [243 238 38]
[242 240 38] [242 241 38] [241 243 38] [240 245 37] [240 246 35]
[239 248 33]
==
::
|%
++ mandelbrot
|= [width=@u height=@u]
^- (list (list render-type))
:: Internally, we emulate floating point numbers by having 1 equal
:: --10.000. This means we want to precompute the incoming values in that
:: coordinate space.
::
=/ signed-width=@s (to-si width)
=/ signed-height=@s (to-si height)
::
=/ width-pixels (gulf 0 (sub width 1))
::
%+ turn (gulf 0 (sub height 1))
|= y=@u
~& [%cal-row y (sub height 1)]
%+ turn width-pixels
|= x=@u
(calc-pixel (to-si x) (to-si y) signed-width signed-height)
::
++ calc-pixel
|= [scr-x=@s scr-y=@s width=@s height=@s]
^- render-type
::
=/ cr=@s (sub-fp (mul-fp (fraction-fp scr-x width) --25.000) --20.000)
=/ ci=@s (sub-fp (mul-fp (fraction-fp scr-y height) --25.000) --12.500)
::
=/ i=@ 0
=/ x0=@s --0
=/ y0=@s --0
::
|-
?: (gte i max-iterations)
(calculate-color-for 255)
::
=/ xx=@s (mul-fp x0 x0)
=/ yy=@s (mul-fp y0 y0)
::
?: =(--1 (cmp:si (add-fp xx yy) --40.000))
(calculate-color-for i)
::
=/ xtemp=@s (add-fp (sub-fp xx yy) cr)
=. y0 (add-fp (pro:si --2 (mul-fp x0 y0)) ci)
=. x0 xtemp
::
$(i +(i))
::
++ calculate-color-for
|= o=@
^- render-type
?: =(o 255)
[0 0 0]
(snag o plasma-colors)
--
::
:: Generator usage:
::
:: @file/ppm +mandelbrot <width> <height>
::
:- %say
|= [^ [w=@ud h=@ud ~] ~]
:- %atom
=/ mandelbrot-data (mandelbrot w h)
::
%- of-wain:format
^- wain
%+ weld
:~ 'P3'
(crip "{<w>} {<h>}")
'255'
==
%+ turn mandelbrot-data
|= y=(list render-type)
^- cord
%- crip
%- zing
%+ turn y
|= render-type
"{<r>} {<g>} {<b>} "
@eglaysher
Copy link
Author

Attaching the raw PPM didn't work; Github didn't treat it as an image. Trying after converting it to a PNG:

result-999

@eglaysher
Copy link
Author

You can fish the raw PPM out of this gist's history if you're interested.

Also, I made mostly stylistic changes to clean up the codebase for release AFTER I generated the above image.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment