45
\$\begingroup\$

Your task is to create a program that is to mimic Big Ben (Twitter).

Task

Whenever a new hour has begun (according to your computer's local time or UTC), you have to output BONG repeated hour times (with a space between the words). For example, when it's 3 o' clock, you have to output BONG BONG BONG. The time format follows the 12-hour time format, ie after 12 o' clock, we have 1 and not 13. The program/function must run forever.

Example:

don't output stuff inside the brackets

(start: 00:34 for example)
BONG               (01:00)
BONG BONG          (02:00)
(...)
BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG (12:00)
BONG               (01:00 again)
(...)
(it continues forever)

Rules

  • Each series of BONGs must be separated by a newline
  • Leading/trailing newlines are allowed
  • However leading/trailing spaces are not allowed
  • The submission must run forever
  • Your output may be printed ±3 seconds from the beginning of the hour
  • You may not assume the program to be run at any specific hour

This is , so the program with the shortest bytecount wins!

\$\endgroup\$
  • 6
    \$\begingroup\$ Testing these submissions is going to be fun... :D \$\endgroup\$ – FlipTack Dec 25 '16 at 15:16
  • 3
    \$\begingroup\$ for 12/24 do we print 0 bongs or 12 bongs? \$\endgroup\$ – Maltysen Dec 25 '16 at 22:42
  • 6
    \$\begingroup\$ +1 for a challenge which isn't easily dominated by dedicated code-golfing languages. \$\endgroup\$ – Philipp Dec 25 '16 at 22:59
  • 2
    \$\begingroup\$ How should the program behave if the system clock is wound back to before 1859? \$\endgroup\$ – Amani Kilumanga Dec 26 '16 at 6:47
  • 3
    \$\begingroup\$ For testing one can use LD_PRELOAD hack overriding time functions: github.com/vi/timeskew . TIMESKEW="60 1" makes minutes flow like seconds. \$\endgroup\$ – Vi. Dec 26 '16 at 18:46

26 Answers 26

2
\$\begingroup\$

05AB1E, 43 bytes

3600žcžb60*+->Lvw}["BONG "ža<12%>×,5°36*.W]

Try it online! (lol this won't work, it will timeout in 60 seconds. Download the 05AB1E interpreter for this)

Explanation:

3600žcžb60*+->                          # Get amount of seconds (plus one) until next hour
              Lvw}                      # Wait said amount of seconds
                  [                     # Infinite loop start
                   "BONG "ža<12%>×,     # Print "BONG " multiplied by the amount of hours (12-hour clock)
                               5°36*.W  # Wait an hour (3600000 milliseconds)
                                      ] # Infinite loop end  

This took me a while to golf! I might be able to golf it a little more, but it beats *><>, so that's cool :)

Quick version:

1Uw["BONG "X<12%>×,wX>U]

Will wait one second on start, and one second between BONGs

\$\endgroup\$
  • \$\begingroup\$ Sorry for the delay, I finally got to running your program locally. Well done, this is particularly good for an esolang! \$\endgroup\$ – Cows quack Apr 28 '17 at 19:01
18
\$\begingroup\$

Bash, 71, 70, 69 bytes

EDITS:

  • Optimized the sleep interval computation a bit, -1 byte;
  • Replaced backticks with xargs, -1 byte (Thanks @jrtc27 !).

Golfed

sleep `date +3600-%s%3600|bc`;yes BONG|sed $(date +%I)q|xargs;exec $0

Explained

#Compute the number of seconds left in the current hour and wait.
sleep `date +3600-%s%3600|bc`; 

#Print "hour" (1-12) worth of "BONG" strings, one per line,
#use xargs to merge them into a single space-separated string.
yes BONG|sed $(date +%I)q|xargs

#Re-execute itself (in the same process).
exec $0

Test Version

Works with minutes instead of hours

sleep `date +60-%s%60|bc`;yes BONG|sed $(date +%I)q|xargs;exec $0
\$\endgroup\$
  • 2
    \$\begingroup\$ @zeppeIin I joined this community with the primary goal of worshipping you. Your solution is so full of sneaky tricks I'm still reeling from the awesomeness - especially yes BONG|sed 12q \$\endgroup\$ – neonzeon Dec 26 '16 at 19:21
  • \$\begingroup\$ @neonzeon wow :) \$\endgroup\$ – zeppelin Dec 27 '16 at 20:03
  • \$\begingroup\$ You can shave 1 byte off the echo by piping to xargs, which calls echo by default. 1 for pipe + 5 for xargs - 2 for backticks - 4 for echo - 1 for space = -1 byte. \$\endgroup\$ – jrtc27 Jan 31 '17 at 13:14
  • \$\begingroup\$ @jrtc27 That's an excellent advice! Thank you ! \$\endgroup\$ – zeppelin Jan 31 '17 at 18:31
