2020-04-25 Island generator using J

I’m trying to write an island generator in J. It’s hard. Every time I look at the documentation I’m close to tears. I feel so dumb. But like many hard things in life, if it works, suddenly you feel so smart. Now I feel smart. 😁

These were my notes:

Image 1 for 2020-04-25 Island generator using J

Here’s what the code looks like:

Image 2 for 2020-04-25 Island generator using J

That is:

mx =: 30
my =: 20

NB. a table of complex numbers
c =: (i. my) j./ i. mx

NB. a table of altitudes
a =: (my, mx) $ _2

NB. a table with the hotspot
hr =: 5
hy =: hr + 1
hx  =: <. 0.5 + (my % 3) + ? <. 0.5 + my % 3
hc =: hx j. hy
r =: ? (my, mx) $ 0
h =: 0.8 < r * hr > {. & *. c - hc

NB. a list of translations
d =: _1j0 0j1 0j1 1j0
s =: ( ? 30 # # d ) { d

NB. start loop
m =: m + h
3 : 0''
for_i. s do.
  hc =: hc + i
  r =: ? (my, mx) $ 0
  h =: 0.8 < r * 5 > {. & *. c - hc
  a =: a + h
end.
)

jv a

I know. It looks terrible. And m is no longer used.

Typical interactions whenever I want to try something in J look like this:

   ?3
1
   ?3
0
   ?3
2
   5 + ?5
9
   5 + ?5
7
   20/6+?20/6
|domain error
|   20/6+?    20/6
   20 / 6 + ? (20 / 6)
|domain error
|   20/6+?(    20/6)
   .i 4.5
|syntax error
|        .i 4.5
   i. 4.4
|domain error
|       i.4.4

Simple stuff works. Add a little bit of extra and it’s domain errors, syntax errors, spelling errors. 😭

It takes a while and then I remember: `%` divides, not `/`, or `_2` is `-2`. Aaaaargh.

I also felt stumped when I had to write the loop. And now I … loop … over it? Help me J, you promised loop-less programming! If you know how to do it, please leave a comment.

loop-less programming

Too bad that reading anything at all in the docs is taking me forever because it’s all in a foreign language, basically. Take a look at the reference section. Every time I look for something it takes me a long time to figure out what I’m actually looking for, and then it takes me a long time to understand what it says. But, slowly, I get the feeling that it might work.

reference section

And this is the current result, including the visualization:

Image 3 for 2020-04-25 Island generator using J

What I’m lacking now is the sinking of land as the hotspot moves away, and ‘cohesion’: land that is close to higher land on the hotspot is pulled along as it rises, land that is close to lower land off the hotspot is pulled along as neighbors sink.

As I look at the preview, I’m not even sure I need cohesion, actually. We’ll see!

Time passes...

Current status:

Image 4 for 2020-04-25 Island generator using J

mx =: 30
my =: 20

NB. a table of complex numbers
c =: (i. my) j./ i. mx

NB. a table of altitudes
a =: (my, mx) $ _2

NB. center of the hotspot
hr =: 5
hy =: >. hr % 2
hx  =: <. 0.5 + (my % 3) + ? <. 0.5 + my % 3
hc =: hx j. hy

NB. a list of translations
d =: _1j0 1j0, 4 $ 0j1
m =: ( ? 30 # # d ) { d

NB. start loop
3 : 0''
for_i. m do.
  hc =: hc + i               NB. move hotspot center
  h =: 5 > {. & *. c - hc    NB. hotspot = 1
  l =: -. _2 = a * -. h      NB. outside the hotspot -2 is the limit
  r =: 0.8 < ? (my, mx) $ 0  NB. 20% of regions are potentially active
  s =: 0.5 < ? (my, mx) $ 0  NB. 50% of regions...
  t =: h + s * -. h          NB. ...will ignore the activity
  a =: a + r * t* l * _1 + 2 * h
end.
)

jv a

​#J ​#Maps ​#Programming

Comments

(Please contact me if you want to remove your comment.)

Oh, and if you have J901, like I do on my laptop, then some changes are in order. First of all, `jv` doesn’t exist but `viewmat` does. Also, we can get rid of the explicit loop and define a dyadic verb instead, but then in order to call it, we need a boxed array where all the movements come first and the map at the end...

mx =: 30
my =: 20

NB. a table of complex numbers
c =: (i. my) j./ i. mx

NB. a table of altitudes
a =: (my, mx) $ _2

NB. center of the hotspot
hr =: 5
hy =: >. hr % 2
hx =: <. 0.5 + (my % 3) + ? <. 0.5 + my % 3
hc =: hx j. hy

NB. a list of translations
d =: _1j0 1j0, 4 $ 0j1
m =: ( ? 30 # # d ) { d

NB. function to run the simulation
NB. left is the map, right is the step to take
run =: dyad define
  hc =: hc + y               NB. move hotspot center
  h =. 5 > {. & *. c - hc    NB. hotspot = 1
  l =. -. _2 = x * -. h      NB. outside the hotspot -2 is the limit
  r =. 0.8 < ? (my, mx) $ 0  NB. 20% of regions are potentially active
  s =. 0.5 < ? (my, mx) $ 0  NB. 50% of regions...
  t =. h + s * -. h          NB. ...will ignore the activity
  x + r * t* l * _1 + 2 * h
)

NB. preparing arguments: a boxed array of all the translations and a at the end
args =: (;/m),<a
a    =: >run&.>~/args

viewmat a

Result:

An island

– Alex Schroeder 2020-04-28 16:16 UTC

---

Working on it! Now with the Gnomeyland palette!

mx =: 30
my =: 20

NB. a table of complex numbers
c =: (i. my) j./ i. mx

NB. starting position of the hotspot
hr =: 6
hy =: >. hr % 2
hx =: <. 0.5 + (my % 3) + ? <. 0.5 + my % 3
hc =: hx j. hy

NB. a function to compute altitude changes based on where the hotspot is
change =: 3 : 0
  h =. hr > {. & *. c - y     NB. hotspot = 1
  u =. 0.85 < ? (my, mx) $ 0  NB. regions atop the hotspot might move up
  d =. 0.7 < ? (my, mx) $ 0  NB. regions off the hotspot might move down
  (u * h) - d * -. h
)

NB. a biased list of steps to take
d =: _1j1 1j1 0j1

NB. a table of altitudes
a =: (my, mx) $ 0

NB. compute the meandering path of the hotspot across the map
NB. compute the change for each step and add it to the altitude
NB. no negative values
3 : 0''
for. i. mx - 2  * hr do.
  hc =: hc+(?#d){d
  a =: 0 & >. a + change hc
end.
)

decimal =:16"_#.'0123456789abcdef'"_ i.]

rgb =: 3 : 0
  n =. decimal }. y     NB. strip leading #
  (<.n % 65536), ((<.n % 256) |~ 256), (n |~ 256)
)
ocean  =: rgb '#1c86ee' NB. 0
water  =: rgb '#6ebae7' NB. 1
sand   =: rgb '#e3bea3' NB. 2
dry    =: rgb '#c97457' NB. 3
nice   =: rgb '#b0b446' NB. 4
green  =: rgb '#77904c' NB. 5
humid  =: rgb '#2d501a' NB. 6
rocky  =: rgb '#dcddbe' NB. 7
colors =: (ocean, water, sand, dry, nice, green, humid,: rocky)
colors viewmat a

Result:

Image 1

I still have to work on this. Something about rounding out the edges, perhaps. Bays filling up, exposed peninsulas getting razed, but lone islands left standing?

Perhaps I should think about generating *Text Mapper* output!

– Alex Schroeder 2020-04-28 20:41 UTC

---

Another idea: generate the path first, then adjust for the average y axis for better horizontal centring?

– Alex Schroeder 2020-04-28 20:50 UTC

---

Fun to see more new J enthusiasts popping up, I started becoming obsessed last december! Here’s a terser alternative for rgb for fun

`rgb=: _2 (+/ .*&16 1)\ '0123456789abcdef'&i. @ }.`

– Anonymous 2020-05-03 19:18 UTC

---

Thank you! 🙂

– Alex Schroeder 2020-05-03 19:29 UTC