ASCII clock with dot & comma time markers

39

7

Introduction

code golf explanation

Imagine that line of chars is in fact two rows. Upper row - dots - represents hours (24 hour system), while lower - commas - represents minutes. One character can represent hour, minute or both - whenever it's possible.

At first probably you'd have to convert minutes since midnight to hours and minutes.

The result is the string showing current time in "dot format". The dot count (apostrophe counts here as a dot and will be called so!) is the hour count since midnight and comma count is minutes count. I'll show a few examples to make it clear.

  • (Remark) hh:mm - result
  • (Only hours) 05:00 - '''''
  • (Only minutes) 00:08 - ,,,,,,,,
  • (hours < minutes) 03:07 - ;;;,,,,
  • (hours > minutes) 08:02 - ;;''''''
  • (hours = minutes) 07:07 - ;;;;;;;
  • (the start of the day) 00:00 - (empty result)

Notice that "both" character can be used max 23 times - for 23:xx, where xx is 23 or more.

Symbols

If character have to (see rule 5.) be escaped in your language, you could changed it to one of alternatives. If said alternatives aren't enough, you may use other symbols - but keep it reasonable. I just don't want escaping to be a barrier.

  • ; (semicolon) - marker for both hours and minutes (alt: :)
  • ' (apostrophe) - marker for hours (alt: '``°)
  • , (comma) - marker for minutes (alt: .)

Additional rules

  1. The code with the least amount of bytes wins!
  2. You have to use both symbol whenever it's possible. For 02:04 the result can't be '',,,,, nor ;',,,. It have to be ;;,,
  3. Input - can be script/app parameter, user input (like readline) or variable inside code
    3.1. If the variable inside code is used, then its lenght have to be the longest possible. It's 1439 (23:59), so it would look like t=1439
  4. The common part which is symbolized by "both" character (12 in 12:05, 3 in 03:10) must be placed on the beginning of the string
  5. Symbols can be replaced to alternatives only if they would have to be escaped in your code.
  6. Input is given in minutes after 00:00. You can assume that this is a non-negative integer.

Test cases

Input: 300
Output: '''''

Input: 8
Output: ,,,,,,,,

Input: 187
Output: ;;;,,,,

Input: 482
Output: ;;''''''

Input: 427
Output: ;;;;;;;

Input: 0
Output:  (empty)

Krzysiu

Posted 2015-12-22T23:52:32.763

Reputation: 491

Thank you, Adnan for editing my post! This way I'll learn by comparison of my, newbie golf to yours :) – Krzysiu – 2015-12-23T02:28:25.327

3No problem! It is a very good first post and a nice challenge :) – Adnan – 2015-12-23T02:45:23.240

1this looks so good with just semicolons and commas, but apostrophes muck it all up :( – Sparr – 2015-12-23T02:55:20.900

Actually 1439 is 23:59 and not 1339. (23 x 60 + 59). – insertusernamehere – 2015-12-23T09:04:07.673

Thank all of you for good words! :) @Sparr, yeah, that's the bad point :( Have you idea how it could be replaced? insertusernamehere, of course that's right! Fixed :) – Krzysiu – 2015-12-23T18:33:52.243

3.1 is kind of weird... What does it mean? Does the variable have to be called qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq? – ev3commander – 2015-12-23T21:45:32.313

+1 I love this way of represent time! Now I'll try to understand the challenge – edc65 – 2015-12-23T21:49:14.703

If you use . for the hours and ' for the minutes and use a newline in between them...... – Magic Octopus Urn – 2017-03-03T20:41:14.543

Answers

10

Pyth, 19 bytes

:.iF*V.DQ60J"',"J\;

Test suite

:.iF*V.DQ60J"',"J\;
      .DQ60            Divmod the input by 60, giving [hours, minutes].
           J"',"       Set J equal to the string "',".
    *V                 Perform vectorized multiplication, giving H "'" and M ','.
 .iF                   Interleave the two lists into a single string.
