New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Year Countdown in Elixir #5

Open
emson opened this Issue Dec 18, 2015 · 13 comments

Comments

Projects
None yet
3 participants
@emson
Owner

emson commented Dec 18, 2015

The puzzle is to create a countdown timer that displays the number of Days:Hours:Minutes:Seconds until the next New Year. This countdown timer will decrease every cond until 000:00:00:00.
See the website for more details : http://elixirgolf.com/articles/new-year-countdown-in-elixir/

  • The code will be executed using the elixir countdown.exs terminal command. We will manually copy all your solutions into this file, so just add comments below to submit your solutions.
  • The timer will be in the following format Days:Hours:Minutes:Seconds
  • The time should be represented as numbers, separated by colons: 000:00:00:00
  • Every second the timer should decrease by 1 second, and all the other fields should adjust accordingly.
  • The timer should only display one timer at any time, i.e. it should have some mechanism to clear the screen or update itself every second. It should NOT display a long list of times, like the example above.
  • The timer should countdown to the next New Year e.g. January 1st 2016.

As a bit of fun and a side project maybe consider the following flourishes:

  • Colour the numbers
  • Allow the countdown timer to dynamically adjust to the following New Year after this one
  • Trigger some exciting output when the countdown reaches 000:00:00:00.
  1. Please add your solutions as comments to this Github issue
  2. Remember to add your Twitter handle (I will link to it if you get a mention)
    Many thanks, Ben
    When the puzzle is over I'll write them up on http://elixirgolf.com and link back to your Twitter handle
@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Dec 18, 2015

213 chars (214 bytes)

  • the timer sends message 0 every second to the current process, this will hopefully prevent timing issues (printing + sleep 1000 will actually take longer than a second and eventually results in a skipped second)
  • stole the trick of encoding the number 1000 as from @henrik
  • Used the f = fn(f) -> f.(f) end trick to be able to do recursion without having to define a module
  • 2016-01-01 00:00 is hard-coded as 1451606400
  • used :erlang.system_time 1 to get the current unix time in seconds
  • Used the DEL character \r to clear the line before printing the new values
:timer.send_interval ,0
f=fn f->receive do 0->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
end
f.(f)end
f.(f)

Twitter: @der_padde

padde commented Dec 18, 2015

213 chars (214 bytes)

  • the timer sends message 0 every second to the current process, this will hopefully prevent timing issues (printing + sleep 1000 will actually take longer than a second and eventually results in a skipped second)
  • stole the trick of encoding the number 1000 as from @henrik
  • Used the f = fn(f) -> f.(f) end trick to be able to do recursion without having to define a module
  • 2016-01-01 00:00 is hard-coded as 1451606400
  • used :erlang.system_time 1 to get the current unix time in seconds
  • Used the DEL character \r to clear the line before printing the new values
:timer.send_interval ,0
f=fn f->receive do 0->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
end
f.(f)end
f.(f)

Twitter: @der_padde

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Dec 19, 2015

176 characters (counting newlines):

for x<-1451606400-:erlang.system_time(1)..0do
m=div x,60
s=rem x,60
h=div m,60
m=rem m,60
:io.fwrite"~3..0B:~2..0B:~2..0B:~2..0B\r",[div(h,24),rem(h,24),m,s]
:timer.sleep end

(Stole the shorter :erlang.system_time(1) from @padde, who also suggested inlining the div and rem – thank you!)

An important difference to @padde's solution is that this one is likely to drift. See notes below.

What it does:

  • Calculates the number of seconds between now and new year 2016.
  • Loops from that number down to 0.
  • On each iteration, it calculates times using a "divmod" strategy (integer division, and the modulus of the same).
  • It uses format strings to output this.
  • It uses \r (carriage return) to rewrite the same line. Since the line length never shrinks (thanks to the specified zero-padding), we don't need to clear out the line first.
  • It sleeps for a second before the next iteration.

