22
\$\begingroup\$

This challenge is in honor of the tacky Christmas lights at my in laws' house.


The challenge is to create a graphical output showing the decoration in "real time".

The video (gif or other format) will have n-by-m vertical and horizontal "lights". 5 <= m,n <= 40. The frame size and resolution may vary dependent on n and m, but must be at least 50x50 pixels for n,m=5 (vector graphics is OK). A picture with n=6 and m=5 will look something like this:

enter image description here


The decoration:

Colors:

All lights will have one of the following 6 RGB-colors {255,0,0}, {0,255,0}, {0,0,255}, {255,255,0}, {0,255,255} and {255,0,255}.

Animation:

  • n and m will be taken as input on any reasonable format and in the order you like
  • The image will change every dt = 25 ms. Deviations are OK if it's due to "outside factors" such as limitation in the interpreter, slow computer etc.
    • If it's impossible to set the time step manually, then the default time step is accepted.
  • All lights will be red ({255,0,0}) at t=0.
  • There's always a 5% chance that the first light (top-left) will change color. All colors (except the color it currently has) should be equally likely.
  • Each light (except the first) will get the color of the light to its left. If the light is at the far left then it will get the color of the light on the far right on the row above. The lights are numbered as shown below. Light number k will get the color of the light number k-1.

     1  2  3  4  5  6
     7  8  9 10 11 12
    13 14 15 16 17 18
    
  • The output should in theory run for ever (unless your language / interpreter has some limitation that prevents this).

  • Please provide a sample of at least 5 seconds, preferably more in the answer (this is an encouragement, not a requirement). (A link to TIO or similar is of course OK too :D )
  • Frames, axes, grid lines etc are accepted.

6-by-5

enter image description here

15-by-30

enter image description here

\$\endgroup\$
  • \$\begingroup\$ If the interpreter is slow, should be adjust the pause time so the total time between image updates is similar to that in the examples? What about if the pause is not needed (the code is already slowe enough)? That would save bytes, maybe against the spirit of the challenge \$\endgroup\$ – Luis Mendo Dec 29 '16 at 19:59
  • 1
    \$\begingroup\$ Since you picked the colors for ease of implementation--in languages like QBasic that have a limited builtin set of colors, is it acceptable to use the closest available colors to the ones you specified? (Red, green, blue, yellow, cyan, magenta) \$\endgroup\$ – DLosc Dec 29 '16 at 21:04
  • \$\begingroup\$ If it's impossible to use the specified colours then yes, it's ok to use the closest alternatives. If it's just a bit longer then no. r,g,y,b, etc are shorter in several languages. \$\endgroup\$ – Stewie Griffin Dec 29 '16 at 21:46
  • \$\begingroup\$ @LuisMendo, apologies for the late reply. I like the way you did it in your answer. It would be OK to use 25 ms, even if that would make the animation slower. I avoided drawnow when I implemented this in MATLAB, since the result was too slow. I think the answer must be: If it's a design choice that the interpreter has a fixed minimum time resolution of >=25 ms then it's OK. If it's due to poor/simple implementation, an online interpreter that is overloaded/slow etc. then it's not OK. \$\endgroup\$ – Stewie Griffin Dec 30 '16 at 14:54
  • 1
    \$\begingroup\$ @Stewie Got it, thanks. And nice challenge! \$\endgroup\$ – Luis Mendo Dec 30 '16 at 15:04
6
\$\begingroup\$

JavaScript/CSS/HTML, 436 bytes

b="red"
f=_=>{o.textContent='';o.style.width=w.value*10+"px";o.style.height=h.value*10+"px"}
setInterval(_=>o.insertBefore(document.createElement("s"),o.firstChild).style.background=b=["red","yellow","lime","aqua","blue","fuchsia"][Math.random()*100|0]||b,25)
#o{overflow:hidden;background:red}s{display:block;float:left;width:10px;height:10px}
<div oninput=f()><input id=h type=number min=1><input id=w type=number min=1></div><div id=o>

\$\endgroup\$
6
\$\begingroup\$

Mathematica, 186 161 158 bytes

