18
\$\begingroup\$

Incremental Game Time Format

Goal

Incremental games often have a countdown timer expressing the days, hours, minutes and seconds until a task is complete. Depending on the space available, they can be formatted as:

2d 13h
23h 59m 48s
14m
3h 0m 0s

The goal of this code golf is to write a function or program that performs this formatting.

Inputs

  • The total number of seconds.
  • The maximum number of segments to output.

Output

  • Segments include:
    • 0w weeks
    • 0d days
    • 0h hours
    • 0m minutes
    • 0s seconds
  • Each segment is separated by a single space.
  • Displayed segments must be contiguous. For example, you will not show hours and seconds without showing minutes, even if there are zero minutes.
  • Single-digit values do not have leading zeros, though a value of zero must be shown as 0.
  • Values are rounded down.
  • The first segment displayed is the first non-zero value.

Test Cases

seconds  segments  output
     0      1      0s
   123      1      2m
   123      2      2m 3s
   123      3      2m 3s
 82815      3      23h 0m 15s
307891      2      3d 13h
307891      4      3d 13h 31m 31s
604800      1      1w
604800      6      1w 0d 0h 0m 0s

Winning

The lowest byte-count solution in one week will win "acceptance".

Edits

  • Clarified which segment is first, as shown in examples.
  • Added test case 4 as per request.
\$\endgroup\$
7
  • \$\begingroup\$ What is expected output for 307891 1? 0w or 1w. \$\endgroup\$
    – jnovacho
    Commented Jul 8, 2015 at 13:06
  • 1
    \$\begingroup\$ @jnovacho Wouldn't it be 3d? "The first segment displayed is the first non-zero value" \$\endgroup\$
    – Luigi
    Commented Jul 8, 2015 at 13:57
  • \$\begingroup\$ @Luigi True. I've missed that. \$\endgroup\$
    – jnovacho
    Commented Jul 8, 2015 at 14:03
  • \$\begingroup\$ Am I the only one thinking that this is a "could some one please write this code for me" question? \$\endgroup\$
    – fho
    Commented Jul 9, 2015 at 9:50
  • \$\begingroup\$ It's not every day a code golf task might actually be useful. I say go with it :D \$\endgroup\$
    – Geobits
    Commented Jul 9, 2015 at 20:13

9 Answers 9

7
\$\begingroup\$

CJam (snapshot), 41 38 bytes

q~"<<^X^G"{imd\}%W%"wdhms":s.+_{0=}#><S*

The above uses caret notation, since two of the characters are unprintable.

Thanks to @Sp3000 for golfing off 2 bytes.

Testing

The latest stable release (0.6.5) has a bug that can cause {}# to return Integers instead of Longs. Quite paradoxically, this can be circumvented by casting to integer (i).

To run this with code with the online interpreter, click this permalink or copy the code from this paste.

Alternatively, you can download and build the latest snapshot by executing the following commands:

hg clone http://hg.code.sf.net/p/cjam/code cjam-code
cd cjam-code/
ant

You can create the CJam file like this:

base64 -d > game-time.cjam <<< cX4iPDwYByJ7aW1kXH0lVyUid2RobXMiOnMuK197MD19Iz48Uyo=

How it works

q~        e# Read an evaluate the input.
"<<^X^G"  e# Push the string corresponding to the array [60 60 24 7
{         e# For each character:
  i       e#   Replace it by its code point.
  md      e#   Push divisor and residue of the division by that code point.
  \       e#   Swap their order.
}%
W%        e# Reverse the resulting array.
"wdhms":s e# Push ["w" "d" "h" "m" "s"].
.+        e# Perform vectorized concatenation.
_         e# Push a copy.
{0=}#     e# Find the index of the first pair with positive integer.
>         e# Remove the preceding pairs.
<         e# Truncate to the number of pairs specified in the input.
S*        e# Join, separating by spaces.
\$\endgroup\$
6
\$\begingroup\$

Java, 197 191 bytes

String p(int s,int m){String a[]={s%60+"s",(s/=60)%60+"m",(s/=60)%24+"h",(s/=24)%7+"d",(s/7)+"w"},b="",z="";for(s=5;s>0&&a[--s].charAt(0)=='0';);for(;s>=0&&--m>=0;z=" ")b+=z+a[s--];return b;}

I just noticed that Java supports declaration like String a[]. This allowed me to pull the declaration of b and z into the same line, which saved me from writing String again.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Like the ;z=" ") - very clever. \$\endgroup\$ Commented Jul 8, 2015 at 13:34
5
\$\begingroup\$

C, 134 127 110 104 103 bytes

New Version:

a,e=5;f(n,x){for(;e;n%=a)a=(int[]){1,60,3600,86400,604800}[--e],x>e?printf("%u%c ",n/a,"smhdw"[e]):0;}

Previous Version:

#define p(a) x>--e?printf("%u%c ",n/a,"smhdw"[e]):0;n%=a;
e=5;f(n,x){p(604800)p(86400)p(3600)p(60)p(1)}
\$\endgroup\$
4
\$\begingroup\$

Pyth, 39 43 bytes

jd_>vz+V?u?GeGPG+m%~/QddCM"<<"Q)Q]0"smhdw

edit: +4 chars, because I forgot the 0s test case.

This includes 2 unprintable chars. Get the actual code and try it online: Demonstration

