0

I am making a Python program in Replit (a text-based adventure game) and use a small subroutine to allow me to make a typewriter effect. After some time of typing (let's say 10-15 seconds) the typewrite effect slows down and I have tried setting it at slower speeds to solve this. If anybody could suggest some work arounds or solutions for my problem that would be greatly appreciated. If Replit is the problem and someone could test it I would be thankful. Here is the small subroutine I use:

import sys
from time import sleep

def write(write, delay):
  for i in write:
    sys.stdout.write(i)
    sys.stdout.flush()
    time.sleep(delay)
  print()

I have dug around Stack Overflow and nothing has come up apart from something that I wasn't really able to apply to my program. I have also searched google and again, nothing. Any help would be greatly appreciated.

  • In case you're wondering, I use a 0.05 second delay per letter whenever I call it. I just wrote it so you can use different speeds without having to rewrite the whole program. – Adam Hatrak Jun 30 '23 at 11:04
  • In what manner exactly, are you measuring the speed of the typewriting effect? Is it purely based on how you feel, whilst looking at it? or are you using some code to time the effect as well? Since I tested the code on spyder and it seems to be working as intended, but it would be nice to check it using the same method that you used for the replit version. – typedecker Jun 30 '23 at 11:10
  • 1
    It's most likely something what the web environment causes. Slowdown may be caused by lack of interactivity (if it's running on their backend - I won't register), or simply the console emulation from JavaScript may get overloaded due to the frequent changes and redraws. – tevemadar Jun 30 '23 at 11:20
  • Side note: `from time import sleep` vs `time.sleep(delay)` indicates that this may not be the real code you're using. – tevemadar Jun 30 '23 at 11:21
  • Coming from someone who's used replit before and transitioned to VS Code, the delay is almost definitely caused by replit itself - it is pretty slow. – vs07 Jun 30 '23 at 12:26
  • @tevemadar I have slightly modified the code to not include anything else but that is the literal code I have in my program. If there is a problem with it please do let me know. Also typedecker I am measuring it by looking at it and seeing a noticeable difference after a short amount of time. Thanks to everybody for their contribution to my question. – Adam Hatrak Jul 02 '23 at 22:11

2 Answers2

0

Disclaimer :

Please note that the results I have provided below have been tested on spyder IDE's ipython. The exact method used by you to time the code provided, has not been mentioned, but in this answer I've used ipython's %timeit magic function(refer to this and this), to time the function.


IPython Tests and Conclusion:

Now, timing a general call to the function with some text like so (running it 10 times to get a better estimate, and hence the -r10, for more info refer to this) -:

%timeit -r10 write('bleh oh my god you really did a good job!', 0.05)

Gave this as output for the time taken to execute it -:

2.55 s ± 7.42 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

Note that this basically implies that the time taken for this to execute can be assumed to be 2.55 seconds roughly.

This means that if the same text was concatenated 5 times to itself like so -:

'bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job!'

it should take 5 times as much time(roughly/approximately, a slight deviation in the calculation is ofcourse acceptable) i.e. 2.55 * 5 ~ 12.75, if the typewriting effect is uniform throughout, since if the typewriter effect slows down, then it must slow down for the repeated text the second, third, fourth and fifth time respectively, thus a major difference will be seen if thats the case.

Now timing the function by passing the above repeated string as an argument -:

%timeit -r10 write('bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job!', 0.05)

The result is -:

12.9 s ± 106 ms per loop (mean ± std. dev. of 10 runs, 1 loop each)

The result(12.9) being very close to 12.75(our estimate) can help us conclude that the typewriting effect is working with uniform speed throughout the text passed as argument.


Replit tests:

Furthermore to test the same on replit, I made a new replit with the following code -:

import sys
import time
import timeit
def write(write, delay):
  for i in write:
    sys.stdout.write(i)
    sys.stdout.flush()
    time.sleep(delay)
  print()

a = timeit.timeit(lambda : write('bleh oh my god you really did a good job!', 0.05), number = 10)

b = timeit.timeit(lambda : write('bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job! bleh oh my god you really did a good job!', 0.05), number = 10)
print(a, b)

It is the same method as used above in the spyder IDE, but this time around, I am using the timeit module's timeit method(for more info, refer to this), with the same configuration of 10 loops in total to get a good estimate of the time taken. Note that since replit has a different way of handling the console, the ipython magic function %timeit -r10 was not working here so I have used the module to time it instead, and the results may vary(as in, the time returned as output might have a larger value than the one outputted by the ipython magic function), but the relation of the 5 times multiplier must remain the same.

The result of running this code was -:

20.799615485000686 105.46821261699733

To confirm that the program is working as intended the second value had to be close to 5 times the first value i.e. 5 * 20.799615485000686 ~ 103.99807742500343, which it is! There is a mere difference of 2 seconds which can be the result of some background web processes and/or the hardware's speed of processing code(noise, in a sense).

Screenshot of replit console output


Final Conclusion:

Thus it can be concluded that the program is working as intended and theoretically and mathematically the typewriter effect's speed is close to, if not, constant throughout the text. Furthermore, as mentioned by @tevemadar the web environment, backend activity, the amount of programs running on your browser and/or your system as a whole can affect the timings quite a bit, but a fairly/roughly constant typewriting effect should be achievable nevertheless, and the above tests suggest that the same has been achieved via the coded provided.

typedecker
  • 1,351
  • 2
  • 13
  • 25
0

time.sleep(x) won't necessary sleep for x seconds. Rather, it will sleep for at least x seconds - in practice, the difference is usually negligible, but the OS is theoretically allowed to add whatever additional delay it likes (to allow other tasks to run).

What you can do instead is to use time.time() to get an epoch, and then sleep based on that. This ensures that any delay in one sleep call is cancelled out by passing a lower value to the next sleep call, so overall, you'll end up with much more accurate timing. You'd do something like this:

import sys
import time

def write(write, delay):
  startTime = time.time()
  currDelay = delay
  numSleeps = 0
  for i in write:
    sys.stdout.write(i)
    sys.stdout.flush()
    if currDelay > 0:
      time.sleep(currDelay)
    currTime = time.time()
    numSleeps += 1
    desiredTotalTime = delay * numSleeps
    actualTotalTime = currTime - startTime
    currDelay = delay + desiredTotalTime - actualTotalTime
  print()
Keiji
  • 880
  • 5
  • 12