Updating movement

This commit is contained in:
hz
2026-05-20 19:11:35 -05:00
parent 84136ad534
commit 94f3b1e258
5 changed files with 414 additions and 89 deletions
@@ -288,7 +288,7 @@ public class LocationService
var location = await GetAsync(request.Q, request.R);
if (location is null ||
!string.Equals(location.OwnerUsername, username, StringComparison.OrdinalIgnoreCase) ||
string.IsNullOrWhiteSpace(location.BuildingType) ||
!CanAssignWorkerToBuilding(location.BuildingType) ||
location.BuildingStatus == "Building" ||
!string.IsNullOrWhiteSpace(location.WorkerUnitId))
{
@@ -314,7 +314,7 @@ public class LocationService
.Set(x => x.DestinationQ, request.Q)
.Set(x => x.DestinationR, request.R)
.Set(x => x.MovementStartedAtUtc, now)
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(Math.Max(1, HexDistance(unit.Q, unit.R, request.Q, request.R))))
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
.Set(x => x.UpdatedAtUtc, now));
if (claimed.ModifiedCount == 0)
{
@@ -535,23 +535,29 @@ public class LocationService
var destinationQ = worker.DestinationQ.Value;
var destinationR = worker.DestinationR.Value;
var currentQ = worker.Q;
var currentR = worker.R;
var nextTick = worker.MovementCompletesAtUtc!.Value;
while (nextTick <= now && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
if (HexDistance(worker.Q, worker.R, destinationQ, destinationR) > 1)
{
(currentQ, currentR) = NextStepToward(currentQ, currentR, destinationQ, destinationR);
nextTick = nextTick.AddMinutes(1);
}
var nextStep = await NextPeasantStepTowardAsync(username, worker.Q, worker.R, destinationQ, destinationR);
if (nextStep is null)
{
await _units.UpdateOneAsync(
x => x.Id == worker.Id,
Builders<UnitInstance>.Update
.Set(x => x.Status, "Idle")
.Unset(x => x.DestinationQ)
.Unset(x => x.DestinationR)
.Unset(x => x.MovementStartedAtUtc)
.Unset(x => x.MovementCompletesAtUtc)
.Set(x => x.UpdatedAtUtc, now));
continue;
}
if (HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
{
await _units.UpdateOneAsync(
x => x.Id == worker.Id,
Builders<UnitInstance>.Update
.Set(x => x.Q, currentQ)
.Set(x => x.R, currentR)
.Set(x => x.MovementCompletesAtUtc, nextTick)
.Set(x => x.Q, nextStep.Value.q)
.Set(x => x.R, nextStep.Value.r)
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
.Set(x => x.UpdatedAtUtc, now));
continue;
}
@@ -560,7 +566,7 @@ public class LocationService
x => x.OwnerUsername == username &&
x.Q == destinationQ &&
x.R == destinationR &&
!string.IsNullOrWhiteSpace(x.BuildingType) &&
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Farm") &&
x.BuildingStatus != "Building" &&
(x.WorkerUnitId == null || x.WorkerUnitId == ""),
Builders<Location>.Update
@@ -591,13 +597,63 @@ public class LocationService
}
}
private static (int q, int r) NextStepToward(int fromQ, int fromR, int toQ, int toR)
private async Task<(int q, int r)?> NextPeasantStepTowardAsync(string username, int fromQ, int fromR, int toQ, int toR)
{
return NeighborCoordinates(fromQ, fromR)
.OrderBy(x => HexDistance(x.Q, x.R, toQ, toR))
.ThenBy(x => x.Q)
.ThenBy(x => x.R)
.First();
var owned = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
var ownedCoordinates = owned.Select(x => (x.Q, x.R)).ToHashSet();
if (!ownedCoordinates.Contains((toQ, toR)))
{
return null;
}
var start = (fromQ, fromR);
var target = (toQ, toR);
var queue = new Queue<(int q, int r)>();
var previous = new Dictionary<(int q, int r), (int q, int r)>();
var visited = new HashSet<(int q, int r)> { start };
queue.Enqueue(start);
while (queue.Count > 0)
{
var current = queue.Dequeue();
if (current == target)
{
break;
}
foreach (var neighbor in NeighborCoordinates(current.q, current.r)
.Select(x => (x.Q, x.R))
.OrderBy(x => HexDistance(x.Q, x.R, toQ, toR))
.ThenBy(x => x.Q)
.ThenBy(x => x.R))
{
if (!ownedCoordinates.Contains(neighbor) || !visited.Add(neighbor))
{
continue;
}
previous[neighbor] = current;
queue.Enqueue(neighbor);
}
}
if (!visited.Contains(target))
{
return null;
}
var step = target;
while (previous.TryGetValue(step, out var before) && before != start)
{
step = before;
}
return step == start ? target : step;
}
private static bool CanAssignWorkerToBuilding(string? buildingType)
{
return buildingType == "LogCamp" || buildingType == "Mine" || buildingType == "Farm";
}
public async Task<bool> CanSeeAsync(string username, int q, int r)