hedgewars/uAI.pas
changeset 191 a03c2d037e24
parent 183 57c2ef19f719
child 193 56885ea29202
equal deleted inserted replaced
190:206aabea2229 191:a03c2d037e24
    17  *)
    17  *)
    18 
    18 
    19 unit uAI;
    19 unit uAI;
    20 interface
    20 interface
    21 {$INCLUDE options.inc}
    21 {$INCLUDE options.inc}
    22 procedure ProcessBot;
    22 procedure ProcessBot(FrameNo: Longword);
    23 procedure FreeActionsList;
    23 procedure FreeActionsList;
    24 
    24 
    25 implementation
    25 implementation
    26 uses uTeams, uConsts, SDLh, uAIMisc, uGears, uAIAmmoTests, uAIActions, uMisc;
    26 uses uTeams, uConsts, SDLh, uAIMisc, uGears, uAIAmmoTests, uAIActions, uMisc,
       
    27      uAIThinkStack, uConsole;
    27 
    28 
    28 var BestActions: TActions;
    29 var BestActions: TActions;
    29     ThinkThread: PSDL_Thread = nil;
       
    30     StopThinking: boolean;
       
    31     CanUseAmmo: array [TAmmoType] of boolean;
    30     CanUseAmmo: array [TAmmoType] of boolean;
       
    31     AIThinkStart: Longword;
       
    32     isThinking: boolean = false;
    32 
    33 
    33 procedure FreeActionsList;
    34 procedure FreeActionsList;
    34 begin
    35 begin
    35 {$IFDEF DEBUGFILE}AddFileLog('FreeActionsList called');{$ENDIF}
    36 isThinking:= false;
    36 if ThinkThread <> nil then
       
    37    begin
       
    38    {$IFDEF DEBUGFILE}AddFileLog('Waiting AI thread to finish');{$ENDIF}
       
    39    StopThinking:= true;
       
    40    SDL_WaitThread(ThinkThread, nil);
       
    41    ThinkThread:= nil
       
    42    end;
       
    43 BestActions.Count:= 0;
    37 BestActions.Count:= 0;
    44 BestActions.Pos:= 0
    38 BestActions.Pos:= 0
    45 end;
    39 end;
    46 
    40 
    47 procedure TestAmmos(var Actions: TActions; Me: PGear);
    41 procedure TestAmmos(var Actions: TActions; Me: PGear);
    90                  AddAction(BestActions, aia_AwareExpl, ExplR, 10, ExplX, ExplY);
    84                  AddAction(BestActions, aia_AwareExpl, ExplR, 10, ExplX, ExplY);
    91               end
    85               end
    92            end;
    86            end;
    93         if a = High(TAmmoType) then a:= Low(TAmmoType)
    87         if a = High(TAmmoType) then a:= Low(TAmmoType)
    94                                else inc(a)
    88                                else inc(a)
    95        until (a = aa) or (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].AttacksNum > 0)
    89        until (a = aa) or (PHedgehog(Me.Hedgehog).AttacksNum > 0)
    96        end
    90        end
    97 end;
    91 end;
    98 
    92 
    99 procedure Walk(Me: PGear);
    93 procedure Walk(Me: PGear);
   100 const FallPixForBranching = cHHRadius * 2 + 8;
    94 const FallPixForBranching = cHHRadius * 2 + 8;
   101       cBranchStackSize = 12;
       
   102       
    95       
   103 type TStackEntry = record
       
   104                    WastedTicks: Longword;
       
   105                    MadeActions: TActions;
       
   106                    Hedgehog: TGear;
       
   107                    end;
       
   108                    
       
   109 var Stack: record
       
   110            Count: Longword;
       
   111            States: array[0..Pred(cBranchStackSize)] of TStackEntry;
       
   112            end;
       
   113 
       
   114     function Push(Ticks: Longword; const Actions: TActions; const Me: TGear; Dir: integer): boolean;
       
   115     begin
       
   116     Result:= (Stack.Count < cBranchStackSize) and (Actions.Count < MAXACTIONS - 5);
       
   117     if Result then
       
   118        with Stack.States[Stack.Count] do
       
   119             begin
       
   120             WastedTicks:= Ticks;
       
   121             MadeActions:= Actions;
       
   122             Hedgehog:= Me;
       
   123             Hedgehog.Message:= Dir;
       
   124             inc(Stack.Count)
       
   125             end
       
   126     end;
       
   127 
       
   128     procedure Pop(out Ticks: Longword; out Actions: TActions; out Me: TGear);
       
   129     begin
       
   130     dec(Stack.Count);
       
   131     with Stack.States[Stack.Count] do
       
   132          begin
       
   133          Ticks:= WastedTicks;
       
   134          Actions:= MadeActions;
       
   135          Me:= Hedgehog
       
   136          end
       
   137     end;
       
   138 
       
   139     function PosInThinkStack(Me: PGear): boolean;
       
   140     var i: Longword;
       
   141     begin
       
   142     i:= 0;
       
   143     Result:= false;
       
   144     while (i < Stack.Count) and not Result do
       
   145           begin
       
   146           Result:= (abs(Stack.States[i].Hedgehog.X - Me.X) +
       
   147                     abs(Stack.States[i].Hedgehog.Y - Me.Y) <= 2)
       
   148                     and (Stack.States[i].Hedgehog.Message = Me.Message);
       
   149           inc(i)
       
   150           end
       
   151     end;
       
   152 
       
   153 
       
   154 var Actions: TActions;
    96 var Actions: TActions;
   155     ticks, maxticks, steps, BotLevel, tmp: Longword;
    97     ticks, maxticks, steps, BotLevel: Longword;
   156     BaseRate, BestRate, Rate: integer;
    98     BaseRate, Rate: integer;
   157     GoInfo: TGoInfo;
    99     GoInfo: TGoInfo;
   158     CanGo: boolean;
   100     CanGo: boolean;
   159     AltMe: TGear;
   101     AltMe: TGear;
   160 begin
   102 begin
   161 Actions.Count:= 0;
       
   162 Actions.Pos:= 0;
       
   163 Actions.Score:= 0;
       
   164 Stack.Count:= 0;
       
   165 BotLevel:= PHedgehog(Me.Hedgehog).BotLevel;
   103 BotLevel:= PHedgehog(Me.Hedgehog).BotLevel;
   166 
       
   167 tmp:= random(2) + 1;
       
   168 Push(0, Actions, Me^, tmp);
       
   169 Push(0, Actions, Me^, tmp xor 3);
       
   170 
   104 
   171 if (Me.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - 4000 * BotLevel)
   105 if (Me.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - 4000 * BotLevel)
   172                                   else maxticks:= TurnTimeLeft;
   106                                   else maxticks:= TurnTimeLeft;
   173 
   107 
   174 if (Me.State and gstAttacked) = 0 then TestAmmos(Actions, Me);
   108 
   175 BestRate:= RatePlace(Me);
   109 BaseRate:= max(RatePlace(Me), 0);
   176 BaseRate:= max(BestRate, 0);
   110 
   177 
   111 repeat
   178 while (Stack.Count > 0) and not StopThinking do
   112     if not Pop(ticks, Actions, Me^) then
   179     begin
   113        begin
   180     Pop(ticks, Actions, Me^);
   114        isThinking:= false;
   181 
   115        exit
       
   116        end;
   182     AddAction(Actions, Me.Message, aim_push, 250);
   117     AddAction(Actions, Me.Message, aim_push, 250);
   183     AddAction(Actions, aia_WaitX, round(Me.X), 0);
   118     AddAction(Actions, aia_WaitX, round(Me.X), 0);
   184     AddAction(Actions, Me.Message, aim_release, 0);
   119     AddAction(Actions, Me.Message, aim_release, 0);
   185     steps:= 0;
   120     steps:= 0;
   186 
   121 
   187     while (not StopThinking) and (not PosInThinkStack(Me)) do
   122     while not PosInThinkStack(Me) do
   188        begin
   123        begin
       
   124        if SDL_GetTicks - AIThinkStart > 3 then
       
   125           begin
       
   126           writetoconsole(inttostr(SDL_GetTicks - AIThinkStart) + ' ');
       
   127           dec(Actions.Count, 3);
       
   128           Push(ticks, Actions, Me^, Me^.Message);
       
   129           exit
       
   130           end;
       
   131           
   189        CanGo:= HHGo(Me, @AltMe, GoInfo);
   132        CanGo:= HHGo(Me, @AltMe, GoInfo);
   190        inc(ticks, GoInfo.Ticks);
   133        inc(ticks, GoInfo.Ticks);
   191        if ticks > maxticks then break;
   134        if ticks > maxticks then break;
   192        
   135        
   193        if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
   136        if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support
   194           if Push(ticks, Actions, AltMe, Me^.Message) then
   137           if Push(ticks, Actions, AltMe, Me^.Message) then
   195              with Stack.States[Pred(Stack.Count)] do
   138              with ThinkStack.States[Pred(ThinkStack.Count)] do
   196                   begin
   139                   begin
   197                   AddAction(MadeActions, aia_HJump, 0, 305);
   140                   AddAction(MadeActions, aia_HJump, 0, 305);
   198                   AddAction(MadeActions, aia_HJump, 0, 350);
   141                   AddAction(MadeActions, aia_HJump, 0, 350);
   199                   end;
   142                   end;
   200        if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
   143        if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support
   201           if Push(ticks, Actions, AltMe, Me^.Message) then
   144           if Push(ticks, Actions, AltMe, Me^.Message) then
   202              with Stack.States[Pred(Stack.Count)] do
   145              with ThinkStack.States[Pred(ThinkStack.Count)] do
   203                   AddAction(MadeActions, aia_LJump, 0, 305);
   146                   AddAction(MadeActions, aia_LJump, 0, 305);
   204 
   147 
   205        if not CanGo then break;
   148        if not CanGo then break;
   206        inc(steps);
   149        inc(steps);
   207        Actions.actions[Actions.Count - 2].Param:= round(Me.X);
   150        Actions.actions[Actions.Count - 2].Param:= round(Me.X);
   208        Rate:= RatePlace(Me);
   151        Rate:= RatePlace(Me);
   209        if Rate > BestRate then
   152        if Rate > BaseRate then
   210           begin
   153           begin
   211           BestActions:= Actions;
   154           BestActions:= Actions;
   212           BestRate:= Rate;
   155           BestActions.Score:= 1;
   213           Me.State:= Me.State or gstAttacked // we have better place, go there and don't use ammo
   156           isThinking:= false;
       
   157           exit
   214           end
   158           end
   215        else if Rate < BestRate then break;
   159        else if Rate < BaseRate then break;
   216        if ((Me.State and gstAttacked) = 0)
   160        if ((Me.State and gstAttacked) = 0)
   217            and ((steps mod 4) = 0) then TestAmmos(Actions, Me);
   161            and ((steps mod 4) = 0) then TestAmmos(Actions, Me);
   218        if GoInfo.FallPix >= FallPixForBranching then
   162        if GoInfo.FallPix >= FallPixForBranching then
   219           Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
   163           Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right
   220        end;
   164        end;
   221 
   165 until false
   222     if BestRate > BaseRate then exit
   166 end;
   223     end
   167 
   224 end;
   168 procedure Think(Me: PGear);
   225 
       
   226 procedure Think(Me: PGear); cdecl;
       
   227 var BackMe, WalkMe: TGear;
   169 var BackMe, WalkMe: TGear;
   228     StartTicks: Longword;
   170 //    StartTicks: Longword;
   229 begin
   171 begin
   230 StartTicks:= GameTicks;
   172 AIThinkStart:= SDL_GetTicks;
   231 BestActions.Count:= 0;
       
   232 BestActions.Pos:= 0;
       
   233 BestActions.Score:= Low(integer);
       
   234 BackMe:= Me^;
   173 BackMe:= Me^;
   235 WalkMe:= BackMe;
   174 WalkMe:= BackMe;
   236 if (Me.State and gstAttacked) = 0 then
   175 if (Me.State and gstAttacked) = 0 then
   237    if Targets.Count > 0 then
   176    if Targets.Count > 0 then
   238       begin
   177       begin
   239       Walk(@WalkMe);
   178       Walk(@WalkMe);
   240       if (StartTicks > GameTicks - 1500) and not StopThinking then SDL_Delay(2000);
   179       if not isThinking then
   241       if BestActions.Score < -1023 then
       
   242          begin
   180          begin
   243          BestActions.Count:= 0;
   181          if BestActions.Score < -1023 then
   244          AddAction(BestActions, aia_Skip, 0, 250);
   182             begin
   245          end;
   183             BestActions.Count:= 0;
       
   184             AddAction(BestActions, aia_Skip, 0, 250);
       
   185             end;
       
   186          Me.State:= Me.State and not gstHHThinking
       
   187          end
   246       end else
   188       end else
   247 else begin
   189 else begin
   248       Walk(@WalkMe);
   190       FillBonuses(true);
   249       while (not StopThinking) and (BestActions.Count = 0) do
   191       Walk(@WalkMe)
   250             begin
   192       end
   251             SDL_Delay(100);
       
   252             FillBonuses(true);
       
   253             WalkMe:= BackMe;
       
   254             Walk(@WalkMe)
       
   255             end
       
   256       end;
       
   257 Me.State:= Me.State and not gstHHThinking
       
   258 end;
   193 end;
   259 
   194 
   260 procedure StartThink(Me: PGear);
   195 procedure StartThink(Me: PGear);
   261 var a: TAmmoType;
   196 var a: TAmmoType;
       
   197     tmp: integer;
   262 begin
   198 begin
   263 if ((Me.State and gstAttacking) <> 0) or isInMultiShoot then exit;
   199 if ((Me.State and gstAttacking) <> 0) or isInMultiShoot then exit;
       
   200 ThinkingHH:= Me;
       
   201 isThinking:= true;
       
   202 
       
   203 ClearThinkStack;
       
   204 
   264 Me.State:= Me.State or gstHHThinking;
   205 Me.State:= Me.State or gstHHThinking;
   265 Me.Message:= 0;
   206 Me.Message:= 0;
   266 StopThinking:= false;
       
   267 ThinkingHH:= Me;
       
   268 FillTargets;
   207 FillTargets;
   269 if Targets.Count = 0 then
   208 if Targets.Count = 0 then
   270    begin
   209    begin
   271    OutError('AI: no targets!?');
   210    OutError('AI: no targets!?');
   272    exit
   211    exit
   273    end;
   212    end;
       
   213 
   274 FillBonuses((Me.State and gstAttacked) <> 0);
   214 FillBonuses((Me.State and gstAttacked) <> 0);
       
   215 
   275 for a:= Low(TAmmoType) to High(TAmmoType) do
   216 for a:= Low(TAmmoType) to High(TAmmoType) do
   276     CanUseAmmo[a]:= Assigned(AmmoTests[a]) and HHHasAmmo(PHedgehog(Me.Hedgehog), a);
   217     CanUseAmmo[a]:= Assigned(AmmoTests[a]) and HHHasAmmo(PHedgehog(Me.Hedgehog), a);
   277 {$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF}
   218 
   278 ThinkThread:= SDL_CreateThread(@Think, Me)
   219 BestActions.Count:= 0;
   279 end;
   220 BestActions.Pos:= 0;
   280 
   221 BestActions.Score:= 0;
   281 procedure ProcessBot;
   222 tmp:= random(2) + 1;
   282 const StartTicks: Longword = 0;
   223 Push(0, BestActions, Me^, tmp);
   283 begin
   224 Push(0, BestActions, Me^, tmp xor 3);
       
   225 BestActions.Score:= Low(integer);
       
   226 
       
   227 Think(Me)
       
   228 end;
       
   229 
       
   230 procedure ProcessBot(FrameNo: Longword);
       
   231 const LastFrameNo: Longword = 0;
       
   232 begin
       
   233 if FrameNo = LastFrameNo then exit;
       
   234 LastFrameNo:= FrameNo;
   284 with CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog] do
   235 with CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog] do
   285      if (Gear <> nil)
   236      if (Gear <> nil)
   286         and ((Gear.State and gstHHDriven) <> 0)
   237         and ((Gear.State and gstHHDriven) <> 0)
   287         and (TurnTimeLeft < cHedgehogTurnTime - 50) then
   238         and (TurnTimeLeft < cHedgehogTurnTime - 50) then
   288         if ((Gear.State and gstHHThinking) = 0) then
   239         if not isThinking then
   289            if (BestActions.Pos >= BestActions.Count) then
   240            if (BestActions.Pos >= BestActions.Count) then StartThink(Gear)
   290               begin
   241                                                      else ProcessAction(BestActions, Gear)
   291               StartThink(Gear);
   242         else Think(Gear)
   292               StartTicks:= GameTicks
       
   293               end else ProcessAction(BestActions, Gear)
       
   294         else if (GameTicks - StartTicks) > cMaxAIThinkTime then StopThinking:= true
       
   295 end;
   243 end;
   296 
   244 
   297 end.
   245 end.