40
\$\begingroup\$

This challenge is inspired by xkcd:

enter image description here

Challenge:

You'll simulate the copying a large file (1 Gigabyte). The transfer rate will vary between 10 kB/second to 100 MB/second. Your task is to output the time remaining of the file transfer. The output should look like:

Time remaining: 03:12    (meaning it's 3 minutes and 12 seconds left)
Time remaining: 123:12   (meaning it's 2 hours, 3 minutes and 12 seconds left)
Time remaining: 02:03:12 (optional output, meaning the same as above)

Leading zeros need not be displayed for minutes and hours (optional), but must be shown for seconds. Showing the time remaining using only seconds is not OK.

The file transfer:

  • The transfer rate will start at 10 MB/second.
  • Every second, there will be a 30% chance that the transfer rate will change
  • The new transfer rate should be picked randomly (uniform distribution) in the range [10 kB/s, 100 MB/s], in steps of 10 kB/s.

Note: You don't need to actually copy a file.

You may choose to use: 1 GB = 1000 MB, 1 MB = 1000 kB, 1 kB = 1000 B, or 1 GB = 1024 MB, 1 MB = 1024 kB, 1 kB = 1024 B.

Output:

  • You start at 01:40, not 01:39.
  • You display the time after the transfer rate changes, but before anything is transferred at that rate
  • The seconds should be displayed as integers, not decimals. It's optional to round up/down/closest.
  • You should clear the screen every second, unless that's impossible in your language.
  • The output should be constant: Time remaining: 00:00 when the file transfer is over.

Example:

I have rounded up all decimal seconds. Assume the lines below are shown with 1 second in between, and the screen is cleared between each one:

Time remaining: 01:40  (Transfer rate: 10 MB/s)
Time remaining: 01:39      1 GB - 10 MB
Time remaining: 01:38      1 GB - 2*10 MB
Time remaining: 01:37      1 GB - 3*10 MB
Time remaining: 01:28:54   1 GB - 4*10 MB  (TR: 180 kB/s)
Time remaining: 01:28:53   1 GB - 4*10 MB - 180 kB
Time remaining: 01:28:52   1 GB - 4*10 MB - 2*180 kB  
Time remaining: 00:13      1 GB - 4*10 MB - 3*180 kB  (TR: 75 MB/s)
Time remaining: 00:12      1 GB - 4*10 MB - 3*180 kB - 75 MB
Time remaining: 00:11      1 GB - 4*10 MB - 3*180 kB - 2*75 MB
Time remaining: 00:10      1 GB - 4*10 MB - 3*180 kB - 3*75 MB
Time remaining: 00:09      1 GB - 4*10 MB - 3*180 kB - 4*75 MB
Time remaining: 00:08      1 GB - 4*10 MB - 3*180 kB - 5*75 MB
Time remaining: 14:09:06   1 GB - 4*10 MB - 3*180 kB - 6*75 MB  (TR: 10 kB/s)
Time remaining: 14:09:05   1 GB - 4*10 MB - 3*180 kB - 6*75 MB - 10 kB
Time remaining: 00:06      1 GB - 4*10 MB - 3*180 kB - 6*75 MB - 20 kB  (TR: 88.110 MB/s)
Time remaining: 00:05
Time remaining: 00:04
Time remaining: 00:03
Time remaining: 00:02
Time remaining: 00:01
Time remaining: 00:00     <- Transfer is finished. Display this.
\$\endgroup\$
  • 1
    \$\begingroup\$ You should put the XKCD tool-tip text below the image. Save people the time of having to look it up themselves. \$\endgroup\$ – mbomb007 Feb 2 '17 at 20:39
  • 6
    \$\begingroup\$ @mbomb007, hover the image :) \$\endgroup\$ – Stewie Griffin Feb 2 '17 at 20:43
  • \$\begingroup\$ Should that be, "you start at 1:40 (or 1:42) not 1:39 (or 1:41)"? \$\endgroup\$ – Jonathan Allan Feb 2 '17 at 20:57
  • \$\begingroup\$ Also if we are using the 1024 version, what are the step sizes we should be using? \$\endgroup\$ – Jonathan Allan Feb 2 '17 at 21:00
  • \$\begingroup\$ If hours remaining is zero, can we leave output as 00:00:10 for example? \$\endgroup\$ – AdmBorkBork Feb 2 '17 at 21:12
9
\$\begingroup\$

Pyth - 70 68 bytes

K^T5J^T3W>KZ%." r3úBTê;¥
í".D/KJ60=J?<OT3O^T4J=-KJ.d1.

Try it online without sleeps.

\$\endgroup\$
  • \$\begingroup\$ @DigitalTrauma sorry, was using Luis' answer as a guide ._. \$\endgroup\$ – Maltysen Feb 3 '17 at 1:58
  • \$\begingroup\$ @DigitalTrauma fixed. \$\endgroup\$ – Maltysen Feb 3 '17 at 1:59
  • 6
    \$\begingroup\$ Lol. When porting from (golfing) language A to (golfing) language B is easier than reading the spec ;-) \$\endgroup\$ – Digital Trauma Feb 3 '17 at 2:00
  • \$\begingroup\$ @Maltysen Sorry about that! :-) \$\endgroup\$ – Luis Mendo Feb 3 '17 at 2:05
  • 2
    \$\begingroup\$ Can you give an explanation of what the heck is going on here? \$\endgroup\$ – David says Reinstate Monica Feb 4 '17 at 1:27
