Incremental Game Time Format

18

1

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.

Hand-E-Food

Posted 2015-07-08T05:00:44.240

Reputation: 7 912

What is expected output for 307891 1? 0w or 1w. – jnovacho – 2015-07-08T13:06:44.633

1@jnovacho Wouldn't it be 3d? "The first segment displayed is the first non-zero value" – Luigi – 2015-07-08T13:57:31.147

@Luigi True. I've missed that. – jnovacho – 2015-07-08T14:03:53.200

Am I the only one thinking that this is a "could some one please write this code for me" question? – fho – 2015-07-09T09:50:09.653

It's not every day a code golf task might actually be useful. I say go with it :D – Geobits – 2015-07-09T20:13:16.307

@fho, if I wanted to write this function for production code, I would be writing it maintainable, not golfing it. ;-P – Hand-E-Food – 2015-07-10T04:09:40.140

@Hand-E-Food point taken ;) – fho – 2015-07-10T09:40:09.343

Answers

7

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.

Dennis

Posted 2015-07-08T05:00:44.240

Reputation: 196 637

6

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.

ECS

Posted 2015-07-08T05:00:44.240

Reputation: 361

1Like the ;z=" ") - very clever. – OldCurmudgeon – 2015-07-08T13:34:50.030

5

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)}

openaddr

Posted 2015-07-08T05:00:44.240

Reputation: 141

4

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

Jakube

Posted 2015-07-08T05:00:44.240

Reputation: 21 462

3

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

f.rodrigues

Posted 2015-07-08T05:00:44.240

Reputation: 645

1Great first attempt! Better than some of my sixth attempts... ;) You can cut off 3 bytes by changing if n!=0 to just if n. – kirbyfan64sos – 2015-07-08T18:22:44.557

Oh yeah, forgot that 0 evaluates to False. Thanks. – f.rodrigues – 2015-07-08T23:49:40.083

2

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"

Alex A.

Posted 2015-07-08T05:00:44.240

Reputation: 23 761

1

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.

kirbyfan64sos

Posted 2015-07-08T05:00:44.240

Reputation: 8 730

What's rs?----- – Caleb Paul – 2015-07-09T23:35:48.850

@Wideshanks I added a link in the title. It's a regex-based language-ish thing I wrote. – kirbyfan64sos – 2015-07-09T23:56:23.170

1

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(" ")

user42083

Posted 2015-07-08T05:00:44.240

Reputation: 21

0

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();
}

Hand-E-Food

Posted 2015-07-08T05:00:44.240

Reputation: 7 912