Text animation format Code Golf

18

2

Working with old files from DOS, I found an ancient text animation format, that specify how much time each frame must be shown in the screen. It's very simple:

F1W5F2W3

This example above indicates that Frame 1 must be shown for 5 units of time, and frame 2 for 3 units more. Now I want to convert it to:

1, 1, 1, 1, 1, 2, 2, 2

In the converted example below, frame 1 is repeated 5 times, and frame 2 three times.

Rules: The only allowed letters are F and W (and the lowercase counterparts, f and w). Numbers can go up to 255. Total input String with no more than 255 chars.

Other examples:

Input: F10W3F11W3F10W3F12W3

Output: 10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 12, 12

Input: f1w0f2w10

Output: 2, 2, 2, 2, 2, 2, 2, 2, 2, 2

Short code wins.

Edited - Accepted formats: Any answer containing the output and ignoring spaces. Ex: 1, 1, 2, 2 or [1,1,2,2] or (1,1,2,2). But NOT 1 1 2 2 or [1; 1; 2; 2] or [1 1 2 2].

Chaotic

Posted 2016-08-23T03:23:51.227

Reputation: 401

Question was closed 2016-09-01T12:03:25.760

7

Welcome to Programming Puzzles & Code Golf! Just so you know, bonuses in code golf are discouraged.

– Dennis – 2016-08-23T03:33:09.417

1Ok, thank you for the information. I have removed the bonus. – Chaotic – 2016-08-23T03:39:21.733

12

This might be a duplicate of this run-length decoding challenge.

– xnor – 2016-08-23T03:54:15.330

1Not a duplicate, because in the link above the numbers range from 1 to 9 only. This makes a big difference. – Chaotic – 2016-08-23T04:09:34.630

3Do we have to support upper and lower case? Or just one or the other? – James – 2016-08-23T04:59:54.603

2Would it be acceptable to output an extra comma at the end of the output? – James – 2016-08-23T06:13:30.183

Can the output be only comma separated I.e. 10,10,10 instead of 10, 10, 10? – TheLethalCoder – 2016-08-23T11:27:47.573

I don't see as a problem having spaces (or not) between commas. But it is not acceptable to output an extra comma at the end of the output (just for fairness with other competitors). – Chaotic – 2016-08-24T14:10:54.747

What output formats are accepted, exactly? [1, 1, 2, 2] as in some answers? [1 1 2 2]? [1; 1; 2; 2]? – Luis Mendo – 2016-08-25T18:31:38.013

@LuisMendo Edit made for this. – Chaotic – 2016-08-25T19:02:59.090

I don't think having multiple-digit numbers is enough of a difference to make this not a duplicate. It's a very minor change for most solutions, especially the regex-based ones. – Mego – 2016-09-01T06:58:32.570

Answers

2

Pyth, 13 bytes

smMcr7Xrz0Gd2

Test suite

This program uses one of my favorite tricks, mM, which maps the map function over a list. It is also uses a relic of Pyth's distant past, the r7 function, which splits a string on whitespace and evaluates the contents, which just so happens to be absolutely perfect for this challenge. Here's how it works, and each intermediate state:

smMcr7Xrz0Gd2     f1W5F2w3 

        z        "f1W5F2w3"       Implicit: z is the input.
       r 0       "f1w5f2w3"       Lowercase
      X   Gd     " 1 5 2 3"       Replace all lowercase letters (G) with spaces (d)
    r7           [1, 5, 2, 3]     Split on whitespace, eval each string.
   c        2    [[1, 5], [2, 3]] Split into groups of length 2
 mM                               Apply the map function to each pair
                 [[1, 1, 1, 1, 1], [2, 2, 2]]
s                                 Flatten
                 [1, 1, 1, 1, 1, 2, 2, 2]

isaacg

Posted 2016-08-23T03:23:51.227

Reputation: 39 268

15

Python 3, 57 bytes

lambda s:eval(s.upper().translate({70:'+[',87:']*'})[1:])

Turns a string like

f1w0f2w10