8
\$\begingroup\$

PowerShell, 190 215 187 bytes

($t="Time remaining: ")+"00:01:42";for($f,$r=1gb,10mb;$f-gt0;$f-=$r){if((Random 10)-lt3){$r=(Random -mi 1kb -ma (10mb+1))*10}$t+[Timespan]::FromSeconds([int]($f/$r));sleep 1}$t+"00:00:00"

Try it online! (TIO doesn't support clearing screen between lines)

Sets our initial $file size and our initial transfer $rate to 1gb and 10mb/s, respectively. Then, so long as we still have $file remaining, we loop.

Inside the loop, the if selects a number from 0 to 9 inclusive, and if it's 0, 1, or 2 (i.e., 30% of the time), we change the rate. This picks a random integer between 1kb and 10mb then that's multiplied by 10 to get our step count.

We then leverage the FromSeconds static method from the TimeSpan .NET library to construct the time remaining. The output format of that call exactly matches the challenge requirements, so no need for additional formatting.

(Saved a bunch thanks to @ConnorLSW)

\$\endgroup\$
  • 1
    \$\begingroup\$ @StewieGriffin TIO has output caching. Select "disable output cache" in the Settings drawer, and it gives different results. \$\endgroup\$ – TheBikingViking Feb 2 '17 at 22:03
  • \$\begingroup\$ Maybe I'm missing something but the -f operator doesn't appear to do anything. By taking that out and using for loop instead of while, and then changing both instances of get-date to date, I was able to shave off 22 bytes. Try it online! \$\endgroup\$ – briantist Feb 3 '17 at 14:05
  • \$\begingroup\$ @briantist TIO requires Get-Date because otherwise it uses the Linux date command, which is different. You can drop it on Windows because PowerShell wraps the Windows date command. But, thanks for the for loop construction! \$\endgroup\$ – AdmBorkBork Feb 3 '17 at 14:18
  • \$\begingroup\$ @AdmBorkBork yeah I noticed that, but in a stock Windows environment it would work. I wonder if it's acceptable to just put nal date get-date in the header in TIO? \$\endgroup\$ – briantist Feb 3 '17 at 14:19
  • \$\begingroup\$ @AdmBorkBork and on windows it doesn't wrap the windows date command, it just ignores it because it's not an .exe on windows, so it falls back to the same behavior as random (try the command with get- prepended if all else fails). \$\endgroup\$ – briantist Feb 3 '17 at 14:22
5
\$\begingroup\$

MATL, 78 bytes

Thanks to @Maltysen and @DigitalTrauma for corrections.

1e5 1e3`XK10&XxyXIy/t0>*12L/'MM:SS'XO'Time remaining: 'whD-r.3<?1e4Yr}K]I0>]xx

Try it at MATL Online! (you may need to press "Run" several times if it doesn't initially work).

The online interpreter times out after 30 seconds. You may want to change 10 (pause time in tenths of second) to something smaller such as 3 in order to increase speed of display

Explanation

1e5                  % Push 1e5: file size in 10-kB units
1e3                  % Push 1e3: initial rate in 10-kB/s units
`                    % Do...while
  XK                 %   Copy current rate into clipboard K (doesn't consume it)
  10&Xx              %   Wait 1 second and clear screen
  y                  %   Duplicate current file size onto the top of the stack
  XI                 %   Copy it to clipboard I (doesn't consume it)
  y                  %   Duplicate current rate onto the top of the stack
  /                  %   Divide. This gives the estimated remaining time in seconds
                     %   It may be negative in the last iteration, because the
                     %   "remaining" file size may have become negative
  t0>*               %   If negative, convert to 0
  12L/               %   Push 86400 and divide, to convert from seconds to days
  'MM:SS'XO          %   Format as a MM:SS string, rounding down
  'Time remaining: ' %   Push this string
  wh                 %   Swap, concatenate
  D                  %   Display
  -                  %   Subtract. This gives the new remaining file size
  r                  %   Push random number uniformly distributed in (0,1)
  .3<                %   Is it less than 0.3?
  ?                  %   If so
    1e4Yr            %     Random integer between 1 and 1e4. This is the new rate 
                     %     in 10-kB/s units
  }                  %   Else
    K                %     Push rate that was copied into clipboard K
  ]                  %   End
  I                  %   Push previous remaining file size from clipboard I
  0>                 %   Is it positive?
]                    % End. If top of the stack is true: next iteration
xx                   % Delete the two numbers that are on the stack
\$\endgroup\$
  • \$\begingroup\$ I don't understand MATL, but it looks to me as if you're always getting a new rate instead of only 30% of the time from your explanation. \$\endgroup\$ – Maltysen Feb 3 '17 at 1:21
  • \$\begingroup\$ @Maltysen Corrected now. Thanks for the heads-up! \$\endgroup\$ – Luis Mendo Feb 3 '17 at 1:38
  • \$\begingroup\$ @DigitalTrauma Corrected now \$\endgroup\$ – Luis Mendo Feb 3 '17 at 1:55