8
\$\begingroup\$

*><>, 48 47 44 bytes

>s?um?uhc%:?!c21.O
v$o" GNOB"oooo$1-:?!
\aofS

Try it here! (or this version which does it every minute for testing)

This outputs a number of BONGs separated by spaces based on what hour it is (and 13 is 1, etc). There are no trailing space after the final BONG, and there is a trailing newline.

Technically this doesn't run forever (but it basically does). It leaks ~28 bytes per day (ignoring interpreter overhead ...). It would take ~105062 years for it to leak 1GiB.

Approximating for interpreter overhead, the stack is just a slice of float64s on the Golang interpreter. So I simply did 28*8 to come up with 224 bytes per day. I divided this number by the number of bytes in a gibibyte (1073741824) then 365 to approximate that it would take 13132.85 years to leak 1 GiB.

Note about the interpreters

The online interpreter is in Javascript. The page must be open and visible for it to check the time it currently is and output the BONGs. The Golang interpreter has no such limitation.

Explanation

Main loop:

s?um?u          O     if seconds == 0 && minutes == 0:
      hc%               push hours % 12 (bongs) to the stack
         :?!c           if bongs is 0, push 12 to the stack
             21.        jump to "output bongs" coords (2, 1)


Output bongs:

Begins at `"` because of the jump.

   " GNOB"            push "BONG " to the stack
          oooo        output "BONG"
              $1-     subtract 1 from bongs
v                :?!  if bongs == 0, move to "newline and sleep"
 $o                   output " "


Newline and sleep:

\                     mirror the IP to the right
 ao                   output a newline
   fS                 sleep for 1.6s
\                     mirror to main loop
\$\endgroup\$
  • \$\begingroup\$ What is the local timezone for the language's interpreter online? Because when a new hour struck for me, it didn't output anything \$\endgroup\$ – Cows quack Dec 30 '16 at 7:53
  • \$\begingroup\$ @KritixiLithos, unfortunately for the online interpreter the page must be open and visible for it to work. I think this is a Javascript/browser limitation. You don't need to worry about it being online or not as the interpreter itself is in Javascript, you could download it yourself if you wanted! The Golang interpreter works regardless of anything though. Sorry for the inconvenience, I'll edit the answer to make that clear. \$\endgroup\$ – redstarcoder Dec 30 '16 at 12:24
  • 1
    \$\begingroup\$ Congratulations on winning this challenge! This is the only golfing-lang to have completed this challenge and that's impressive :) \$\endgroup\$ – Cows quack Jan 7 '17 at 12:03
  • \$\begingroup\$ @KritixiLithos thanks!! This is the first challenge I've won at all :D \$\endgroup\$ – redstarcoder Jan 7 '17 at 14:58
7
\$\begingroup\$

JavaScript (ES6), 99 93 bytes

f=_=>setTimeout('alert("BONG ".repeat(new Date/36e5%12|0||12).trim(f()))',36e5-new Date%36e5)

This uses UTC time (which lines up with the actual thing). Due to the untestable nature of the code, you can try the following which does the same thing, but every 60 seconds:

f=_=>setTimeout('alert("BONG ".repeat(new Date/36e5%12|0||12).trim(f()))',6e4-new Date%6e4)

f()

Here's a bonus 99-byte version which uses local time:

f=_=>setTimeout('alert("BONG ".repeat(new Date().getHours()%12||12).trim(f()))',36e5-new Date%36e5)
\$\endgroup\$
  • \$\begingroup\$ This (the snippet) alerts every minute for me (but the number of BONGs is correct), but the program is supposed to output every hour only \$\endgroup\$ – Cows quack Dec 25 '16 at 19:06
  • \$\begingroup\$ @KritixiLithos "Due to the untestable nature of the code, you can try the following which does the same thing, but every 60 seconds:" ;-) \$\endgroup\$ – ETHproductions Dec 25 '16 at 19:07
6
\$\begingroup\$

JavaScript(ES6), 125 123 117 115 bytes

Thanks to @Flp.Tkc for saving 5 bytes!

Thanks to @BenAston for saving 2 more bytes!

a=eval(b=`(new Date).getHours()`);setInterval(w=>eval(b)!=a?console.log(Array(++a%12+1).join`BONG `.trim()):"",1e3)

Snack Snippet

a=eval(b=`(new Date).getHours()`);setInterval(w=>eval(b)!=a?console.log(Array(++a%12+1).join`BONG `.trim()):"",1e3)

