updating ignore

This commit is contained in:
hz
2026-05-18 14:54:37 -05:00
parent afeb9cf625
commit 32b953aa61
62 changed files with 295 additions and 2313 deletions
@@ -173,6 +173,21 @@ public class LocationService
var existingLocations = await GetRangeAsync(minQ, maxQ, minR, maxR);
var existingByCoordinate = existingLocations.ToDictionary(x => (x.Q, x.R), x => x);
var missingCoordinates = visibleCoordinates
.Where(coordinate => !existingByCoordinate.ContainsKey(coordinate))
.OrderBy(coordinate => HexDistance(0, 0, coordinate.q, coordinate.r))
.ThenBy(coordinate => coordinate.q)
.ThenBy(coordinate => coordinate.r)
.ToList();
if (missingCoordinates.Count > 0)
{
var generatedLocations = await GenerateVisibleLocationsAsync(missingCoordinates, existingByCoordinate);
foreach (var generated in generatedLocations)
{
existingByCoordinate[(generated.Q, generated.R)] = generated;
}
}
return visibleCoordinates
.OrderBy(x => x.q)
@@ -180,7 +195,7 @@ public class LocationService
.Select(coordinate =>
existingByCoordinate.TryGetValue(coordinate, out var existing)
? LocationResponse.FromLocation(existing)
: LocationResponse.FromCoordinate(coordinate.q, coordinate.r))
: throw new InvalidOperationException($"Visible location {coordinate.q},{coordinate.r} was not generated."))
.ToList();
}
@@ -192,9 +207,17 @@ public class LocationService
}
var existing = await GetAsync(q, r);
return existing is null
? LocationResponse.FromCoordinate(q, r)
: LocationResponse.FromLocation(existing);
if (existing is not null)
{
return LocationResponse.FromLocation(existing);
}
var nearbyLocations = await GetRangeAsync(q - 1, q + 1, r - 1, r + 1);
var nearbyByCoordinate = nearbyLocations.ToDictionary(x => (x.Q, x.R), x => x);
var generated = await GenerateVisibleLocationsAsync(
new List<(int q, int r)> { (q, r) },
nearbyByCoordinate);
return generated.Count == 0 ? null : LocationResponse.FromLocation(generated[0]);
}
public async Task<bool> CanSeeAsync(string username, int q, int r)
@@ -242,6 +265,120 @@ public class LocationService
}
}
private async Task<List<Location>> GenerateVisibleLocationsAsync(
List<(int q, int r)> missingCoordinates,
Dictionary<(int Q, int R), Location> existingByCoordinate)
{
var generated = new List<Location>();
var now = DateTime.UtcNow;
foreach (var coordinate in missingCoordinates)
{
var terrain = GenerateTerrain(coordinate.q, coordinate.r, existingByCoordinate);
var location = new Location
{
Q = coordinate.q,
R = coordinate.r,
Terrain = terrain,
Kind = "Open",
Level = 1,
CreatedAtUtc = now,
UpdatedAtUtc = now
};
try
{
await _locations.InsertOneAsync(location);
generated.Add(location);
existingByCoordinate[(location.Q, location.R)] = location;
}
catch (MongoWriteException)
{
var existing = await GetAsync(coordinate.q, coordinate.r);
if (existing is not null)
{
generated.Add(existing);
existingByCoordinate[(existing.Q, existing.R)] = existing;
}
}
}
return generated;
}
private static string GenerateTerrain(
int q,
int r,
Dictionary<(int Q, int R), Location> existingByCoordinate)
{
var neighborTerrains = NeighborCoordinates(q, r)
.Select(coordinate => existingByCoordinate.TryGetValue(coordinate, out var location) ? location.Terrain : "")
.Where(terrain => !string.IsNullOrWhiteSpace(terrain) && terrain != "Command")
.ToList();
var weights = new Dictionary<string, int>
{
["Field"] = 48,
["Forest"] = 24,
["Highland"] = 16,
["Ore"] = 12
};
foreach (var terrain in neighborTerrains)
{
if (!weights.ContainsKey(terrain))
{
continue;
}
weights[terrain] += terrain switch
{
"Forest" => 18,
"Highland" => 14,
"Ore" => 8,
_ => 10
};
}
var hash = StableCoordinateHash(q, r);
var totalWeight = weights.Values.Sum();
var roll = hash % totalWeight;
foreach (var option in weights)
{
if (roll < option.Value)
{
return option.Key;
}
roll -= option.Value;
}
return "Field";
}
private static IEnumerable<(int Q, int R)> NeighborCoordinates(int q, int r)
{
yield return (q + 1, r);
yield return (q + 1, r - 1);
yield return (q, r - 1);
yield return (q - 1, r);
yield return (q - 1, r + 1);
yield return (q, r + 1);
}
private static int StableCoordinateHash(int q, int r)
{
unchecked
{
var hash = 17;
hash = hash * 31 + q;
hash = hash * 31 + r;
hash = hash * 31 + 7919;
return Math.Abs(hash);
}
}
private IEnumerable<(int q, int r)> HomeCandidates(string username)
{
var preferredDirection = Math.Abs(username.GetHashCode()) % 6;