3

How can I run a timer while asking for user input from the console? I was reading about multiprocessing, and I tried to use this answer: Python: Executing multiple functions simultaneously. When I tried to get it going, it gave me a bunch of framework errors.

Right now it runs start_timer(), but then stops it when it runs cut_wire().

Here's my start_timer function:

def start_timer():
    global timer
    timer = 10
    while timer > 0:
        time.sleep(1)
        timer -= 1
        sys.stdout.write ("There's only %i seconds left. Good luck. \r" % (timer))
        sys.stdout.flush()
        cut_wire()
    if timer == 0:
        print("Boom!")
        sys.exit()

and this is the cut_wire function:

def cut_wire():
    wire_choice = raw_input("\n> ")
    if wire_choice == "cut wire" or wire_choice == "Cut Wire":
        stop_timer()
    else:
        print("Boom!")
        sys.exit()
Community
  • 1
  • 1
TrickSpades
  • 62
  • 1
  • 10

3 Answers3

1

Of course it stops running when it plays the cut_wire function because "raw_input" command reads the text and wait for the user to put the text and press enter.

My suggestion is to check for they key press "Enter" and when then key was press, read the line. If the key wasn't press, just continue with your timer.

Regards.

1

Instead of using raw_input() use this function taken from here.

def readInput( caption, timeout = 1):
start_time = time.time()
sys.stdout.write('\n%s:'%(caption));
input = ''
while True:
    if msvcrt.kbhit():
        chr = msvcrt.getche()
        if ord(chr) == 13: # enter_key
            break
        elif ord(chr) >= 32: #space_char
            input += chr
    if len(input) == 0 and (time.time() - start_time) > timeout:
        break

print ''  # needed to move to next line
if len(input) > 0:
    return input
else:
    return ""

Thearding option

To make sure that both functions run completely simultaneously you can use this example of threading event:

import threading
event = threading.Event()
th = theading.Thread(target=start_timer, args=(event, ))
th1 = theading.Thread(target=cut_wire, args=(event, ))
th.start()
th1.start()
th.join()
th1.join()

In your function you can set an event using event.set(), check it using event.is_set() and clear it using event.clear().

Community
  • 1
  • 1
Guy Goldenberg
  • 809
  • 7
  • 20
  • The first function doesn't do what I want it to, and when I try to use threading I get more framework errors. – TrickSpades Oct 10 '15 at 23:03
  • 1
    @TrickSpades What is the problem with the first function? It is designed to set an input timeout. When you combine this with threading it should work perfectly. – Guy Goldenberg Oct 10 '15 at 23:05
  • No matter what I try to do, the console says msvcrt is not defined. – TrickSpades Oct 11 '15 at 00:21
  • @TrickSpades type `import msvcrt` at the beginning of the code. – Guy Goldenberg Oct 11 '15 at 04:16
  • Still says there's no module (using a Mac) – TrickSpades Oct 11 '15 at 22:29
  • @TrickSpades oh OK, I assumed that you are using Windows. This answer will help you replace `msvcrt`: http://stackoverflow.com/questions/8718561/python-3-how-to-input-data-without-pressing-return-in-osx. If it still doesn't work try to use a module named `getch` – Guy Goldenberg Oct 11 '15 at 22:53
  • Sorry, I'm pretty sure curses still doesn't do anything that I need. I just need my cut_wire to run without stopping start_timer. It really doesn't seem like something that should be very complicated. – TrickSpades Oct 11 '15 at 23:11
  • @TrickSpades In most cases thearding will take care of everything you need with 4 lines of code, but since you print something and simultaneously request for Input it makes it much more complex. – Guy Goldenberg Oct 11 '15 at 23:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91989/discussion-between-trickspades-and-hackinguy). – TrickSpades Oct 12 '15 at 00:11
1

Only addressing your concerns, here is a quick fix using threading :

import time
import sys  
import os 

def start_timer():
  global timer
  timer = 10 
  while timer > 0:
    time.sleep(1)
    timer -= 1
    sys.stdout.write ("There's only %i seconds left. Good luck. \r" % (timer))
    sys.stdout.flush()
    #cut_wire() ==> separate call is easier to handle
  if timer == 0:
  print("Boom!")
  os._exit(0)    #sys.exit() only exits thread

def cut_wire():
  wire_choice = raw_input("\n> ")
  if wire_choice == "cut wire" or wire_choice == "Cut Wire":
    stop_timer()
  else:
    print("Boom!")
    os._exit(0)    #same reason

if __name__ == '__main__':
  import threading
  looper = threading.Thread(target=start_timer)
  looper.start()
  cut_wire()
downhillFromHere
  • 1,967
  • 11
  • 11
  • This was helpful, but for some reason in the console, it runs cut_wire before start_timer, therefore running the timer in the space for user input. – TrickSpades Oct 11 '15 at 01:30