--- 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.