How to write an AI function with a timeout in python - python

Context
I am writing an AI for a deterministic two player game in python. I wish to write a function which takes a timeout value as one of its parameters and returns a move shortly after the timeout. The function searches (negamax or similar) until the timeout is up and then returns the best move it can find.
Specification
The function should return a valid move no matter how or when it is caused to return.
The function may return a little after the timeout, so long as this is not noticeable to the user (~100ms).
The function should return if a custom AI_INTERRUPT event is placed on the pygame event queue. (This is so that impatient users can force the computer to play).
Proposed Implementation
I think I have an idea of how to implement this, but I have found a lot of conflicting advice online (and mostly for problems not quite the same as this one). I am also concerned that I am over-engineering things. I am therefore asking whether or not this implementation suggestion is a sensible one, or whether you recommend something else.
I am considering writing my AI algorithm as a generator that yields successively better moves. Time delays between yields could be long, but the first yield would be almost immediate.
I would then call this generator in a subprocess and have it feed yield values into a pipe.
The main process would then run in a loop of:
Poll the pipe. If a new value has been yielded it is stored.
Check the time. If the timeout has been exceeded, return the latest value.
Check for an AI_INTERRUPT event, returning the latest value if one is found.
Handle other pygame events as necessary
I am using Python 3 with pygame.

You could use a timed-out thread that wrappes your negamax method.
The method will update a shared data structure with the optimal solution so far. The shared data structure can simply be a list that you pass to your negamax method. When the timeout occurs, the caller will read the solution from the list.

If you are working on UNIX, you can use the signal lib to implement a timeout function : Timeout function if it takes too long to finish

Since you're already using pygame, use either:
def foo(duration):
# time as MS
start = pygame.time.get_ticks()
while True:
now = pygame.time.get_ticks()
if now - start >= duration:
return
# do stuff
Or one of these two functions:
pygame.time.wait or pygame.time.delay
You could make a slightly more complicated version, that still lets your main loop continue. But if your display doesn't update in the short time, it might be overkill.

Related

What is the correct way to run a pydrake simulation "online"?

In Drake/pydrake, all of the examples I have seen create an instance of Simulator and then advance the simulation by a set duration, e.g. sim.AdvanceTo(10) will step the simulation until it has simulated 10 seconds of activity.
How can I instead run a simulation indefinitely, where I don't have a specific duration to advance to, just have the simulation running in its own node and step at a fixed interval forever?
My intention is to just have the simulator running, and then send requests to update commands that will be sent to the robot. Is there a straightforward way to achieve this that won't break the simulation? I figured there would be a public Step function on Simulator, but have only encountered AdvanceTo. My first thought was to try to take the context from a call to AdvanceTo over a short interval, e.g. AdvanceTo(0.01) and then overwrite the context for the next call so that it's updating from the new context instead of the original, but I'm not sure it will work. Maybe there's a more official way to achieve this scheme?
You can do
simulator.AdvanceTo(std::numeric_limits<double>::infinity()); to keep the simulation running indefinitely.
https://github.com/RobotLocomotion/drake/tree/master/examples/kuka_iiwa_arm may be helpful as an example.
You can do the scheme you proposed. But AdvanceTo() takes a time rather than an interval. To avoid annoying accumulated roundoff you should use an integer step counter and then do AdvanceTo(step_number * dt) where dt is the length of step you would like to take between interruptions.
An alternative would be to use AdvanceTo(infinity) as Xuchen suggested but define some regular update Event that can modify the state when needed.

Is there a way to pause a code in the middle of a run?

How do you handle a code where you have to pause the code at any given moment. For example, you could be reading files from server and server is going to be rebooted; you would want to pause the code so it stops trying to read the file from the server. You also wouldn't want to rerun the code if you have been running it for a long time. Is there a way to pause a code for certain amount of time in python?
I looked into this everywhere and couldn't find any solution. There were few solution that was mentioned.
raw_input("") :if you are reading millions of file,I don't think you would want to manually enter every time it reaches this part of code.
sleep(): you wouldn't know when to pause the code and for how long so I don't think this would work.
There is a anything I can implement to take care of this issue?
Thanks,
Shone
I understand you don't see any snippet of code and I am sorry for not having any code snippet. I have been thinking about this issue and trying to find a solution in case this issue were to arise in future.
I don't know how this will affect efficiency-wise but can't you use sleep() inside a while loop or something like that.
As in,
while not condition: sleep(100)
or just,
while not condition: pass
What I've done in the past is have my script periodically check for the existence of a stop file somewhere, which can be manually put there when you want to pause.
So for this contrived example of an infinite while loop, the script checks for the file, and if it exists, it goes into a sleep loop and continues to check every second. When the file disappears the main loop will continue
import time, os.path
while True: # Main processing loop
while os.path.exists('path/to/file'):
time.sleep(1)
# Do processing stuff
# here
It's a bit of an ugly hack, but simple to implement.

Bad timing when playing audio files with PyGame