5
\$\begingroup\$

Ruby, 116 110 bytes

Try it online, except repl.it reads \r as a newline and also can't use $><< so it's replaced with its 5-byte equivalent, print.

Shoutout to JonasWielicki for the initial idea of using \r to reset the line.

f=1e5;r=1e3;(k=f/r=rand<0.3?1+rand(1e4):r;$><<"\rTime remaining: %02d:%02d"%[k/60,k%60];f-=r;sleep 1)while f>0

This version is untested on Windows, but works on Unix.

\$\endgroup\$
4
\$\begingroup\$

Bash + common utils, 117

Straightforward implementation. A few bytes saved by dividing out by 10000:

for((b=10**5,r=1000;b>0;r=RANDOM%10<3?RANDOM%10000+1:r,b-=r));{
clear
date -ud@$[b/r] "+Time remaining: %T"
sleep 1
}

Try it online. Using sleep 0 on the TIO so you don't have to wait. clear doesn't work on TIO.

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

JavaScript (ES6), 162 bytes

Shows minutes as is with padded seconds (floored)

E.g., 123:45

t=1e5
s=1e3
setInterval(c=>c.log(`Time remaining: ${c.clear(d=t/s),d/60|0}:`+`0${t-=s>t?t:s,r=Math.random,s=r()<0.3?1+r()*1e4|0:s,d%60|0}`.slice(-2)),1e3,console)

\$\endgroup\$
  • \$\begingroup\$ I think you forgot to shorten console.clear to c.clear ;-) That's a great idea, BTW \$\endgroup\$ – ETHproductions Feb 3 '17 at 18:47
  • \$\begingroup\$ @ETHproductions Ooooops! Thanks :) \$\endgroup\$ – George Reith Feb 3 '17 at 18:55
  • \$\begingroup\$ You could get this down to 154 bytes by adding HTML - <input id=o> - and making a couple of other adjustments: t=1e5;i=s=1e3;setInterval(_=>o.value=`Time remaining: ${(d=t/s)/60|0}:`+`0${t-=s>t?t:s,r=Math.random(),s=r<.3?1+r*1e4|0:s,d%60|0}`.slice(-2),i) \$\endgroup\$ – Shaggy May 12 '17 at 14:51