Notes:

  • Hard-coded to UTC new year 2016 (the magic number 1451606400 is that timestamp)
  • The implementation is obviously a bit stupid (probably wouldn't handle e.g. computer sleep gracefully, and risks some drift since each iteration takes more than zero time) – optimised for length :)
  • Probably behaves weirdly if run after the fact (but it does stop nicely at 0, if run before)
  • is 1000. Figured it out like so: to_string [1000]

Some abandoned ideas:

  • Tried using hexadecimal for the hardcoded timestamp but it was the same length (0x5685C180)
  • Tried to abbreviate :os.system_time(:seconds) with something like :os.system_time/1.0e9 but with little luck since you get a float, not an int.

My Gist is here if you want to see a bit of the progression: https://gist.github.com/henrik/856b02213fddb7829fdd

Twitter: @henrik

henrik commented Dec 19, 2015

176 characters (counting newlines):

for x<-1451606400-:erlang.system_time(1)..0do
m=div x,60
s=rem x,60
h=div m,60
m=rem m,60
:io.fwrite"~3..0B:~2..0B:~2..0B:~2..0B\r",[div(h,24),rem(h,24),m,s]
:timer.sleep end

(Stole the shorter :erlang.system_time(1) from @padde, who also suggested inlining the div and rem – thank you!)

An important difference to @padde's solution is that this one is likely to drift. See notes below.

What it does:

  • Calculates the number of seconds between now and new year 2016.
  • Loops from that number down to 0.
  • On each iteration, it calculates times using a "divmod" strategy (integer division, and the modulus of the same).
  • It uses format strings to output this.
  • It uses \r (carriage return) to rewrite the same line. Since the line length never shrinks (thanks to the specified zero-padding), we don't need to clear out the line first.
  • It sleeps for a second before the next iteration.

Notes:

  • Hard-coded to UTC new year 2016 (the magic number 1451606400 is that timestamp)
  • The implementation is obviously a bit stupid (probably wouldn't handle e.g. computer sleep gracefully, and risks some drift since each iteration takes more than zero time) – optimised for length :)
  • Probably behaves weirdly if run after the fact (but it does stop nicely at 0, if run before)
  • is 1000. Figured it out like so: to_string [1000]

Some abandoned ideas:

  • Tried using hexadecimal for the hardcoded timestamp but it was the same length (0x5685C180)
  • Tried to abbreviate :os.system_time(:seconds) with something like :os.system_time/1.0e9 but with little luck since you get a float, not an int.

My Gist is here if you want to see a bit of the progression: https://gist.github.com/henrik/856b02213fddb7829fdd

Twitter: @henrik

@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Dec 19, 2015

@henrik quick win: by inlining the div/rem as I did, you can shave off another 10 chars or so. I tried hard to extract a function for this but it was always much longer than writing it directly.

If you would allow me to criticise your solution: it will run slow rather quickly because doing the computations and printing, then sleeping for a second will actually take longer than a second.

padde commented Dec 19, 2015

@henrik quick win: by inlining the div/rem as I did, you can shave off another 10 chars or so. I tried hard to extract a function for this but it was always much longer than writing it directly.

If you would allow me to criticise your solution: it will run slow rather quickly because doing the computations and printing, then sleeping for a second will actually take longer than a second.

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Dec 19, 2015

@padde Good call on the div/rem. Never tried the non-abbreviated version there :) Thank you!

Yeah, I realized pretty quickly that it is prone to drift (put it in my notes above). I might make a stab at a drift-safe one, though you've done a good job of that already :)

henrik commented Dec 19, 2015

@padde Good call on the div/rem. Never tried the non-abbreviated version there :) Thank you!

Yeah, I realized pretty quickly that it is prone to drift (put it in my notes above). I might make a stab at a drift-safe one, though you've done a good job of that already :)

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Dec 19, 2015

@padde Looked for ways to abbreviate yours; not easy… If one doesn't care about performance, seems it can be shortened to skip the whole interval thing and just have a very CPU-wasteful loop:

f=fn f->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
f.(f)end
f.(f)

henrik commented Dec 19, 2015

