14
\$\begingroup\$

The Task:

Given a .txt file with frames of ASCII art each separated by a \n (see this example if you are unclear) output a motion picture with frame with 1 frame per second.

Note that there is a trailing \n on the final frame.

Each frames dimensions will be:

  • X<80
  • Y<20

The Rules

  • The Previous frame must be cleared before the next is displayed, so just printing each frame onto the terminal isn't a valid answer.
  • New You can grab the file name however you want, either from it being stored in a variable or from sys args.
  • New The images must Loop indefinitely
  • This is code golf: smallest program wins.

Example

Input

0   0
0   0
00000
0   0
0   0

00000
0
00000
0   
00000

0   0
 0 0
  0
  0
  0

Output

Example Output

Un-golfed

import curses, time

stdscr = curses.initscr()

Frames = file.read(file('Frames.txt')).split('\n')
while True:
    y = 0
    for i in range(len(Frames)):
        stdscr.addstr(y,0,Frames[i])
        stdscr.refresh()
        y += 1
        if Frames[i] == '':
            y = 0
            stdscr.clear()
            time.sleep(1)
\$\endgroup\$
3
  • 5
    \$\begingroup\$ In languages that don't really support file handling (like JavaScript), is it also OK to put the input in a variable? \$\endgroup\$
    – ProgramFOX
    Commented May 17, 2014 at 15:46
  • 2
    \$\begingroup\$ @ProgramFOX I guess you can open the file in a browser and use document.body.innerText \$\endgroup\$
    – user12205
    Commented May 17, 2014 at 18:19
  • 3
    \$\begingroup\$ @ProgramFOX Make's it a little unfair, the file handling aspect adds many chars in most languages \$\endgroup\$ Commented May 17, 2014 at 23:41

15 Answers 15

10
\$\begingroup\$

Mathematica, 41 bytes

Import@f~StringSplit~"\n\n"~ListAnimate~1

Expects the file name to be stored in variable f.

This is the first time Mathematica's precedence rules for @ and .~.~. are exactly the way I need them.

Btw, this snippet could go horribly wrong if the file extension is anything else than .txt (because Mathematica will try to guess how to do the import based on that), but luckily that file ending is part of the challenge specification.

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

Bash, 82

IFS=
clear
for((;;)){
while read a;do
[ "$a" ]&&echo $a||(sleep 1;clear)
done<$1
}

Assumes the file name of the .txt file is provided as the first argument to the script.

Note that a trailing empty line must be present at the end of the .txt file for this to work.

Special thanks to @professorfish and @DigitalTrauma.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ isn't $IFS blank by default? also, use for ((;;)){ ... } instead of while :;do ... done \$\endgroup\$
    – user16402
    Commented May 18, 2014 at 20:19
  • \$\begingroup\$ @professorfish IFS by default is <space><tab><newline>. Need to set it to '' so that read can read multiple consecutive spaces, as in the last line of Y \$\endgroup\$
    – user12205
    Commented May 18, 2014 at 20:44
  • 1
    \$\begingroup\$ A couple of small reductions: IFS= and [ "$a" ] instead of [ -n "$a" ] \$\endgroup\$ Commented May 19, 2014 at 19:45
4
\$\begingroup\$

Ruby, 88 86 56 55 characters