(b=Table[{1,0,0},1##];Dynamic@Image[Partition[Pause@.025;If[Random[]<.06,b[[1]]={1,1,0,0}~RandomSample~3];b=RotateRight@b;b[[1]]=b[[2]];b,#],ImageSize->50#])&

Explanation

b=Table[{1,0,0},1##];

Create the initial board in 1D, filled with red. Store that in b.

Pause@.025

Pause for 25ms

If[Random[]<.06,b[[1]]={1,1,0,0}~RandomSample~3]

If a (pseudo-)random real number is less than 0.06, replace the first element of b with a random sample length 3 of the list {1,1,0,0}. (i.e. any one of {1, 1, 0}, {1, 0, 1}, {1, 0, 0}, {0, 1, 1}, {0, 1, 0}, {0, 0, 1})

b=RotateRight@b

Cyclic rotate right.

b[[1]]=b[[2]]

Change the first cell value to the second cell value (i.e. undo the shift of the first cell)

Partition[ ... ;b,#]

Partition b into (height).

Dynamic@Image[ ... ,ImageSize->50#]

Make that into a dynamic (constantly updating) image, whose width is 50(width)

Cellular automaton version (186 bytes)

(b=Table[{1,0,0},1##];Dynamic@Image[Partition[Pause@.025;If[Random[]<.06,b[[1]]={1,1,0,0}~RandomSample~3];i=2;b={#[[2-Boole[i--<0],2]]&,{},{1,1}}~CellularAutomaton~b,#],ImageSize->50#])&

Sample Output (inputs: 16, 10)

enter image description here

\$\endgroup\$
6
\$\begingroup\$

MATLAB, 255 210 bytes

This is my first golf, so there are probably improvements to be made.

Thanks to Luis for helping me save 45 bytes :)

function f(n,m)
c=dec2bin(1:6)-48;r=1;p=c(r,:);x=zeros(1,n*m,3);x(:,:,1)=1;while 1
x=circshift(x,[0,1,0]);if rand>0.94;r=randi(6);end
x(1,1,:) = c(r,:);imagesc(permute(reshape(x,n,m,3),[2 1 3]));pause(1/40);end

Explanation:

c=dec2bin(1:6)-48  % c is the colormap
r=1;p=c(r,:);                % p is color number r (starting at 1) from the colormap c
x=zeros(1,n*m,3);x(:,:,1)=1; % 2D matrix in the third dimension. The first layer is 1
while 1                      % while true
x=circshift(x,[0,1,0]);      % shift the vector horizontally along the second dimension
if rand()>0.94;              % 5 percent chance of changing color
k=randperm(6);k=k(k~=r);r=k(1); % Create a vector with color numbers 1..6. Discard the current color, and choose the first color
x(1,1,:) = c(r,:);           % The first light gets color number r
imagesc(permute(reshape(x,n,m,3),[2 1 3]));  % Reshape the vector so that it's a 3D matrix
% Permute it so that the dimensions are correct
% Use imagesc to display
pause(1/40)  % 0.025 seconds pause

Unfortunately, this doesn't save the animation, it just runs it. In order to save it I either need a screen capture program, or rewrite it all using imwrite. Instead, I'll provide two pictures showing different times, for n=15,m=30.

enter image description here

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Some golfing suggestions: dec2bin([4 2 1 6 3 5])-48 instead of [1 0 0;0 1 0;0 0 1;1 1 0; 0 1 1;1 0 1]. .95 instead of 0.95. You can also replace .95 by .94 and get rid of k=k(k~=r); (because 0.94 + 0.06/6 = 0.95; see my answer for a more detailed explanation) \$\endgroup\$ – Luis Mendo Dec 29 '16 at 22:14
  • 1
    \$\begingroup\$ Better yet, c=dec2bin(1:6)-48, as order doesn't matter \$\endgroup\$ – Luis Mendo Dec 30 '16 at 0:40
  • \$\begingroup\$ Nice first answer! However, I'm afraid I have outgolfed you by 40%. \$\endgroup\$ – Sanchises Jan 1 '17 at 17:36
  • \$\begingroup\$ Golfed it down a bit :) Thanks for the help Luis. ! :) Well done Sanchises! \$\endgroup\$ – Chelsea G. Jan 2 '17 at 12:09
4
\$\begingroup\$

MATL, 52 47 bytes

6:BoHZGKipY"`tGe!2YG50Yr3>?t1)}6Yr]0(1YS.015Y.T

Input is an array [ncols nrows]. Output is a figure with vector graphics.

Example run for 15 cols × 10 rows:

enter image description here

How it works

Pause time has been set to 15 ms (for the same byte count as 25 ms) to try compensate for the processing time.

To keep the color with 19/20 probability (change it with 1/20), we proceed as follows:

  • With 47/50 probability we keep the color.
  • With 3/50 probability we pick a new color choosen uniformly among the 6 colors. It may happen that the "new" color is the same as the old, and this occurs with probability 1/6.

Thus the probability of keeping the color is 47/50 + 3/(50*6) = 19/20.

6:        % Push [1 2 3 4 5 6]
B         % Convert to binary. This gives a 6×3 matrix, where each row 
          % corresponds to a number. First row is [0 0 1] (blue), second is
          % [0 1 0] (green), etc
o         % Convert to double
HZG       % Set as colormap (creates a figure)
K         % Push 4
i         % Take input array
p         % Product of array. This gives the total number of squares
Y"        % Repeat 4 that many times. This gives a row vector representing the
          % image. The initial value, 4, corresponds to red in the colormap
`         % Do...while
  t       %   Duplicate
  Ge      %   Reshape to size given by the input. Gives a matrix where each
          %   entry  will be interpreted as a pointer to the colormap
  !       %   Transpose. This is required because the color shifting will be
          %   done in column-major order: down, then across; whereas we want
          %   the opposite
  2YG     %   Show matrix as image using the defined colormap
  50Yr    %   Push a uniformly distributed random integer between 1 and 50
  3>      %   True if greater than 3. This happens with probability 47/50
  ?       %   If true
    t1)   %     Duplicate and get first entry (to repeat the first color)
  }       %   Else
    6Yr   %     Push a uniformly distributed random integer between 1 and 6.
          %     This is the new color (possibly the same as the old)
  ]       %   End
  0(      %   Assign that color (repeated or new) to the last entry of the row
          %   vector representing the image
  1YS     %   Circularly shift to the right. The last value becomes the first
 .015Y.   %   Pause 0.015 ms
 T        %   Push true
          % End (implicit). Since the top of the stack is true, this creates
          % an infinite loop
\$\endgroup\$
3
\$\begingroup\$

MATLAB, 153 147 bytes

Note: The GIF shown is of the older version, which is nice as it does not display axes (see edit history), but was extremely slow due to the implementation of imshow. For the current version, Chelsea G.'s MATLAB answer or Luis Mendo's MATL answer show the same result as my current version.

Size is taken as a 2x1 vector, so call as e.g.:

>> l([5 5])

function l(s)
c=eye(3);x=eye(s);while 1
a=rand>.94;x=[a*randi(6)+~a*x(1),x(1:end-1)];imagesc(reshape(x,s)',[1,6]);colormap([c;1-c])
pause(.025)
end

This answer exploits the subtleties of the MATLAB language. For example, x is initalized as an m x n zero matrix, but so-called linear indexing allows for circular shifting with 1-dimensional indices. Weak typing allows for multiplication with logicals, so that if statements are avoided (a trick I heavily used back in the days of programming on a TI-84 calculator). Even though a colormap is read row-wise, MATLAB treats it as a normal matrix, so that eye(3) can be used to create red, green and blue, and 1-eye(3) the other three colours. A simple reshape brings the linear vector back into matrix form, which is mapped to the desired colours using ind2rgb. Finally, imagesc, shows the image, shown at default figure size (which is big enough for the requirements). As luck would have it, imagesc does not mind values being outside the specified range, so eye can be used to initialize the matrix since both 1 and 0 are considered red.

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Oops, forgot to upvote you... I love all your small tricks :-) \$\endgroup\$ – Chelsea G. Jan 4 '17 at 22:30
  • \$\begingroup\$ Is it correct that the random color never is red in the updated version? It appears that way in Octave at least (don't have MATLAB). \$\endgroup\$ – Stewie Griffin Mar 16 at 22:00
  • \$\begingroup\$ @StewieGriffin I must've been sleeping when I made this. You are of course perfectly right - and it saved me a byte as well... \$\endgroup\$ – Sanchises Mar 17 at 7:31
  • \$\begingroup\$ (make that two bytes) \$\endgroup\$ – Sanchises Mar 17 at 7:37
2
\$\begingroup\$

Python 3.6 (316 Bytes)

Using ANSI colour codes and the new formatted string literals of Python 3.6 (PEP 489) (the f"{X}" magic).

Otherwise it’s just pretty basic, but obfuscated python. Width and Height are passed as arguments on the command line.

import random as n,time,sys
r=range
X="\x1b["
C=[f"{X}1;4{x}m " for x in r(1,7)]
w,h=list(map(int,sys.argv[1:]))
a=[C[0]for i in r(w*h)]
while 1:
 print(f"{X}0m{X}2J{X}f");f=a[0];a.pop();a[:0]=n.choice([x for x in C if x!=f])if n.random()<=.05 else f,
 for i in r(0,h*w,w):print(*a[i:i+w],sep="")
 time.sleep(.025)

enter image description here

\$\endgroup\$
  • \$\begingroup\$ You can spare 6 bytes by using w,h=map(int,sys.argv[1:]), unpacking works with any iterable (of the right size), the call to list is superfluous. \$\endgroup\$ – Sebastian Riese Jul 19 '18 at 23:22
  • \$\begingroup\$ Another few byte down: "\x1b[" => "\33[" (using octal instead of hex escapes), then the X abbreviation and the format strings actually make it longer (and by getting rid of f"" you get compatibility with any python3). (this will bring it down to 301 bytes). \$\endgroup\$ – Sebastian Riese Jul 19 '18 at 23:28
  • \$\begingroup\$ Oops, you use {x} once ... but you still win with getting rid of X. \$\endgroup\$ – Sebastian Riese Jul 19 '18 at 23:32

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.