8
\$\begingroup\$

The Challenge

GIFs are the most common image format for animation, and are used pretty heavily in today's social media. For the purpose of this challenge, I'm going to redefine what a GIF can be. This challenge will require you to take in a 3D array containing some sort of representation of a 2D 'image' and iterate through them, displaying an animation. This animation can be done anywhere, in a GIF, in your console, in a GUI, etc; the delivery doesn't matter, so long as it is animated.

The Input

  • A 3D array where the data inside somehow represents a 2D image.
    • The array may contain RGB data, true/false data or anything else you see fit.
    • I'm also fine with you dumbing it down to a 2D array of strings or something similar, but the animation must be a 2D animation.
  • The time between each frame in a format of your choosing (Seconds, Milliseconds, etc...).
    • People have been asking me whether or not they HAVE to include the duration length. My answer is "meh", as long as you are able to show animation. I'm more concerned that you adhere to the "Array" parameter than this one, meaning no random animations.

The Output

  • A seamlessly iterated sequence of output that looks like a 2D animation with the correct delay on each transition based on the value input.

The Rules

  • Output can be, but is not limited to:
    • GIF image.
    • GUI animation (my example).
    • In-console animation.
    • Honestly, any "animation" that you see fit, as long as it follows the below rules.
  • When outputting your image you must clear the console before showing the next frame, you cannot just print them sequentially.
    • Emulating a console "clear" is also acceptable, as long as it looks like a seamless animation (see the hint under my example for more information on what I mean).
  • Regardless of implementation, your animation should loop forever, or until stopped.
    • The "looping" can be as simple as while(true){} or infinite recursion, you may assume the user wants to view this masterpiece until they hit "ctrl+c".
  • You must be able to handle any size 2D 'images', if your language is limited by buffer sizes, this is acceptable and you may state this in your explanation.
  • Standard loopholes are disallowed.

Example I/O

Input (3D Array, Delay)

f([
  [[1,0,0],
   [0,0,0],
   [0,0,0]],
  [[0,0,0],
   [0,1,0],
   [0,0,0]],
  [[0,0,0],
   [0,0,0],
   [0,0,1]],
], 1)

Output (Example, 2020 Bytes - Java)

import javax.swing.JFrame;
import javax.swing.JTextArea;

/**
 * Simple GIF class to animate a 3D integer array in a swing text area.
 * (Clearing the console in java isn't something you really do, so I chose
 * java on purpose to make it an extremely ungolf-able answer that someone
 * wouldn't bother to steal).
 */
public class Gif implements Runnable {
    /**
     * The output area.
     */
    private final JTextArea area;

    /**
     * The list of images.
     */
    private final int[][][] images;

    /**
     * The delay between image transitions.
     */
    private final long transitionDelay;

    /**
     * Main method, instantiates a GIF object and runs it.
     * @param args Does absolutely nothing.
     */
    public static void main(String[] args) {
        final int[][][] images = {{{1,0,0},{0,0,0},{0,0,0}},{{0,0,0},{0,1,0},{0,0,0}},{{0,0,0},{0,0,0},{0,0,1}}};
        final long transitionDelay = 1000L;
        new Thread(new Gif(images, transitionDelay)).start();
    }

    /**
     * Constructor for a GIF, takes in a 3D array of images and a transition
     * delay to wait between transitioning the images.
     * @param images The list of images.
     * @param delay The delay between each image.
     */
    public Gif(int[][][] images, long transitionDelay) {
        this.images = images;
        this.transitionDelay = transitionDelay;
        this.area = new JTextArea();
        final JFrame frame = new JFrame("It's a GIF!");
        frame.setSize(10,100);
        frame.add(area);
        frame.setVisible(true);
    }

    /**
     * When run, it will alter the area to imitate an animated GIF.
     */
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < images.length; i++) {
                final StringBuffer frame = new StringBuffer();
                for (int j = 0; j < images[i].length; j++) {
                    for (int k = 0; k < images[i][j].length; k++) {
                        frame.append("" + images[i][j][k]);
                    }
                    frame.append("\n");
                }
                this.area.setText(frame.toString());
                try{Thread.sleep(transitionDelay);}catch(Exception e){}
                this.area.setText("");
            }
        }
    }
}