into a expression like

[1]*0+[2]*10

that it evaluated as code. This is done by turning the string uppercase, turning each f into +[ and each w into ]*, and removing the initial +. Thanks to Dennis for saving 7 bytes in Python 3 by using translate with a dictionary.

xnor

Posted 2016-08-23T03:23:51.227

Reputation: 115 687

3lambda s:eval(s.upper().translate({70:'+[',87:']*'})[1:]) saves 7 bytes in Python 3. – Dennis – 2016-08-23T04:51:27.047

@Dennis Thanks, I'd been trying to get that to work with a list, didn't think to use a dictionary. – xnor – 2016-08-23T04:52:47.457

3 bytes more to have it match the examples: eval(input().upper().translate({70:'+", ',87:'"*'})[1:])[2:] – Cees Timmerman – 2016-08-23T14:34:07.213

4

V, 25 bytes

Óá¨ä«©á¨ä«©/²a±, 
D@"hD

Try it online!

Here is a hexdump of the answer, which is encoded in latin1:

0000000: d3e1 a8e4 aba9 e1a8 e4ab a92f b261 b12c  .........../.a.,
0000010: 2016 1b0a 4440 2268 44                    ...D@"hD

Explanation:

<C-v> is byte 0x16 and <esc> is byte 0x1B. Since they are both unprintable, I am using this notation to refer to them.

Óá¨ä«©á¨ä«©/²a±, <C-v><esc>

This is a compressed regex, that basically transforms the input into V code. Here's what the buffer looks like after running this regex:

3a10, <esc>3a11, <esc>3a10, <esc>3a12, <esc>

Here's how that works:

3           "3 times:
 a    <esc> "Append the following text:
  10,       " '10, '

Running this in V (or its parent, vim) would create:

10, 10, 10, 

And then a similar command repeats for each element of the input.


So, after running this regex, we've got valid V code that will create the desired output. Thankfully, V can easily self-interpret, as long as the code is in a buffer. So, we run the following:

D      "Delete this line into the unnamed register
 @"    "Run the text in the unnamed register as V code

This is exactly what we want, but now the output has a trailing ,. So:

h      "Move one character to the left. Now we are on the second to last character
 D     "Delete until the end of the current line

James

Posted 2016-08-23T03:23:51.227

Reputation: 54 537

3

Pyth, 18 bytes

r_McvM:z"\d+"1 2 9

Try it online. Test suite.

PurkkaKoodari

Posted 2016-08-23T03:23:51.227

Reputation: 16 699

3

MATL, 22 bytes

t58<*cU2eZ}Y"&D32','XE

Try it online!

Explanation

t        % Implicitly input string, say 'F10W2F1W3'. Duplicate
58<      % Array that contains 1 for numeric chars, 0 otherwise: [0 1 1 0 1 0 1 0 1]
*        % Multiply element-wise. Converts chars to numeric code
c        % Cast to char. Gives the original string with letters replaced by char 0
U        % Interprets as a numeric array. So the string ' 10 2 4 3' (where spaces are
         % actually char 0) gives the array [10 2 4 3]
2e       % Reshapes into a 2-column array in column-major order: [10 4; 2 3]
Z}       % Split into rows: [10 4], [2 3]
Y"       % Run-length decoding: [10 10 4 4 4]. Implicitly display 
&D       % Get string representation, in the format '[10 10 4 4]'
32','XE  % Replace spaces by commas

Luis Mendo

Posted 2016-08-23T03:23:51.227

Reputation: 87 464

Where are the commas? ;-) – Chaotic – 2016-08-25T17:55:04.643

@Chaotic I thought the output format was flexible, as usual. I'll try to solve that later, I'm seeing this on the phone now – Luis Mendo – 2016-08-25T18:13:08.370

@Chaotic Solved (9 bytes!) – Luis Mendo – 2016-08-25T21:32:30.407

2

JavaScript ES6, 68 bytes

s=>s.replace(/F(\d+)W(\d+)/gi,(z,a,b)=>(f=n=>n&&f(n-1,alert(a)))(b))

Hopefully an alert box counts as a frame as I couldn't think of another way to count as a 'frame'.

Slightly modified version to try in-browser

t=function(s){s.replace(/F(\d+)W(\d+)/gi,function(z,a,b){(f=function(n){return n&&f(n-1,alert(a))})(b)})}

// Demo
document.getElementById('go').onclick=function(){
  document.getElementById('output').innerHTML = t(document.getElementById('input').value)
};
<div style="padding-left:5px;padding-right:5px;"><h2 style="font-family:sans-serif">Text Animation</h2><div><div  style="background-color:#EFEFEF;border-radius:4px;padding:10px;"><input placeholder="Input here..." style="resize:none;border:1px solid #DDD;" id="input"><button id='go'>Run!</button></div><br><div style="background-color:#EFEFEF;border-radius:4px;padding:10px;"><span style="font-family:sans-serif;">Output:</span><br><pre id="output" style="background-color:#DEDEDE;padding:1em;border-radius:2px;overflow-x:auto;"></pre></div></div></div>

Downgoat

Posted 2016-08-23T03:23:51.227

Reputation: 27 116

I don't think you need the F in the regex. – Jordan – 2016-08-23T04:47:18.663

Why are you using alert? As I understand the challenge, the output should be as a single list of frames. – DanTheMan – 2016-08-23T06:24:50.343

2

Perl, 28 bytes

27 bytes of code, plus 1 for the p flag in perl -pe '…':

s|f(\d+)w(\d+)|"$1
"x$2|gie

Output for F10W3F11W3F10W3F12W3:

10
10
10
11
11
11
10
10
10
12
12
12

Lynn

Posted 2016-08-23T03:23:51.227

Reputation: 55 648

2The handicap for -p is only 1 since you can run as perl -pe 'code' which is only 1 character longer than a plain perl -e 'code'. So you are actually at 28 bytes :-) – Ton Hospel – 2016-08-23T08:32:55.453

@TonHospel Scoring flags is so tricky. Thanks! – Lynn – 2016-08-23T10:09:43.267

2

Jelly, 18 (strict), 8 (relaxed) bytes

Strict input (any upper or lower) & strict output form of a flat list

Œl“wẋ”yṣ”fj“ð;ø”VḊ

How?

Œl“wẋ”yṣ”fj“ð;ø”VḊ - takes an input, example: F11w7f13W5F17w3f19W2
Œl                 - to lower case            f11w7f13w5f17w3f19w2
  “wẋ”             - make string "wẋ"
      y            - map "w":"ẋ"              f11ẋ7f13ẋ5f17ẋ3f19ẋ2
        ”f         - make string "f"
       s           - split on "f"             [,11ẋ7,13ẋ5,17ẋ3,19ẋ2]
           “ð;ø”   - make string "ð;ø"
          j        - join with "ð;ø"s         ð;ø11ẋ7ð;ø13ẋ5ð;ø17ẋ3ð;ø19ẋ2
                V  - eval Jelly code...
each ẋ will repeat left right times, e.g. 17ẋ3 yields [17,17,17]
; will concatenate,
ð will treat the last chain as a dyadic link (the first will yield 0 as there is no link)
ø will treat the last chain as a niladic link
- so the example evaluates to:
[0, 11, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, 17, 17, 17, 19, 19]
                 Ḋ - dequeue
[11, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, 17, 17, 17, 19, 19]

Test it at TryItOnline

Non-strict version: only lower input, returns smashed lists [a,a,...][b,b,..][...

“wẋfø”yv

How?

“wẋfø”yv - takes an input, example: f11w7f13w5f17w3f19w2
“wẋfø”   - make the string "wẋfø"
      y  - map "w":"ẋ";"f":"ø"      ø11ẋ7ø13ẋ5ø17ẋ3ø19ẋ2
       v - eval Jelly code left with input right (empty)
           this is a hack as V should work (I think)
           but by forcing no input the leading ø evaluates to nothing
evaluation is as above, but simply yields the ẋ lists in turn
- so the example evaluates to:
[11, 11, 11, 11, 11, 11, 11][13, 13, 13, 13, 13][17, 17, 17][19, 19]

Test it at TryItOnline

Jonathan Allan

Posted 2016-08-23T03:23:51.227

Reputation: 67 804

2

Perl 6, 30 bytes

{m:g/\d+/.map:{|(+$^f xx$^w)}}

Anonymous function (aka: lambda) which uses a regex match to pull out all the numbers.

I then map over this list, pulling out 2 items at a time using self-declared positional variables $^f and $^w. Self-declared positional variables are assigned alphabetically, so f and w works nicely.

The regex match actually produces a list of Match objects, so I use the + prefix operator to coerce f to an Int.

The map creates a list of f, w times. This would normally create a List-of-Lists, so I use the Slip prefix operator |. A Slip is a List sub-type that flattens into an outer list, ie. It slips a list into the surrounding list, so in the end we get a flat list.

Usage example: {m:g/\d+/.map:{|(+$^f xx $^w)}}('F1W5F2W3') returns (1, 1, 1, 1, 1, 2, 2, 2).

Here is the same function written as a full-blown named subroutine, with a more explicit definition.

sub f(Str $s) {
    ($s ~~ m:g/\d+/).map(-> $f, $w {
        slip( $f.Int xx $w )
    });
}

Joshua

Posted 2016-08-23T03:23:51.227

Reputation: 261

The space after xx isn't necessary. I would have used .comb(/\d+/), I will have to remember to try m:g/.../ in the future instead. – Brad Gilbert b2gills – 2016-08-23T16:48:34.713

My initial solution used comb! I realised the regex match syntax was slightly shorter so I edited my answer. The benefit of using comb is that you don't get Match objects, so no Int coercion necessary inside the map... However, I just Bench'd it and the regex is slightly faster.

– Joshua – 2016-08-23T16:52:42.810

2

05AB1E, 16 bytes

l'f¡vy'w¡`FDïˆ}\

Explanation

                   # implicit input
l                  # convert to lower case: 'f1w5f2w3'
 'f¡               # split on "f": ['','1w5','2w3']
    v              # for each: ex '1w5'
     y'w¡          # split on "w": ['1','5']
         `         # flatten: '5','1'
          FDïˆ}    # N times do; duplicate, convert to int, push to global array: [1,1,1,1,1] 
               \   # discard last copy
                   # implicitly print list at the end of the program

Try it online

Emigna

Posted 2016-08-23T03:23:51.227

Reputation: 50 798

1

R, 78 bytes

m=strsplit(scan(,""),"[FWfw]")[[1]][-1];cat(rep(m[c(T,F)],m[c(F,T)]),sep=", ") 

Credit for the rep(m[c(T,F)],m[c(F,T)]) bit goes to @flodel. Usage:

> m=strsplit(scan(,""),"[FWfw]")[[1]][-1];cat(rep(m[c(T,F)],m[c(F,T)]),sep=", ")
1: F10W3F11W3F10W3F12W3
2: 
Read 1 item
10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 12, 12
> m=strsplit(scan(,""),"[FWfw]")[[1]][-1];cat(rep(m[c(T,F)],m[c(F,T)]),sep=", ")
1: f1w0f2w10
2: 
Read 1 item
2, 2, 2, 2, 2, 2, 2, 2, 2, 2

plannapus

Posted 2016-08-23T03:23:51.227

Reputation: 8 610

Nice one ! I don't get the m[c(T,F)] part however... – Frédéric – 2016-08-23T11:00:32.970

1@Frédéric c(T,F) is the same as c(TRUE,FALSE). This vector will get recycled along the indexed vector, meaning in this case that it will be TRUE for each odd member and FALSE for each even member, meaning it will return every odd member of m. Similarly c(F,T) returns every even member. – plannapus – 2016-08-23T11:03:19.740

Credit for that particular bit of code goes to flodel. The linked challenge is very similar to this one.

– plannapus – 2016-08-23T11:05:31.957

1

Pyth, 18 bytes

r9m_sMdcR\Wtcr1Q\F

If you don't need to allow for both upper and lower case, you can take out the r1 for 16 bytes:

r9m_sMdcR\WtcQ\F

Try it online!

Explanation:

            c      split:
             r1Q    the uppercase of the input
                \F  on the letter "F"
           t       Remove the first result 
                       The first "F" in the notation has nothing in front of it,
                       so this removes the empty string that prefaces everything
       cR\W        Split each of the results on "W"
  m_               Reverse each of the splits so that the "W" part is first (how many repetitions, then what is to be repeated)  
    sMd            Cast everything within the splits to integers
r9                 Run length decode

Steven H.

Posted 2016-08-23T03:23:51.227

Reputation: 2 841

If the output format is flexible (and many other solutions assume so), you don't need to stringify or remove the opening/trailing braces which should save 3 chars. Also, why do you need to explicitly cast to integer? – Robert Fraser – 2016-08-23T09:09:27.577

Explicit cast to integer is to allow run length decoding (which doesn't work with strings as the "key"). I'll remove the stringification. – Steven H. – 2016-08-23T09:13:15.627

1

Perl, 32 bytes

29 bytes code + 3 for -n.

print"$1 "x$' while/(\d+)w/gi

Usage

cat text-animation.pl
print"$1 "x$' while/(\d+)w/gi
perl -n text-animation.pl <<< 'F1W5F2W3'
1 1 1 1 1 2 2 2

Perl, 29 bytes

26 bytes code + 3 for -n.

If no separator is required, this works:

print$1x$' while/(\d+)w/gi

Dom Hastings

Posted 2016-08-23T03:23:51.227

Reputation: 16 415

You can fix the separator issue at the cost of 1 byte: s%\d+w%say for($&+0)x$'%gie (needs -E or -M5.010 to activate say) – Ton Hospel – 2016-08-23T11:14:28.973

1

C#, 160 155 bytes

s=>{var r="";int i=1,j;var t=s.Split('f','F');while(i<t.Length){var u=t[i++].Split('w','W');for(j=0;j++<int.Parse(u[1]);)r+=u[0]+",";}return r.Trim(',');};

TheLethalCoder

Posted 2016-08-23T03:23:51.227

Reputation: 6 930

1

VBA, 162 bytes 147 bytes

Okay, this is only for fun since it's kinda hard to beat esoteric programming languages but I don't care too much about winning the challenge. I do enjoy solving the challenge, though. Here is my stab for this challenge:

Function F(a):b=Split(Replace(a,"F","W"),"W"):For i=1To Ubound(b)/2:c="":For j=1To b(2*i):c=c & b(2*i-1) & ",":Next:d=d & c:Next:F=Left(d,Len(d)-1)

Ungolfed the code:

Function F(a)

b = Split(Replace(a, "F", "W"), "W")

    For i = 1 To UBound(b) / 2
        c = ""
        For j = 1 To b(2 * i)
            c = c & b(2 * i - 1) & ","
        Next
        d = d & c
    Next

F = Left(d, Len(d) - 1)

End Function

Explanation:

  1. Substitute the letter F in the string input with W using VBA function Replace.
  2. Split the string result with delimited letter W into a 1D array.
  3. Looping through each element array where every odd element is replicated as many as its next element value (the nearest even element).
  4. Concatenate each of looping output.
  5. Truncate the output so that the trailing , is excluded.

Thanks Kevin Cruijssen for the advice.

Anastasiya-Romanova 秀

Posted 2016-08-23T03:23:51.227

Reputation: 1 673

I've never programmed in VBA, so correct me if I'm wrong, but isn't there a Replace in VBA which is shorter than Application.Substitute? So b=Split(Replace(a,"F","W"),"W") instead? – Kevin Cruijssen – 2016-08-23T13:14:16.127

@KevinCruijssen Ahh, you're correct. I didn't use it since it Excel function with 5 arguments, I forgot there is a VBA version of it. Edited. Spasibo. – Anastasiya-Romanova 秀 – 2016-08-23T13:30:41.203

1

Haskell, 68 bytes

p""=[]
p(_:b)|[(c,_:d)]<-reads b,[(e,f)]<-reads d=(c+0<$[1..e])++p f

Usage example: p "F1W5F2W3" -> [1,1,1,1,1,2,2,2].

reads takes a string and reads something from the front of it and returns a singleton list with a pair of the something and the rest of the string. The type system knows from the usage c+0 and [1..e] that the somethings must be numbers, so reads consumes all digits from the beginning of the string. The _ in the patterns match the letters F and W that we don't need otherwise.

nimi

Posted 2016-08-23T03:23:51.227

Reputation: 34 639

1

Clojure, 86 bytes

(fn[a](mapcat #(repeat(read-string(last %))(first %))(partition 2 (re-seq #"\d+" a))))

Depending on requirements, I could also drop "cat" from "mapcat".

Michael M

Posted 2016-08-23T03:23:51.227

Reputation: 101

0

PowerShell v2+, 67 bytes

($args[0]-replace'F','+,'-replace'W','*').trim('+')+'-join", "'|iex

Takes input $args[0] as a string, pumps it through two -replace statements to swap the F for a +, and the W for a *. Then .trims the errant initial + before concatenating -join with a ,<space>, and piping to iex to evaluate the resulting string into a new string. That's left on the pipeline, and output is implicit.

As an example, with input F1W5F2W3, after the -replaces, our string will be +,1*5+,2*3. After the .trim, it'll be ,1*5+,2*3. That's concatenated with the -join statement, like ,1*5+,2*3-join", ". The iex then evaluates that string by forming an array of 5 1s via the comma-operator, using array concatenation to add on an array of 3 2s, so we have an array like (1,1,1,1,1,2,2,2), which is then fed into -join to put the comma-space between the elements.

Since -replace is by default case-insensitive, it handles lowercase as well.

Test cases

PS C:\Tools\Scripts\golfing> .\text-animation-format.ps1 'F1W5F2W3'
1, 1, 1, 1, 1, 2, 2, 2

PS C:\Tools\Scripts\golfing> .\text-animation-format.ps1 'F10W3F11W3F10W3F12W3'
10, 10, 10, 11, 11, 11, 10, 10, 10, 12, 12, 12

PS C:\Tools\Scripts\golfing> .\text-animation-format.ps1 'f1w0f2w10'
2, 2, 2, 2, 2, 2, 2, 2, 2, 2

AdmBorkBork

Posted 2016-08-23T03:23:51.227

Reputation: 41 581

0

Retina, 51 bytes

Might be able to be golfed further, I'm not super familiar with Retina.

i`F(\d+)W(\d+)
$1_$2$*n
(?<=(\d+).*?)n
$1,
\d+_|,$

The trailing linefeed is significant.

Try it online!

Explanation:

The code consists of three replacement stages.

i`F(\d+)W(\d+)
$1_$2$*n

This replaces each group of FxWy into x_ followed by n repeated y times. For example, F2W3 is replaced with 2_nnn. i` makes the regex case insensitive.

(?<=(\d+).*?)n
$1,

This matches all the repeated n's. and replaces each of them with the number closest before it, followed by a comma. Using our previous example of F2W3, 2_nnn is replaced with 2_2,2,2,.

\d+_|,$

This removes the final garbage left behind. It replaces the numbers directly followed by underscores, and the comma at the end of the line, with nothing. So 2_2,2,2, becomes 2,2,2, which is the desired output.

Business Cat

Posted 2016-08-23T03:23:51.227

Reputation: 8 927

Drop the look behind and perhaps and after the capture group reference – Downgoat – 2016-08-29T13:50:41.353

@Downgoat: I'm not entirely sure what you mean... if I drop the lookbehind then it will replace all the ns with 1 number, rather than each n with the number. – Business Cat – 2016-08-29T14:03:52.903