\$\endgroup\$
  • 1
    \$\begingroup\$ @BenAston Thanks for noticing that :) \$\endgroup\$ – Cows quack Dec 25 '16 at 16:41
  • 1
    \$\begingroup\$ @BenAston It doesn't work without the first semi-colon \$\endgroup\$ – Cows quack Dec 25 '16 at 16:43
5
\$\begingroup\$

Batch, 142 bytes

@timeout/t>nul 1
@if not %time:~3,5%==00:00 %0
@set/ah=-%time:~0,2%%12
@set s=............
@call set s=%%s:~%h%%%
@echo %s:.=BONG %
@%0

Since the file runs as an infinite loop, I start with a 1s delay, as I need one anyway after the bongs, and this saves CPU cycles. The >nul is positioned carefully to save a byte (1>nul would cause the 1 to be eaten by the redirection). We then loop until both minutes and seconds are zero. The bongs are constructed by taking the negative hour modulo 12, and asking for the last h characters from a 12-character string. When h is zero this actually gives us the whole string, therefore 12 bongs. It then suffices to replace the characters with the word BONG. When run it looks something like this (note that the image does not loop, so you'll need to force-reload to see the animation again):

Sample Output

\$\endgroup\$
  • \$\begingroup\$ Could you provide a gif of it running and outputting? \$\endgroup\$ – Cows quack Dec 26 '16 at 9:36
  • 1
    \$\begingroup\$ @KritixiLithos Not sure what you're looking for here; I can take screenshots from before and after the hour and add a delay of up to 11 minutes in an animated GIF but I don't see how that proves anything. \$\endgroup\$ – Neil Dec 26 '16 at 13:58
  • \$\begingroup\$ I am asking for a gif because I can't test it on my computer (it's a mac) \$\endgroup\$ – Cows quack Dec 26 '16 at 13:59
  • \$\begingroup\$ @KritixiLithos Something like this OK? \$\endgroup\$ – Neil Dec 26 '16 at 14:21
  • \$\begingroup\$ Good enough, I'll take your word for it :) \$\endgroup\$ – Cows quack Dec 26 '16 at 14:21
5
\$\begingroup\$

Bash + Linux crontab, 90

I was hoping this would be shorter than the other shell answers. Still, I think it's an interesting approach:

for i in {0..11};{
s+=\ BONG
echo "0 $i,$[i+12] * * * echo$s>/proc/$PPID/fd/1"
}|crontab -

The script runs once, populates the crontab, then exits. However, the output from the cronjobs is sent to the terminal from which the script was run. I think this satisfies the submission must run forever requirement.

Warning - this will clear out any existing crontab entries, so make sure you have existing ones backed up.

This works on Ubuntu 16.04, which is using Vixie cron by default.

\$\endgroup\$
  • \$\begingroup\$ I ran it and got some "mail". When I checkout out the mail, there was one more BONG than necessary. \$\endgroup\$ – Cows quack Dec 30 '16 at 7:03
  • \$\begingroup\$ @KritixiLithos Thats odd. Which Linux distro are you using? Which cron are you using? \$\endgroup\$ – Digital Trauma Dec 30 '16 at 16:27
  • \$\begingroup\$ I'm on a mac, wait, that's not Linux \$\endgroup\$ – Cows quack Dec 30 '16 at 16:32
  • \$\begingroup\$ @KritixiLithos Yup ;-). This answer relies on Linux /proc/<PID>/fd/<N>. \$\endgroup\$ – Digital Trauma Dec 30 '16 at 16:33
3
\$\begingroup\$

Ruby, 112 99 Bytes

loop{sleep 2;n=Time.now;if(n.min==0);puts ('BONG '*n.strftime('%I').to_i).chop;sleep 60-n.sec end}

Old Version

loop{sleep(2);n=Time.now; if(n.min.zero?) then puts ('BONG ' * n.strftime('%I').to_i).chop;sleep(60-n.sec) end}

Thanks to QPaysTaxes for the tips

\$\endgroup\$
  • \$\begingroup\$ @Flp.Tkc Oh yes, nice catch! Forgot to delete the last character \$\endgroup\$ – Jatin Dhankhar Dec 25 '16 at 16:02
  • \$\begingroup\$ I don't know ruby, but the program must output within 3 seconds of the start of the new hour. I don't think sleep(60) makes that happen \$\endgroup\$ – Cows quack Dec 25 '16 at 16:02
  • \$\begingroup\$ @KritixiLithos We can make the program sleep for every 3 seconds and then do the caculation Loop -> Wake every 3 Seconds ; Check time and do stuff ? \$\endgroup\$ – Jatin Dhankhar Dec 25 '16 at 16:06
  • \$\begingroup\$ @JatinDhankhar Or you can make it sleep for 2 seconds (just to give some breathing space) \$\endgroup\$ – Cows quack Dec 25 '16 at 16:07
  • \$\begingroup\$ @KritixiLithos Yes, making the change to 2 seconds than Thanks \$\endgroup\$ – Jatin Dhankhar Dec 25 '16 at 16:12