This results in a swing GUI popping up, animating the array:

Frame One Frame Two Frame Three

HINT HINT: Use a language where console clearing is possible, or specify why what you are doing will end up with a result that looks like an animation in the language you chose. I think some languages have default buffer sizes on their consoles, you may use this to your advantage, but I expect an explanation or example. Just because I output my animation as a string, you don't have to; I could've just as easily used 0 for black and 1 for white and made a real GIF.

Judging

This is code-golf, lowest byte count wins (inputs excluded).
I'll +1 anyone who uses a language in a cool or unexpected way as well.

\$\endgroup\$
9
  • \$\begingroup\$ How many lines long does the "clear" have to be? Can it be the same as the number of characters per line? \$\endgroup\$
    – Riley
    Sep 14, 2016 at 21:29
  • \$\begingroup\$ Similar challenge with more strict input: codegolf.stackexchange.com/questions/27101/… \$\endgroup\$ Sep 15, 2016 at 1:54
  • \$\begingroup\$ @Riley I'm not sure I get what you're asking. The clear is essentially to keep the output on the same line; your code may not actually "clear" anything, but replace in line as well. I don't care how you accomplish the animation, more that it essentially functions using frames. \$\endgroup\$ Sep 15, 2016 at 12:07
  • \$\begingroup\$ @luserdroog I hadn't seen that one, but I also saw one on "create a snowscene" as well, but I don't see either as close enough to warrant not posting this. \$\endgroup\$ Sep 15, 2016 at 12:08
  • 1
    \$\begingroup\$ @carusocomputing No worries, more than happy to do the grammar check. By the way, in terms of what language is used for the animation, does it matter if it's one no longer in popular use? \$\endgroup\$
    – Monomeeth
    Sep 15, 2016 at 19:05

7 Answers 7

3
\$\begingroup\$

MATL, 16 12 11 bytes

`G@)D1Y.XxT

Input is a cell array of 2D. For example:

{[1 0 0; 0 0 0; 0 0 0] [0 0 0; 0 1 0; 0 0 0] [0 0 0; 0 0 0; 0 0 1]}

The pause time is the 1 in the code. It can be changed to any real number, such as .5 or `.2 .

