hedgewars/uAI.pas
branch0.9.17
changeset 6400 a057306acea6
parent 6395 bb04d7a9f7e2
child 6415 af2047bb4f70
equal deleted inserted replaced
6375:fcea0c053bc1 6400:a057306acea6
    57            StopMessages(Gear^.Message);
    57            StopMessages(Gear^.Message);
    58 
    58 
    59 BestActions.Count:= 0;
    59 BestActions.Count:= 0;
    60 BestActions.Pos:= 0
    60 BestActions.Pos:= 0
    61 end;
    61 end;
       
    62 
       
    63 
       
    64 
       
    65 const cBranchStackSize = 12;
       
    66 type TStackEntry = record
       
    67                    WastedTicks: Longword;
       
    68                    MadeActions: TActions;
       
    69                    Hedgehog: TGear;
       
    70                    end;
       
    71 
       
    72 var Stack: record
       
    73            Count: Longword;
       
    74            States: array[0..Pred(cBranchStackSize)] of TStackEntry;
       
    75            end;
       
    76 
       
    77 function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean;
       
    78 var bRes: boolean;
       
    79 begin
       
    80     bRes:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5);
       
    81     if bRes then
       
    82         with Stack.States[Stack.Count] do
       
    83             begin
       
    84             WastedTicks:= Ticks;
       
    85             MadeActions:= Actions;
       
    86             Hedgehog:= Me;
       
    87             Hedgehog.Message:= Dir;
       
    88             inc(Stack.Count)
       
    89             end;
       
    90     Push:= bRes
       
    91 end;
       
    92 
       
    93 procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear);
       
    94 begin
       
    95     dec(Stack.Count);
       
    96     with Stack.States[Stack.Count] do
       
    97         begin
       
    98         Ticks:= WastedTicks;
       
    99         Actions:= MadeActions;
       
   100         Me:= Hedgehog
       
   101         end
       
   102 end;
       
   103 
       
   104 
    62 
   105 
    63 procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean);
   106 procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean);
    64 var BotLevel: Byte;
   107 var BotLevel: Byte;
    65     ap: TAttackParams;
   108     ap: TAttackParams;
    66     Score, i: LongInt;
   109     Score, i: LongInt;
    87            if Actions.Score + Score > BestActions.Score then
   130            if Actions.Score + Score > BestActions.Score then
    88             if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then
   131             if (BestActions.Score < 0) or (Actions.Score + Score > BestActions.Score + Byte(BotLevel) * 2048) then
    89               begin
   132               begin
    90               BestActions:= Actions;
   133               BestActions:= Actions;
    91               inc(BestActions.Score, Score);
   134               inc(BestActions.Score, Score);
       
   135               BestActions.isWalkingToABetterPlace:= false;
    92 
   136 
    93               if (ap.Angle > 0) then AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
   137               if (ap.Angle > 0) then AddAction(BestActions, aia_LookRight, 0, 200, 0, 0)
    94               else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
   138               else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0);
    95 
   139 
    96               AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
   140               AddAction(BestActions, aia_Weapon, Longword(a), 300 + random(400), 0, 0);
   127              (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon
   171              (CurrentHedgehog^.MultiShootAttacks > 0) or // shooting same weapon
   128              StopThinking
   172              StopThinking
   129        end
   173        end
   130 end;
   174 end;
   131 
   175 
   132 procedure Walk(Me: PGear);
   176 procedure Walk(Me: PGear; var Actions: TActions);
   133 const FallPixForBranching = cHHRadius * 2 + 8;
   177 const FallPixForBranching = cHHRadius * 2 + 8;
   134       cBranchStackSize = 12;
   178 var
   135 
       
   136 type TStackEntry = record
       
   137                    WastedTicks: Longword;
       
   138                    MadeActions: TActions;
       
   139                    Hedgehog: TGear;
       
   140                    end;
       
   141 
       
   142 var Stack: record
       
   143            Count: Longword;
       
   144            States: array[0..Pred(cBranchStackSize)] of TStackEntry;
       
   145            end;
       
   146 
       
   147     function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean;
       
   148     var bRes: boolean;
       
   149     begin
       
   150     bRes:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5);
       
   151     if bRes then
       
   152        with Stack.States[Stack.Count] do
       
   153             begin
       
   154             WastedTicks:= Ticks;
       
   155             MadeActions:= Actions;
       
   156             Hedgehog:= Me;
       
   157             Hedgehog.Message:= Dir;
       
   158             inc(Stack.Count)
       
   159             end;
       
   160     Push:= bRes
       
   161     end;
       
   162 
       
   163     procedure Pop(var Ticks: Longword; var Actions: TActions; var Me: TGear);
       
   164     begin
       
   165     dec(Stack.Count);
       
   166     with Stack.States[Stack.Count] do
       
   167          begin
       
   168          Ticks:= WastedTicks;
       
   169          Actions:= MadeActions;
       
   170          Me:= Hedgehog
       
   171          end
       
   172     end;
       
   173 
       
   174 var Actions: TActions;
       
   175     ticks, maxticks, steps, tmp: Longword;
   179     ticks, maxticks, steps, tmp: Longword;
   176     BaseRate, BestRate, Rate: integer;
   180     BaseRate, BestRate, Rate: integer;
   177     GoInfo: TGoInfo;
   181     GoInfo: TGoInfo;
   178     CanGo: boolean;
   182     CanGo: boolean;
   179     AltMe: TGear;
   183     AltMe: TGear;
   180     BotLevel: Byte;
   184     BotLevel: Byte;
       
   185     a: TAmmoType;
   181 begin
   186 begin
   182 ticks:= 0; // avoid compiler hint
   187 ticks:= 0; // avoid compiler hint
   183 Actions.Count:= 0;
       
   184 Actions.Pos:= 0;
       
   185 Actions.Score:= 0;
       
   186 Stack.Count:= 0;
   188 Stack.Count:= 0;
       
   189 
       
   190 for a:= Low(TAmmoType) to High(TAmmoType) do
       
   191     CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(Me^.Hedgehog^, a);
       
   192 
   187 BotLevel:= Me^.Hedgehog^.BotLevel;
   193 BotLevel:= Me^.Hedgehog^.BotLevel;
   188 
   194 
   189 tmp:= random(2) + 1;
   195 tmp:= random(2) + 1;
   190 Push(0, Actions, Me^, tmp);
   196 Push(0, Actions, Me^, tmp);
   191 Push(0, Actions, Me^, tmp xor 3);
   197 Push(0, Actions, Me^, tmp xor 3);
   238        Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   244        Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X);
   239        Rate:= RatePlace(Me);
   245        Rate:= RatePlace(Me);
   240        if Rate > BestRate then
   246        if Rate > BestRate then
   241           begin
   247           begin
   242           BestActions:= Actions;
   248           BestActions:= Actions;
       
   249           BestActions.isWalkingToABetterPlace:= true;
   243           BestRate:= Rate;
   250           BestRate:= Rate;
   244           Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   251           Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo
   245           end
   252           end
   246        else if Rate < BestRate then break;
   253        else if Rate < BestRate then break;
   247        if ((Me^.State and gstAttacked) = 0)
   254        if ((Me^.State and gstAttacked) = 0)
   254     end
   261     end
   255 end;
   262 end;
   256 
   263 
   257 function Think(Me: Pointer): ptrint;
   264 function Think(Me: Pointer): ptrint;
   258 var BackMe, WalkMe: TGear;
   265 var BackMe, WalkMe: TGear;
   259     StartTicks: Longword;
   266     StartTicks, currHedgehogIndex, itHedgehog, switchesNum, i: Longword;
       
   267     switchImmediatelyAvailable, switchAvailable: boolean;
       
   268     Actions: TActions;
   260 begin
   269 begin
   261 InterlockedIncrement(hasThread);
   270 InterlockedIncrement(hasThread);
   262 StartTicks:= GameTicks;
   271 StartTicks:= GameTicks;
   263 BackMe:= PGear(Me)^;
   272 currHedgehogIndex:= CurrentTeam^.CurrHedgehog;
       
   273 itHedgehog:= currHedgehogIndex;
       
   274 switchesNum:= 0;
       
   275 
       
   276 switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher);
       
   277 switchAvailable:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch);
   264 
   278 
   265 if (PGear(Me)^.State and gstAttacked) = 0 then
   279 if (PGear(Me)^.State and gstAttacked) = 0 then
   266    if Targets.Count > 0 then
   280    if Targets.Count > 0 then
   267       begin
   281       begin
   268       WalkMe:= BackMe;
   282         // iterate over current team hedgehogs
   269       Walk(@WalkMe);
   283         repeat
   270       if (StartTicks > GameTicks - 1500) and (not StopThinking) then SDL_Delay(1000);
   284             WalkMe:= CurrentTeam^.Hedgehogs[itHedgehog].Gear^;
   271       if BestActions.Score < -1023 then
   285 
   272          begin
   286             Actions.Count:= 0;
   273          BestActions.Count:= 0;
   287             Actions.Pos:= 0;
   274          AddAction(BestActions, aia_Skip, 0, 250, 0, 0);
   288             Actions.Score:= 0;
   275          end;
   289             if switchesNum > 0 then
       
   290                 begin
       
   291                 if not switchImmediatelyAvailable then
       
   292                     begin
       
   293                     // when AI has to use switcher, make it cost smth
       
   294                     Actions.Score:= -20000;
       
   295                     AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0);                    
       
   296                     AddAction(Actions, aia_attack, aim_push, 300 + random(300), 0, 0);
       
   297                     AddAction(Actions, aia_attack, aim_release, 1, 0, 0);
       
   298                     end;
       
   299                 for i:= 1 to switchesNum do
       
   300                     AddAction(Actions, aia_Switch, 0, 300 + random(200), 0, 0);
       
   301                 end;
       
   302             Walk(@WalkMe, Actions);
       
   303 
       
   304             // find another hog in team
       
   305             repeat
       
   306                 itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber;
       
   307             until (itHedgehog = currHedgehogIndex) or (CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil);
       
   308 
       
   309             inc(switchesNum);
       
   310         until (not (switchImmediatelyAvailable or switchAvailable))
       
   311             or StopThinking 
       
   312             or (itHedgehog = currHedgehogIndex)
       
   313             or BestActions.isWalkingToABetterPlace;
       
   314 
       
   315         if (StartTicks > GameTicks - 1500) and (not StopThinking) then SDL_Delay(1000);
       
   316 
       
   317         if (BestActions.Score < -1023) and (not BestActions.isWalkingToABetterPlace) then
       
   318             begin
       
   319             BestActions.Count:= 0;
       
   320             AddAction(BestActions, aia_Skip, 0, 250, 0, 0);
       
   321             end;
       
   322 
   276       end else
   323       end else
   277 else begin
   324 else begin
   278       while (not StopThinking) and (BestActions.Count = 0) do
   325     BackMe:= PGear(Me)^;
   279             begin
   326     while (not StopThinking) and (BestActions.Count = 0) do
   280             FillBonuses(true);
   327         begin
   281             WalkMe:= BackMe;
   328         FillBonuses(true);
   282             Walk(@WalkMe);
   329         WalkMe:= BackMe;
   283             if not StopThinking then SDL_Delay(100)
   330         Actions.Count:= 0;
   284             end
   331         Actions.Pos:= 0;
   285       end;
   332         Actions.Score:= 0;
       
   333         Walk(@WalkMe, Actions);
       
   334         if not StopThinking then SDL_Delay(100)
       
   335         end
       
   336     end;
       
   337 
   286 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking;
   338 PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking;
   287 Think:= 0;
   339 Think:= 0;
   288 InterlockedDecrement(hasThread)
   340 InterlockedDecrement(hasThread)
   289 end;
   341 end;
   290 
   342 
   291 procedure StartThink(Me: PGear);
   343 procedure StartThink(Me: PGear);
   292 var a: TAmmoType;
       
   293 begin
   344 begin
   294 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   345 if ((Me^.State and (gstAttacking or gstHHJumping or gstMoving)) <> 0)
   295    or isInMultiShoot then exit;
   346    or isInMultiShoot then exit;
   296 
   347 
   297 //DeleteCI(Me); // this might break demo
   348 //DeleteCI(Me); // this might break demo
   299 Me^.Message:= 0;
   350 Me^.Message:= 0;
   300 
   351 
   301 BestActions.Count:= 0;
   352 BestActions.Count:= 0;
   302 BestActions.Pos:= 0;
   353 BestActions.Pos:= 0;
   303 BestActions.Score:= Low(LongInt);
   354 BestActions.Score:= Low(LongInt);
       
   355 BestActions.isWalkingToABetterPlace:= false;
   304 
   356 
   305 StopThinking:= false;
   357 StopThinking:= false;
   306 ThinkingHH:= Me;
   358 ThinkingHH:= Me;
   307 
   359 
   308 FillTargets;
   360 FillTargets;
   311    OutError('AI: no targets!?', false);
   363    OutError('AI: no targets!?', false);
   312    exit
   364    exit
   313    end;
   365    end;
   314 
   366 
   315 FillBonuses((Me^.State and gstAttacked) <> 0);
   367 FillBonuses((Me^.State and gstAttacked) <> 0);
   316 for a:= Low(TAmmoType) to High(TAmmoType) do
       
   317     CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(Me^.Hedgehog^, a);
       
   318 AddFileLog('Enter Think Thread');
   368 AddFileLog('Enter Think Thread');
   319 BeginThread(@Think, Me, ThinkThread)
   369 BeginThread(@Think, Me, ThinkThread)
   320 end;
   370 end;
   321 
   371 
   322 procedure ProcessBot;
   372 procedure ProcessBot;