-1

I do believe that thread may accomplish this, although I am not sure. Most of the threads out there that address this problem doesn't address it to match my problem. I have created a simple mud-like fighting system that executes when you 'fight' an NPC. I have the code that runs under a while loop that checks health between you and NPC and if one of you dies then the loop ends.

However

During the loop I want to have it where a user can type in commands, instead of being stuck watching a looping code block without you being able to do anything. From what I have read online it looks like thread module may be of some help to me? Also if anyone has PyGame experience, maybe looking into that would be a solution? Please let me know what you think.

Below is a very simple example of what I am trying to accomplish.

import time

fighting = True
while fighting:
    # do the magic here
    time.sleep(4)       # to give it a nice even pace between loop intervals

Although at any time i want to be able do input a command like a skill or spell. Any ideas or suggestions?

pypy
  • 160
  • 1
  • 8
  • Do the commands need to be executed as soon as they're typed, or can they wait for a new iteration of the loop? – Dan Oberlam Aug 22 '14 at 21:18
  • @Dannnno they can wait until the new iteration of the loop is fine, I can work with whatever works. – pypy Aug 22 '14 at 21:18
  • possible duplicate of [Python - Infinite while loop, break on user input](http://stackoverflow.com/questions/20576960/python-infinite-while-loop-break-on-user-input) – Dan Oberlam Aug 22 '14 at 21:24
  • Not a perfect duplicate, but should be enough to point you in the right direction – Dan Oberlam Aug 22 '14 at 21:25
  • I already looked at that forum @Dannnno , and it is not close to my problem, and it isn't a duplicate. It asks the same question, but in two different aspects. – pypy Aug 22 '14 at 21:26
  • PyGame _could_ be a solution here, but if you're not planning on doing any graphics, a server-type event loop will probably be a lot easier to understand than a game-type or GUI-type event loop. Or, if you just want a "sleep 4 seconds then check for input", _any_ more complicated event loop is probably overkill. – abarnert Aug 22 '14 at 21:37
  • It is essentially the same. You want non-blocking user input which is provided in the `msvcrt` module. Then you can just perform certain functions when the proper input is provided – Dan Oberlam Aug 22 '14 at 21:37
  • @abarnert can you please provide a very simple code example that waits for user input if nothing if found within x seconds it loops through following iteration of loop? because that concept is exactly what i am looking for. – pypy Aug 22 '14 at 21:55
  • @pypy: Why do you want to wait 4 seconds? Why not just have one thread doing the magic computations, while another thread handles input at any time, rather than pausing the work every so often to wait for input? – abarnert Aug 22 '14 at 22:22

3 Answers3

2

You can separate your human interface and fight game into separate threads. The fight game uses a queue for input, which uses a timeout to continue. Here is a very simple queue structure that should minimally do what you want.

import time
import threading
import Queue


def fighter(input_queue):
    while True:
        start = time.time()
        # do stuff
        wait = time.time() - start()
        if wait <= 0.0:
            wait = 0
        try:
            msg = input_queue.get(wait, wait)
            if msg == 'done':
                return
            # do something else with message
        except Queue.Empty:
            pass

def main():
    input_queue = Queue.Queue()
    fight_thread = threading.Thread(target=fighter, args=(input_queue,))
    fight_thread.start()
    while True:
        msg = raw_input('hello ')  # py 2.x
        input_queue.put(msg)
        if msg == 'done':
            break
    fight_thread.join()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • What is the `done_event` for? You're neither signaling it nor waiting on it anywhere (and the queue is already internally synchronized, so I don't think you need anything else). – abarnert Aug 22 '14 at 23:26
  • @abarnet - that was to be part of a feedback mechanism but it was just making the example complicated. It should have been deleted from the example. – tdelaney Aug 23 '14 at 02:13
1

If you only want this to work on Windows, and you want to keep your simple event loop:

fighting = True
inputbuf = ''
while fighting:
    # do the magic here
    while msvcrt.khbit():
        newkey = msvcrt.getwche()
        inputbuf += newkey
        if newkey == '\r':
            process_command(inputbuf)
            inputbuf = ''
    time.sleep(4)       # to give it a nice even pace between loop intervals

On the other hand, if you want to use a background thread, it would be a lot simpler:

def background():
    for line in sys.stdin:
        process_command(line)
bt = threading.Thread(target=background)
bt.start

fighting = True
while fighting:
    # do the magic here
    time.sleep(4)       # to give it a nice even pace between loop intervals

This works cross-platform, and it gives normal line-buffered input (including full readline support), which people will probably like.

However, I'm assuming you want that process_command to share information with the # do the magic here code, and possibly even to set fighting = False. If you do that without any thread synchronization, it will no longer work cross-platform. (It may work on both Windows CPython and Unix CPython, but will probably not work on IronPython or Jython—or, worse, it will work most of the time but randomly fail just often enough that you have to fix it but not often enough that you can debug it…)

abarnert
  • 354,177
  • 51
  • 601
  • 671
-1

What you may be looking for is a non-blocking raw_input implementation. This would allow the loop to keep going while allowing the user a possibility at entering commands.

There is an example of an implementation of this here and here. Maybe you can adapt one of them to suit your purpose.

Edit:

Or, if you're working on Windows...

TheGoatMan7
  • 512
  • 3
  • 5