Changeset 202 for trunk/UGame.pas
- Timestamp:
- May 17, 2018, 5:41:47 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/UGame.pas
r199 r202 290 290 TPlayerMode = (pmHuman, pmComputer); 291 291 TComputerAgressivity = (caLow, caMedium, caHigh); 292 TComputer = class;293 292 TUnitMove = class; 294 293 … … 310 309 procedure CheckCounterMove(Move: TUnitMove); 311 310 procedure SetMode(AValue: TPlayerMode); 312 function SetMove(CellFrom, CellTo: TCell; Power: Integer; Confirmation: Boolean = True): TUnitMove;313 311 procedure UpdateRepeatMoves; 314 312 procedure RemoveEmptyUnitMoves; … … 328 326 TurnStats: TGameTurnStats; 329 327 Moves: TUnitMoves; 330 Computer: TComputer;328 function SetMove(CellFrom, CellTo: TCell; Power: Integer; Confirmation: Boolean = True): TUnitMove; 331 329 procedure Reset; 332 330 function IsAlive: Boolean; … … 343 341 property Mode: TPlayerMode read FMode write SetMode; 344 342 property OnMove: TMoveEvent read FOnMove write FOnMove; 345 end;346 347 { TComputer }348 349 TComputer = class350 Game: TGame;351 //Targets: TFPGObjectList<TPlayer>;352 CellProcessDirection: Boolean;353 Player: TPlayer;354 procedure AttackNeutral;355 procedure AttackPlayers;356 procedure InnerMoves;357 procedure IncreaseMoves;358 procedure Process;359 procedure FallBack;360 function AttackersCount(Cell: TCell): Integer;361 343 end; 362 344 … … 474 456 procedure SaveToFile(FileName: string); 475 457 procedure ComputePlayerStats; 476 procedure Next Turn;458 procedure NextPlayer; 477 459 procedure CheckWinObjective; 478 460 constructor Create; … … 502 484 503 485 procedure InitStrings; 486 function CellCompare(const Item1, Item2: TCell): Integer; 487 function CellCompareDescending(const Item1, Item2: TCell): Integer; 504 488 505 489 resourcestring … … 2096 2080 FGame := AValue; 2097 2081 Moves.Game := AValue; 2098 Computer.Game := AValue;2099 2082 end; 2100 2083 … … 2187 2170 PlayerMap.Player := Self; 2188 2171 TurnStats := TGameTurnStats.Create; 2189 Computer := TComputer.Create;2190 Computer.Player := Self;2191 2172 end; 2192 2173 … … 2194 2175 begin 2195 2176 //Client := nil; 2196 FreeAndNil(Computer);2197 2177 FreeAndNil(TurnStats); 2198 2178 FreeAndNil(PlayerMap); … … 2214 2194 Agressivity := Source.Agressivity; 2215 2195 Defensive := Source.Defensive; 2216 Computer.Game := Source.Computer.Game;2217 Computer.CellProcessDirection := Source.Computer.CellProcessDirection;2218 2196 end; 2219 2197 … … 2301 2279 else if Item1.Power < Item2.Power then Result := 1 2302 2280 else Result := 0; 2303 end;2304 2305 { TComputer }2306 2307 procedure TComputer.AttackNeutral;2308 var2309 AllCells: TCells;2310 TotalPower: Integer;2311 AttackPower: Integer;2312 TotalAttackPower: Integer;2313 CanAttack: Integer;2314 TargetCells: TCells;2315 Cell: TCell;2316 NeighborCell: TCell;2317 const2318 AttackDiff = 1;2319 begin2320 AllCells := Game.Map.Cells;2321 TargetCells := TCells.Create;2322 TargetCells.FreeObjects := False;2323 2324 // Get list of all attack target cells2325 for Cell in AllCells do2326 with Cell do begin2327 if (Terrain <> ttVoid) and (Player = nil) then begin2328 CanAttack := 0;2329 for NeighborCell in Neighbors do2330 if NeighborCell.Player = Game.CurrentPlayer then begin2331 Inc(CanAttack);2332 end;2333 if CanAttack > 0 then TargetCells.Add(Cell);2334 end;2335 end;2336 2337 // Sort ascending to attack cells with lower power first2338 // Low power cells are better for expanding our teritorry2339 TargetCells.Sort(CellCompare);2340 2341 for Cell in TargetCells do2342 with Cell do begin2343 // Attack to not owned cell yet2344 // Count own possible power2345 TotalPower := 0;2346 for NeighborCell in Neighbors do2347 if NeighborCell.Player = Game.CurrentPlayer then2348 TotalPower := TotalPower + NeighborCell.GetAvialPower;2349 2350 // Attack if target is weaker2351 if TotalPower >= (Power + AttackDiff) then begin2352 TotalAttackPower := 0;2353 for NeighborCell in Neighbors do2354 if NeighborCell.Player = Game.CurrentPlayer then begin2355 // Use only necessary power2356 AttackPower := Power - TotalAttackPower + AttackDiff;2357 if NeighborCell.GetAvialPower < AttackPower then2358 AttackPower := NeighborCell.GetAvialPower;2359 Self.Player.SetMove(NeighborCell, Cell, AttackPower, False);2360 TotalAttackPower := TotalAttackPower + AttackPower;2361 end;2362 end;2363 end;2364 2365 FreeAndNil(TargetCells);2366 end;2367 2368 procedure TComputer.AttackPlayers;2369 var2370 AllCells: TCells;2371 TotalPower: Integer;2372 AttackPower: Integer;2373 TotalAttackPower: Integer;2374 CanAttack: Integer;2375 TargetCells: TCells;2376 TargetCell: TCell;2377 NeighborCell: TCell;2378 begin2379 if Player.Defensive then Exit;2380 2381 AllCells := Game.Map.Cells;2382 TargetCells := TCells.Create;2383 TargetCells.FreeObjects := False;2384 2385 // Get list of all attack target cells2386 for TargetCell in AllCells do begin2387 if (TargetCell.Terrain <> ttVoid) and (TargetCell.Player <> Player) and2388 (TargetCell.Player <> nil) then begin2389 CanAttack := 0;2390 for NeighborCell in TargetCell.Neighbors do2391 if NeighborCell.Player = Player then begin2392 Inc(CanAttack);2393 end;2394 if CanAttack > 0 then TargetCells.Add(TargetCell);2395 end;2396 end;2397 2398 // Sort descending to attack cells with higher power first2399 // Higher power enemy cells can grow faster and is more dangerous2400 TargetCells.Sort(CellCompareDescending);2401 2402 for TargetCell in TargetCells do begin2403 // Attack to not owned cell yet2404 // Count own possible power2405 TotalPower := 0;2406 for NeighborCell in TargetCell.Neighbors do2407 if NeighborCell.Player = Player then begin2408 TotalPower := TotalPower + NeighborCell.GetAvialPower;2409 end;2410 // Attack if target is weaker2411 if Game.AttackProbability(TotalPower, TargetCell.Power) >=2412 ComputerAggroProbability[Player.Agressivity] then begin2413 // Try to limit total attacking power to necessary minimum2414 while Game.AttackProbability(TotalPower - 1, TargetCell.Power) >=2415 ComputerAggroProbability[Player.Agressivity] do2416 Dec(TotalPower);2417 2418 // Collect required attack units from our cells2419 TotalAttackPower := 0;2420 for NeighborCell in TargetCell.Neighbors do2421 if NeighborCell.Player = Player then begin2422 // Use only necessary power2423 AttackPower := TotalPower - TotalAttackPower;2424 if NeighborCell.GetAvialPower < AttackPower then2425 AttackPower := NeighborCell.GetAvialPower;2426 Self.Player.SetMove(NeighborCell, TargetCell, AttackPower, False);2427 TotalAttackPower := TotalAttackPower + AttackPower;2428 if TotalAttackPower >= TotalPower then Break;2429 end;2430 end;2431 end;2432 2433 FreeAndNil(TargetCells);2434 end;2435 2436 procedure TComputer.InnerMoves;2437 var2438 AllCells: TCells;2439 I, J: Integer;2440 C: Integer;2441 CanAttack: Integer;2442 TargetCells: TCells;2443 NewTargetCells: TCells;2444 Cells2: TCells;2445 MovedPower: Integer;2446 begin2447 // We need to move available power to borders to be available for attacks2448 // or defense2449 AllCells := Game.Map.Cells;2450 TargetCells := TCells.Create;2451 TargetCells.FreeObjects := False;2452 NewTargetCells := TCells.Create;2453 NewTargetCells.FreeObjects := False;2454 2455 // Get list of all enemy border cells2456 for C := 0 to AllCells.Count - 1 do2457 with AllCells[C] do begin2458 if (Player <> Game.CurrentPlayer) and (Player <> nil) and (Terrain <> ttVoid) then begin2459 CanAttack := 0;2460 for I := 0 to Neighbors.Count - 1 do2461 if ((Neighbors[I].Player = Game.CurrentPlayer) or2462 (Neighbors[I].Player = nil)) and (Neighbors[I].Terrain <> ttVoid) then begin2463 Inc(CanAttack);2464 end;2465 if CanAttack > 0 then TargetCells.Add(AllCells[C]);2466 end;2467 end;2468 2469 if CellProcessDirection then begin2470 // Reverse array2471 for I := 0 to (TargetCells.Count div 2) - 1 do2472 TargetCells.Exchange(I, TargetCells.Count - 1 - I);2473 end;2474 2475 Game.Map.Cells.ClearMark;2476 2477 while TargetCells.Count > 0 do begin2478 // Set mark for selected border cells2479 for C := 0 to TargetCells.Count - 1 do2480 TargetCells[C].Mark := True;2481 2482 // Move all power from unmarked cells and mark them2483 NewTargetCells.Count := 0;2484 for C := 0 to TargetCells.Count - 1 do2485 with TargetCells[C] do begin2486 for I := 0 to Neighbors.Count - 1 do begin2487 if (Neighbors[I].Terrain <> ttVoid) and (not Neighbors[I].Mark) then begin2488 if (TargetCells[C].Player = Game.CurrentPlayer) and2489 (Neighbors[I].Player = Game.CurrentPlayer) then begin2490 // Do not take units from front line2491 Cells2 := Neighbors[I].Neighbors;2492 CanAttack := 0;2493 for J := 0 to Cells2.Count - 1 do2494 if ((Cells2[J].Player <> Game.CurrentPlayer) or (Cells2[J].Player = nil))2495 and (Cells2[J].Terrain <> ttVoid) then begin2496 Inc(CanAttack);2497 end;2498 if CanAttack = 0 then begin2499 MovedPower := Neighbors[I].GetAvialPower;2500 if (TargetCells[C].GetAvialPower + TargetCells[C].GetAttackPower + MovedPower) > Game.Map.MaxPower then2501 MovedPower := Game.Map.MaxPower - TargetCells[C].GetAvialPower - TargetCells[C].GetAttackPower;2502 Player.SetMove(Neighbors[I], TargetCells[C], MovedPower, False);2503 end;2504 end;2505 Neighbors[I].Mark := True;2506 NewTargetCells.Add(Neighbors[I]);2507 end;2508 end;2509 end;2510 2511 // Use source cells NewTargetCells as new TargetCells2512 FreeAndNil(TargetCells);2513 TargetCells := NewTargetCells;2514 NewTargetCells := TCells.Create;2515 NewTargetCells.FreeObjects := False;2516 end;2517 2518 FreeAndNil(TargetCells);2519 FreeAndNil(NewTargetCells);2520 end;2521 2522 procedure TComputer.IncreaseMoves;2523 var2524 Move: TUnitMove;2525 AvailPower: Integer;2526 begin2527 // If available power remains then use all for existed unit moves2528 for Move in Player.Moves do2529 with Move do begin2530 if CellFrom.GetAvialPower > 0 then begin2531 AvailPower := CellFrom.GetAvialPower;2532 CountOnce := CountOnce + Min(AvailPower div CellFrom.MovesFrom.Count, AvailPower);2533 end;2534 end;2535 end;2536 2537 procedure TComputer.Process;2538 begin2539 AttackPlayers;2540 AttackNeutral;2541 InnerMoves;2542 IncreaseMoves;2543 //FallBack;2544 CellProcessDirection := not CellProcessDirection;2545 end;2546 2547 procedure TComputer.FallBack;2548 var2549 C: Integer;2550 I: Integer;2551 AllCells: TCells;2552 BorderCells: TCells;2553 EnemyPower: Integer;2554 begin2555 BorderCells := TCells.Create;2556 BorderCells.FreeObjects := False;2557 AllCells := Game.Map.Cells;2558 2559 // Get list of border cells2560 for C := 0 to AllCells.Count - 1 do2561 with AllCells[C] do begin2562 if (Terrain <> ttVoid) and (Player = Game.CurrentPlayer) then begin2563 if AttackersCount(AllCells[C]) > 0 then2564 BorderCells.Add(AllCells[C]);2565 end;2566 end;2567 2568 // Move all units back to inner area from weak border cells2569 for C := 0 to BorderCells.Count - 1 do2570 with BorderCells[C] do begin2571 // Calculate enemy power2572 // TODO: Do not sum different enemy power to one value2573 EnemyPower := 0;2574 for I := 0 to Neighbors.Count - 1 do2575 if (Neighbors[I].Player <> Game.CurrentPlayer) and (Neighbors[I].Player <> nil) then begin2576 Inc(EnemyPower, Neighbors[I].Power);2577 end;2578 if EnemyPower > (GetAvialPower + GetAttackPower) then begin2579 // Fallback2580 for I := MovesTo.Count - 1 downto 0 do2581 Player.Moves.Remove(MovesTo[I]);2582 for I := 0 to Neighbors.Count - 1 do2583 if (Neighbors[I].Player = Player) and (AttackersCount(Neighbors[I]) = 0) then begin2584 Player.SetMove(BorderCells[C], Neighbors[I], GetAvialPower, False);2585 Break;2586 end;2587 end;2588 end;2589 2590 FreeAndNil(BorderCells);2591 end;2592 2593 function TComputer.AttackersCount(Cell: TCell): Integer;2594 var2595 I: Integer;2596 begin2597 Result := 0;2598 for I := 0 to Cell.Neighbors.Count - 1 do2599 if (Cell.Neighbors[I].Player <> Game.CurrentPlayer) and2600 (Cell.Neighbors[I].Player <> nil) then begin2601 Inc(Result);2602 end;2603 2281 end; 2604 2282 … … 3457 3135 end; 3458 3136 3459 procedure TGame.Next Turn;3137 procedure TGame.NextPlayer; 3460 3138 var 3461 3139 PrevPlayer: TPlayer; 3462 3140 begin 3463 // TODO CurrentPlayer.View.SelectedCell := nil;3141 // Finalize current player 3464 3142 CurrentPlayer.MoveAll; 3465 3143 Map.Grow(CurrentPlayer); 3466 3144 CurrentPlayer.UpdateRepeatMoves; 3467 3145 ComputePlayerStats; 3146 3147 // Select new player 3468 3148 PrevPlayer := CurrentPlayer; 3469 3149 // Skip dead players … … 3482 3162 CurrentPlayer.PlayerMap.CheckVisibility; 3483 3163 CurrentPlayer.ReduceMovesPower; 3484 // For computers take view from previous human3485 //if CurrentPlayer.Mode = pmComputer then CurrentPlayer.View.Assign(PrevPlayer.View);3486 3164 if Assigned(FOnChange) then 3487 3165 FOnChange(Self);
Note:
See TracChangeset
for help on using the changeset viewer.