$<.read.split($/*2).cycle{|i|system'cls';$><<i;sleep 1}

This program assumes the file name is given as the first argument.

Thanks a lot to Ventero for sharing great improvements!

Un-golfed:

$<.read.split($/*2).cycle{ |i|   # read file, split by two newlines, and loop
    system 'cls'   # clear screen
    $><<i   # print the current array item
    sleep 1   # sleep one second
}

This program reads the file, splits it into chunks, and prints each chunk separately after clearing the screen. cls only works on Windows. A variant with clear is 57 characters.

\$\endgroup\$
19
  • \$\begingroup\$ you can save a character or two, by using a line break instead of the first ; and omitting the parentheses when calling split. \$\endgroup\$ Commented May 17, 2014 at 17:55
  • 2
    \$\begingroup\$ That depends on how you configure your editor. :P I'm using almost exclusively Windows, but my Sublime is configured to use \n anyway. Also here on code golf no one will make you add another point to your score for each line break just because you are using Windows. ;) \$\endgroup\$ Commented May 17, 2014 at 18:07
  • 1
    \$\begingroup\$ $* is shorthand for ARGV, which would save two characters. In this case, you can save even more by using ARGF (or $<) though: a=$<.read.split"\n\n". a.size is also shorter than a.length. And since sleep returns its argument after returning, you can combine the last two statements in your loop into i+=sleep 1. \$\endgroup\$
    – Ventero
    Commented May 17, 2014 at 23:45
  • 1
    \$\begingroup\$ Actually, nevermind the last bit, you can completely eliminate i by using Array#cycle, which loops forever if no argument is given: a.cycle{|i|system"cls";$><<i;sleep 1}. And splitting at $/+$/ is another character shorter than "\n\n". \$\endgroup\$
    – Ventero
    Commented May 17, 2014 at 23:47
  • 1
    \$\begingroup\$ That also allows you to inline the definition of a: $<.read.split($/+$/).cycle{...} (Sorry about the triple comment, I always think of new improvements right after the comment edit period is over :) ) \$\endgroup\$
    – Ventero
    Commented May 17, 2014 at 23:54
2
\$\begingroup\$

Dyalog APL (64)

(Can't beat Mathematica this time. It seems to have a built-in for everything.)

{⎕ML←3⋄{⎕SM←1 1,⍨⊂⊃⍵⊂⍨~⍵∊⎕TC⋄⎕DL 1}¨M⊂⍨~(4/1)⍷⎕TC∊⍨M←80 ¯1⎕MAP⍵}

This is a function that takes the filename as its argument. It assumes the file is in Windows (\r\n) format.

Explanation:

  • ⎕ML←3: set migration level to 3 (allowing to be used as APL2's split feature)
  • M←80 ¯1⎕MAP⍵: read the file given by the right argument as an ASCII file, and store the contents in M.
  • M⊂⍨~(4/1)⍷⎕TC∊⍨M: find all occurrences of four consecutive terminal control characters, and split M on those. This gives each frame.
  • {...: for each of these...
    • ⊂⊃⍵⊂⍨~⍵∊⎕TC: split the argument (=one frame) on terminal control characters, and then turn the vector-of-vectors into a matrix (so it will display each line on a separate line, this is necessary because ⎕SM does not understand control characters.)
    • ⎕SM←1 1,⍨: then display it in the upper left of the ⎕SM window.
    • ⎕DL 1: and then wait for one second.
\$\endgroup\$
2
  • \$\begingroup\$ Ha, finally! And still my answer is not a lot shorter because the function names are just so damn long! :D \$\endgroup\$ Commented May 17, 2014 at 18:30
  • 1
    \$\begingroup\$ Someone needs to write a Mathematica preprocessor that maps every built in function to a Unicode character \$\endgroup\$ Commented May 17, 2014 at 20:54
2
\$\begingroup\$

Awk, 53

BEGIN{RS=RS RS}{system("clear")}1;{system("sleep 1")}


New rules:

Awk, 74

BEGIN{RS=z}{a[NR]=$0}END{while(!system("sleep 1;clear"))print a[i++%NR+1]}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ This only loops once, but it can be shortened to BEGIN{RS=z}{system("sleep 1;clear")}1 ... In awk, "" is special as RS meaning multiline records. To support the new rule of looping indefinitely, I have this so far: BEGIN{RS=z}END{for(;!system("sleep 1;clear");)print a[i++%NR+1]}{a[NR]=$0} at 74 characters. gawk supports changing ARGV so you can do BEGIN{RS=z}{system("sleep 1;clear");ARGV[ARGC++]=ARGV[ARGC-1]}1 at 63 characters. \$\endgroup\$
    – laindir
    Commented May 19, 2014 at 15:08
  • \$\begingroup\$ @laindir: Thanks, I can't come up with anything better. \$\endgroup\$
    – ephemient
    Commented May 19, 2014 at 16:23
1
\$\begingroup\$

Perl, 40

seek ARGV,0,!eof;sleep 1;system clear

run as

perl -p00 frames.pl < animation.txt

(i.e. animation file is read through STDIN). 3 bytes for p00 were added to count. It's 2 characters shorter i.e. 38 on Windows because of cls instead of clear. Or, to be portable:

seek ARGV,0,!eof;sleep 1;system$^O=~/Win/?cls:clear

Or, stretching rules a bit (and then 31+3=34):

seek ARGV,sleep(1)&`reset`,!eof
\$\endgroup\$
1
\$\begingroup\$

Rebol, 74

forever[foreach s split to-string read f"^/^/"[call"clear"print s wait 1]]


Expects the filename to be stored in variable f. Below is an ungolfed example:

f: %ascii-art.txt

forever [
    foreach s split to-string read f "^/^/" [
        call "clear"
        print s
        wait 1
    ]
]
\$\endgroup\$
1
\$\begingroup\$

Java, 678 characters(when golfed)

Of course with GUI, since doing stuff in console sucks with Java, especially if you want to clear the screen ...

import java.awt.Font;
import java.io.File;
import java.util.Scanner;

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

public class G extends JFrame
{
    static JTextArea b = new JTextArea();

    G()
    {
        setSize(170, 370);

        add(b);
        b.setFont(new Font(Font.MONOSPACED, 0, 50));
    }

    public static void main(final String[] args)
    {   
        new G().setVisible(true);
        new SwingWorker()
        {
            protected Void doInBackground()
            {
                for(;;)
                {
                    try(Scanner s = new Scanner(new File(args[0])))
                    {
                        String l = null;
                        while(s.hasNextLine())
                        {                           
                            if(l == null  || (l = s.nextLine()).isEmpty())
                            {
                                Thread.sleep(1000);
                                b.setText(l == null ? (l = s.nextLine()) + '\n' : null);
                            }
                            else
                                b.setText(b.getText() + l + '\n');
                        }
                    }
                    catch(Exception i){}
                }
            }
        }.execute();
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Just realized there were dimensions in the author's post, but I'm too lazy to change my code now. Won't win anyway :P \$\endgroup\$
    – Leo Pflug
    Commented May 19, 2014 at 14:05
1
\$\begingroup\$

Cobra - 163

class P
    def main
        while 1
            for i in File.readAllLines("t.txt")
                print i
                if i=="",.x
            .x
    def x
        Threading.Thread.sleep(1000)
        Console.clear
\$\endgroup\$
1
\$\begingroup\$

Python 117

Assumes the file name is stored in variable f.

import time,os
while 1:
 for i in file.read(file(f)).split('\n'):
  print i
  if i=='':time.sleep(1);os.system('cls')

Note: replace 'cls' with 'clear' if on a unix based system, adding 2 chrs.

ctl+C to quit

\$\endgroup\$
2
  • \$\begingroup\$ for i in F: s.addstr(y,0,i); ... if i=='': ... \$\endgroup\$
    – user12205
    Commented May 18, 2014 at 8:52
  • \$\begingroup\$ Use open(f).read() instead of file.read(file(f)), shorter by 4 bytes. \$\endgroup\$
    – user344
    Commented Jul 2, 2014 at 18:02
0
\$\begingroup\$

Groovy - 121 119 chars

Ported ProgramFOX's answer to Groovy 2.2.1. The "clear console" is weak.

edit: replaced recursive closure with simple while loop, which is shorter and no stack overflow

a=new File(args[0]).text.split "\n\n";i=0;p={println it};while(1){p a[i++%a.size()];Thread.sleep(1000);80.times{p ""}}

Ungolfed:

a = new File(args[0]).text.split "\n\n"
i = 0

p = { println it }

while(1) {
    p a[i++%a.size()]
    Thread.sleep(1000)
    80.times{p ""}
}
\$\endgroup\$
0
\$\begingroup\$

GNU sed, 32

1eclear
/^$/{
esleep 1;clear
d
}
\$\endgroup\$
0
\$\begingroup\$

Groovy, 81

This is a more groovy way:

new File(args[0]).text.split("\n\n").each{["cls"].execute();print it;sleep(1000)}

ungolfed

new File(args[0]).text.split("\n\n").each{
    ["cls"].execute()
    print it
    sleep(1000)
}
\$\endgroup\$
2
  • \$\begingroup\$ The command "cls" doesn't work on my Mac. Also, the requirements suggest that the motion picture loops. \$\endgroup\$ Commented May 17, 2014 at 22:02
  • 2
    \$\begingroup\$ @Michael Easter cls is for Windows I think... try clear \$\endgroup\$
    – user12205
    Commented May 18, 2014 at 8:47
0
\$\begingroup\$

C# 226

Why bother eh?

namespace System{class P{static void Main(){for(;;)foreach(var x in Text.RegularExpressions.Regex.Split(new IO.StreamReader("f.txt").ReadToEnd(),"\n\r\n")){Console.Clear();Console.WriteLine(x);Threading.Thread.Sleep(1000);}}}}

Un-golfed:

namespace System
{
    class P
    {
        static void Main()
        {
            for(;;)
            foreach (var x in Text.RegularExpressions.Regex.Split(new IO.StreamReader("f.txt").ReadToEnd(), "\n\r\n"))
            {
                Console.Clear();
                Console.WriteLine(x); 
                Threading.Thread.Sleep(1000);
            }
        }
    }
}

Or in LINQPAD (so C# can stay semi-competitive with uber shorthand langs :D)

C# LINQPAD - 134

for(;;)foreach(var x in Regex.Split(new StreamReader("f.txt").ReadToEnd(),"\n\r\n")){x.Dump();Thread.Sleep(1000);Util.ClearResults();}

I feel a bit dirty, but hey, this is code-golf.

\$\endgroup\$
0
\$\begingroup\$

SmileBASIC, 74 bytes

F=LOAD(F)@L
IF" "*!CSRX>F[I]THEN WAIT 60CLS
?F[I];
I=(I+1)MOD LEN(F)GOTO@L

F should be the file name

\$\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.