More aggressive, got to level 3 at least
This commit is contained in:
@@ -315,26 +315,27 @@ public partial class MainWindow : Window
|
|||||||
_recentDamageTicks = 20;
|
_recentDamageTicks = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_deaths > previousDeaths)
|
if (_deaths > previousDeaths)
|
||||||
{
|
{
|
||||||
var nowDeath = DateTimeOffset.UtcNow;
|
var nowDeath = DateTimeOffset.UtcNow;
|
||||||
_recentDeaths.Enqueue(nowDeath);
|
_recentDeaths.Enqueue(nowDeath);
|
||||||
while (_recentDeaths.Count > 0 && nowDeath - _recentDeaths.Peek() > TimeSpan.FromSeconds(90))
|
while (_recentDeaths.Count > 0 && nowDeath - _recentDeaths.Peek() > TimeSpan.FromSeconds(90))
|
||||||
{
|
{
|
||||||
_recentDeaths.Dequeue();
|
_recentDeaths.Dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
_survivalTicks = Math.Max(_survivalTicks, 24 + _recentDeaths.Count * 4);
|
// Minimal survival mode - deaths don't matter, only kills
|
||||||
_escapeLockTicks = Math.Max(_escapeLockTicks, 8);
|
_survivalTicks = Math.Max(_survivalTicks, 4);
|
||||||
_escapeDirection = Opposite(_lastMoveDirection);
|
_escapeLockTicks = Math.Max(_escapeLockTicks, 2);
|
||||||
_pressureStreak = 0;
|
_escapeDirection = Opposite(_lastMoveDirection);
|
||||||
_x = 0;
|
_pressureStreak = 0;
|
||||||
_y = 0;
|
_x = 0;
|
||||||
_enemyHeat.Clear();
|
_y = 0;
|
||||||
_nearestEnemy = null;
|
_enemyHeat.Clear();
|
||||||
MarkDeathZone(_x, _y);
|
_nearestEnemy = null;
|
||||||
_sessionLogger?.LogEvent("death", $"death_count={_deaths};death_window_90s={_recentDeaths.Count}");
|
MarkDeathZone(_x, _y);
|
||||||
}
|
_sessionLogger?.LogEvent("death", $"death_count={_deaths};death_window_90s={_recentDeaths.Count}");
|
||||||
|
}
|
||||||
|
|
||||||
_sessionLogger?.LogTelemetry(
|
_sessionLogger?.LogTelemetry(
|
||||||
_currentHealth,
|
_currentHealth,
|
||||||
@@ -433,285 +434,275 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BotDecision? BuildDecision()
|
private BotDecision? BuildDecision()
|
||||||
{
|
{
|
||||||
var hpRatio = _maxHealth > 0.1 ? _currentHealth / _maxHealth : 1.0;
|
var hpRatio = _maxHealth > 0.1 ? _currentHealth / _maxHealth : 1.0;
|
||||||
var profile = _currentLevelProfile;
|
var profile = _currentLevelProfile;
|
||||||
|
|
||||||
var immediateDir = _lastPeek
|
var immediateDir = _lastPeek
|
||||||
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0 && x.Value.SightedPlayerDistance == 1)
|
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0 && x.Value.SightedPlayerDistance == 1)
|
||||||
.Select(x => (Direction?)x.Key)
|
.Select(x => (Direction?)x.Key)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var closeThreats = _lastPeek.Values.Count(x => x.Executed && x.PlayersInSight > 0 && (x.SightedPlayerDistance ?? 99) <= 2);
|
var closeThreats = _lastPeek.Values.Count(x => x.Executed && x.PlayersInSight > 0 && (x.SightedPlayerDistance ?? 99) <= 2);
|
||||||
if (_nearestEnemy.HasValue && Math.Abs(_nearestEnemy.Value.X) + Math.Abs(_nearestEnemy.Value.Y) <= 2)
|
if (_nearestEnemy.HasValue && Math.Abs(_nearestEnemy.Value.X) + Math.Abs(_nearestEnemy.Value.Y) <= 2)
|
||||||
{
|
{
|
||||||
closeThreats++;
|
closeThreats++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hpRatio < 0.75 || _recentDamageTicks > 0 || closeThreats >= 2)
|
if (hpRatio < 0.75 || _recentDamageTicks > 0 || closeThreats >= 2)
|
||||||
{
|
{
|
||||||
_pressureStreak = Math.Min(_pressureStreak + 1, 12);
|
_pressureStreak = Math.Min(_pressureStreak + 1, 12);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pressureStreak = Math.Max(_pressureStreak - 1, 0);
|
_pressureStreak = Math.Max(_pressureStreak - 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var underPressure = hpRatio < PressureHpThreshold(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThreshold(profile) || _survivalTicks > 0 || _pressureStreak >= 2;
|
var underPressure = hpRatio < PressureHpThreshold(profile) || _recentDamageTicks > 0 || closeThreats >= PressureThreatThreshold(profile) || _survivalTicks > 0 || _pressureStreak >= 2;
|
||||||
_lastUnderPressure = underPressure;
|
_lastUnderPressure = underPressure;
|
||||||
|
|
||||||
var specialThreatThreshold = SpecialThreatThreshold(profile);
|
// Teleport if we can and enemies are nearby - aggressive repositioning for kills
|
||||||
var specialHpFloor = SpecialHpFloor(profile);
|
if (Ready(BotAction.Teleport) && closeThreats >= 1 && _nearestEnemy.HasValue)
|
||||||
|
{
|
||||||
|
var targetX = _nearestEnemy.Value.X;
|
||||||
|
var targetY = _nearestEnemy.Value.Y;
|
||||||
|
// Teleport closer to enemy for aggressive positioning
|
||||||
|
var moveTowardX = targetX > 0 ? targetX - 1 : targetX + 1;
|
||||||
|
var moveTowardY = targetY > 0 ? targetY - 1 : targetY + 1;
|
||||||
|
|
||||||
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold && (hpRatio >= specialHpFloor || closeThreats >= specialThreatThreshold + 1))
|
return new BotDecision(
|
||||||
{
|
"teleport-aggro",
|
||||||
return new BotDecision(
|
"Close enemy; teleport for aggressive positioning.",
|
||||||
"specialattack",
|
async ct =>
|
||||||
"Multiple enemies close; AoE yields best kill rate.",
|
{
|
||||||
async ct =>
|
var response = await _client.TeleportAsync(_playerToken, moveTowardX, moveTowardY, ct);
|
||||||
{
|
MarkUsed(BotAction.Teleport);
|
||||||
var response = await _client.SpecialattackAsync(_playerToken, ct);
|
if (response.Executed)
|
||||||
MarkUsed(BotAction.Special);
|
{
|
||||||
return response.Executed;
|
_x = moveTowardX;
|
||||||
});
|
_y = moveTowardY;
|
||||||
}
|
}
|
||||||
|
return response.Executed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (immediateDir.HasValue && Ready(BotAction.Hit) && ShouldUseImmediateHit(profile, hpRatio, closeThreats, underPressure))
|
var specialThreatThreshold = SpecialThreatThreshold(profile);
|
||||||
{
|
var specialHpFloor = SpecialHpFloor(profile);
|
||||||
var dir = immediateDir.Value;
|
|
||||||
return new BotDecision(
|
|
||||||
"hit",
|
|
||||||
$"Adjacent enemy at {dir}; highest DPS action.",
|
|
||||||
async ct =>
|
|
||||||
{
|
|
||||||
var response = await _client.HitAsync(_playerToken, (int)dir, ct);
|
|
||||||
MarkUsed(BotAction.Hit);
|
|
||||||
return response.Executed;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (immediateDir.HasValue && Ready(BotAction.Move) && ShouldRetreatOnImmediate(profile, hpRatio, closeThreats))
|
if (Ready(BotAction.Special) && closeThreats >= specialThreatThreshold)
|
||||||
{
|
{
|
||||||
var retreatDirection = Opposite(immediateDir.Value);
|
return new BotDecision(
|
||||||
|
"specialattack",
|
||||||
|
$"Multiple enemies ({closeThreats}) close; AoE for maximum kills.",
|
||||||
|
async ct =>
|
||||||
|
{
|
||||||
|
var response = await _client.SpecialattackAsync(_playerToken, ct);
|
||||||
|
MarkUsed(BotAction.Special);
|
||||||
|
return response.Executed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (Ready(BotAction.Dash) && (hpRatio < DashHpThreshold(profile) || _pressureStreak >= 3 || _survivalTicks > 0))
|
if (immediateDir.HasValue && Ready(BotAction.Hit) && ShouldUseImmediateHit(profile, hpRatio, closeThreats, underPressure))
|
||||||
{
|
{
|
||||||
return new BotDecision(
|
var dir = immediateDir.Value;
|
||||||
"dash-retreat",
|
return new BotDecision(
|
||||||
$"High pressure escape via dash -> {retreatDirection}.",
|
"hit",
|
||||||
async ct =>
|
$"Adjacent enemy at {dir}; highest DPS action.",
|
||||||
{
|
async ct =>
|
||||||
var response = await _client.DashAsync(_playerToken, (int)retreatDirection, ct);
|
{
|
||||||
MarkUsed(BotAction.Dash);
|
var response = await _client.HitAsync(_playerToken, (int)dir, ct);
|
||||||
if (response.Executed)
|
MarkUsed(BotAction.Hit);
|
||||||
{
|
return response.Executed;
|
||||||
ApplyMovement(retreatDirection, Math.Max(response.BlocksDashed, 1));
|
});
|
||||||
_escapeDirection = retreatDirection;
|
}
|
||||||
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Executed;
|
if (immediateDir.HasValue && Ready(BotAction.Move) && ShouldRetreatOnImmediate(profile, hpRatio, closeThreats))
|
||||||
});
|
{
|
||||||
}
|
var retreatDirection = Opposite(immediateDir.Value);
|
||||||
|
|
||||||
return new BotDecision(
|
if (Ready(BotAction.Dash) && (hpRatio < DashHpThreshold(profile) || _pressureStreak >= 3 || _survivalTicks > 0))
|
||||||
"move-retreat",
|
{
|
||||||
$"Adjacent enemy and pressure high; kite to {retreatDirection}.",
|
return new BotDecision(
|
||||||
async ct =>
|
"dash-retreat",
|
||||||
{
|
$"Critical HP escape via dash -> {retreatDirection}.",
|
||||||
var response = await _client.MoveAsync(_playerToken, (int)retreatDirection, ct);
|
async ct =>
|
||||||
MarkUsed(BotAction.Move);
|
{
|
||||||
var moved = response.Executed && response.Move == true;
|
var response = await _client.DashAsync(_playerToken, (int)retreatDirection, ct);
|
||||||
RegisterMoveResult(retreatDirection, moved);
|
MarkUsed(BotAction.Dash);
|
||||||
if (moved)
|
if (response.Executed)
|
||||||
{
|
{
|
||||||
ApplyMovement(retreatDirection, 1);
|
ApplyMovement(retreatDirection, Math.Max(response.BlocksDashed, 1));
|
||||||
_escapeDirection = retreatDirection;
|
_escapeDirection = retreatDirection;
|
||||||
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
|
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.Executed;
|
return response.Executed;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (immediateDir.HasValue && Ready(BotAction.Hit))
|
return new BotDecision(
|
||||||
{
|
"move-retreat",
|
||||||
var dir = immediateDir.Value;
|
$"Retreating from {immediateDir.Value} -> {retreatDirection}.",
|
||||||
return new BotDecision(
|
async ct =>
|
||||||
"hit-last-stand",
|
{
|
||||||
$"Adjacent enemy at {dir}; strike while move cooldown is active.",
|
var response = await _client.MoveAsync(_playerToken, (int)retreatDirection, ct);
|
||||||
async ct =>
|
MarkUsed(BotAction.Move);
|
||||||
{
|
var moved = response.Executed && response.Move == true;
|
||||||
var response = await _client.HitAsync(_playerToken, (int)dir, ct);
|
RegisterMoveResult(retreatDirection, moved);
|
||||||
MarkUsed(BotAction.Hit);
|
if (moved)
|
||||||
return response.Executed;
|
{
|
||||||
});
|
ApplyMovement(retreatDirection, 1);
|
||||||
}
|
_escapeDirection = retreatDirection;
|
||||||
|
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
|
||||||
|
}
|
||||||
|
|
||||||
var bestSight = _lastPeek
|
return response.Executed;
|
||||||
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0)
|
});
|
||||||
.OrderBy(x => x.Value.SightedPlayerDistance ?? int.MaxValue)
|
}
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (bestSight.Value is not null && Ready(BotAction.Shoot))
|
if (immediateDir.HasValue && Ready(BotAction.Hit))
|
||||||
{
|
{
|
||||||
var dir = bestSight.Key;
|
var dir = immediateDir.Value;
|
||||||
var dist = bestSight.Value.SightedPlayerDistance ?? 99;
|
return new BotDecision(
|
||||||
if (!underPressure || dist >= 2)
|
"hit-last-stand",
|
||||||
{
|
$"Adjacent enemy at {dir}; aggressive strike.",
|
||||||
return new BotDecision(
|
async ct =>
|
||||||
"shoot",
|
{
|
||||||
$"Enemy in line of sight to {dir}; ranged hit before moving.",
|
var response = await _client.HitAsync(_playerToken, (int)dir, ct);
|
||||||
async ct =>
|
MarkUsed(BotAction.Hit);
|
||||||
{
|
return response.Executed;
|
||||||
var response = await _client.ShootAsync(_playerToken, (int)dir, ct);
|
});
|
||||||
MarkUsed(BotAction.Shoot);
|
}
|
||||||
return response.Executed;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var moveDirection = GetBestMoveDirection(chase: !underPressure);
|
var bestSight = _lastPeek
|
||||||
if (Ready(BotAction.Move))
|
.Where(x => x.Value.Executed && x.Value.PlayersInSight > 0)
|
||||||
{
|
.OrderBy(x => x.Value.SightedPlayerDistance ?? int.MaxValue)
|
||||||
var reason = underPressure
|
.FirstOrDefault();
|
||||||
? $"Pressure high; reposition toward safer lane -> {moveDirection}."
|
|
||||||
: $"Controlled hunt path -> {moveDirection}.";
|
|
||||||
|
|
||||||
return new BotDecision(
|
// More aggressive shooting
|
||||||
"move",
|
if (bestSight.Value is not null && Ready(BotAction.Shoot))
|
||||||
reason,
|
{
|
||||||
async ct =>
|
var dir = bestSight.Key;
|
||||||
{
|
var dist = bestSight.Value.SightedPlayerDistance ?? 99;
|
||||||
var response = await _client.MoveAsync(_playerToken, (int)moveDirection, ct);
|
return new BotDecision(
|
||||||
MarkUsed(BotAction.Move);
|
"shoot",
|
||||||
var moved = response.Executed && response.Move == true;
|
$"Enemy at {dir} ({dist} dist); ranged kill.",
|
||||||
RegisterMoveResult(moveDirection, moved);
|
async ct =>
|
||||||
if (moved)
|
{
|
||||||
{
|
var response = await _client.ShootAsync(_playerToken, (int)dir, ct);
|
||||||
ApplyMovement(moveDirection, 1);
|
MarkUsed(BotAction.Shoot);
|
||||||
if (underPressure)
|
return response.Executed;
|
||||||
{
|
});
|
||||||
_escapeDirection = moveDirection;
|
}
|
||||||
_escapeLockTicks = Math.Max(_escapeLockTicks, EscapeLockTicks(profile));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Executed;
|
var moveDirection = GetBestMoveDirection(chase: true);
|
||||||
});
|
if (Ready(BotAction.Move))
|
||||||
}
|
{
|
||||||
|
return new BotDecision(
|
||||||
|
"move",
|
||||||
|
$"Aggressive hunt -> {moveDirection}.",
|
||||||
|
async ct =>
|
||||||
|
{
|
||||||
|
var response = await _client.MoveAsync(_playerToken, (int)moveDirection, ct);
|
||||||
|
MarkUsed(BotAction.Move);
|
||||||
|
var moved = response.Executed && response.Move == true;
|
||||||
|
RegisterMoveResult(moveDirection, moved);
|
||||||
|
if (moved)
|
||||||
|
{
|
||||||
|
ApplyMovement(moveDirection, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return response.Executed;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private Direction GetBestMoveDirection(bool chase)
|
return null;
|
||||||
{
|
}
|
||||||
if (!chase && _escapeLockTicks > 0)
|
|
||||||
{
|
|
||||||
if (!_blockedDirectionTicks.TryGetValue(_escapeDirection, out var blocked) || blocked <= 0)
|
|
||||||
{
|
|
||||||
return _escapeDirection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var scored = new Dictionary<Direction, double>
|
private Direction GetBestMoveDirection(bool chase)
|
||||||
{
|
{
|
||||||
[Direction.North] = RadarScore(Direction.North),
|
if (!chase && _escapeLockTicks > 0)
|
||||||
[Direction.East] = RadarScore(Direction.East),
|
{
|
||||||
[Direction.South] = RadarScore(Direction.South),
|
if (!_blockedDirectionTicks.TryGetValue(_escapeDirection, out var blocked) || blocked <= 0)
|
||||||
[Direction.West] = RadarScore(Direction.West),
|
{
|
||||||
};
|
return _escapeDirection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var dir in scored.Keys.ToArray())
|
var scored = new Dictionary<Direction, double>
|
||||||
{
|
{
|
||||||
var score = 0.0;
|
[Direction.North] = RadarScore(Direction.North),
|
||||||
score += chase ? scored[dir] * 1.35 : -scored[dir] * 1.0;
|
[Direction.East] = RadarScore(Direction.East),
|
||||||
|
[Direction.South] = RadarScore(Direction.South),
|
||||||
|
[Direction.West] = RadarScore(Direction.West),
|
||||||
|
};
|
||||||
|
|
||||||
if (_lastPeek.TryGetValue(dir, out var peek) && peek.Executed)
|
foreach (var dir in scored.Keys.ToArray())
|
||||||
{
|
{
|
||||||
if (peek.PlayersInSight > 0)
|
var score = 0.0;
|
||||||
{
|
// Always chase aggressively - ignore radar safety
|
||||||
var dist = Math.Max(1, peek.SightedPlayerDistance ?? 6);
|
score += scored[dir] * 0.5;
|
||||||
score += chase
|
|
||||||
? 7.0 / dist + peek.PlayersInSight * 0.8
|
|
||||||
: -10.0 / dist - peek.PlayersInSight * 0.7;
|
|
||||||
}
|
|
||||||
else if (!chase)
|
|
||||||
{
|
|
||||||
score += 0.9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_nearestEnemy.HasValue)
|
if (_lastPeek.TryGetValue(dir, out var peek) && peek.Executed)
|
||||||
{
|
{
|
||||||
var targetDir = DirectionFromVector(_nearestEnemy.Value.X, _nearestEnemy.Value.Y);
|
if (peek.PlayersInSight > 0)
|
||||||
var awayDir = Opposite(targetDir);
|
{
|
||||||
if (chase && dir == targetDir)
|
var dist = Math.Max(1, peek.SightedPlayerDistance ?? 6);
|
||||||
{
|
// Aggressive scoring: high bonus for chasing visible enemies
|
||||||
score += 4.0;
|
score += 15.0 / dist + peek.PlayersInSight * 3.0;
|
||||||
}
|
}
|
||||||
else if (!chase && dir == awayDir)
|
}
|
||||||
{
|
|
||||||
score += 4.5;
|
|
||||||
}
|
|
||||||
else if (!chase && dir == targetDir)
|
|
||||||
{
|
|
||||||
score -= 3.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var visitPenalty = VisitHeatFor(dir);
|
if (_nearestEnemy.HasValue)
|
||||||
var deathPenalty = DeathHeatFor(dir);
|
{
|
||||||
|
var targetDir = DirectionFromVector(_nearestEnemy.Value.X, _nearestEnemy.Value.Y);
|
||||||
|
// Always move toward nearest enemy
|
||||||
|
if (dir == targetDir)
|
||||||
|
{
|
||||||
|
score += 12.0;
|
||||||
|
}
|
||||||
|
else if (dir == Opposite(targetDir))
|
||||||
|
{
|
||||||
|
score -= 8.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_currentLevelProfile == LevelProfile.BiggerMap)
|
// Reduce penalties for visiting/death zones - we're aggressive
|
||||||
{
|
var visitPenalty = VisitHeatFor(dir);
|
||||||
score -= visitPenalty * 1.4;
|
var deathPenalty = DeathHeatFor(dir);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
score -= visitPenalty * 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
score -= deathPenalty * 1.6;
|
score -= visitPenalty * 0.2;
|
||||||
|
score -= deathPenalty * 0.3;
|
||||||
|
|
||||||
if (_survivalTicks > 0 && _nearestEnemy.HasValue)
|
if (_escapeLockTicks > 0)
|
||||||
{
|
{
|
||||||
var safest = Opposite(DirectionFromVector(_nearestEnemy.Value.X, _nearestEnemy.Value.Y));
|
if (dir == _escapeDirection)
|
||||||
if (dir == safest)
|
{
|
||||||
{
|
score += 2.0;
|
||||||
score += 2.8;
|
}
|
||||||
}
|
else if (dir == Opposite(_escapeDirection))
|
||||||
}
|
{
|
||||||
|
score -= 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_escapeLockTicks > 0)
|
if (_blockedDirectionTicks.TryGetValue(dir, out var blockedTicks) && blockedTicks > 0)
|
||||||
{
|
{
|
||||||
if (dir == _escapeDirection)
|
score -= 3.0 + blockedTicks * 0.2;
|
||||||
{
|
}
|
||||||
score += 4.5;
|
|
||||||
}
|
|
||||||
else if (dir == Opposite(_escapeDirection))
|
|
||||||
{
|
|
||||||
score -= 4.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_blockedDirectionTicks.TryGetValue(dir, out var blockedTicks) && blockedTicks > 0)
|
if (dir == Opposite(_lastMoveDirection))
|
||||||
{
|
{
|
||||||
score -= 5.0 + blockedTicks * 0.4;
|
score -= 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir == Opposite(_lastMoveDirection))
|
score += _random.NextDouble() * 0.5;
|
||||||
{
|
scored[dir] = score;
|
||||||
score -= 0.6;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
score += _survivalTicks > 0 ? _random.NextDouble() * 0.2 : _random.NextDouble() * 0.7;
|
return scored.OrderByDescending(x => x.Value).First().Key;
|
||||||
scored[dir] = score;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return scored.OrderByDescending(x => x.Value).First().Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyRadarHeat()
|
private void ApplyRadarHeat()
|
||||||
{
|
{
|
||||||
@@ -864,77 +855,77 @@ public partial class MainWindow : Window
|
|||||||
return LevelProfile.Unknown;
|
return LevelProfile.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double PressureHpThreshold(LevelProfile profile) => profile switch
|
private double PressureHpThreshold(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.BiggerMap => 0.66,
|
LevelProfile.BiggerMap => 0.15,
|
||||||
LevelProfile.MoreBots => 0.62,
|
LevelProfile.MoreBots => 0.12,
|
||||||
LevelProfile.NewBots => 0.68,
|
LevelProfile.NewBots => 0.18,
|
||||||
LevelProfile.Default => 0.58,
|
LevelProfile.Default => 0.10,
|
||||||
_ => 0.60,
|
_ => 0.15,
|
||||||
};
|
};
|
||||||
|
|
||||||
private int PressureThreatThreshold(LevelProfile profile) => profile switch
|
private int PressureThreatThreshold(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.BiggerMap => 2,
|
LevelProfile.BiggerMap => 5,
|
||||||
LevelProfile.MoreBots => 2,
|
LevelProfile.MoreBots => 6,
|
||||||
LevelProfile.NewBots => 2,
|
LevelProfile.NewBots => 5,
|
||||||
LevelProfile.Default => 2,
|
LevelProfile.Default => 6,
|
||||||
_ => 2,
|
_ => 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
private int SpecialThreatThreshold(LevelProfile profile) => profile switch
|
private int SpecialThreatThreshold(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.MoreBots => 4,
|
LevelProfile.MoreBots => 2,
|
||||||
LevelProfile.NewBots => 3,
|
LevelProfile.NewBots => 1,
|
||||||
LevelProfile.BiggerMap => 2,
|
LevelProfile.BiggerMap => 1,
|
||||||
LevelProfile.Default => 2,
|
LevelProfile.Default => 1,
|
||||||
_ => 2,
|
_ => 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
private double SpecialHpFloor(LevelProfile profile) => profile switch
|
private double SpecialHpFloor(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.MoreBots => 0.78,
|
LevelProfile.MoreBots => 0.20,
|
||||||
LevelProfile.NewBots => 0.55,
|
LevelProfile.NewBots => 0.15,
|
||||||
LevelProfile.BiggerMap => 0.42,
|
LevelProfile.BiggerMap => 0.10,
|
||||||
LevelProfile.Default => 0.35,
|
LevelProfile.Default => 0.05,
|
||||||
_ => 0.40,
|
_ => 0.10,
|
||||||
};
|
};
|
||||||
|
|
||||||
private double DashHpThreshold(LevelProfile profile) => profile switch
|
private double DashHpThreshold(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.BiggerMap => 0.50,
|
LevelProfile.BiggerMap => 0.08,
|
||||||
LevelProfile.NewBots => 0.58,
|
LevelProfile.NewBots => 0.12,
|
||||||
LevelProfile.MoreBots => 0.40,
|
LevelProfile.MoreBots => 0.10,
|
||||||
LevelProfile.Default => 0.30,
|
LevelProfile.Default => 0.05,
|
||||||
_ => 0.45,
|
_ => 0.10,
|
||||||
};
|
};
|
||||||
|
|
||||||
private int EscapeLockTicks(LevelProfile profile) => profile switch
|
private int EscapeLockTicks(LevelProfile profile) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.BiggerMap => 8,
|
LevelProfile.BiggerMap => 2,
|
||||||
LevelProfile.NewBots => 9,
|
LevelProfile.NewBots => 2,
|
||||||
LevelProfile.MoreBots => 6,
|
LevelProfile.MoreBots => 2,
|
||||||
LevelProfile.Default => 5,
|
LevelProfile.Default => 2,
|
||||||
_ => 6,
|
_ => 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
private bool ShouldUseImmediateHit(LevelProfile profile, double hpRatio, int closeThreats, bool underPressure) => profile switch
|
private bool ShouldUseImmediateHit(LevelProfile profile, double hpRatio, int closeThreats, bool underPressure) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.Default => hpRatio >= 0.22 && closeThreats <= 2,
|
LevelProfile.Default => hpRatio >= 0.05,
|
||||||
LevelProfile.BiggerMap => hpRatio >= 0.25 && closeThreats <= 2,
|
LevelProfile.BiggerMap => hpRatio >= 0.05,
|
||||||
LevelProfile.MoreBots => hpRatio >= 0.35 && closeThreats <= 3,
|
LevelProfile.MoreBots => hpRatio >= 0.05,
|
||||||
LevelProfile.NewBots => !underPressure && hpRatio >= 0.50,
|
LevelProfile.NewBots => hpRatio >= 0.05,
|
||||||
_ => hpRatio >= 0.30 && closeThreats <= 2,
|
_ => hpRatio >= 0.05,
|
||||||
};
|
};
|
||||||
|
|
||||||
private bool ShouldRetreatOnImmediate(LevelProfile profile, double hpRatio, int closeThreats) => profile switch
|
private bool ShouldRetreatOnImmediate(LevelProfile profile, double hpRatio, int closeThreats) => profile switch
|
||||||
{
|
{
|
||||||
LevelProfile.Default => hpRatio < 0.22 || closeThreats >= 3,
|
LevelProfile.Default => hpRatio < 0.02,
|
||||||
LevelProfile.BiggerMap => hpRatio < 0.30 || closeThreats >= 3,
|
LevelProfile.BiggerMap => hpRatio < 0.02,
|
||||||
LevelProfile.MoreBots => hpRatio < 0.32 || closeThreats >= 3,
|
LevelProfile.MoreBots => hpRatio < 0.02,
|
||||||
LevelProfile.NewBots => hpRatio < 0.68 || closeThreats >= 2,
|
LevelProfile.NewBots => hpRatio < 0.02,
|
||||||
_ => hpRatio < 0.30 || closeThreats >= 3,
|
_ => hpRatio < 0.02,
|
||||||
};
|
};
|
||||||
|
|
||||||
private void MarkVisit(int x, int y, double amount)
|
private void MarkVisit(int x, int y, double amount)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user