3
\$\begingroup\$

Cheddar v1.0.5, 162 bytes

Cheddar has no built-in time reader/cmd output reader, so I had to improvise!

Golfed:

var f=->{IO.exec("time/t>c");(String::IO.read("c")).split(":")};var a=f()[0];for(;1;){var b=f();if(b[0]!=a){var c=Number::(a=b[0]);print("BONG "*c).head(5*c-1);}}

Ungolfed:

var f=->{
    IO.exec("time/t>c");
    (String::IO.read("c")).split(":")};
var a=f()[0];
for(;1;){
    var b=f();
    if(b[0]!=a){
        var c=Number::(a=b[0]);
        print("BONG "*c).head(5*c-1);
    }
}

Explanation:

Due to Cheddar's limited standard library, I had to use cmd to generate the time. I did this by saving the output of "time /t", which prints the time in 12-hour format, to a file named "c". IO.read returns a buffer which I casted to a string and split by ":" which ensured the hour is always in index zero. I saved that whole operation into a lambda expression which saved me 44 bytes. After that point it goes into the logic of "if stored hour doesn't equal current hour, set previous hour to current and print BONG n times, trim off the trailing space."

Cheddar may not be the least verbose language but it can be fun to find workarounds like this!

Sadly this is a Windows-only solution.

Edit 1: Saved two bytes by replacing "0<1" in the for-condition to "1" I didn't expect 1 to evaluate to true in this language!

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

Ruby, 82 81 bytes

loop{l=Time.new
puts ("BONG "*(l.hour%12+1)).chop if(l+1).hour!=l.hour
sleep 1}

Every second we check whether it's last second of the hour, and BONG accordingly. Could probably be golfed further with some dirty tricks, but I don't know too many. Also it works differently than the other Ruby answer.

One byte saved thanks to courtesy of QPaysTaxes.

\$\endgroup\$
  • \$\begingroup\$ Need to get into Ruby. It seems a bit less verbose than Python for golfing. \$\endgroup\$ – ElPedro Dec 26 '16 at 14:50
  • \$\begingroup\$ Do you need the space immediately after if? \$\endgroup\$ – Nic Hartley Dec 26 '16 at 16:04
  • \$\begingroup\$ @QPaysTaxes I don't, thank you. I was so mad about space after puts I forgot about that one. \$\endgroup\$ – Borsunho Dec 26 '16 at 18:03
3
\$\begingroup\$

Python 2, 105 106 bytes

import time
h=0
while 1:
 l=time.localtime();c=l[3]%12
 if l[4:6]==(0,0)and h!=c:print('BONG '*c)[:-1];h=c

Edit

Added one byte by changing < to != after feedback from @pinkfloydx33. Good spot.

Tested as much as possible locally but doesn't work on TIO as it (obviously) exceeds the 60 second execution limit. Please feel free to test locally :-)

btw, losing that pesky trailing space cost me 7 bytes otherwise this would have been under 100.

In the absence of TIO here is output after waiting an hour. Prog was started at 15:27 with extra debug code to show the time of the print (12 hour format).

python bigben.py
time is 4:0:0
BONG BONG BONG BONG
time is 5:0:0
BONG BONG BONG BONG BONG

Pretty straightforward but here is an explanation for anyone who is interested.

import time                 #Import the time module
h=0                         #Create a variable to store the hour that has just been printed
while 1:                    #Loop forever
 l=time.localtime()         #Get the local time from the time module
 c=l[3]%12                  #Set a variable to the current hour in 12 hour format
 if l[4:6]==(0,0)and h!=c:   #If minutes=0 and hours=0 and the last hour that was printed is not the current hour
  print "time is "+`c`+":"+`l[4]`+":"+`l[5]`    #Debug code to show hour
  print('BONG '*c)[:-1]     #Print 'BONG '*number of hours and lose the space from the end 
  h=c                       #Update the last hour that was printed
