116
\$\begingroup\$

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.

\$\endgroup\$
6
  • 33
    \$\begingroup\$ I would upvote but I have no votes left. I'm leaving this comment so I'll remember to upvote tomorrow. \$\endgroup\$ Aug 20, 2016 at 17:55
  • 27
    \$\begingroup\$ I'm upvoting your comment because I've run out of upvotes too. \$\endgroup\$ Aug 20, 2016 at 18:13
  • 5
    \$\begingroup\$ "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? \$\endgroup\$
    – Caridorc
    Aug 21, 2016 at 11:06
  • 2
    \$\begingroup\$ @Caridorc Doubling in each direction? \$\endgroup\$
    – wizzwizz4
    Aug 21, 2016 at 14:51
  • \$\begingroup\$ @wizzwizz4 Yes, each pixel becomes 4, correct? \$\endgroup\$
    – Caridorc
    Aug 21, 2016 at 14:52

8 Answers 8

21
\$\begingroup\$

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
\$\endgroup\$
3
  • \$\begingroup\$ "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? \$\endgroup\$ Aug 22, 2016 at 10:04
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Luis Mendo
    Aug 22, 2016 at 11:14
  • 2
    \$\begingroup\$ I like how the code starts with a smiley that is holding back his tears because of the intense emotions this code makes him feel :"') \$\endgroup\$ Aug 22, 2016 at 13:07
15
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ 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) \$\endgroup\$
    – Tobia
    Aug 22, 2016 at 13:30
12
\$\begingroup\$

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.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ the colours seem slightly off in the image here. Did you perhaps screenshot with f.lux on? \$\endgroup\$
    – Jezzamon
    Aug 22, 2016 at 4:39
  • \$\begingroup\$ @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. \$\endgroup\$ Aug 22, 2016 at 9:22
  • \$\begingroup\$ @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. \$\endgroup\$ Aug 25, 2016 at 18:12
7
\$\begingroup\$

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.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ For some reason C answers are pretty elegant in my mind. \$\endgroup\$ Aug 22, 2016 at 23:31
7
\$\begingroup\$

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, #}] &
\$\endgroup\$
7
  • 1
    \$\begingroup\$ b=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: pastebin.com/YnkUwvwV \$\endgroup\$ Aug 22, 2016 at 7:35
  • \$\begingroup\$ @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.) \$\endgroup\$
    – user58632
    Aug 22, 2016 at 8:09
  • \$\begingroup\$ 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. \$\endgroup\$ Aug 22, 2016 at 8:27
  • \$\begingroup\$ Whoops, that's 4 bytes longer than it needs to be: #&[##&[#,#]&//@x] \$\endgroup\$ Aug 22, 2016 at 8:30
  • \$\begingroup\$ 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. \$\endgroup\$ Aug 22, 2016 at 11:54
5
\$\begingroup\$

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()

\$\endgroup\$
6
  • \$\begingroup\$ any suggestions are more than welcome :) especially to shrink the template array \$\endgroup\$
    – Aaron
    Aug 22, 2016 at 20:40
  • \$\begingroup\$ 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. \$\endgroup\$
    – Sherlock9
    Aug 27, 2016 at 8:48
  • \$\begingroup\$ Ah, in Python 2, [0x2df0777ca228b9c18447a6fb/3**i%3for i in range(64)] may be better. \$\endgroup\$
    – Sherlock9
    Aug 27, 2016 at 9:02
  • \$\begingroup\$ Thanks @Sherlock9 being new to golfing, could you explain how this (I assume) change of base code works? \$\endgroup\$
    – Aaron
    Aug 30, 2016 at 13:01
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Sherlock9
    Aug 30, 2016 at 13:48
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

Java 8, 512 bytes

import java.awt.*;n->new Frame(){{add(new Panel(){public void paint(Graphics g){for(int N=n,o=0,p=1,t,q,u;N-->0;o+=8*p,p*=2)for(t=(int)Math.pow(2,N);t-->0;g.setColor(new Color(116,196,96)),g.fillRect(o,q=u*t,u,u),g.setColor(new Color(110,170,90)),g.fillRect(p+o,p+q,6*p,6*p),g.fillRect(o,4*p+q,p,p),g.fillRect(3*p+o,q,p,p),g.fillRect(7*p+o,5*p+q,p,p),g.fillRect(3*p+o,7*p+q,p,p),g.setColor(Color.BLACK),g.fillRect(p+o,2*p+q,2*p,2*p),g.fillRect(5*p+o,2*p+q,2*p,2*p),g.fillRect(4*p+o,5*p+q,p,p))u=8*p;}});show();}}

Results for \$n=4,5,6\$:

enter image description here
enter image description here
enter image description here

Explanation:

import java.awt.*;       // Required import for almost everything
n->                      // Method with integer parameter and Frame return-type
  new Frame(){           //  Create the Frame
   {                     //   In an inner code-block:
     add(new Panel(){    //    Add a Panel we can draw on:
       public void paint(Graphics g){
                         //     Overwrite its paint method:
         for(int N=n,    //      Create a copy of the (effectively final) input
                 o=0,    //      Offset integer, starting at 0
                 p=1,    //      Power integer, starting at 1
                 t,      //      Inner loop integer, starting uninitialized
                 q,u;    //      Temp integers, starting uninitialized
             N-->0       //      Loop `N` in the range (`n`, 0]:
             ;           //        After every iteration:
              o+=8*p,    //         Increase the offset by 8 times the power
              p*=2)      //         And go to the next power by doubling it
           for(t=(int)Math.pow(2,N);
                         //       Set `t` to 2^`N`
               t-->0     //       Inner loop `t` in the range (2^`N`, 0]:
               ;         //         After every iteration:
                g.setColor(new Color(116,196,96)),
                         //          Set the color to the lighter green
                g.fillRect(o,q=u*t,u,u),
                         //          Draw the background rectangle,
                         //          and set `q` to `u*t` to save bytes
                g.setColor(new Color(110,170,90)),
                         //          Change the color to the darker green
                g.fillRect(p+o,p+q,6*p,6*p),
                         //          Draw the inner rectangle
                g.fillRect(o,4*p+q,p,p),
                         //          Draw the left dot
                g.fillRect(3*p+o,q,p,p),
                         //          Draw the top dot
                g.fillRect(7*p+o,5*p+q,p,p),
                         //          Draw the right dot
                g.fillRect(3*p+o,7*p+q,p,p),
                         //          Draw the bottom dot
                g.setColor(Color.BLACK),
                         //          Change the color to black
                g.fillRect(p+o,2*p+q,2*p,2*p),
                         //          Draw the left eye
                g.fillRect(5*p+o,2*p+q,2*p,2*p),
                         //          Draw the right eye
                g.fillRect(4*p+o,5*p+q,p,p))
                         //          Draw the mouth
             u=8*p;}});  //        Set `u` to `8*p` to save bytes
     show();}}           //    And afterwards show the Frame
\$\endgroup\$

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.