source: tags/1.3.0/UClientAI.pas

Last change on this file was 231, checked in by chronos, 6 years ago
  • Modified: UGame unit was split to UPlayer, UMap and UClientGUI units to have better logical separation of game classes.
  • Modified: Drawing methods moved from TMap and TPlayerMap to TClientGUI. Generic TClient class and TComputer classes don't need have any drawing support.
File size: 10.6 KB
Line 
1unit UClientAI;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, UGameClient, UGame, Math, UPlayer, UMap;
9
10type
11 { TComputer }
12
13 TComputer = class(TClient)
14 protected
15 procedure DoTurnStart; override;
16 public
17 //Targets: TFPGObjectList<TPlayer>;
18 CellProcessDirection: Boolean;
19 procedure AttackNeutral;
20 procedure AttackPlayers;
21 procedure InnerMoves;
22 procedure IncreaseMoves;
23 procedure Process;
24 procedure FallBack;
25 function AttackersCount(Cell: TPlayerCell): Integer;
26 end;
27
28
29implementation
30
31{ TComputer }
32
33procedure TComputer.DoTurnStart;
34begin
35 Process;
36 Protocol.TurnEnd;
37end;
38
39procedure TComputer.AttackNeutral;
40var
41 AllCells: TPlayerCells;
42 TotalPower: Integer;
43 AttackPower: Integer;
44 TotalAttackPower: Integer;
45 CanAttack: Integer;
46 TargetCells: TPlayerCells;
47 Cell: TPlayerCell;
48 NeighborCell: TPlayerCell;
49const
50 AttackDiff = 1;
51begin
52 AllCells := ControlPlayer.PlayerMap.Cells;
53 TargetCells := TPlayerCells.Create;
54 TargetCells.FreeObjects := False;
55
56 // Get list of all attack target cells
57 for Cell in AllCells do
58 with Cell do begin
59 if (MapCell.Terrain <> ttVoid) and (MapCell.Player = nil) then begin
60 CanAttack := 0;
61 for NeighborCell in Neighbors do
62 if NeighborCell.MapCell.Player = ControlPlayer then begin
63 Inc(CanAttack);
64 end;
65 if CanAttack > 0 then TargetCells.Add(Cell);
66 end;
67 end;
68
69 // Sort ascending to attack cells with lower power first
70 // Low power cells are better for expanding our teritorry
71 TargetCells.Sort(CellCompare);
72
73 for Cell in TargetCells do
74 with Cell do begin
75 // Attack to not owned cell yet
76 // Count own possible power
77 TotalPower := 0;
78 for NeighborCell in Neighbors do
79 if NeighborCell.MapCell.Player = ControlPlayer then
80 TotalPower := TotalPower + NeighborCell.GetAvialPower;
81
82 // Attack if target is weaker
83 if TotalPower >= (MapCell.Power + AttackDiff) then begin
84 TotalAttackPower := 0;
85 for NeighborCell in Neighbors do
86 if NeighborCell.MapCell.Player = ControlPlayer then begin
87 // Use only necessary power
88 AttackPower := MapCell.Power - TotalAttackPower + AttackDiff;
89 if NeighborCell.GetAvialPower < AttackPower then
90 AttackPower := NeighborCell.GetAvialPower;
91 ControlPlayer.SetMove(NeighborCell, Cell, AttackPower, False);
92 TotalAttackPower := TotalAttackPower + AttackPower;
93 end;
94 end;
95 end;
96
97 FreeAndNil(TargetCells);
98end;
99
100procedure TComputer.AttackPlayers;
101var
102 AllCells: TPlayerCells;
103 TotalPower: Integer;
104 AttackPower: Integer;
105 TotalAttackPower: Integer;
106 CanAttack: Integer;
107 TargetCells: TPlayerCells;
108 TargetCell: TPlayerCell;
109 NeighborCell: TPlayerCell;
110begin
111if ControlPlayer.Defensive then Exit;
112
113 AllCells := ControlPlayer.PlayerMap.Cells;
114 TargetCells := TPlayerCells.Create;
115 TargetCells.FreeObjects := False;
116
117 // Get list of all attack target cells
118 for TargetCell in AllCells do begin
119 if (TargetCell.MapCell.Terrain <> ttVoid) and (TargetCell.MapCell.Player <> ControlPlayer) and
120 (TargetCell.MapCell.Player <> nil) then begin
121 CanAttack := 0;
122 for NeighborCell in TargetCell.Neighbors do
123 if NeighborCell.MapCell.Player = ControlPlayer then begin
124 Inc(CanAttack);
125 end;
126 if CanAttack > 0 then TargetCells.Add(TargetCell);
127 end;
128 end;
129
130 // Sort descending to attack cells with higher power first
131 // Higher power enemy cells can grow faster and is more dangerous
132 TargetCells.Sort(CellCompareDescending);
133
134 for TargetCell in TargetCells do begin
135 // Attack to not owned cell yet
136 // Count own possible power
137 TotalPower := 0;
138 for NeighborCell in TargetCell.Neighbors do
139 if NeighborCell.MapCell.Player = ControlPlayer then begin
140 TotalPower := TotalPower + NeighborCell.GetAvialPower;
141 end;
142 // Attack if target is weaker
143 if Game.AttackProbability(TotalPower, TargetCell.MapCell.Power) >=
144 ComputerAggroProbability[ControlPlayer.Agressivity] then begin
145 // Try to limit total attacking power to necessary minimum
146 while Game.AttackProbability(TotalPower - 1, TargetCell.MapCell.Power) >=
147 ComputerAggroProbability[ControlPlayer.Agressivity] do
148 Dec(TotalPower);
149
150 // Collect required attack units from our cells
151 TotalAttackPower := 0;
152 for NeighborCell in TargetCell.Neighbors do
153 if NeighborCell.MapCell.Player = ControlPlayer then begin
154 // Use only necessary power
155 AttackPower := TotalPower - TotalAttackPower;
156 if NeighborCell.GetAvialPower < AttackPower then
157 AttackPower := NeighborCell.GetAvialPower;
158 Self.ControlPlayer.SetMove(NeighborCell, TargetCell, AttackPower, False);
159 TotalAttackPower := TotalAttackPower + AttackPower;
160 if TotalAttackPower >= TotalPower then Break;
161 end;
162 end;
163 end;
164
165 FreeAndNil(TargetCells);
166end;
167
168procedure TComputer.InnerMoves;
169var
170 AllCells: TPlayerCells;
171 I, J: Integer;
172 C: Integer;
173 CanAttack: Integer;
174 TargetCells: TPlayerCells;
175 NewTargetCells: TPlayerCells;
176 Cells2: TPlayerCells;
177 MovedPower: Integer;
178begin
179 // We need to move available power to borders to be available for attacks
180 // or defense
181 AllCells := ControlPlayer.PlayerMap.Cells;
182 TargetCells := TPlayerCells.Create;
183 TargetCells.FreeObjects := False;
184 NewTargetCells := TPlayerCells.Create;
185 NewTargetCells.FreeObjects := False;
186
187 // Get list of all enemy border cells
188 for C := 0 to AllCells.Count - 1 do
189 with AllCells[C] do begin
190 if (MapCell.Player <> ControlPlayer) and (MapCell.Player <> nil) and (MapCell.Terrain <> ttVoid) then begin
191 CanAttack := 0;
192 for I := 0 to Neighbors.Count - 1 do
193 if ((Neighbors[I].MapCell.Player = ControlPlayer) or
194 (Neighbors[I].MapCell.Player = nil)) and (Neighbors[I].MapCell.Terrain <> ttVoid) then begin
195 Inc(CanAttack);
196 end;
197 if CanAttack > 0 then TargetCells.Add(AllCells[C]);
198 end;
199 end;
200
201 if CellProcessDirection then begin
202 // Reverse array
203 for I := 0 to (TargetCells.Count div 2) - 1 do
204 TargetCells.Exchange(I, TargetCells.Count - 1 - I);
205 end;
206
207 Game.Map.Cells.ClearMark;
208
209 while TargetCells.Count > 0 do begin
210 // Set mark for selected border cells
211 for C := 0 to TargetCells.Count - 1 do
212 TargetCells[C].MapCell.Mark := True;
213
214 // Move all power from unmarked cells and mark them
215 NewTargetCells.Count := 0;
216 for C := 0 to TargetCells.Count - 1 do
217 with TargetCells[C] do begin
218 for I := 0 to Neighbors.Count - 1 do begin
219 if (Neighbors[I].MapCell.Terrain <> ttVoid) and (not Neighbors[I].MapCell.Mark) then begin
220 if (TargetCells[C].MapCell.Player = ControlPlayer) and
221 (Neighbors[I].MapCell.Player = ControlPlayer) then begin
222 // Do not take units from front line
223 Cells2 := Neighbors[I].Neighbors;
224 CanAttack := 0;
225 for J := 0 to Cells2.Count - 1 do
226 if ((Cells2[J].MapCell.Player <> ControlPlayer) or (Cells2[J].MapCell.Player = nil))
227 and (Cells2[J].MapCell.Terrain <> ttVoid) then begin
228 Inc(CanAttack);
229 end;
230 if CanAttack = 0 then begin
231 MovedPower := Neighbors[I].GetAvialPower;
232 if (TargetCells[C].GetAvialPower + TargetCells[C].GetAttackPower + MovedPower) > Game.Map.MaxPower then
233 MovedPower := Game.Map.MaxPower - TargetCells[C].GetAvialPower - TargetCells[C].GetAttackPower;
234 TPlayer(MapCell.Player).SetMove(Neighbors[I], TargetCells[C], MovedPower, False);
235 end;
236 end;
237 Neighbors[I].MapCell.Mark := True;
238 NewTargetCells.Add(Neighbors[I]);
239 end;
240 end;
241 end;
242
243 // Use source cells NewTargetCells as new TargetCells
244 FreeAndNil(TargetCells);
245 TargetCells := NewTargetCells;
246 NewTargetCells := TPlayerCells.Create;
247 NewTargetCells.FreeObjects := False;
248 end;
249
250 FreeAndNil(TargetCells);
251 FreeAndNil(NewTargetCells);
252end;
253
254procedure TComputer.IncreaseMoves;
255var
256 Move: TUnitMove;
257 AvailPower: Integer;
258begin
259 // If available power remains then use all for existed unit moves
260 for Move in ControlPlayer.Moves do
261 with Move do begin
262 if CellFrom.GetAvialPower > 0 then begin
263 AvailPower := CellFrom.GetAvialPower;
264 CountOnce := CountOnce + Min(AvailPower div CellFrom.MovesFrom.Count, AvailPower);
265 end;
266 end;
267end;
268
269procedure TComputer.Process;
270begin
271 AttackPlayers;
272 AttackNeutral;
273 InnerMoves;
274 IncreaseMoves;
275 //FallBack;
276 CellProcessDirection := not CellProcessDirection;
277end;
278
279procedure TComputer.FallBack;
280var
281 C: Integer;
282 I: Integer;
283 AllCells: TPlayerCells;
284 BorderCells: TPlayerCells;
285 EnemyPower: Integer;
286begin
287 BorderCells := TPlayerCells.Create;
288 BorderCells.FreeObjects := False;
289 AllCells := ControlPlayer.PlayerMap.Cells;
290
291 // Get list of border cells
292 for C := 0 to AllCells.Count - 1 do
293 with AllCells[C] do begin
294 if (MapCell.Terrain <> ttVoid) and (MapCell.Player = ControlPlayer) then begin
295 if AttackersCount(AllCells[C]) > 0 then
296 BorderCells.Add(AllCells[C]);
297 end;
298 end;
299
300 // Move all units back to inner area from weak border cells
301 for C := 0 to BorderCells.Count - 1 do
302 with BorderCells[C] do begin
303 // Calculate enemy power
304 // TODO: Do not sum different enemy power to one value
305 EnemyPower := 0;
306 for I := 0 to Neighbors.Count - 1 do
307 if (Neighbors[I].MapCell.Player <> ControlPlayer) and (Neighbors[I].MapCell.Player <> nil) then begin
308 Inc(EnemyPower, Neighbors[I].MapCell.Power);
309 end;
310 if EnemyPower > (GetAvialPower + GetAttackPower) then begin
311 // Fallback
312 for I := MovesTo.Count - 1 downto 0 do
313 TPlayer(MapCell.Player).Moves.Remove(MovesTo[I]);
314 for I := 0 to Neighbors.Count - 1 do
315 if (Neighbors[I].MapCell.Player = MapCell.Player) and (AttackersCount(Neighbors[I]) = 0) then begin
316 TPlayer(MapCell.Player).SetMove(BorderCells[C], Neighbors[I], GetAvialPower, False);
317 Break;
318 end;
319 end;
320 end;
321
322 FreeAndNil(BorderCells);
323end;
324
325function TComputer.AttackersCount(Cell: TPlayerCell): Integer;
326var
327 I: Integer;
328begin
329 Result := 0;
330 for I := 0 to Cell.Neighbors.Count - 1 do
331 if (Cell.Neighbors[I].MapCell.Player <> ControlPlayer) and
332 (Cell.Neighbors[I].MapCell.Player <> nil) then begin
333 Inc(Result);
334 end;
335end;
336
337
338end.
339
Note: See TracBrowser for help on using the repository browser.