\$\endgroup\$
  • 1
    \$\begingroup\$ You can just check if the minutes are 0: l[4]==0and h<c. \$\endgroup\$ – Carra Dec 25 '16 at 18:51
  • \$\begingroup\$ Now that I think of it, there's the small problem that it doesn't work if you start the timer on 20:00:01. Minutes will be zero, seconds not and it will print the bongs \$\endgroup\$ – Carra Dec 25 '16 at 19:04
  • \$\begingroup\$ This doesn't output anything when I ran it locally \$\endgroup\$ – Cows quack Dec 26 '16 at 11:10
  • \$\begingroup\$ @KritixiLithos No idea why you get no output. I'm on Ubuntu 14 and Python 2.7.9. Want to take this to chat to discuss further? \$\endgroup\$ – ElPedro Dec 26 '16 at 16:04
  • 2
    \$\begingroup\$ Does this work from 11h->12h. (12%12=0)? Seems that 11>0, so h>c or am I missing something? \$\endgroup\$ – pinkfloydx33 Dec 27 '16 at 10:40
3
\$\begingroup\$

Python 3 - 100 97 92 bytes

from time import*
while 1:x=3600;sleep(x-time()%x);print(('BONG '*int(strftime("%I")))[:-1])[:-1])

Explanation:

import time;
while 1:
 t=time;x=3600;
 t.sleep(x-t.time()%x);#sleep for the remaining seconds until the next hour
 print(('BONG '*int(t.strftime("%I")))[:-1])#strftime("%")=nr of hours (1-12). Print the bongs and remove the last char
\$\endgroup\$
  • \$\begingroup\$ from time import*<NL>while 1:x=3600;sleep(x-time()%x);print(('BONG '*int(strftime("%I")))[:-1]) is 93 bytes \$\endgroup\$ – Roman Gräf Dec 27 '16 at 11:32
  • \$\begingroup\$ I don't think you need the semicolon at the end of the first line. \$\endgroup\$ – Nic Hartley Dec 27 '16 at 14:20
  • \$\begingroup\$ Removed the trailing ; \$\endgroup\$ – Carra Dec 29 '16 at 15:43
  • \$\begingroup\$ 92 bytes if you do from time import*, like this \$\endgroup\$ – FlipTack Dec 30 '16 at 12:30
  • \$\begingroup\$ Thanks for the tip, I've added it. Learning new things about Python every day :) \$\endgroup\$ – Carra Dec 30 '16 at 14:24
2
\$\begingroup\$

C, 238 bytes

#include<time.h>
#include<unistd.h>
i,j;f(){time_t t=time(0);struct tm l=*localtime(&t);for(;;){t=time(0),l=*localtime(&t),j=l.tm_hour;sleep(1);if(!(l.tm_min+l.tm_sec)){j=j%12?j<12?j:j-12:12;for(i=0;i<=j;i++)printf("BONG%c",i^j?32:10);}}}

I'm not sure if this works correctly, and I'm mobile, and my phone doesn't have a C compiler. (Only works on UNIX-like systems)

\$\endgroup\$
  • \$\begingroup\$ This produced infinite output (newlines) when I tried it \$\endgroup\$ – Cows quack Dec 25 '16 at 19:01
  • \$\begingroup\$ @KritixiLithos yes, I forgot to remove the part that I don't use anymore. Can you test in 7 minutes? :) \$\endgroup\$ – betseg Dec 25 '16 at 19:53
  • \$\begingroup\$ f instead of main? How is this supposed to work? \$\endgroup\$ – Thomas Padron-McCarthy Dec 26 '16 at 13:10
  • 1
    \$\begingroup\$ @ThomasPadron-McCarthy I'm fairly sure that providing a function, as opposed to a full program, is fine. \$\endgroup\$ – Nic Hartley Dec 26 '16 at 15:55
2
\$\begingroup\$

sh, 66 bytes

yes 'echo `yes BONG|sed $(date +%I)q`'|sh -s|awk '$0!=a&&a;{a=$0}'

Explained

#Pipe a command into a subshell repeatedly
yes 'some command'|sh -s

#Print "hour" (1-12) worth of "BONG" strings, one per line,
#use backticks to merge them into a single space-separated string.
#(stolen from zeppelin's answer)
echo `yes BONG|sed $(date +%I)q`

#Print every time the output changes
awk '$0!=a&&a;{a=$0}
\$\endgroup\$
  • \$\begingroup\$ This prints immediately once the program is run, it should not do that. The program must only output when a new hour has began \$\endgroup\$ – Cows quack Dec 26 '16 at 17:11
  • \$\begingroup\$ The same problem still appears \$\endgroup\$ – Cows quack Dec 26 '16 at 17:22
  • \$\begingroup\$ @KritixiLithos My bad. I had only updated explanation and byte count, not the actual code. \$\endgroup\$ – Rainer P. Dec 26 '16 at 17:32
  • \$\begingroup\$ Now all that is remaining is for me to test it at the hour \$\endgroup\$ – Cows quack Dec 26 '16 at 17:33
  • \$\begingroup\$ @KritixiLithos Replace %I with %M and it works for minutes. \$\endgroup\$ – Rainer P. Dec 26 '16 at 17:34