When I play a sound every 0.5 second with PyGame:
import pygame, time
pygame.mixer.init()
s = pygame.mixer.Sound("2.wav")
for i in range(8):
pygame.mixer.Channel(i).play(s)
time.sleep(0.5)
it doesn't respect the timing correctly at all.
It's like there are pause of 0.2 sec than 0.7 sec then 0.2 sec again, it's very irregular.
Notes:
I know that time.sleep() is not the most accurate in the world, but even with the more accurate solutions from here, the problem is still present
Tested on a RaspberryPi
The problem is still there if I play many different files s[i].play(), with i in a big range. So the problem doesn't come from the fact it tries to replay the same file
Here is the reason:
Even if we decrease the audio buffer to the minimum supported by the soundcard (1024 or 512 samples instead of pygame's default 4096), the differences will still be there, making irregulat what should be a "metronome beat".
I'll update with a working solution as soon as I find one. (I have a few ideas in this direction).
As you wrote in your own answer, the reason for the timing problems very likely is the fact that the audio callback runs decoupled from the rest of the application.
The audio backend typically has some kind of a clock which is accessible from both inside the callback function and outside of it.
I see two possible solutions:
use a library that allows you to implement the callback function yourself, calculate the starting times of your sounds inside the callback function, compare those times with the current time of the "audio clock" and write your sound to the output at the appropriate position in the output buffer.
use a library that allows you to specify the exact time (in terms of the "audio clock") when to start playing your sounds. This library would do the steps of the previous point for you.
For the first option, you could use the sounddevice module. The callback function (which you'll have to implement) will get an argument named time, which has an attribute time.outputBufferDacTime, which is a floating point value specifying the time (in seconds) when the first sample of the output buffer will be played back.
Full disclosure: I'm the author of the sounddevice module, so my recommendation is quite biased.
Quite recently, I've started working on the rtmixer module, which can be used for the second option.
Please note that this is in very early development state, so use it with caution.
With this module, you don't have to write a callback function, you can use the function rtmixer.Mixer.play_buffer() to play an audio buffer at a specified time (in seconds). For reference, you can get the current time from rtmixer.Mixer.time.

How to get function to run at specyfic time using python and PyQt not using Cron

I'm creating RSS app in PyQt and I'm trying to find a good way to program updates. I found this Executing periodic actions in Python but maybe there is Qt specific way to do this things.
I know update period for each feed so I want to run update at specific time(hh:mm).
Making 10 minute loop that will check current time and run a update if its grater than next predicted feed update seems missing the point of knowing specific time to run it.
You should use QTimer in Qt applications. Usually you don't need to care about specific update time, as the goal is regular periodic check. So the most straightforward approarch is to create a timer for each feed and set the update interval of each timer (e.g. 10 minutes).
If you for some reason really want to make an update at specific time, you can use something like QDateTime::currentDateTime().msecsTo(targetTime) to calculate timer interval, use QTimer::setSingleShot to make the timer non-periodic and set another timer when the first one is expired.
It may be reasonable to do timer->setTimerType(Qt::VeryCoarseTimer) because you don't need much accuracy and Qt can optimize performance and power consuming in some cases.
Note that you generally cannot use Python's means to set up timers because Qt has its own event loop and won't allow other libraries to run something in the middle of it.

how to get a real callback from os in python3

i wrote actionscript and javascript. add callback to invoke a piece of code is pretty normal in everyday life.
but cames to python it seems not quit an easy job. i can hardly see things writing in callback style.i mean real callback,not a fake one,here's a fake callback example:
a list of file for download,you can write:
urls = []
def downloadfile(url,callback):
//download the file
callback()
def downloadNext():
if urls:
downloadfile(urls.pop(),downloadNext)
downloadNext()
this works but would finally meet the maximum recursion limit.while a really callback won't.
A real callback,as far as i understand,can't not come from program, it's must come from physics,like CPU clock,or some hardware IO state change,this would invoke some interception to CPU ,CPU interrupt current operating flow and check if the runtime registered any code about this int,if has,run it,the OS wrapped it as signal or event or something else ,and finally pass it to application.(if i'm wrong ,please point it out)thus would avoid the function calling stack pile up to overflow,otherwise you'll drop into infinite recursion .
there was something like coroutine in python to handle multi tasks,but must be very carefully.if in any of the routine you are blocked,all tasks would be blocked
there's some third party libs like twisted or gevent,but seems very troublesome to get and install,platform limited,not well supported in python 3,it's not good for writing a simple app and distribute.
multiprocessing, heavy and only works on linux
threading,because of GIL, never be the first choice,and it seems a psuedo one.
why not python give an implementation in standard libraries?and is there other easy way to get the real callback i want?
Your example code is just a complicated way of sequentially downloading all files.
If you really want to do asyncronous downloading, using a multiprocessing.Pool, especially the Pool.map_async member function. is the best way to go. Note that this uses callbacks.
According to the documentation for multiprocessing:
"It runs on both Unix and Windows."
But it is true that multiprocessing on ms windows has some extra restrictions.

Categories

Resources