:               J\;    Perform a substitution, replacing J with ';'.

isaacg

Posted 2015-12-22T23:52:32.763

Reputation: 39 268

8

CJam, 22 20 19 bytes

Takes input from STDIN:

ri60md]',`.*:.{;K+}

Test it here.

Explanation

ri     e# Read input and convert to integer.
60md   e# Divmod 60, pushes hours H and minutes M on the stack.
]      e# Wrap in an array.
',`    e# Push the string representation of the comma character which is "',".
.*     e# Repeat apostrophe H times and comma M times.
:.{    e# Apply this block between every pair of characters. This will only applied to
       e# first N characters where N = min(hours,minutes). The others will remain
       e# untouched. So we want the block to turn that pair into a semicolon...
  ;    e#   Discard the comma.
  K+   e#   Add 20 to the apostrophe to turn it into a semicolon.
}

It was really lucky how well things worked together here, in particular the assignment of hours to ' and minutes to , such that the order of hours and minutes on the stack matched up with the string representation of the character.

This is the only 3-byte block I've found so far. There were tons of 4-character solutions though:

{;;';}
{';\?}
{^'0+}
{^'F-}
{-'@+}
{-'6-}
...

Martin Ender

Posted 2015-12-22T23:52:32.763

Reputation: 184 808

6

GNU Sed, 37

Score includes +1 for -E option to sed.

I wasn't particularly impressed with the golfiness of my bash answer, so I thought I'd try with sed for the fun.

Input is in unary, as per this meta-answer.

y/1/,/          # Convert unary 1's to commas (minutes)
s/,{60}/'/g     # divmod by 60.  "'" are hours
:               # unnamed label
s/(.*)',/;\1/   # replace an apostrophe and comma with a semicolon
t               # jump back to unnamed label until no more replacements

Try it online

Digital Trauma

Posted 2015-12-22T23:52:32.763

Reputation: 64 644

unnamed label?? – mikeserv – 2015-12-23T07:32:41.607

@mikeserv, see Digital Trauma's related tip in Tips for golfing in sed.

– manatwork – 2015-12-23T12:26:26.363

@manatwork - i think it must be a GNU bug. – mikeserv – 2015-12-23T18:12:55.613

@mikeserv - but using bugs is OK as well, right? I'm not asking to mock you, I just don't know :) – Krzysiu – 2015-12-23T18:40:27.303

@Krzysiu - ok? hmm. on this site i think it would be a mark of excellence. otherwise, almost definitely no. when programmers stray from API and use implementation details programs become version/implementation dependent - which is a bad thing. – mikeserv – 2015-12-23T18:59:31.593

@Krzysiu - by the way, i dont consider that GNU accepts the empty label : definition to be a bug, exactly, though i would expect it to throw an error without a parameter. but t's branching back to the null label is pretty buggy - it's supposed to branch out of the script when given no params. according to spec, that is.

– mikeserv – 2015-12-23T19:15:41.273

@mikeserv Welcome to the wild-west world of PPCG! ;-) Undocumented language features are generally allowed here; encouraged even - to heck with Posix ;-). Another one of my favourites

– Digital Trauma – 2015-12-23T19:46:41.137

thats definitely how i figured it. clever and short is what the puzzles here are all about. thats why i upvoted you. the bad news is that i mean to report it, and hopefully it will get fixed. that would be an ugly bug to get caught up with. – mikeserv – 2015-12-23T19:54:08.910

I don't understand why 1 in first line (instead of space, this will permit to whipe out your ugly yes 1 | head in your sample and replace them by simple printf %$1s for sample...) – F. Hauri – 2015-12-23T21:07:19.000

@F.Hauri Typically unary numbers are expressed as a string of 1s.

– Digital Trauma – 2015-12-23T21:18:15.913

6

Python 2, 56 bytes

def g(t):d=t%60-t/60;print(t/60*";")[:t%60]+","*d+"'"*-d

A function that prints (one char shorter than t=input();).

The method is similar to Loovjo's. The number of , is the different between minutes and hours, with an implicit minimim of 0. For ', it's the negation. For ;, computes the min implicitly by taking as many ; as hours, then truncating to the number of minutes.

It saves chars to save d, but not the number of hours and minutes here. The analogue with lambda was two chars longer (58), so the variable assignments are worth it.

lambda t:(t%60*";")[:t/60]+","*(t%60-t/60)+"'"*(t/60-t%60)

Processing the input directly didn't save chars either (58):

h,m=divmod(input(),60);d=m-h;print(";"*m)[:h]+","*d+"'"*-d

Another strategy with slicing, much longer (64):

def g(t):m=t%60;h=t/60;return(";"*m)[:h]+(","*m)[h:]+("'"*h)[m:]

xnor

Posted 2015-12-22T23:52:32.763

Reputation: 115 687

3

Haskell, 68 66 Bytes

g(h,m)=id=<<zipWith replicate[min h m,h-m,m-h]";',"
g.(`divMod`60)

Usage example:

(g.(`divMod`60)) 482

The clever bit here is that replicate will return the empty string if the length given is negative or zero so I can apply it to both differences and only the positive one will show up. The first part is easy, since the number of semicolons is just the minimum of the two. Then zipWith applies the function to the corresponding items.

EDIT: Realized I was using the wrong char for minutes

EDIT 2: Saved 2 bytes thanks to @Laikoni

user1472751

Posted 2015-12-22T23:52:32.763

Reputation: 1 511

You can save two bytes by replacing concat$ with id=<<. – Laikoni – 2017-03-02T08:38:45.277

3

Pure Bash (no external utilities), 103

p()(printf -vt %$2s;printf "${t// /$1}")
p \; $[h=$1/60,m=$1%60,m>h?c=m-h,h:m]
p , $c
p \' $[m<h?h-m:0]

Thanks to @F.Hauri for saving 2 bytes.

Digital Trauma

Posted 2015-12-22T23:52:32.763

Reputation: 64 644

Nice! But you could save 2 chars by swapping $1 and $2 in p() and write p , $c at line 3. – F. Hauri – 2015-12-23T21:03:24.473

Yes, but as it's used only in a printf "%s", having c empty will work fine (while not reused) – F. Hauri – 2015-12-24T07:35:37.060

@F.Hauri Now I get it - thanks! – Digital Trauma – 2015-12-24T22:43:06.207

3

Retina, 24

Trivial port of my sed answer.

Input is in unary, as per this meta-answer.

1
,
,{60}
'
+`(.*)',
;$1

Try it online.

Digital Trauma

Posted 2015-12-22T23:52:32.763

Reputation: 64 644

3

C, 119 bytes

#define p(a,b) while(a--)putchar(b);
main(h,m,n){scanf("%d",&m);h=m/60;m%=60;n=h<m?h:m;h-=n;m-=n;p(n,59)p(h,39)p(m,44)}

Detailed

// macro: print b, a times
#define p(a,b) while(a--)putchar(b)

int main(void)
{
    int h,m,n;
    scanf("%d",&m);  // read input

    h=m/60;m%=60;    // get hours:minutes
    n=h<m?h:m;       // get common count
    h-=n;m-=n;       // get remaining hours:minutes

    p(n,59);        // print common
    p(h,39);        // print remaining hours
    p(m,44);        // print remaining minutes

    return 0;
}

Khaled.K

Posted 2015-12-22T23:52:32.763

Reputation: 1 435

1Using putchar & integer literals as characters saves one byte, pulling the semicolons inside the macro saves two more :) – Quentin – 2015-12-23T22:35:45.163

@Quentin note taken, saved 5 bytes – Khaled.K – 2015-12-24T07:09:19.393

You can lose the space before your while in your #define macro. -1 byte – Albert Renshaw – 2017-03-02T08:41:34.530

1You can also save some more bytes by just making p(a,b) a function instead of a macro. (And sprinkling a few more semi-colons to your main function) – Albert Renshaw – 2017-03-02T08:48:09.397

2

Powershell, 99 85 bytes

param($n)";"*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+"'"*(($h-$m)*!$b)+","*(($m-$h)*$b)

Using Loovjo's method, this is my powershell implementation.

ungolfed

param($n) 
# set the number of minutes and hours, and a boolean which one is bigger
# and also output the correct number of ;s
";"*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+ 
# add the difference between h and m as 's but only if h > m
"'"*(($h-$m)*!$b)+
# add the difference between m and h as ,s but only if m > h
","*(($m-$h)*$b)

Saved 14 bytes thanks to AdmBorkBork

Bjorn Molenmaker

Posted 2015-12-22T23:52:32.763

Reputation: 141

You can save by using a pseudo-ternary for the first one, moving the $m and $h declarations into it, and then using Boolean multiplication. Like so -- param($n)';'*(($m=$n%60),($h=$n/60))[($b=$m-gt$h)]+'°'*(($h-$m)*!$b)+','*(($m-$h)*$b)

– AdmBorkBork – 2017-03-02T14:01:06.197

2

JavaScript (ES6) 69

m=>";".repeat((h=m/60|0)>(m%=60)?m:h)+",'"[h>m|0].repeat(h>m?h-m:m-h)

edc65

Posted 2015-12-22T23:52:32.763

Reputation: 31 086

1

Perl 6, 103 101 98 97 69 bytes

$_=get;say ";"x min($!=($_-$_%60)/60,$_=$_%60)~"'"x $!-$_~","x $_-$!;

Outputs several arrays, but fuck it, enjoy. As usual, any golfing oppertunities are appericated.

Edit: -2 bytes: got brave and removed some casts.

Edit2: -3 bytes by removing the arrays.

Edit3: -1 byte to print in right format, using "lambdas" and removing parantheses.

Edit4: (sorry guys) abusing that hours - minutes should return 0 and the opposite. Removed if statements. Then removing brackets, then realising i didnt need the lambda at all. -28 bytes :)

Woah im getting better at this.

Håvard Nygård

Posted 2015-12-22T23:52:32.763

Reputation: 341

1

Python 3, 98 bytes

d=int(input());m=d%60;h=int((d-m)/60)
if m>=h:print(";"*h+","*(m-h))
else:print(";"*(m)+"'"*(h-m))

Probably not the best answer, but it was a lot of fun!

Adnan

Posted 2015-12-22T23:52:32.763

Reputation: 41 965

1

Python 2, 61 bytes

t=input();m,h=t%60,t/60
print";"*min(h,m)+","*(m-h)+"'"*(h-m)

Explaination:

t=input();              # Read input
          m,  t%60,     # Do a divmod, h = div, m = mod
            h=     t/60

print";"*min(h,m)+                    # Print the minimum of the h and m, but in ";"s
                  ","*(m-h)+          # Print (m-h) ","s (if m-h is negative, print nothing)
                            "'"*(h-m) # Print (h-m) "'"s (if h-m is negative, print nothing)

Loovjo

Posted 2015-12-22T23:52:32.763

Reputation: 7 357

1

PHP, 81 bytes

I went for the variable input as it is shorter than reading from STDIN or taking command line arguments.

for($_=1439;$i<max($h=0|$_/60,$m=$_%60);++$i)echo$i<$h?$i<min($h,$m)?';':"'":",";

insertusernamehere

Posted 2015-12-22T23:52:32.763

Reputation: 4 551

I thought that I know PHP rather well, but I see | for the first time. I think I'll use it to exercise a bit - I'll analyze it :) – Krzysiu – 2015-12-23T18:38:50.150

Fails for 240. Try $i>=min($h,$m)?$h<$m?",":"'":";" (+1 byte). Or use for($_=1439;$i<max($h=0|$_/60,$m=$_%60);)echo"',;"[$i++<min($h,$m)?2:$h<$m]; (76 bytes). Btw: single quote renders -r impossible; so you should use backtick for hours if in a string or ° standalone (needs no quotes -> -1 byte). – Titus – 2017-03-01T16:10:36.833

1

JavaScript (ES6), 77 71 bytes

x=>';'[r='repeat'](y=Math.min(h=x/60|0,m=x%60))+"'"[r](h-y)+','[r](m-y)

Mwr247

Posted 2015-12-22T23:52:32.763

Reputation: 3 494

Great use of assignments in attribute access/function arguments. +1 – Cyoce – 2017-03-02T01:48:19.190

0

SmileBASIC, 59 bytes

INPUT M
H%=M/60M=M-H%*60?";"*MIN(H%,M);",'"[M<H%]*ABS(H%-M)

Explained:

INPUT MINUTES 'input
HOURS=MINUTES DIV 60 'separate the hours and minutes
MINUTES=MINUTES MOD 60
PRINT ";"*MIN(HOURS,MINUTES); 'print ;s for all positions with both
PRINT ",'"[MINUTES<HOURS]*ABS(HOURS-MINUTES) 'print extra ' or ,

It looks pretty terrible, since the bottom part of ; is not even the same as , in SmileBASIC's font

12Me21

Posted 2015-12-22T23:52:32.763

Reputation: 6 110

0

PHP, 81 bytes

some more solutions:

echo($r=str_repeat)(";",min($h=$argn/60,$m=$argn%60)),$r(",`"[$h>$m],abs($h-$m));
// or
echo($p=str_pad)($p("",min($h=$argn/60,$m=$argn%60),";"),max($h,$m),",`"[$h>$m]);

Run with echo <time> | php -R '<code>'.

<?=($r=str_repeat)(";",min($h=($_=1439)/60,$m=$_%60)),$r(",`"[$h>$m],abs($h-$m));
// or
<?=($r=str_repeat)(";",min($h=.1/6*$_=1439,$m=$_%60)),$r(",`"[$h>$m],abs($h-$m));
// or
<?=str_pad(str_pad("",min($h=($_=1439)/60,$m=$_%60),";"),max($h,$m),",`"[$h>$m]);

Replace 1439 with input, save to file, run.

Titus

Posted 2015-12-22T23:52:32.763

Reputation: 13 814

0

Java 8, 101 99 86 bytes

n->{String r="";for(int m=n%60,h=n/60;h>0|m>0;r+=h--*m-->0?";":h<0?",":"'");return r;}

Explanation:

Try it here.

n->{                      // Method with integer parameter and String return-type
  String r="";            //  Result-String (starting empty)
  for(int m=n%60,h=n/60;  //   Get the minutes and hours from the input integer
      h>0|m>0;            //   Loop as long as either the hours or minutes is above 0
    r+=                   //   Append the result-String with:
       h--*m-->0?         //    If both hours and minutes are above 0
                          //    (and decrease both after this check):
        ";"               //     Use ";"
       :h<0?              //    Else-if only minutes is above 0 (hours is below 0)
        ","               //     Use ","
       :                  //    Else:
        "'"               //     Use "'"
  );                      //  End loop
  return r;               //  Return the result
}                         // End of method

Kevin Cruijssen

Posted 2015-12-22T23:52:32.763

Reputation: 67 575

0

05AB1E, 25 bytes

60‰vy„'.Nè×}‚.BøJ„'.';:ðK

Try it online!

60‰vy„'.Nè×} can definitely be shortened, I just couldn't figure it out, and doubt I'll be able to shave off 7 bytes to win with this approach unless there's a vectored version of ×.


Example (With input equal to 63):

60‰                       # Divmod by 60.
                          # STACK: [[1,3]]
   vy      }              # For each element (probably don't need the loop)...
                          # STACK: []
     „'.Nè×               # Push n apostrophe's for hours, periods for minutes.
                          # STACK: ["'","..."]
            ‚             # Group a and b.
                          # STACK: [["'","..."]]
             .B           # Boxify.
                          # STACK: [["'  ","..."]]
               ø          # Zip it (Transpose).
                          # STACK: [["'."," ."," ."]
                J         # Join stack.
                          # STACK: ["'. . ."]
                 „'.';:   # Replace runs of "'." with ";".
                          # STACK: ["; . ."]
                       ðK # Remove all spaces.
                          # OUTPUT: ;..

D60÷''×s60%'.ׂ.BøJ„'.';:ðK was my original version, but that's even MORE costly than divmod.

60‰WDµ';ˆ¼}-¬0Qi'.ë''}ZׯìJ yet another method I tried...

Magic Octopus Urn

Posted 2015-12-22T23:52:32.763

Reputation: 19 422

0

dc, 95 bytes

[60~sdsp39sj]sd[60~spsd44sj]se?ddd60~<d60~!<e[59Plp1-spld1-dsd0<y]syld0<y[ljPlp1-dsp0<y]sylp0<y

Try it online!

R. Kap

Posted 2015-12-22T23:52:32.763

Reputation: 4 730

0

C, 141 bytes

main(h,m){scanf("%d",&m);h=(m/60)%24;m%=60;while(h||m){if(h&&m){printf(";");h--;m--;}else if(h&&!m){printf("'");h--;}else{printf(",");m--;}}}

user2064000

Posted 2015-12-22T23:52:32.763

Reputation: 270

I think you could save a few bytes by using h>0||m>0. Then you need to h--;m--; only once in every iteration and the {} for if/else would get obsolete. – insertusernamehere – 2015-12-23T08:57:22.443

You can also save a few bytes on your second conditional: instead of else if(h&&!m) you can just have else if(h) – Hellion – 2015-12-23T19:57:39.393

And finally try to use the ternary operator, it will save you from using "long" words like if and else. – insertusernamehere – 2015-12-23T21:14:55.343

Consider refactoring as a function that takes the input as an int parameter - that should at least save you the scanf(). – Digital Trauma – 2015-12-25T00:57:13.453

I don't think the %24 is necessary - max input is 23:59. – Digital Trauma – 2015-12-25T00:58:37.600

0

Ruby, 50 characters

->t{(?;*h=t/60)[0,m=t%60]+",',"[0<=>m-=h]*m.abs}

Thanks to:

  • G B for
    • reminding me that I can't take more characters from a string than it has (-1 character)
    • reorganizing my calculation (-1 character)

Waited so long to use Numeric.divmod, just to realize that its horribly long.

Sample run:

2.1.5 :001 > puts ->t{(?;*h=t/60)[0,m=t%60]+",',"[0<=>m-=h]*m.abs}[252]
;;;;,,,,,,,,

manatwork

Posted 2015-12-22T23:52:32.763

Reputation: 17 865

1Save 1 character by truncating the string instead of using min: (?;*h=t/60)[0,m=t%60] – G B – 2017-03-02T12:23:39.160

1And another byte by subtracting h from m: ",',"[0<=>m-=h]*m.abs – G B – 2017-03-02T12:40:26.720

0

Gema, 119 characters

<D>=@set{h;@div{$0;60}}@set{m;@mod{$0;60}}@repeat{@cmpn{$h;$m;$h;$h;$m};\;}@repeat{@sub{$h;$m};'}@repeat{@sub{$m;$h};,}

Sample run:

bash-4.3$ gema '<D>=@set{h;@div{$0;60}}@set{m;@mod{$0;60}}@repeat{@cmpn{$h;$m;$h;$h;$m};\;}@repeat{@sub{$h;$m};`}@repeat{@sub{$m;$h};,}' <<< '252'
;;;;,,,,,,,,

manatwork

Posted 2015-12-22T23:52:32.763

Reputation: 17 865

0

Matlab: 89 bytes

i=input('');m=mod(i,60);h=(i-m)/60;[repmat(';',1,min(h,m)),repmat(39+5*(m>h),1,abs(h-m))]

Test:

310
ans =
;;;;;,,,,,

brainkz

Posted 2015-12-22T23:52:32.763

Reputation: 349