1
\$\begingroup\$

C, 198 bytes

#import<time.h>
h,i;f(){time_t t=time(0);struct tm l=*localtime(&t);for(h=l.tm_hour;;t=time(0),l=*localtime(&t))if(h-l.tm_hour%12){h=l.tm_hour%12;for(i=h?h%12:12;--i;)printf("BONG ");puts("BONG");}}
\$\endgroup\$
1
\$\begingroup\$

Javascript ES6 87 bytes

Edit: Shamelessly borrowed @ETHProductions' new Date/36e5%12|0||12 code to save 6 bytes

setInterval('Date().match`:00:00`?alert("BONG ".repeat(new Date/36e5%12|0||12)):5',1e3)

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

R, 104 105 bytes

f=format;repeat{Sys.sleep(1);q=Sys.time();if(f(q,"%M%S")=="0000")print(rep("BONG",as.double(f(q,"%I"))))}

Each second, it will (should) test whether we are at the end of an hour, then print that amount of BONGs.

\$\endgroup\$
  • \$\begingroup\$ When will this program output when the program is run at 12:00:01? \$\endgroup\$ – Cows quack Dec 25 '16 at 15:25
  • \$\begingroup\$ I don't know R, but the program must output within 3 seconds of the start of the new hour. I am not really sure if Sys.sleep(60) makes that happen \$\endgroup\$ – Cows quack Dec 25 '16 at 16:04
  • \$\begingroup\$ You can replace while(1) by repeat. \$\endgroup\$ – plannapus Dec 25 '16 at 18:10
  • \$\begingroup\$ The sleep interval must be shorter than the grace period after the hour for correctness. How about Sys.sleep(2) ? \$\endgroup\$ – newcoder Dec 26 '16 at 5:35
  • 1
    \$\begingroup\$ @newcoder Each loop it sleeps for 1 second now, because otherwise it would print BONG for 1 second, instead of just once. This is to ensure it only checks once per second. \$\endgroup\$ – JAD Dec 27 '16 at 12:09
1
\$\begingroup\$

JavaScript ES2015, 100 99 98 96 94 88 bytes

h=_=>new Date/36e5%12|0,p=h();for(;;)h()!=p&&(p=h(),alert('BONG '.repeat(p||12).trim()))

Explanation:

h is a function that gets the 12-hour-based hour of the day using the remainder operator (%12). 36e5 is the number of milliseconds in one hour using the exponential syntax to save characters. The new operator does not require that parentheses are used with functions if there are no arguments, hence new Date. JavaScript only has floating point arithmetic, the | bitwise OR operator forces the number to be an integer because JS bitwise operators work with the integer subset of the numbers represented by IEEE 754 floating point.

The comma delineates sub-expressions. p is initialized to the current hour (p=h()).

for(;;) is used to check repeatedly whether any BONGs should be alerted. Checking is performed as rapidly as the runtime will allow.

If the hour has changed (h()!=p), then we update p and then alert the BONGs. The logical AND operator is used as a guard (it short-circuits if h()===p) to determine if the BONGs are output.

String.prototype.repeat is new in ES2015 and saves some characters over using something like ES5's Array.prototype.join.

h returns zero for exact multiples of 12 (i.e. 12pm, 12am), so we change it to 12 using the logical OR p||12.

With thanks to Kritixi Lithos and ETHProductions for ideas.

\$\endgroup\$
  • \$\begingroup\$ I think you can remove the last semi-colon \$\endgroup\$ – Cows quack Dec 26 '16 at 9:42
1
\$\begingroup\$

Excel VBA, 143 Bytes

Code Outputs to the VBE Immediates Window

Sub b:Do:n=Now
If Minute(n)=0 Then:s="":For i=1To Hour(n) Mod 12:s=s &"BONG ":Next:Debug.?Trim(s):Application.Wait n+#0:1#:End If:Loop:End Sub

Fun version, 143 Bytes (Non-Competing)

While it would be rather difficult to get excel to go BONG, it is pretty straight forward to get excel to go Beep. The Beep call produces a beeping sound, and the code below uses this to produce beeps indicating the hour, on the hour, separated by 1 second pauses.

As with above, it this code makes excel appear unresponsive and adding a :DoEvents call to the end of the first line is recommended as it improves the user experience, however, this is not necessary for correct code execution.

