Threaded concurrent AI?
J-Gamer

I'm thinking of a project in which the AI might take many cycles to complete its thought process. The problem is that I'll have to be able to get player input(without any lag) while the AI is thinking. I already thought of just doing a full AI cycle each timer tick, but then I got a thought about threads.

What if I would declare a thread in which the AI does its thinking, and use the main for user input handling/rendering(or split it up even further). Couldn't this result in much cleaner code? I have a few questions about this:

  • How well does timing work when using multiple threads? I want to be able to limit the amount of cycles the AI can have per second.

  • What about events? Does each thread need its own event queue and all that? I looked at the tutorial on threads on the wiki but couldn't get much wiser...

  • Lastly, should I even be using threads for this? If not, what do you need them for?

I'm open to any programming paradigms you might throw at me. I'm someone who wants/likes to learn the right way of doing things ;D

AMCerasoli

If you want something more complicated, elaborated, etc... check out Peter Wang´s ex_thread files... The tutorials in the wiki give you the concept so you can get it faster, then you can complicate you code all you want. :P

J-Gamer said:

How well does timing work when using multiple threads? I want to be able to limit the amount of cycles the AI can have per second.
What about events? Does each thread need its own event queue and all that? I looked at the tutorial on threads on the wiki but couldn't get much wiser...

Peter's examples shows you that you can create events inside a thread. you can do whatever you want inside a thread. But you must be very carefully with data exchanging.

Insted of a int main(){} you have a static void *thread_func(ALLEGRO_THREAD *thr, void *arg){}

Quote:

Lastly, should I even be using threads for this? If not, what do you need them for?

You could do it, but I think that instead of making clearer your code, could make it more complicated if you're not careful, since you're going to need to exchange a lot of data, depending on your game of course. To me, a thread for just the AI is too much, but I may be wrong. :-X

Matthew Leverton

I've used threads for AI before. It works well.

For fun, you can even have the AI simulate key presses as a second player would. Thus the AI is just another person pressing buttons to your game. (Depends on the type of game if that makes any sense.)

I don't know if Allegro event queues are thread safe.

Timing should work just fine in multiple threads.

Thomas Fjellstrom

I don't know if Allegro event queues are thread safe.

Yeah, they are afaik. Thats why they were designed to be so annoying. Events are coppied into each queue, etc. But when I last looked at it, it was thread safe.

Matthew Leverton

Well there are two different things to worry about:

  1. can the same event be registered to queues in different threads?


  2. can the same queue be accessed by different threads?

Thomas Fjellstrom

can the same event be registered to queues in different threads?

I assume yes.

Quote:

can the same queue be accessed by different threads?

Each event source at the very least has a mutex/lock. I'd think the event queue may as well. I'd have to check.

Sirocco

For fun, you can even have the AI simulate key presses as a second player would. Thus the AI is just another person pressing buttons to your game.

That's how I handled things in my last project. Whether it's you, a bot, or a remote player, all input gets funneled into the same handler. That really simplified things in the long run. Then you can also do neat stuff like simulate mouse movement and make it look like the bot is "playing" the game on the same screen, complete with the occasional bit of random cursor movement :)

gnolam

You also only have to save/load inputs to make a replay function (assuming the rest of your game is deterministic).

J-Gamer

Thanks for the advice :)

check out Peter Wang´s ex_thread files

I sure will(as soon as my exams are finished, which is next Wednesday)

I've used threads for AI before. It works well.For fun, you can even have the AI simulate key presses as a second player would. Thus the AI is just another person pressing buttons to your game. (Depends on the type of game if that makes any sense.)

The AI will actually be doing the exact same thing as the player: solving a minesweeper field, so that approach should be possible.

Sirocco said:

That's how I handled things in my last project. Whether it's you, a bot, or a remote player, all input gets funneled into the same handler. That really simplified things in the long run. Then you can also do neat stuff like simulate mouse movement and make it look like the bot is "playing" the game on the same screen, complete with the occasional bit of random cursor movement :)

Nice ;D

gnolam said:

You also only have to save/load inputs to make a replay function (assuming the rest of your game is deterministic).

Yeah, that might come in handy when testing and understanding my own AI's behaviour when it gets more complicated ^^

axilmar
J-Gamer said:

I'm open to any programming paradigms you might throw at me.

You need the Active Object pattern.