Explanation:

                                         z = 1st input line (segments, as string)
                                         Q = 2nd input line (time, as int)
                         "<<.."          string with 4 chars
                       CM                convert to ASCCI-values => [60,60,24,7]
                m                        map each d of ^ to:
                   /Qd                     Q / d 
                  ~                        update Q, but use the old value for
                 %  Q d                    Q mod d
                                         this gives [sec, min, hour, day]
               +               Q         add Q (week)
        u                       )        apply the following expression to G, 
                                         starting with G = [s,m,h,d,w], until
                                         G stops changing:
         ? eG                              if eG != 0:
          G                                  update G with G (stop changing)
                                           else:
             PG                              update G with G[-1]
                                         this gets rid of trailing zeros
      +V                         "smhdw  vectorized add with "smhdw"
   >vz                                   only use the last eval(z) items
  _                                      reverse order
jd                                       join by spaces and print
\$\endgroup\$
3
\$\begingroup\$

Python 2.7 - 181 178 174 bytes

My first attempt to golf something.

def I(s,M):
 z=[0]*5;j=0
 for i in [604800,86400,3600,60,1]:z[j],s=s/i,s%i;j+=1
 l=[z.index(n)for n in z if n][0]
 return" ".join([str(i)+n for n,i in zip('wdhms',z)][l:l+M])
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Great first attempt! Better than some of my sixth attempts... ;) You can cut off 3 bytes by changing if n!=0 to just if n. \$\endgroup\$ Commented Jul 8, 2015 at 18:22
  • \$\begingroup\$ Oh yeah, forgot that 0 evaluates to False. Thanks. \$\endgroup\$ Commented Jul 8, 2015 at 23:49
2
\$\begingroup\$

Julia, 158 bytes

I'm sure this could be shorter with a more clever approach, but this is what I have for now.

(s,g)->(j=0;p=cell(5,1);for i=[604800,86400,3600,60,1] p[j+=1],s=s÷i,s%i end;z=findfirst(p);z>0?join([string(p[i],"wdhms"[i])for i=z:min(z+g-1,5)]," "):"0s")

This creates an unnamed function that accepts two integers as input and returns a string. To call it, give it a name, e.g. f=(s,g)->....

Ungolfed + explanation:

function f(s, g)
    # Initialize an array and an index
    p = cell(5, 1)
    j = 0

    # Loop over the number of seconds in a week, day, hour,
    # minute, and second
    for i in [604800, 86400, 3600, 60, 1]
        # Set the jth element in p to be the quotient and s
        # to be the remainder of i into s
        p[j+=1], s = s ÷ i, s % i
    end

    # Get the index of the first nonzero value in p
    z = findfirst(p)

    if z > 0
        # We start the string at the first nonzero value
        # and continue until we hit the desired number of
        # units (z+g-1) or the maximum number of units (5),
        # whichever comes first. The appropriate unit is
        # appended to each value and the values are then
        # joined with a space.
        join([string(p[i], "wdhms"[i]) for i in z:min(z+g-1,5)], " ")
    else
        # If there are no nonzero values in p, we just
        # have 0 seconds
        "0s"
    end
end

Examples:

julia> f(82815, 6)
"23h 0m 15s"

julia> f(604800, 4)
"1w 0d 0h 0m"
\$\endgroup\$
1
\$\begingroup\$

Scala, 147 bytes

def p(s:Int,i:Int)=List(s/604800+"w",s/86400%7+"d",s/3600%24+"h",s/60%60+"m",s%60+"s").dropWhile(k=>k.head=='0'&&k.tail!="s").take(i).mkString(" ")
\$\endgroup\$
1
\$\begingroup\$

rs, 367 bytes

^(\d+)/(_)^^(\1)
(_*) (\d)/\1!\2
_{60}/#
#{60}/@
@{24}/:
:{7}/;
(_+)/(^^\1)s
(#+)/(^^\1)m
(@+)/(^^\1)h
(:+)/(^^\1)d
(;+)/(^^\1)w
([a-z])/\1 
w ((\d+[^\dd])|!)/w 0d \1
d ((\d+[^\dh])|!)/d 0h \1
h ((\d+[^\dm])|!)/h 0m \1
(m|^) ?!/\1 0s!
!(\d+)/!(_)^^(\1)
#
+#(\d+)([a-z]) ?(.*)!(_*)/\1\2 #\3!\4@
#/
(@+)/ (_)^^((^^\1))
!(_+) \1(_*)/!\2
_+ _+/
+\d+[a-z] ?!_/!
 *!/
^$/0s

Live demo and all test cases.

Messy, messy, messy...

Takes about 3-7 seconds to execute the test cases on Chrome for Android. Do not use debug mode, which can freeze your browser in this case because of all the output that would be printed.

\$\endgroup\$
2
  • \$\begingroup\$ What's rs?----- \$\endgroup\$
    – Caleb Paul
    Commented Jul 9, 2015 at 23:35
  • \$\begingroup\$ @Wideshanks I added a link in the title. It's a regex-based language-ish thing I wrote. \$\endgroup\$ Commented Jul 9, 2015 at 23:56
0
\$\begingroup\$

C#, 239 237 170 164 bytes

This is no where near as compact as other solutions, but I can't pose this challenge without having a stab at it myself.

This latest iteration was inspired by ESC's answer.

Indented for clarity:

string G(int s,int n){
    int[]x={s%60,(s/=60)%60,(s/=60)%24,(s/=24)%7,s/7};
    for(s=5;x[--s]==0&s>0;);
    var o="";
    while(n-->0&s>=0)
        o+=" "+x[s]+"smhdw"[s--];
    return o.Trim();
}
\$\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.