2
\$\begingroup\$

Python 3.6 (212 203 bytes)

from random import*
import time,datetime
r=1e7
d=1e9
while 1:
 print(f"\x1b[KTime remaining: {datetime.timedelta(seconds=d//r)}",end="\r");d=max(0,d-r);time.sleep(1)
 if random()>.7:r=randint(1,1e4)*1e4

Pretty straightforward, I think. Erases the line using ANSI escape sequence and K command.

\$\endgroup\$
  • 1
    \$\begingroup\$ Skip a space in your first line with from random import*. d//r is shorter than int(d/r). Also, might as well go with r=1e7;d=1e9 from the start. \$\endgroup\$ – Value Ink Feb 3 '17 at 23:55
  • \$\begingroup\$ @ValueInk Right, didn’t think of 1eX for r and d because I wanted them to be integers; when I shortened the randint line, I forgot about that ... :) \$\endgroup\$ – Jonas Schäfer Feb 4 '17 at 8:45
1
\$\begingroup\$

Batch, 193 bytes

@set/ap=10000,s=p*10,r=p/10
:l
@set/at=s/r,m=t/60,n=t%%60+100,s-=r
@cls
@echo Time remaining: %m%:%n:~1%
@timeout/t>nul 1
@if %random:~-1% lss 3 set/ar=%random%%%p+1
@if %t% gtr 0 goto l

Note: Slight bias towards rates of 27.68 MB/s or less.

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

C 184 171 155 bytes

f(){i,j=0,r=1e7;for(i=1e9;i>0;i-=r){j=i/r;printf("Time remaining: %02d:%02d:%02d\r",j/3600,(j/60)%60,j%60);sleep(1);if(rand()%10<3)r=(rand()%10000)*1e4;}}

I hope this qualifies.

Ungolfed version:

void f()
{
    int j=0;
    float rate=1e7; 
    for(int size=1e9;i>0; size-=rate)
    {     
       j=size/rate;      
       printf("Time remaining: %02d:%02d:%02d\r",j/3600,(j/60)%60,j%60);
       sleep(1);

       if(rand()%10<3)
          rate=(rand()%10000)*1e4;          



   }

}

Explanation: In the golfed version i corresponds to size in ungolfed version and r is rate in ungolfed version. j stores the time remaining in seconds.

  • I have 10^9 bytes to copy. I start copying at the rate of 10 Megabytes/second,
  • If the probablity is less than 30% , change the rate (from 10 kilobytes to 100 Megabytes per second)

@ValueInk Thanks for saving 13 bytes.

@nmjcman101 Thanks for saving 16 bytes.

\$\endgroup\$
  • \$\begingroup\$ This doesn't look like it actually does what the challenge says. Can you explain how it works? \$\endgroup\$ – Value Ink Feb 4 '17 at 6:45
  • \$\begingroup\$ It just simulates time output, i have not figured out how to do the data transfer part. Guess I'm gonna put this on hold until then. \$\endgroup\$ – Abel Tom Feb 4 '17 at 6:53
  • \$\begingroup\$ You don't change the rate after 3 iterations. It has a 30% chance of changing. So you probably want to do something similar to the following: if(rand()%10<3)r=(rand()%10000+1)*1e4; (Especially since the minimum rate is 10 kB/s, not 1MB/s like your solution is saying, and the rate chance should be a somewhat uniform distribution.) \$\endgroup\$ – Value Ink Feb 8 '17 at 3:40
  • \$\begingroup\$ @ValueInk Thanks so much. :) Updated. Gets the work done! I did not know how exactly to simulate the 30% probability part. So much clearer now. \$\endgroup\$ – Abel Tom Feb 8 '17 at 10:01
  • \$\begingroup\$ you can golf j/3600,(j/60)%60,j%60 (21) with s=60; and j/s/s,j/s%s,j%s (20) \$\endgroup\$ – Davide Feb 9 '17 at 15:19

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.