I have attached a sample implementation that solves the Dining Philosophers problem very elegantly.

J-Gamer

The wikipedia page about it is more of a stub than something else... But it seems promising, so I'll see if I can find a book about it somewhere ;D

axilmar
J-Gamer said:

The wikipedia page about it is more of a stub than something else... But it seems promising, so I'll see if I can find a book about it somewhere

Basically, concurrency comes down to state isolation: you can have as much of a concurrent state as you wish, as long as it is isolated from the rest of the world.

So, the Active Object pattern doesn't do anything groundbreaking: it just offers a way to isolate state: each active object instance is the only instance that can manipulate its state; all other active objects (i.e. all other threads) must issue a request to that object in order to modify state.

But the good thing with this is that state can be shared if state is an active object! you can have active objects passed around to other active objects, as if you were passing normal objects around, but you would not have concurrency issues.

If you check out the code I posted, feel free to ask questions.

J-Gamer

I already thought of something like that: both players(AI or human) has to have the ability to look at the whole playing field(both his own and the other ones minefield). So I make a separate Map data class, so that I could pass that to the other player as soon as something changes. I want to do this so that the AI can get desparate while comparing both fields as you are almost finishing his ;D

axilmar
J-Gamer said:

I already thought of something like that: both players(AI or human) has to have the ability to look at the whole playing field(both his own and the other ones minefield). So I make a separate Map data class, so that I could pass that to the other player as soon as something changes. I want to do this so that the AI can get desparate while comparing both fields as you are almost finishing his

So you have 3 objects from the above description:

  • the map.

  • the human player.

  • the AI player.

If you make the objects active, then you can pass the map object to both the human player and the AI player. And then you can make the AI player 'think' for as long as it likes, being a separate thread, while the AI player modifies the map in parallel.

J-Gamer

I'll look in the details of implementation later ^^ I just wanted to be sure it was possible to do this with threads, which it apparently is ;D

Thanks to all(now I'm wishing I had put something other in the "kind of question" box... I could've given you all cookies :D)

wombat

Not sure if I'm too late to the party on this thread but I thought I'd add my thoughts on this :)

Putting AI into a separate thread is a perfectly reasonable thing to do. In fact, it almost makes sense because it means the computer is now "thinking" separately to player input and the responses may be more natural.

The last project I worked on was a flight simulator for one of the big defence corporations. Our design had every flight system running as a separate process. There were never any issues in terms of timing or coordination of the AI between CSCIs (NB: this wasn't a personal project, it was my normal job).

It was a multi-process simulation, not multi-threaded, but the paradigm of separating the logic processing performed by CSCIs was the same. I did the flight model and weapon systems for the simulation and having them in separate processes meant the weapon systems couldn't "cheat" by directly accessing exact environmental data. They had to go by the data the instrumentation CSCIs fed them.

The AI for the enemy craft went into the tactical CSCI, which was run on a separate machine altogether. This kept the CSCIs for the enemy AI totally separate from the CSCIs that the pilot/player controlled.

This flight simulator cost $30 million to make. If putting AI processing in separate CSCIs is good enough for that it's certainly good enough for small personal projects.

Jonatan Hedborg

The drawback of using a threaded system might be increased complexity and changing behavior depending on how many cycles the AI thread gets.

axilmar

The drawback of using a threaded system might be increased complexity and changing behavior depending on how many cycles the AI thread gets.

I think those problems are alleviated by using the right abstraction. For example, active objects.

The Dining Philosophers problem is used as an instructional tool for the complexities of using threads, demonstrating how easily potential dead-locks, live-locks and data races can be introduced by using mutexes, semaphores and wait conditions; however, by using the Active Object pattern, I managed to write an example implementation of it effortlessly, without using any synchronization mechanism, and the result (seems to) not have any of the aforementioned problems.

I am a great believer in this pattern. I've used it quite successfully in many projects that required multitasking. I have yet to find another pattern that allows multithreaded programming to be as easy as non-threaded programming.

J-Gamer
axilmar said:

I have yet to find another pattern that allows multithreaded programming to be as easy as non-threaded programming.

You probably won't ;D Each feature that gets added to a program increases the complexity.

axilmar
J-Gamer said:

ou probably won't ;D Each feature that gets added to a program increases the complexity.

And the good thing with the active object pattern is that you can add as many features as you want, but concurrency will not be affected.

Thread #607617. Printed from Allegro.cc