18
\$\begingroup\$

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].

\$\endgroup\$
  • 7
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! Just so you know, bonuses in code golf are discouraged. \$\endgroup\$ – Dennis Aug 23 '16 at 3:33
  • 1
    \$\begingroup\$ Ok, thank you for the information. I have removed the bonus. \$\endgroup\$ – Chaotic Aug 23 '16 at 3:39
  • 12
    \$\begingroup\$ This might be a duplicate of this run-length decoding challenge. \$\endgroup\$ – xnor Aug 23 '16 at 3:54
  • 3
    \$\begingroup\$ Do we have to support upper and lower case? Or just one or the other? \$\endgroup\$ – DJMcMayhem Aug 23 '16 at 4:59
  • 2
    \$\begingroup\$ Would it be acceptable to output an extra comma at the end of the output? \$\endgroup\$ – DJMcMayhem Aug 23 '16 at 6:13

19 Answers 19

2
\$\begingroup\$

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

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.

\$\endgroup\$
  • 3
    \$\begingroup\$ lambda s:eval(s.upper().translate({70:'+[',87:']*'})[1:]) saves 7 bytes in Python 3. \$\endgroup\$ – Dennis Aug 23 '16 at 4:51
  • \$\begingroup\$ @Dennis Thanks, I'd been trying to get that to work with a list, didn't think to use a dictionary. \$\endgroup\$ – xnor Aug 23 '16 at 4:52
  • \$\begingroup\$ 3 bytes more to have it match the examples: eval(input().upper().translate({70:'+", ',87:'"*'})[1:])[2:] \$\endgroup\$ – Cees Timmerman Aug 23 '16 at 14:34
4
\$\begingroup\$

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

Pyth, 18 bytes

r_McvM:z"\d+"1 2 9

Try it online. Test suite.

\$\endgroup\$
3
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Where are the commas? ;-) \$\endgroup\$ – Chaotic Aug 25 '16 at 17:55
  • \$\begingroup\$ @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 \$\endgroup\$ – Luis Mendo Aug 25 '16 at 18:13
  • \$\begingroup\$ @Chaotic Solved (9 bytes!) \$\endgroup\$ – Luis Mendo Aug 25 '16 at 21:32
2
\$\begingroup\$

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>

\$\endgroup\$
  • \$\begingroup\$ I don't think you need the F in the regex. \$\endgroup\$ – Jordan Aug 23 '16 at 4:47
  • \$\begingroup\$ Why are you using alert? As I understand the challenge, the output should be as a single list of frames. \$\endgroup\$ – DanTheMan Aug 23 '16 at 6:24
2
\$\begingroup\$

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
\$\endgroup\$
  • 2
    \$\begingroup\$ The 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 :-) \$\endgroup\$ – Ton Hospel Aug 23 '16 at 8:32
  • \$\begingroup\$ @TonHospel Scoring flags is so tricky. Thanks! \$\endgroup\$ – Lynn Aug 23 '16 at 10:09
2
\$\begingroup\$

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

\$\endgroup\$
2
\$\begingroup\$

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 )
    });
}
\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – Brad Gilbert b2gills Aug 23 '16 at 16:48
  • \$\begingroup\$ 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. \$\endgroup\$ – Joshua Aug 23 '16 at 16:52
2
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ 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) \$\endgroup\$ – Ton Hospel Aug 23 '16 at 11:14
1
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – Robert Fraser Aug 23 '16 at 9:09
  • \$\begingroup\$ Explicit cast to integer is to allow run length decoding (which doesn't work with strings as the "key"). I'll remove the stringification. \$\endgroup\$ – Steven H. Aug 23 '16 at 9:13
1
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Nice one ! I don't get the m[c(T,F)] part however... \$\endgroup\$ – Frédéric Aug 23 '16 at 11:00
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – plannapus Aug 23 '16 at 11:03
  • \$\begingroup\$ Credit for that particular bit of code goes to flodel. The linked challenge is very similar to this one. \$\endgroup\$ – plannapus Aug 23 '16 at 11:05
1
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – Kevin Cruijssen Aug 23 '16 at 13:14
  • \$\begingroup\$ @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. \$\endgroup\$ – Anastasiya-Romanova 秀 Aug 23 '16 at 13:30
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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".

\$\endgroup\$
1
\$\begingroup\$

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(',');};
\$\endgroup\$
0
\$\begingroup\$

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

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.

\$\endgroup\$
  • \$\begingroup\$ Drop the look behind and perhaps and after the capture group reference \$\endgroup\$ – Downgoat Aug 29 '16 at 13:50
  • \$\begingroup\$ @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. \$\endgroup\$ – Business Cat Aug 29 '16 at 14:03

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