Exponentially Slimy Programming: Stacking Minecraft Slimes

108

6

Slimes are cube shaped enemies in Minecraft that break into multiple smaller versions of themselves when killed. For the purposes of this challenge we'll depict them as an 8×8 pixel image with 3 colors:

64x64 slime

8x8 slime ← True 8×8 version.

The precise RGB colors are:

  • 0, 0, 0 for the eyes and mouth
  • 110, 170, 90 for the central, darker green
  • 116, 196, 96 for the outer, lighter green

Challenge

Write a program or function that takes in a positive integer N and outputs an image of N sizes of slimes packed into a rectangle. Going from left to right, the image should follow the pattern of having:

  • A stack of 2(N-1) 8×8 slimes.
  • A stack of 2(N-2) 16×16 slimes.
  • A stack of 2(N-3) 32×32 slimes.
  • And so on until the stack only contains one slime.

The slime images larger than the 8×8 version (8x8 slime) are generated by nearest-neighbor upsampling (i.e. just doubling all the pixels). Note that you must use the exact slime design and colors given here.

The final image will contain 2N-1 slimes and be 2(N+3)-8 pixels wide and 2(N+2) pixels tall.

The image may be output in any common image file format, saved to a file or printed/returned as a raw data stream, or directly displayed during runtime.

The shortest code in bytes wins.

Examples

Your program should produce these exact results.

N = 1:

N = 1

N = 2:

N = 2

N = 3:

N = 3

N = 4:

N = 4

N = 5:

N = 5

N = 6:

N = 6

Larger N should work just as well.

Calvin's Hobbies

Posted 2016-08-20T17:46:47.277

Reputation: 84 000

30I would upvote but I have no votes left. I'm leaving this comment so I'll remember to upvote tomorrow. – NoOneIsHere – 2016-08-20T17:55:24.333

23I'm upvoting your comment because I've run out of upvotes too. – trichoplax – 2016-08-20T18:13:35.883

4"The slime images larger than the 8×8 version () are generated by nearest-neighbor upsampling (i.e. just doubling all the pixels)." Did you mean quadruple all the pixels, make each pixel into a 2x2 square? – Caridorc – 2016-08-21T11:06:29.137

1@Caridorc Doubling in each direction? – wizzwizz4 – 2016-08-21T14:51:59.313

@wizzwizz4 Yes, each pixel becomes 4, correct? – Caridorc – 2016-08-21T14:52:38.503

@wizzwizz4 Ok, I get it now, thanks for explaining – Caridorc – 2016-08-21T14:56:54.973

Answers

21

MATL, 77 76 74 bytes

:"')^.,9&Xze`}+.E=p'F3ZaQ8e@qWt3$Y"G@-W1X"]&h[OOO;11 17E]5*29 7U24hhE&vEYG

The code works in this commit, which is earlier than the challenge.

You can try it in MATL online. This interpreter is still experimental. If it doesn't work, try refreshing the page and pressing "Run" again.

Here's an example run in the offline interpreter:

enter image description here

Explanation

:                     % Input N implicitly. Generate range [1 2 ... N]
"                     % For each k in [1 2 ... N]
  ')^.,9&Xze`}+.E=p'  %   Compressed string
  F3Za                %   Decompress with target alphabet [0 1 2]
  Q                   %   Add 1
  8e                  %   Reshape into 8×8 array containing values 1, 2, 3
  @qW                 %   Push 2 raised to k-1
  t                   %   Duplicate
  3$Y"                %   Repelem: interpolate image by factor 2 raised to k-1
  G@-W                %   Push 2 raised to N-k
  1X"                 %   Repmat: repeat the array vertically. Gives a vertical strip
                      %   of repeated subimages
]                     % End for each
&h                    % Concatenate all vertical strips horizontally. This gives a big
                      % 2D array containing 1, 2, 3, which represent the three colors