Try it at MATL Online! (If it doesn't work, refresh the page and press "Run" again.)

The input can also be a cell array of 2D char arrays. For example:

{['x...';'+...';'....';'....'] ['+x..';'....';'....';'....'] ['.+x.';'....';'....';'....'] ['..+x';'....';'....';'....'] ['...+';'...x';'....';'....'] ['....';'...+';'...x';'....'] ['....';'....';'...+';'...x'] ['....';'....';'....';'..x+'] ['....';'....';'....';'.x+.'] ['....';'....';'....';'x+..'] ['....';'....';'x...';'+...'] ['....';'x...';'+...';'....']}

Try this one too!

Explanation

`       % Do...while
  G     %   Push input: cell array
  @     %   Push iteration index
  )     %   Index to obtain that cell. This uses modular indexing,
        %   so each cell is addressed cyclically
  D     %   Display
  1     %   Push 1: number of seconds to pause
  Y.    %   Pause for that many seconds
  Xx    %   Clear screen
  T     %   True. This is used as loop condition: infinite loop
        % End. Implicitly end do...while loop  
\$\endgroup\$
8
  • 1
    \$\begingroup\$ Can you save a few bytes using my trick? Filling the matrix with [0.2 0 0.2;0 0.2 0] ... , and thus reduce xx to x, and avoid 1G and 2G? I believe it adheres to the rules. You need to add a few bytes in order to convert 0.2 to 1, unless you want 0.2 to jump around of course, and some way to store the pausing value. I still think it could reduce the byte count though :) \$\endgroup\$ Sep 15, 2016 at 6:16
  • 1
    \$\begingroup\$ @Weeingitfirst Thanks! Well, the challenge specifies two inputs: the array and the pause, so I think both are needed. Let's wait for confirmation anyway \$\endgroup\$
    – Luis Mendo
    Sep 15, 2016 at 7:10
  • 2
    \$\begingroup\$ Wow. You followed the brief perfectly, even adhering to the inputs. This is a very impressive answer. Definitely will be hard to beat, and compared to answers that didn't include pause duration, this is basically flawless, bravo. \$\endgroup\$ Sep 15, 2016 at 11:57
  • 1
    \$\begingroup\$ @carusocomputing Great! Thanks for letting me know. 4 bytes off! The duration can still be changed, it's pretty obvious in the code \$\endgroup\$
    – Luis Mendo
    Sep 15, 2016 at 14:00
  • 1
    \$\begingroup\$ I'm going to be honest, I doubt this is going to be beat, so until further submissions I'm marking this as best answer. \$\endgroup\$ Sep 20, 2016 at 15:44
2
\$\begingroup\$

Octave, 56 54 47 bytes

Removed the possibility to input the pausing time as part of the input matrix. I was very satisfied with it, so have a look in the edit history if you want to have a look. This solution is 7 bytes shorter.

n=input('');while(any(n=~n))spy(n);pause(1);end

n=input('');  % Takes input as a matrix of zeros and ones

k=n(1);       % maximum of the input matrix is the desired pause time. Have to store
              % this, because n is soon to be messed with
              % NOTE: k=n(1); is not needed anymore, since the pause time can be hardcoded!

any(n=~n)     % Check if there are any truthy values in `n` (there is), and at the 
              % same time negate it, thus creating a matrix where all elements
              % alternates between 1 and 0.
while(any(n=~n))   % Loop as long as there are any non-zero elements (always some)
spy(n)        % Create a spy-plot where all non-zero elements are shown as a dot
pause(1)      % Pauses for k seconds
end           % ends the loop (will never happen, since it's infinite).

The input will be something like this: [4 0 0 4;0 4 4 0;4 0 0 0], where this will be a matrix of dimensions 3x4, and the desired pause time is 4 seconds.

It displays a plot like the one below, but alternates between showing the true and the false values of the input. So all the blue dots will become white in the next iteration, and all the white will become blue.

In the below plot, I used the input rand(10,10)>0.6*2. This means it will have dimensions 10x10, and all elements of the random matrix that are larger than 0.6 will be true. After that I multiply it by the desired pausing time, 2 seconds. I used a random matrix here, but I could have created the matrix manually too.

I don't have Octave installed on this computer, so I made a minor alteration to make this work in MATLAB. It's the exact same principle, but n=~n doesn't work in MATLAB.

enter image description here

enter image description here

\$\endgroup\$
4
  • 2
    \$\begingroup\$ @carusocomputing, do I have to take the pausing time as input, or can I choose it myself? For instance always have 1 seconds? \$\endgroup\$ Sep 15, 2016 at 6:20
  • 1
    \$\begingroup\$ @carusocomputing, also: Is it OK to let the user choose the pause time, but don't have it as a separate parameter? In my not so humble opinion, this qualifies as: "a cool or unexpected way" ;-) \$\endgroup\$ Sep 15, 2016 at 8:45
  • 1
    \$\begingroup\$ Yeah, I agree completely, this qualifies; as long as you are allowing the user to specify some parameter of input, and it is not entirely randomized, I think it's fine. The whole point of the pausing was to be able to see the animation. I didn't want any for loops where people state, "well, you can't see it, but it's definitely animating." \$\endgroup\$ Sep 15, 2016 at 11:54
  • 1
    \$\begingroup\$ Also, I liked both of your ideas; the "TV Static Generator" was a very unique implementation, using randomization, which I didn't even consider. This is also impressive in that you managed to take the first iteration and adhere closer to the brief. Great job man. \$\endgroup\$ Sep 15, 2016 at 11:58
2
\$\begingroup\$

sed 141 134 90

-51 thanks to seshoumara

/^$/!{H;d}
:;/^$/g;s,^\n,,;s,$, ,;s,^,\d27[2J,p
:p;P;s,[^\n]*\n,,;/^ \n/!bp;N;s,[ \n]*,,;b

Input: First takes each frame separated by a line with a single space then display the next frame after each blank line is received (looks like a flipbook). Minimum 3 frames.

By default on my system (Windows 7) when I open cygwin it have 24 lines vertically. Between frames, there are always at least that many blank lines printed. This effectively clears the screen.

Over 1/3 of the bytes come from clearing the console. I'm sure there's a better way.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ You can reduce 1 byte by having the first p command as part of s///p, plus 6 bytes more by removing /^\n/! before P, which I think is not needed. For the effort, +1, though I'm also sure there's a better way. \$\endgroup\$
    – seshoumara
    Sep 19, 2016 at 3:09
  • 1
    \$\begingroup\$ After some time browsing the internet, I found a simple way to manipulate the terminal's cursor, thus also clearing a screen: using ANSI Escape Sequences. The mechanism is also used to print text in colors. Please see my answer for details and an example usage. I don't know if they work on cygwin, but you can try. \$\endgroup\$
    – seshoumara
    Sep 19, 2016 at 10:51
  • \$\begingroup\$ @seshoumara It works in cygwin when it comes from sed, but for some reason it doesn't work with cat or echo. \$\endgroup\$
    – Riley
    Sep 19, 2016 at 14:47
  • \$\begingroup\$ Try echo -e "\e[2Jtest". With cat the escape character must already be in the file/input, try echo -e "\e[2Jtest"|cat -n and scroll up. \$\endgroup\$
    – seshoumara
    Sep 19, 2016 at 17:02
  • \$\begingroup\$ @seshoumara I knew it had to be something like that. thanks! \$\endgroup\$
    – Riley
    Sep 19, 2016 at 17:03
2
\$\begingroup\$

GNU sed, 88 84 + 1(n flag) = 85 bytes

Edit: 3 bytes less thanks to Riley

H;1h;${:
g;s:\n.*::;H;x;s:[^\n]*\n::;x;y:,:\n:;s:^:ESC[2J:;s:ESC:\d27:gp;esleep 1
b}

The input format is one animation frame per line. For multiple output lines in a frame, use comma as separator. Because I run the program in a Linux console, the maximum image size available (measured in rows and columns) is dependent on the size of the terminal window. The pause between two frames is accomplished by the sleep shell command; to get a faster animation call esleep 0.4 (seconds).

100,000,000            # The timer could be read from the input as well, but that
000,010,000            #would require a lot more bytes and I understand I'm allowed
000,000,001            #to hardcode the value.

The best part is that I support color animation! To do this, I used the so called ANSI Escape Sequences to control the text font, foreground and background color, plus the position of the cursor, thus being able to clear the screen before each frame (code ESC[2J). To add color information, use the following format in the input, which is better explained here.

ESC[$FORMATm$textESC[0m     # 'ESC' is an actual string, it is then replaced
                            #in sed by the character with the ASCII value 27

Run:

sed -nf animate.sed input.txt

Examples: for each test, 2 animation cycles were screen-captured and saved in image GIF format (apologies for the low resolution)

0.4 seconds pause Happy birthday!

1 second by default "pixel" movement

Explanation:

H;1h                           # read each line/frame and store them in hold space
${:                            # when the input was read, start a loop
   g                           # copy hold space to pattern space
   s:\n.*::                    # remove all except the first/current frame
   H                           # append frame to hold space
   x;s:[^\n]*\n::;x            # delete first frame from hold space
   y:,:\n:                     # replace all commas with a newline
   s:^:ESC[2J:;s:ESC:\d27:gp   # use an ANSI Escape Sequence to clear the screen
                               #and print frame in color
   esleep 1                    # wait 1 second
b}                             # repeat
\$\endgroup\$
3
  • \$\begingroup\$ You could save a few bytes by replacing 1h;1d;H; with H;1h; \$\endgroup\$
    – Riley
    Sep 19, 2016 at 14:21
  • \$\begingroup\$ @Riley Thanks, I updated the code. \$\endgroup\$
    – seshoumara
    Sep 19, 2016 at 17:25
  • \$\begingroup\$ Wow, this was more in depth than a lot of the others, I like the color support and it's the only answer that does that :). Pretty unique use of newlines as well. +1 for color support and the uniqueness of the answer itself. I honestly wouldn't've believed it if I hadn't seen it myself! \$\endgroup\$ Sep 20, 2016 at 15:42
1
\$\begingroup\$

Ruby, 89 45 bytes

f=->h,t{h.cycle{|x|puts"^[[2J",x.map(&:join)}}

The ^[ is an escape character.

Hexdump:

00000000: 663d 2d3e 682c 747b 682e 6379 636c 657b  f=->h,t{h.cycle{
00000010: 7c78 7c70 7574 7322 1b5b 324a 222c 782e  |x|puts".[2J",x.
00000020: 6d61 7028 263a 6a6f 696e 297d 7d         map(&:join)}}

Saved a lot of bytes thanks to @Jordan

\$\endgroup\$
3
  • \$\begingroup\$ @DLosc Ah, yes, fixing \$\endgroup\$ Sep 14, 2016 at 22:07
  • \$\begingroup\$ You can save a lot of bytes here. ->h,t{h.cycle{|x|puts"^[[2J",x.map(&:join)}} \$\endgroup\$
    – Jordan
    Sep 14, 2016 at 22:32
  • \$\begingroup\$ Good answer, also as an FYI the brief was changed, you no longer have to adhere to the duration being an input, as this restricts the possible languages. You just need to pause so the animation is apparent. \$\endgroup\$ Sep 15, 2016 at 15:01
1
\$\begingroup\$

Lua(LÖVE), 296 287 bytes

c=0;f=1;t=10;l=love
function l.load()loadstring('i='..arg[2])()s=tonumber(arg[3])end
function l.update(d)if c>s then
c=0;f=f==#i and 1 or f+1
end;c=c+d;end
function l.draw()for K,V in pairs(i[f])do
for k,v in pairs(V)do if v>0 then l.graphics.rectangle('fill',k*t,K*t,t,t)end
end
end
end

Usage Example

love main.love '{{{1,0,0},{0,0,0},{0,0,0}},{{0,1,0},{0,0,0},{0,0,0}},{{0,0,1},{0,0,0},{0,0,0}},{{0,0,0},{0,0,1},{0,0,0}},{{0,0,0},{0,0,0},{0,0,1}},{{0,0,0},{0,0,0},{0,1,0}},{{0,0,0},{0,0,0},{1,0,0}},{{0,0,0},{1,0,0},{0,0,0}},{{1,0,0},{1,0,0},{0,0,0}},{{1,1,0},{1,0,0},{0,0,0}},{{1,1,1},{1,0,0},{0,0,0}},{{1,1,1},{1,0,1},{0,0,0}},{{1,1,1},{1,0,1},{0,0,1}},{{1,1,1},{1,0,1},{0,1,1}},{{1,1,1},{1,0,1},{1,1,1}},{{1,1,1},{1,1,1},{1,1,1}},{{0,0,0},{0,0,0},{0,0,0}}}' 1

Output : https://youtu.be/0kDhPbbyG9E

\$\endgroup\$
3
  • \$\begingroup\$ Hmm, I've not had much exposure to lua, I didn't know it had graphics support as well, but knew it had great performance. A very interesting and unexpected answer. This is probably the answer that is closest to allowing colored input based on the numbers passed. Also the first answer to not use ASCII, despite the high byte count, great job man +1 for uniqueness. \$\endgroup\$ Sep 15, 2016 at 12:14
  • 1
    \$\begingroup\$ @carusocomputing Thanks! LÖVE is a framework for making 2d games. You should check it out :-) \$\endgroup\$
    – Master_ex
    Sep 15, 2016 at 20:22
  • \$\begingroup\$ Oh man, really? Can you link me to some of your other work man? I would absolutely love to see it dude. \$\endgroup\$ Sep 15, 2016 at 21:19
1
\$\begingroup\$

SmallBasic, 167 bytes

As a parameter, define and set the global var i! Sadly, SmallBasic does not support parameters for own Sub-routines.

sub animate
for j=0 to Array.getItemCount(i)
for k=0 to Array.getItemCount(i[0])
TextWindow.writeLine(i[j][k])
endfor
Program.delay(9)
TextWindow.clear()
endfor
endsub
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.