diff -r b0f693024b50 -r 9f8f22094c0e hedgewars/uAI.pas --- a/hedgewars/uAI.pas Sun Feb 11 12:27:45 2007 +0000 +++ b/hedgewars/uAI.pas Sun Feb 11 15:33:19 2007 +0000 @@ -20,21 +20,28 @@ interface uses uFloat; {$INCLUDE options.inc} -procedure ProcessBot(FrameNo: Longword); +procedure ProcessBot; procedure FreeActionsList; implementation uses uTeams, uConsts, SDLh, uAIMisc, uGears, uAIAmmoTests, uAIActions, uMisc, - uAIThinkStack, uAmmos; + uAmmos; var BestActions: TActions; + ThinkThread: PSDL_Thread = nil; + StopThinking: boolean; CanUseAmmo: array [TAmmoType] of boolean; - AIThinkStart: Longword; - isThinking: boolean = false; procedure FreeActionsList; begin -isThinking:= false; +{$IFDEF DEBUGFILE}AddFileLog('FreeActionsList called');{$ENDIF} +if ThinkThread <> nil then + begin + {$IFDEF DEBUGFILE}AddFileLog('Waiting AI thread to finish');{$ENDIF} + StopThinking:= true; + SDL_WaitThread(ThinkThread, nil); + ThinkThread:= nil + end; BestActions.Count:= 0; BestActions.Pos:= 0 end; @@ -46,6 +53,7 @@ a, aa: TAmmoType; begin BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; + for i:= 0 to Pred(Targets.Count) do if (Targets.ar[i].Score >= 0) then begin @@ -67,7 +75,7 @@ else if (Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0); if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then begin - Angle:= LongInt(Me^.Angle) - Abs(Angle); + Angle:= integer(Me^.Angle) - Abs(Angle); if Angle > 0 then begin AddAction(BestActions, aia_Up, aim_push, 500, 0, 0); @@ -86,42 +94,102 @@ end; if a = High(TAmmoType) then a:= Low(TAmmoType) else inc(a) - until (a = aa) or (PHedgehog(Me^.Hedgehog)^.AttacksNum > 0) + until (a = aa) or (CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog].AttacksNum > 0) end end; procedure Walk(Me: PGear); const FallPixForBranching = cHHRadius * 2 + 8; - + cBranchStackSize = 12; + +type TStackEntry = record + WastedTicks: Longword; + MadeActions: TActions; + Hedgehog: TGear; + end; + +var Stack: record + Count: Longword; + States: array[0..Pred(cBranchStackSize)] of TStackEntry; + end; + + function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean; + var Result: boolean; + begin + Result:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5); + if Result then + with Stack.States[Stack.Count] do + begin + WastedTicks:= Ticks; + MadeActions:= Actions; + Hedgehog:= Me; + Hedgehog.Message:= Dir; + inc(Stack.Count) + end; + Push:= Result + end; + + procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear); + begin + dec(Stack.Count); + with Stack.States[Stack.Count] do + begin + Ticks:= WastedTicks; + Actions:= MadeActions; + Me:= Hedgehog + end + end; + + function PosInThinkStack(Me: PGear): boolean; + var i: Longword; + begin + i:= 0; + while (i < Stack.Count) do + begin + if(not(hwAbs(Stack.States[i].Hedgehog.X - Me^.X) + + hwAbs(Stack.States[i].Hedgehog.Y - Me^.Y) > 2)) and + (Stack.States[i].Hedgehog.Message = Me^.Message) then exit(true); + inc(i) + end; + PosInThinkStack:= false + end; + + var Actions: TActions; - ticks, maxticks, steps, BotLevel: Longword; - BaseRate, Rate: LongInt; + ticks, maxticks, steps, BotLevel, tmp: Longword; + BaseRate, BestRate, Rate: integer; GoInfo: TGoInfo; CanGo: boolean; AltMe: TGear; begin +Actions.Count:= 0; +Actions.Pos:= 0; +Actions.Score:= 0; +Stack.Count:= 0; BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; +tmp:= random(2) + 1; +Push(0, Actions, Me^, tmp); +Push(0, Actions, Me^, tmp xor 3); + if (Me^.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - 4000 * BotLevel) - else maxticks:= TurnTimeLeft; + else maxticks:= TurnTimeLeft; -BaseRate:= RatePlace(Me); +if (Me^.State and gstAttacked) = 0 then TestAmmos(Actions, Me); +BestRate:= RatePlace(Me); +BaseRate:= max(BestRate, 0); -repeat - if not Pop(ticks, Actions, Me^) then - begin - isThinking:= false; - exit - end; +while (Stack.Count > 0) and not StopThinking do + begin + Pop(ticks, Actions, Me^); - AddAction(Actions, Me^.Message, aim_push, 10, 0, 0); + AddAction(Actions, Me^.Message, aim_push, 250, 0, 0); if (Me^.Message and gm_Left) <> 0 then AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); AddAction(Actions, Me^.Message, aim_release, 0, 0, 0); steps:= 0; - if ((Me^.State and gstAttacked) = 0) then TestAmmos(Actions, Me); - while not PosInThinkStack(Me) do + while (not StopThinking) and (not PosInThinkStack(Me)) do begin CanGo:= HHGo(Me, @AltMe, GoInfo); inc(ticks, GoInfo.Ticks); @@ -129,128 +197,107 @@ if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support if Push(ticks, Actions, AltMe, Me^.Message) then - with ThinkStack.States[Pred(ThinkStack.Count)] do + with Stack.States[Pred(Stack.Count)] do begin AddAction(MadeActions, aia_HJump, 0, 305, 0, 0); AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); - if (Me^.dX < 0) then AddAction(MadeActions, aia_WaitXL, hwRound(AltMe.X), 0, 0, 0) - else AddAction(MadeActions, aia_WaitXR, hwRound(AltMe.X), 0, 0, 0); end; if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support if Push(ticks, Actions, AltMe, Me^.Message) then - with ThinkStack.States[Pred(ThinkStack.Count)] do - begin + with Stack.States[Pred(Stack.Count)] do AddAction(MadeActions, aia_LJump, 0, 305, 0, 0); - if (Me^.dX < 0) then AddAction(MadeActions, aia_WaitXL, hwRound(AltMe.X), 0, 0, 0) - else AddAction(MadeActions, aia_WaitXR, hwRound(AltMe.X), 0, 0, 0); - end; + if not CanGo then break; inc(steps); Actions.actions[Actions.Count - 2].Param:= hwRound(Me^.X); Rate:= RatePlace(Me); - if Rate > BaseRate then + if Rate > BestRate then begin BestActions:= Actions; - BestActions.Score:= 1; - isThinking:= false; - exit + BestRate:= Rate; + Me^.State:= Me^.State or gstAttacked // we have better place, go there and don't use ammo end - else if Rate < BaseRate then break; + else if Rate < BestRate then break; + if ((Me^.State and gstAttacked) = 0) + and ((steps mod 4) = 0) then TestAmmos(Actions, Me); if GoInfo.FallPix >= FallPixForBranching then Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right + end; - if ((Me^.State and gstAttacked) = 0) - and ((steps mod 4) = 0) then - begin - TestAmmos(Actions, Me); - if SDL_GetTicks - AIThinkStart >= Pred(cTimerInterval) then - begin - dec(Actions.Count, 3); - Push(ticks, Actions, Me^, Me^.Message); - exit - end - end - end; -until false + if BestRate > BaseRate then exit + end end; -procedure Think(Me: PGear); +procedure Think(Me: PGear); cdecl; var BackMe, WalkMe: TGear; + StartTicks: Longword; begin -AIThinkStart:= SDL_GetTicks; +StartTicks:= GameTicks; +BestActions.Count:= 0; +BestActions.Pos:= 0; +BestActions.Score:= Low(integer); BackMe:= Me^; WalkMe:= BackMe; if (Me^.State and gstAttacked) = 0 then if Targets.Count > 0 then begin Walk(@WalkMe); - if not isThinking then + if (StartTicks > GameTicks - 1500) and not StopThinking then SDL_Delay(2000); + if BestActions.Score < -1023 then begin - if BestActions.Score < -1023 then - begin - BestActions.Count:= 0; - AddAction(BestActions, aia_Skip, 0, 250, 0, 0); - end; - Me^.State:= Me^.State and not gstHHThinking - end + BestActions.Count:= 0; + AddAction(BestActions, aia_Skip, 0, 250, 0, 0); + end; end else else begin - FillBonuses(true); Walk(@WalkMe); - AddAction(BestActions, aia_Wait, GameTicks + 100, 100, 0, 0); - end + while (not StopThinking) and (BestActions.Count = 0) do + begin + SDL_Delay(100); + FillBonuses(true); + WalkMe:= BackMe; + Walk(@WalkMe) + end + end; +Me^.State:= Me^.State and not gstHHThinking end; procedure StartThink(Me: PGear); var a: TAmmoType; - tmp: LongInt; begin if ((Me^.State and gstAttacking) <> 0) or isInMultiShoot then exit; -ThinkingHH:= Me; -isThinking:= true; - -ClearThinkStack; - Me^.State:= Me^.State or gstHHThinking; Me^.Message:= 0; +StopThinking:= false; +ThinkingHH:= Me; FillTargets; if Targets.Count = 0 then begin OutError('AI: no targets!?', false); exit end; - FillBonuses((Me^.State and gstAttacked) <> 0); - for a:= Low(TAmmoType) to High(TAmmoType) do CanUseAmmo[a]:= Assigned(AmmoTests[a]) and HHHasAmmo(PHedgehog(Me^.Hedgehog), a); +{$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF} +ThinkThread:= SDL_CreateThread(@Think, Me) +end; -BestActions.Count:= 0; -BestActions.Pos:= 0; -BestActions.Score:= 0; -tmp:= random(2) + 1; -Push(0, BestActions, Me^, tmp); -Push(0, BestActions, Me^, tmp xor 3); -BestActions.Score:= Low(LongInt); - -Think(Me) -end; - -procedure ProcessBot(FrameNo: Longword); -const LastFrameNo: Longword = 0; +procedure ProcessBot; +const StartTicks: Longword = 0; begin with CurrentTeam^.Hedgehogs[CurrentTeam^.CurrHedgehog] do if (Gear <> nil) and ((Gear^.State and gstHHDriven) <> 0) and (TurnTimeLeft < cHedgehogTurnTime - 50) then - if not isThinking then - if (BestActions.Pos >= BestActions.Count) then StartThink(Gear) - else ProcessAction(BestActions, Gear) - else if FrameNo <> LastFrameNo then - begin - LastFrameNo:= FrameNo; - Think(Gear) - end; + if ((Gear^.State and gstHHThinking) = 0) then + if (BestActions.Pos >= BestActions.Count) then + begin + StartThink(Gear); + StartTicks:= GameTicks + end else ProcessAction(BestActions, Gear) + else if (GameTicks - StartTicks) > cMaxAIThinkTime then StopThinking:= true end; + end.