@padde Looked for ways to abbreviate yours; not easy… If one doesn't care about performance, seems it can be shortened to skip the whole interval thing and just have a very CPU-wasteful loop:

f=fn f->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
f.(f)end
f.(f)
@emson

This comment has been minimized.

Show comment
Hide comment
@emson

emson Dec 19, 2015

Owner

Oh wow... very interesting. It's amazing what these puzzles bring out. Well done @padde and @henrik

Owner

emson commented Dec 19, 2015

Oh wow... very interesting. It's amazing what these puzzles bring out. Well done @padde and @henrik

@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Dec 20, 2015

@henrik nice idea! However it seems to be stuck at the first second. I guess the massive amount of printing takes way too long for this to work.

Maybe one could combine that approach with sleeping for some time. According to the sampling theorem we need a total cycle time that is below 500ms in order not to miss a second. So we should be safe with a sleep time < (500ms - max(time for other computations)). In theory we cannot predict how long it will take, but in practice we should be safe with a sleep time of say 100ms (or ?d).

f=fn f->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
:timer.sleep ?d
f.(f)end
f.(f)

For the record: this joint effort takes 185 chars (and an equal amount of bytes since there are no multi byte characters involved).

padde commented Dec 20, 2015

@henrik nice idea! However it seems to be stuck at the first second. I guess the massive amount of printing takes way too long for this to work.

Maybe one could combine that approach with sleeping for some time. According to the sampling theorem we need a total cycle time that is below 500ms in order not to miss a second. So we should be safe with a sleep time < (500ms - max(time for other computations)). In theory we cannot predict how long it will take, but in practice we should be safe with a sleep time of say 100ms (or ?d).

f=fn f->t=1451606400-:erlang.system_time 1
s=rem t,60
t=div t,60
m=rem t,60
t=div t,60
:io.format'\r~3..0B:~2..0B:~2..0B:~2..0B',[div(t,24),rem(t,24),m,s]
:timer.sleep ?d
f.(f)end
f.(f)

For the record: this joint effort takes 185 chars (and an equal amount of bytes since there are no multi byte characters involved).

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Dec 31, 2015

@padde Hm, stuck at the first second? Seems to run fine for me, though it spikes the CPU. Haven't left it running for a long time, maybe it degrades.

henrik commented Dec 31, 2015

@padde Hm, stuck at the first second? Seems to run fine for me, though it spikes the CPU. Haven't left it running for a long time, maybe it degrades.

@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Jan 6, 2016

@henrik checked again, still does not work for me. Very strange. Are you running the latest versions of Erlang and Elixir?

padde commented Jan 6, 2016

@henrik checked again, still does not work for me. Very strange. Are you running the latest versions of Erlang and Elixir?

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Jan 6, 2016

@padde Yeah, now running Elixir 1.2 and Erlang/OTP 18. On OS X.

Bumped the timestamp since it's past new year's:

countdown

henrik commented Jan 6, 2016

@padde Yeah, now running Elixir 1.2 and Erlang/OTP 18. On OS X.

Bumped the timestamp since it's past new year's:

countdown

@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Jan 7, 2016

@henrik me too. It seems to update the time once as soon as I send Ctrl-C to iex though:

ezgif com-video-to-gif

padde commented Jan 7, 2016

@henrik me too. It seems to update the time once as soon as I send Ctrl-C to iex though:

ezgif com-video-to-gif

@henrik

This comment has been minimized.

Show comment
Hide comment
@henrik

henrik Jan 7, 2016

I use iTerm - maybe it has a problem in Terminal.app? Will try that tomorrow.

henrik commented Jan 7, 2016

I use iTerm - maybe it has a problem in Terminal.app? Will try that tomorrow.

@padde

This comment has been minimized.

Show comment
Hide comment
@padde

padde Jan 7, 2016

I think I found it. This seems to be a tmux problem, don't really understand why this happens though.

padde commented Jan 7, 2016

I think I found it. This seems to be a tmux problem, don't really understand why this happens though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment