updating ignore
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user