Problem with Python AI in 2 modules
Moderator: Forum Moderators
-
- Inactive Developer
- Posts: 787
- Joined: March 31st, 2006, 6:55 am
Problem with Python AI in 2 modules
At the moment I'm busy writing a Python AI and I just split my code in 2 modules. After this split the second module is only imported the first turn. Is this a bug or not, if it's a bug I'll file it on gna.
I did find a work-around by starting the first module with the following code
I did find a work-around by starting the first module with the following code
Code: Select all
if( sys.modules.has_key( 'module2' )):
del sys.modules[ 'module2' ]
import module2
In short: It's not necessarily a bug - in Python, the code of a module is only run the first time it is imported. The Python import is very different from the C++ #include.
The "good" way to split code into modules is to have classes/functions in your other modules, and then call those from your main module which gets run every turn.
But, this still gets me thinking - maybe it would be better to actually re-initialize the whole Python interpreter at every turn. It might have a slight performance impact because of the re-initializing, but quite probably completely negligible. And it would make sure there can be no hidden bugs in a script when saving/reloading - since right now you can store global variables and they stay available between turns. Always starting with a new interpreter would prevent that (and also make your import working - but it still would be bad practice to use it like you tried ).
The "good" way to split code into modules is to have classes/functions in your other modules, and then call those from your main module which gets run every turn.
But, this still gets me thinking - maybe it would be better to actually re-initialize the whole Python interpreter at every turn. It might have a slight performance impact because of the re-initializing, but quite probably completely negligible. And it would make sure there can be no hidden bugs in a script when saving/reloading - since right now you can store global variables and they stay available between turns. Always starting with a new interpreter would prevent that (and also make your import working - but it still would be bad practice to use it like you tried ).
-
- Inactive Developer
- Posts: 787
- Joined: March 31st, 2006, 6:55 am
I import a module to call a class inside them, the problem occured when I found a bug in the imported module and the fix didn't seem te work at first. After restarting the game the fix worked... so then I found the work-around I described.
I'm new to Python but this is the way it should work isn't it??? Like good old Pascal.
I also recall to have read somewhere, that the Python interpreter was re-initialized every turn, but can't seem to find it
I'm new to Python but this is the way it should work isn't it??? Like good old Pascal.
I also recall to have read somewhere, that the Python interpreter was re-initialized every turn, but can't seem to find it
Eh...the way Python normally works is exactly like Pascal. To update the module, you normally have to stop the current instance of the program, Python, then restart it with the new code.I'm new to Python but this is the way it should work isn't it??? Like good old Pascal.
That is, unless you explicitly reload the module every turn:
Code: Select all
reload(my_module)
That is how Python normally works, yes. But you could file a Feature Request to have a way to re-initialize Python (and therefore reload all modules). It would most likely be done with a debug function - since this is only useful for AI-developers, not for users.I import a module to call a class inside them, the problem occured when I found a bug in the imported module and the fix didn't seem te work at first. After restarting the game the fix worked... so then I found the work-around I described.
Yes, so won't change itI must say that that sounds like fundamentally bad design to me. Of course I'm no Wesnoth (or C++/Python) coder, but still.
The problem is, the user may save/load the game, so I can't see a way to have this working (except storing the complete Python state in savegames). You can still keep data across turns in a limited way, by using get_variable/set_variable, where you can assign strings to savegame variables, which are reloaded.Allefont: I'd rather the Python AI didn't reinitialize every turn. That defeats any attempt to cache intermediate results across turns, and I'm likely to want to do that if I actually start coding one.
The point of a cache is that it can be regenerated, it's just expensive to. No need to stuff it into the savefile. [The strategy I'm thinking of relies fairly heavily on accurate, memory-intensive modeling of ZoC.]
I don't mind making the user pay a speed hit for massive savescumming by forcing the AI to regenerate the cache on every reload.
I don't mind making the user pay a speed hit for massive savescumming by forcing the AI to regenerate the cache on every reload.
-
- Inactive Developer
- Posts: 787
- Joined: March 31st, 2006, 6:55 am
I won't place a feature request since this simply answers my question, thanks to zaimoni I managed to get my code a bit cleaner. I now use the following codeThat is how Python normally works, yes. But you could file a Feature Request to have a way to re-initialize Python (and therefore reload all modules). It would most likely be done with a debug function - since this is only useful for AI-developers, not for users.
ai_main.py
Code: Select all
#!WPY
import wesnoth, ai_helper
if( True ):
reload( ai_helper )
class AI:
def __init__( self ):
foo = ai_helper.bar()
AI()
Code: Select all
class bar:
def __init__( self ):
print 'Hello wrold'
Are you sure about that? I just tried the following code and only has foobar the second time also the second turn. (Please note that I'm pretty new to Python.)But, this still gets me thinking - maybe it would be better to actually re-initialize the whole Python interpreter at every turn. It might have a slight performance impact because of the re-initializing, but quite probably completely negligible. And it would make sure there can be no hidden bugs in a script when saving/reloading - since right now you can store global variables and they stay available between turns. Always starting with a new interpreter would prevent that (and also make your import working - but it still would be bad practice to use it like you tried Razz).
Code: Select all
#!WPY
import wesnoth
print dir()
foo_bar = "test"
print dir()
class AI:
def __init__( self ):
pass
AI()
Sure.. could have a page with different useful script fragments in the Wiki.After fixing the typo the second turn I get the proper text. Would it be oke to add this example to http://www.wesnoth.org/wiki/ReferencePythonAPI ?
Yes, you're right - the main script does get reloaded each time, so all its globals get lost. (Globals inside a module would stay though.)Are you sure about that? I just tried the following code and only has foobar the second time also the second turn. (Please note that I'm pretty new to Python.)
It would be easy to change this though. In fact, a much cleaner way for Python scripts would probably be to not just execute the contents of the script, but load it as a module, and execute a function inside it, e.g. "main" or "turn". That way, there would be no file with a special status.
So, you would have e.g. my_ai.py, and inside it have a function "turn". Then Wesnoth would do "import my_ai", and call the funtion "turn" inside it for each turn. The question is, can such a change be made for 1.2, or would there be lots of angry AI writers who would need to adjust their scripts
-
- Inactive Developer
- Posts: 787
- Joined: March 31st, 2006, 6:55 am
I'll add something later to the wiki, but I'm pretty busy at the moment.Sure.. could have a page with different useful script fragments in the Wiki.
I don't know about changing the AI interface, this change would also mean that the main AI script isn't loaded each time... That is one of the things I really like about the current interface. It would be trivial to store a cache as zaimoni mentioned in another module (and not reload the module every turn of course .)It would be easy to change this though. In fact, a much cleaner way for Python scripts would probably be to not just execute the contents of the script, but load it as a module, and execute a function inside it, e.g. "main" or "turn". That way, there would be no file with a special status.
I'm also thinking about using a cache like zaimoni montioned instead of storing a lot of data in the savefile. I'm only wondering about cache consistency. I'm playing a game and load (a totally different) game, will there be a new Python instance created or the old one used?
How is it with multiple AI's in an AI war, do they share the same Python instance? (If so would offer great ways for dirty warface )
-
- Inactive Developer
- Posts: 787
- Joined: March 31st, 2006, 6:55 am
I updated http://www.wesnoth.org/wiki/ReferencePythonAPI and added http://www.wesnoth.org/wiki/PythonAISampleCode
I looked for all the python samples on this forum and found only one
I've some pieces of code I'm working on, but those are not ready yet and some need a patch to the API. (Which I'll post on http://patches.wesnoth.org later.)
I looked for all the python samples on this forum and found only one
I've some pieces of code I'm working on, but those are not ready yet and some need a patch to the API. (Which I'll post on http://patches.wesnoth.org later.)