[OOO;11 17E]5*        % Push array [0 0 0; 11 17 9] and multiply by 5
29 7U24hhE            % Push array [29 49 24] and multiply by 2
&vE                   % Concatenate the two arrays vertically and multiply by 2.
                      % This gives the colormap [0 0 0; 110 170 90; 116 196 96]
YG                    % Take the array and the colormap and display as an image

Luis Mendo

Posted 2016-08-20T17:46:47.277

Reputation: 87 464

"Larger N should work just as well.", but yours seems to give Out Of Memory/index errors already at n = 9. Is this only the online interpreter, or does this happen in the offline version as well? – David Mulder – 2016-08-22T10:04:03.893

1@DavidMulder I have tested offline (compiler running on Matlab R2015b, Windows 7 64 bits, 4 GB RAM) for input up to 11 and it works. For 11 the result is an 8192×16376 image. For 12 it would be 16384×32760 (536 megapixels), requiring over 4 GB of RAM, which is more than my laptop can handle. – Luis Mendo – 2016-08-22T11:14:56.897

2I like how the code starts with a smiley that is holding back his tears because of the intense emotions this code makes him feel :"') – Tom Doodler – 2016-08-22T13:07:24.963

14

Dyalog APL, 118 113 bytes

('P3',⌽∘⍴,255,∊)(3↑(116 196 96)(110 170 90))[⊃,/i{⊃⍪/⍵⍴⊂⍺⌿⍺/8 8⍴∊22923813097005 926134669613412⊤¨⍨⊂32⍴3}¨⌽i←2*⍳⎕]

assuming ⎕IO=0

From right to left:

i←2*⍳⎕ powers 1 2 4 ... 2n-1

i{ }¨⌽i iterate over powers (with ) and reversed powers ()

⊤¨⍨⊂32⍴3 decode each of the numbers on the left as 32 ternary digits

8 8⍴∊ flatten and reshape to 8×8

⍺⌿⍺/ replicate each row and column times

⍵⍴⊂ take copies

⊃⍪/ and stack them vertically

⊃,/ join all results horizontally

3↑(116 196 96)(110 170 90) colours; 3↑ extends them with (0 0 0)

[ ] index the colours with each element of the matrix; result is a matrix of RGBs

('P3',⌽∘⍴,255,∊) is a "train" - a function that returns 'P3' followed by the reversed shape of the argument, 255, and the argument flattened.

ngn

Posted 2016-08-20T17:46:47.277

Reputation: 11 449

I think you can write your program assuming ⎕IO←0 and just state it as a condition, outside of byte count. Many APL systems use that as a default. (Including yours LOL) – Tobia – 2016-08-22T13:30:25.947

11

JavaScript (ES7), 326 327 bytes

n=>{x=(d=document).body.appendChild(c=d.createElement`canvas`).getContext`2d`;c.width=2*(c.height=4*(p=2**n)));for(i=0;i<n;i++){c=-1;for(j of[...'0001000001111110022112200221122011111110011121110111111000010000'])for(x.fillStyle=['#74c460','#6eaa5a','#000'][j],c++,k=0;k<p;)x.fillRect(c%8*(_=2**i)+_*8,~~(c/8)*_+_*8*k++,_,_)}}

Ungolfed ES6 Version

Try it yourself.

(n=>{
    x=(d=document).body.appendChild(c=d.createElement`canvas`).getContext`2d`;
    c.width=2*(c.height=4*(p=Math.pow(2,n)));
    for(i=0;i<n;i++){
        c=-1;
        for(j of[...'0001000001111110022112200221122011111110011121110111111000010000'])
            for(x.fillStyle=['#74c460','#6eaa5a','#000'][j],c++,k=0;k<p;)
                x.fillRect(c%8*(_=Math.pow(2,i))+_*8,~~(c/8)*_+_*8*k++,_,_)
    }
})(4);

The only difference between the ES7 and ES6 version is using ** instead of Math.pow(). You can also see, how you can invoke the function – in this example with n=4.

Result

enter image description here


Edits

  • saved 1 byte - found an unnecessary trailing semicolon ;

This is pretty slow and might take some time for numbers greater 10.

