Give an indicator that the AI is thinking

Hello,

I’m working on a strategy game. When the player ends his turn, it switches over to the “computer’s” turn. Understandably, there is a one or two-second delay at this point, as the game logic iterates through a few thousand potential moves and calculates the optimum move. I’m trying to give the player some indication that this is happening, so he can be sure that the button at least registered when he clicked, “End Turn”. Just a simple text display that reads, “Thinking”, along with making the player’s “End Turn” button invisible.

Nothing I’ve tried so far has made this happen. It appears that the program is running the entire AI analysis, and then hiding the “End Turn” button afterward, which is not the order that the commands appear in the code.

Thank you for your thoughts and your help in this matter!

local function computerTurn () local fenceToBuild = false local broonie = {} couldBeMat = {} moveMax = 0 moveToChoose = {} potential = 0 for a1 = 1, #fence do for b1 = 1, #fence[a1] do for c1 = 1, #fence[a1][b1] do broonie = fence[a1][b1][c1] -- Next line checks whether the move is legal if broonie.showing == 0 and checkForAdjacent(broonie) then -- Next line checks whether the move scores any points if tryItOut(broonie) then -- Check whether the move scores more points than other -- moves analyzed so far. potential = testForTiles(false) if potential \> moveMax then nextCBM = #couldBeMat+1 couldBeMat[nextCBM] = {} couldBeMat[nextCBM][1] = potential couldBeMat[nextCBM][2] = broonie moveMax = potential moveToChoose = nextCBM end else -- This trySecondLayer function is where the iteration gets -- really intensive. It is almost exactly the same as this -- "computerTurn" function, so that AI can analyze combinations -- of two moves during the same turn. trySecondLayer(broonie) end turnFenceBack(broonie) end end end end thinkingMsg.isVisible = false -- Turn off the indicator that AI is thinking. for z1 = 2, #couldBeMat[moveToChoose] do buildFence(couldBeMat[moveToChoose][z1]) end endTurn() end local function endTurn() -- Called when human or AI finishes a turn lookForNewLoops(true) -- Check whether the player has scored any points endTurnGroup.isVisible = false -- Make the "End Turn" button invisible -- About twenty lines here. I don't think they affect the process. switchPlayer() -- Changes player from 1 to 2, or vice-versa if player == 2 and compPlayer == 1 then thinkingMsg.isVisible = true -- Should make a "thinking" message visible. computerTurn() -- Begin AI end end

Hi @zivkovic.jeff,

Can you add some basic print() statements in your code to check/debug what exactly is happening, and if it’s in the order you expect it?

Best regards,

Brent

Hi Brent,

Thanks for the reply. I tried adding print statements, as you suggested.

Like this:

print(“making End Turn invisible”)

endTurnGroup.isVisible = false

print(“just made end turn invisible”)

The output window prints the messages at the correct time that I would expect. But the end turn button is still visible until the AI finishes thinking. Any ideas?

Thanks,

Jeff

I see your endTurn() function is scoped locally, below where it’s actually being called. Are you sure it’s being called in the correct way? Is there another endTurn() function that is was being over-written?

Can you try hiding the button first, and then calling the rest of the “AI-thinking” code on a timer a few ms later?

local function processAITurn() local function AIStuff() --lots of calculations here end endTurnGroup.isVisible = false timer.performWithDelay(50, AIStuff, 1) end

The 50ms delay should be completely undetectable to the player, but if it pushes the AI stuff into the next frame hopefully it will allow your UI changes to appear.

Obviously this method only allows you to display a static image of some kind while the processing occurs (rather than a spinner of some kind).

If you wanted to have some kind of animation, perhaps you could break up your AI code somehow and process it in stages:

local function processAITurn() endTurnGroup.isVisible = false local spinner = display.newImageRect("mySpinner.png", 100, 100) local AICount = 0 local function AIStuff() if AICount \< 1 then --do some AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 2 then --do some more AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 3 then --do some AI stuff again spinner.rotation = spinner.rotation + 90 elseif AICount \< 4 then --do even more AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 5 then --do last bit of AI stuff spinner:removeSelf() spinner = nil end AICount = AICount + 1 end timer.performWithDelay(50, AIStuff, 5) end

Thanks, QuizTix. That solution worked perfectly. For now, I’ll just the static version, because my AI process is a large iteration that would be difficult to split into pieces. But that approach might be further down the road. 

You also helped my with my last problem, when I was asking about servers.

Alex@Panc, thanks for the insight. I did move the function, just to avoid possible future problems.

Thanks again,

Jeff

Hi @zivkovic.jeff,

Can you add some basic print() statements in your code to check/debug what exactly is happening, and if it’s in the order you expect it?

Best regards,

Brent

Hi Brent,

Thanks for the reply. I tried adding print statements, as you suggested.

Like this:

print(“making End Turn invisible”)

endTurnGroup.isVisible = false

print(“just made end turn invisible”)

The output window prints the messages at the correct time that I would expect. But the end turn button is still visible until the AI finishes thinking. Any ideas?

Thanks,

Jeff

I see your endTurn() function is scoped locally, below where it’s actually being called. Are you sure it’s being called in the correct way? Is there another endTurn() function that is was being over-written?

Can you try hiding the button first, and then calling the rest of the “AI-thinking” code on a timer a few ms later?

local function processAITurn() local function AIStuff() --lots of calculations here end endTurnGroup.isVisible = false timer.performWithDelay(50, AIStuff, 1) end

The 50ms delay should be completely undetectable to the player, but if it pushes the AI stuff into the next frame hopefully it will allow your UI changes to appear.

Obviously this method only allows you to display a static image of some kind while the processing occurs (rather than a spinner of some kind).

If you wanted to have some kind of animation, perhaps you could break up your AI code somehow and process it in stages:

local function processAITurn() endTurnGroup.isVisible = false local spinner = display.newImageRect("mySpinner.png", 100, 100) local AICount = 0 local function AIStuff() if AICount \< 1 then --do some AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 2 then --do some more AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 3 then --do some AI stuff again spinner.rotation = spinner.rotation + 90 elseif AICount \< 4 then --do even more AI stuff spinner.rotation = spinner.rotation + 90 elseif AICount \< 5 then --do last bit of AI stuff spinner:removeSelf() spinner = nil end AICount = AICount + 1 end timer.performWithDelay(50, AIStuff, 5) end

Thanks, QuizTix. That solution worked perfectly. For now, I’ll just the static version, because my AI process is a large iteration that would be difficult to split into pieces. But that approach might be further down the road. 

You also helped my with my last problem, when I was asking about servers.

Alex@Panc, thanks for the insight. I did move the function, just to avoid possible future problems.

Thanks again,

Jeff