Sub b:Set a=Application:Do:n=Now
If Minute(n)=0 Then:For i=1To Hour(n) Mod 12:Beep:a.Wait(Now+#0:0:1#):Next:a.Wait(n+#0:1#):End If:Loop:End Sub

Ungolfed Version

Public Sub BigBen()
    Dim i As Byte
    Dim n As Date
    Dim w As Worksheet
    Dim a As Excel.Application
    Set a = Application
    Set w = a.ThisWorkbook.Sheets(1)
    Let w.Name = "Big Ben"

    Let w.[A1] = Now
    w.Columns("A:A").AutoFit

    Do
        DoEvents
        Let n = Now
        If Minute(n) = 0 Then

            ''  Print BONG
            Let s = ""
            For i = 1 To Hour(n) Mod 12 Step 1
                Let s = s & "BONG "
            Next i
            Debug.Print Trim(s)

            ''  Go Beep
            For i = 1 To Hour(n) Mod 12 Step 1
                Beep
                a.Wait (Now + #12:00:01 AM#) ''  <- #0:0:1# resolves to #12:00:01 AM#
            Next i

            ''  Keep Ticking After Going BONG
            While Now < n + #12:01:00 AM#    ''  <- #0:1# resolves to #12:01:00 AM#
                Let w.[A1] = Now
                Let a.StatusBar = IIf(Second(Now) Mod 2, "Tick", "Tock")
                DoEvents
            Wend
        End If

        ''  Tick Tock until its time to Go BONG again
        Let a.StatusBar = IIf(Second(n) Mod 2, "Tick", "Tock")
        Let w.[A1] = Now
    Loop

End Sub
\$\endgroup\$
  • \$\begingroup\$ Is it possible to test this on a non-Windows computer? If not, could you provide a gif of the output when a new hour begins? \$\endgroup\$ – Cows quack Dec 27 '16 at 14:21
  • \$\begingroup\$ To be entirely honest, I am not immediately sure. It will not be possible to test this code on a linux machine, but it should function properly on a Mac. However, it may be that the Beep or DoEvents Calls do not function properly on mac machines. \$\endgroup\$ – Taylor Scott Dec 27 '16 at 14:24
0
\$\begingroup\$

C# 234 Bytes

I'm not planning on winning any prizes here, but a C# implementation is compulsory.

using System;
using System.Linq;namespace B{class P{static void Main(){Func<int> h=()=>DateTime.Now.Hour % 12;var p=h();while (true){var t=h();if (t!=p)Console.WriteLine(string.Concat(Enumerable.Repeat("BONG",t== 0?12:t)));p=t;}}}}

Ungolfed with comments:

using System;
using System.Linq;

namespace B
{
    class P
    {
        static void Main()
        {
            Func<int> h = () => DateTime.Now.Hour % 12; // h(): the hour in the range [0, 11], making this a lambda saves a few chars
            var p = h(); // p: Previous time
            while (true)
            {
                var t = h(); // t: Current time
                if (t != p) // If current hour is different to previous hour
                    Console.WriteLine(string.Concat(Enumerable.Repeat("BONG", t == 0 ? 12 : t))); // Print "BONG" t times (also correcting t = 0 to 12)
                p = t; // Current time is now previous time
            } // Repeat ad nauseum
        }
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Use for(;;), change h=()=>1+(DateTime.Now.Hour-1)%12; (note no whitespace either) and then Enumerable.Repeat becomes ("BONG",t) (saves you either two or three) then get rid of extra whitespace ie if(...) Also note this will print all the bongs concatenated, probably take those byte savings to turn concat into join with a space as its first argument. \$\endgroup\$ – pinkfloydx33 Dec 27 '16 at 11:16
0
\$\begingroup\$

Groovy, 72 bytes

{x={new Date().getHours()};y=x();while(1){if(y!=(y==x()){print "BONG "*y}}​}​​​

How?

Store a method to get current hours.

x={new Date().getHours()};

Store initial hours.

y=x();

While true, if current hour not equal previous hour, output current hour multiplied by "BONG " to output current hour of bongs.

while(1){if(y!=(y==x()){print "BONG "*y}}

+3 bytes %12 for non-military bongs.

\$\endgroup\$
0
\$\begingroup\$

perl, 60 bytes

Update

Replaced " " with $", removed CORE::, corrected count.

Golf

say join$",(BONG)x(time/3600%12||12)while sleep -time%3600+1

This needs to be run with perl -E.

Remarks

  • In perl, x while y is equivalent to while(y){x} (where x is a single statement) but does not need the brackets. sleep is executed the first time before anything is printed.
  • time uses UTC. The original Big Ben is on summer time (British Summer Time, BST) from the end of March until the end of October.
  • One second is added to the wait time in order to ensure that the program waits for at least one second. This means that the BONGs will always be printed one second late, which is legal according to the rules. Let's say you're standing on Westminster Bridge, ca. 300 m away from Big Ben. On the plus side, this also means that the program will print the correct amount of BONGs if it is started at exactly the beginning of an hour (instead of waiting 3600 seconds).
  • sleep returns the number of seconds waited. This will always be true.
\$\endgroup\$
  • 1
    \$\begingroup\$ 2 things. 1, I'm pretty sure the -E flag is +1 byte (there's a page somewhere about measuring flags...). 2, I'm not sure how to run this as perl -E golf.pl appears to terminate immediately. \$\endgroup\$ – redstarcoder Dec 30 '16 at 16:44
0
\$\begingroup\$

QBIC, 82 bytes

X=$left$|(_d,2){Y=left$$|(_d,2)~Y<>X|x=!Y!%12~x=0|x=12]B=C[x|B=B+@BONG |]?_tB|]X=Y

Really need to change the token for code literals ($) and implement a substring feature (left$(x,y) can be shorter).

The inner workings:

In the first part, we want to set X$ to the hour-component
of our system's time. The DATE is implemented in QBIC, but
Substring (LEFT$, RIGHT$ and MID$ in QBasic) is not (yet).
We need to use the QBasic LEFT$ function, and QBIC can do 
that using a 'code literal': everything from '$' to '|'
is not parsed by QBIC but passed on to QBasic.
X=               Set X$ to
$left$|(         the leftmost (note the '$' and '|' for the code literal)
_d,2)            2 characters of TIME$ (hh:mm format)
{                DO - infinite loop
Y=left$$|(_d,2)  Set Y$ in the same way
~Y<>X            If Y$ is not equal to X$ the hour has changed
|x=!Y!%12        THEN set x to the modulo 12 of Y$ cast to number
~x=0|x=12]       If Y% happens to be divisible by 12, set x to 12
B=C              Clear B$ (c$ never gets assiged a value)
[x|B=B+@BONG |]  For the given number of hours, add "BONG " to B$
?_tB|            Print B$, trim the trailing space
]                end if
X=Y              Update X$
<DO LOOP is implicitly closed>

Update (NC): The $ is no longer used in QBICs instruction set, so it can now be used freely as code for QBasic without the need for code literals. In this case, it saves 4 bytes, bringing QBIC to 78 bytes:

X=left$(_d,2){Y=left$(_d,2)~Y<>X|x=!Y!%12~x=0|x=12]B=C[x|B=B+@BONG `]?_tB|]X=Y
\$\endgroup\$
0
\$\begingroup\$

SmileBASIC, 74 67 bytes

WAIT 61TMREAD OUT H,M,S?("BONG"+" BONG"*((H+11)MOD 12))*!(M+S)EXEC.

Outputs large amounts of "trailing" line breaks ;)

Edit: saved 7 bytes with a better 24->12 hour algorithm.

\$\endgroup\$
0
\$\begingroup\$

PHP, 63 bytes

I could save two more bytes with extended ASCII. But I am currently too lazy for that.

for(;;sleep(1))+date(is)?:print str_pad("
",5*date(h),"BONG ");

prints the BONGs with a leading linebreak precisely at the full hour. Run with -nr.

\$\endgroup\$
  • \$\begingroup\$ You have to include the flags in your bytecount \$\endgroup\$ – Cows quack Jan 31 '17 at 7:28
  • \$\begingroup\$ @KritixiLithos No I don´t. -n is kind of implicit (ignore php.and fall back to default config values); -r tells PHP to run code from a command line parameter instead of from a file. \$\endgroup\$ – Titus Jan 31 '17 at 7:36
  • \$\begingroup\$ Ah, my bad, I don't know PHP. \$\endgroup\$ – Cows quack Jan 31 '17 at 9:15
0
\$\begingroup\$

C, 152

int a=0,i,L=25;main(){char s[9];for(i=-1;++i<48;){sprintf(s,"%02i:00:00",i);if(!strcmp(s,__TIME__)&&i!=L)a=L=i,i=-1;printf(a-->0?"BONG ":"\n");}main();}

Readable:

int a=0,i,L=25;

main(){
    char s[9];
    for(i=-1;++i<48;){
        sprintf(s,"%02i:00:00",i);
        if(!strcmp(s,__TIME__)&&i!=L)
            a=L=i,i=-1;
        printf(a-->0?"BONG ":"\n");
    }
    main();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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