insertusernamehere

Posted 2016-08-20T17:46:47.277

Reputation: 4 551

2the colours seem slightly off in the image here. Did you perhaps screenshot with f.lux on? – Jezzamon – 2016-08-22T04:39:18.477

@Jezzamon Thanks for pointing it out – I did notice that, too. There's a slight possibility that I might have chosen "Convert document's colors to the working space" while importing the screenshot into Photoshop. The image is fixed now. – insertusernamehere – 2016-08-22T09:22:31.657

@Giles - Appreciate your comment, and in SO, that'd be totally appropriate, but here, we don't change others' programs - we tell them in comments. – Not that Charles – 2016-08-25T18:12:24.400

7

C, 220 bytes

x,y,r;f(n){
printf("P3 %d %d 255 ",(8<<n)-8,4<<n);
for(y=0;y<4<<n;++y)for(r=0;r<n;++r)for(x=0;x<8<<r;++x)
puts("110 170 90\0 116 196 96\0 0 0 0"+12*
(117-"` t5L\rL\ru5tst5` "[x>>r+2|(y>>r)%8*2]>>(x>>r)%4*2&3));}

I added useless newlines for readability, score is without these newlines.

Defines a function f(n) that outputs a plain PPM image on stdout.

orlp

Posted 2016-08-20T17:46:47.277

Reputation: 37 067

1For some reason C answers are pretty elegant in my mind. – downrep_nation – 2016-08-22T23:31:52.797

7

Mathematica, 267 255 254 225 212 bytes

G=10{11,17,9};Image@Join[##,2]&@@Table[Join@@Table[ImageData@ImageResize[Image[{t={g=G+{6,26,6},g,g,G,g,g,g,g},f={g,a=##&[G,G,G],a,g},e={g,b=0g,b,G,G,b,b,g},e,{a,a,G,g},{g,a,b,a},f,t}/255],4*2^j],2^(#-j)],{j,#}]&

Saved 29 42 bytes thanks to Martin Ender

Golfing suggestions welcome, especially for constructing the 8 by 8 (by 3) array s. Unfortunately, there is no "ArrayResize" analogue for ImageResize, so the array needs to be converted to an image (Image) before resizing, and then back to an array (ImageData) to do the Joining.

Ungolfed:

(* dark green, light green, black *)
G = 10 {11, 17, 9};
g = G + {6, 26, 6};
b = 0 g;

(* abbreviation for triple G sequence, top row, forehead, eye level *)
a = ##&[G, G, G];
t = {g, g, g, G, g, g, g, g};
f = {g, a, a, g};
e = {g, b, b, G, G, b, b, g};

(* slime *)
s =
  {
    t,
    f,
    e,
    e,
    {a, a, G, g},
    {g, a, b, a},
    f,
    t
  }/255;

(* jth column *)
c[n_, j_] := Join @@ Table[ImageData@ImageResize[Image[s], 4*2^j], 2^(n - j)]

(* final program *)
Image@Join[##, 2] & @@ Table[c[#, j], {j, #}] &

for Monica

Posted 2016-08-20T17:46:47.277

Reputation: 1 172

1b=0g. To generate s it might be shorter to encode the pixel values as a base-3 number but I'd have to try to be sure. In the meantime, you can save bytes by not defining b, g, f, e, t until you need them, and s doesn't need a name at all and neither does c. For 2^(j-1)8 you can use 4*2^j. Applying all of those, I end up at 225 bytes: http://pastebin.com/YnkUwvwV – Martin Ender – 2016-08-22T07:35:10.197

@MartinEnder Much gratitude, these are all very good suggestions! (Note to self: avoid naming things if possible, otherwise do the assignment at (rather than before) the first occurrence.) – for Monica – 2016-08-22T08:09:39.847

I don't have time to figure it out completely right now, but here is an idea to avoid the Image, ImageResize, ImageData stuff. This bit blows up an array by a factor of 2: #&@@{##&@@{#,#}&//@x} where x is the array. So if you do store the initial 8x8 grid in a variable x, and then do x=#&@@{##&@@{#,#}&//@x} after each use, you can generate the successive tiles quite easily. – Martin Ender – 2016-08-22T08:27:12.887

Whoops, that's 4 bytes longer than it needs to be: #&[##&[#,#]&//@x] – Martin Ender – 2016-08-22T08:30:15.663

Hm, I'm not getting this to work yet, but you can save some more by a) using ##~Join~2 and b) f={g,a=##&[G,G,G],a,g} and then replace every further occurrence of G,G,G with a as well. – Martin Ender – 2016-08-22T11:54:59.760

@MartinEnder a) While Join[##,2]& and ##~Join~2& are the same, Image@Join[##,2]& and Image@##~Join~2& aren't, as @ takes precedence over ~Join~. b) works fine, thanks. – for Monica – 2016-08-24T07:30:27.020

Ah sorry about the Join, I had made some other local changes, where I didn't pass it straight to Image@. – Martin Ender – 2016-08-24T07:33:16.123

4

Python 2.7: 424 412 405 376 357 Bytes

I'm a bit new to golfing.... here we go

from numpy import*
import PIL
def c(n,col):e=log2((col+8)/8)//1;r=2**e;t=2**(n-e-1);return tile(repeat(array([0x2df0777ca228b9c18447a6fb/3**i%3for i in range(64)],dtype=int8).reshape([8,8])[:,(col-(8*r-8))//r],r),t)
n=input();i=PIL.Image.fromarray(column_stack([c(n,col) for col in range(2**(n+3)-8)]),mode='P');i.putpalette('t\xc4`n\xaaZ'+' '*762);i.show()

ungolfed and length tested..

from numpy import*
import PIL

def c(n,col): #creates array for a given column
    s = array([0x2df0777ca228b9c18447a6fb/3**i%3for i in range(64)],dtype=int8).reshape([8,8]) #slime template (golfed inline)
    e=log2((col+8)/8)//1 #exponent for tiles and repititions
    r=2**e #number of repitions (scale factor)
    t=2**(n-e-1) #number of tiles (vertically)
    return tile(
            repeat(
             s[:,(col-(8*r-8))//r] #select appropriate column from template
              ,r) #repeat it r times
               ,t) #tile it t times

n = input()
arr = column_stack([c(n,col) for col in range(2**(n+3)-8)]) #create image array by stacking column function
i=PIL.Image.fromarray(arr,mode='P'); #colormap mode
i.putpalette('t\xc4`n\xaaZ'+' '*762); #set colormap
i.show()

s = r'''from numpy import*
import PIL
def c(n,col):e=log2((col+8)/8)//1;r=2**e;t=2**(n-e-1);return tile(repeat(array([0x2df0777ca228b9c18447a6fb/3**i%3for i in range(64)],dtype=int8).reshape([8,8])[:,(col-(8*r-8))//r],r),t)
n=input();i=PIL.Image.fromarray(column_stack([c(n,col) for col in range(2**(n+3)-8)]),mode='P');i.putpalette('t\xc4`n\xaaZ'+' '*762);i.show()'''

print len(s)

edit1: removed sys.argv[1] in favor of raw_input() to save extra import statement

edit2: shortened PIL import: removed from Image added PIL.

edit3: Thanks @Sherlock9 for the hex encode of the slime template

edit4: didn't need function def and used input() instead of raw_input()

Aaron

Posted 2016-08-20T17:46:47.277

Reputation: 1 213

any suggestions are more than welcome :) especially to shrink the template array – Aaron – 2016-08-22T20:40:34.753

Something like using '0000100001111110111211100111111102211220022112200111111000001000' (your array backwards) converted from base 3 to base 16 0x2df0777ca228b9c18447a6fb. With that number, use code like this [0x2df0777ca228b9c18447a6fb//3**i%3 for i in range(64)] to get your integers in the correct order. – Sherlock9 – 2016-08-27T08:48:54.490

Ah, in Python 2, [0x2df0777ca228b9c18447a6fb/3**i%3for i in range(64)] may be better. – Sherlock9 – 2016-08-27T09:02:43.613

Thanks @Sherlock9 being new to golfing, could you explain how this (I assume) change of base code works? – Aaron – 2016-08-30T13:01:03.803

First, I pretended that 00001000011111101112111001111111022112200221122001111110000‌​01000 is a base 3 integer (because there are 3 integers, 0, 1, and 2). The shortest way to represent a number this that Python will still recognize as an number is in hexadecimal, base 16. So, in this case, I converted from base 3 to base 16 to get 0x2df0777ca228b9c18447a6fb. – Sherlock9 – 2016-08-30T13:44:19.903

1

The second part is to get your array back from that number 0x2df0777ca228b9c18447a6fb. This is simple. For a simpler example, to get the 0th digit from 01221100, just divide by 3 0 times, and then take the last digit (using mod 3) to get 0. To take the 2nd digit, divide by 3 2 times, then mod 3 to get 1. The list comprehension just divides by 3 64 times to get your full array back. If you have any more questions, we can discuss them in the PPCG chat.

– Sherlock9 – 2016-08-30T13:48:57.523

1

R, 378 356 346 334 bytes

f=function(n){r=rep;k=r(0,4);m=r(1,6);L=c();for(i in 1:n)L=cbind(L,r(max(L,0)+2^(n-i):1,e=2^(i-1)));png(w=sum(w<-4*2^(1:n)),h=sum(h<-r(8,2^(n-1))));layout(L,w,h);for(i in 1:max(L)){par(mar=k);image(matrix(c(0,0,0,1,k,0,m,0,0,1,1,1,2,r(1,10),0,0,r(r(c(2,1,2,0),e=2),2),m,k,1,k),nr=8),col=c("#74C460","#6EAA5A",1),ax=F,an=F)};dev.off()}

Saves as a png file. Indented, with linefeeds:

f=function(n){
    r=rep
    k=r(0,4)
    m=r(1,6)
    L=c()
    for(i in 1:n)L=cbind(L,r(max(L,0)+2^(n-i):1,e=2^(i-1)))
    png(w=sum(w<-4*2^(1:n)),h=sum(h<-r(8,2^(n-1))))
    layout(L,w,h)
    for(i in 1:max(L)){
        par(mar=k)
        image(matrix(c(0,0,0,1,k,0,m,0,
                       0,1,1,1,2,r(1,10),0,
                       0,r(r(c(2,1,2,0),e=2),2),
                       m,k,1,k),
                     nr=8),
              col=c("#74C460","#6EAA5A",1),ax=F,an=F)
    }
    dev.off()
}

N=2: N=2
N=3: N=3
N=4: N=4

Some explanations:

Here's the matrix that's being plotted (0 represent lightgreen, 1 darkgreen and 2 black; the matrix is tilted because columns are the y-axis and rows the x-axis):

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]    0    0    0    1    0    0    0    0
[2,]    0    1    1    1    2    2    1    0
[3,]    0    1    1    1    2    2    1    0
[4,]    1    1    1    1    1    1    1    1
[5,]    0    1    2    1    1    1    1    0
[6,]    0    1    1    1    2    2    1    0
[7,]    0    1    1    1    2    2    1    0
[8,]    0    0    1    0    0    0    0    0

Each call to image plot that matrix (with each integer corresponding to a color). For N=4, here is L (the layout matrix, each unique number represents one single plot), w (the widths of the matrix columns) and h (the heights of the matrix rows):

> L
     [,1] [,2] [,3] [,4]
[1,]    8   12   14   15
[2,]    7   12   14   15
[3,]    6   11   14   15
[4,]    5   11   14   15
[5,]    4   10   13   15
[6,]    3   10   13   15
[7,]    2    9   13   15
[8,]    1    9   13   15
> w
[1]  8 16 32 64
> h
[1] 8 8 8 8 8 8 8 8

plannapus

Posted 2016-08-20T17:46:47.277

Reputation: 8 610