Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/beardgame/td into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
paulcscharf committed Dec 5, 2023
2 parents b369926 + 339c9a8 commit ebf266d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 25 deletions.
1 change: 1 addition & 0 deletions TD.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,5 @@ namespace $NAMESPACE$
<s:Boolean x:Key="/Default/UserDictionary/Words/=Targetable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=targeter/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Teleport/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tilemap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=veterancy/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Bearded.TD.Game.Generation.Semantic.Features;
using Bearded.TD.Game.Generation.Semantic.Fitness;
Expand All @@ -10,15 +11,14 @@

namespace Bearded.TD.Game.Generation.Semantic.Logical;

using Tilemap = LogicalTilemap;
using FF = SimpleFitnessFunction<LogicalTilemap>;

static class LogicalTilemapFitness
{
public static FF AcuteAnglesCount { get; } = new AcuteAngles();
public static FF ConnectedComponentsCount { get; } = new ConnectedComponents();
public static FF DisconnectedCrevices { get; } = new ConnectedCrevices();
public static FF ConnectedTrianglesCount { get; } = new ConnectedTriangles();
public static FF CriticalConnectionCount { get; } = new CriticalConnections();
public static FF BiomeComponentCount { get; } = new DisconnectedBiomes();

public static FF NodeBehaviorFitness { get; } = new NodeBehavior();
Expand All @@ -27,10 +27,10 @@ private sealed class NodeBehavior : SimpleFitnessFunction<LogicalTilemap>
{
public override string Name => "Node Behaviour";

protected override double CalculateFitness(Tilemap tilemap)
protected override double CalculateFitness(LogicalTilemap tilemap)
{
return (
from tile in Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius)
from tile in Tilemap.EnumerateTilemapWith(tilemap.Radius)
let node = tilemap[tile]
where node.Blueprint != null
select node.Blueprint!.Behaviors.Sum(b => b.GetFitnessPenalty(tilemap, tile))
Expand Down Expand Up @@ -63,12 +63,12 @@ public ConnectionDegreeHistogram(IEnumerable<double> idealHistogram)
targetHistogram = builder.MoveToImmutable();
}

protected override double CalculateFitness(Tilemap tilemap)
protected override double CalculateFitness(LogicalTilemap tilemap)
{
var actualHistogram = new int[7];
var tileCount = 0;

foreach (var tile in Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius)
foreach (var tile in Tilemap.EnumerateTilemapWith(tilemap.Radius)
.Select(t => tilemap[t]).Where(n => n.Blueprint != null))
{
var connections = tile.ConnectedTo.Enumerate().Count();
Expand All @@ -88,11 +88,11 @@ private sealed class ConnectedTriangles : FF
{
public override string Name => "Connected Triangles";

protected override double CalculateFitness(Tilemap tilemap)
protected override double CalculateFitness(LogicalTilemap tilemap)
{
var count = 0;

foreach (var (tile, node) in Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius)
foreach (var (tile, node) in Tilemap.EnumerateTilemapWith(tilemap.Radius)
.Select(t => (t, tilemap[t])))
{
var connected = node.ConnectedTo;
Expand All @@ -106,30 +106,96 @@ protected override double CalculateFitness(Tilemap tilemap)
}
}

private sealed class AcuteAngles : FF
private sealed class CriticalConnections : FF
{
public override string Name => "Acute Angles";
private static readonly ImmutableHashSet<Direction> rightFacingDirections =
ImmutableHashSet.Create(Direction.Right, Direction.UpRight, Direction.DownRight);

public override string Name => "Critical Connections";

protected override double CalculateFitness(Tilemap tilemap)
protected override double CalculateFitness(LogicalTilemap tilemap)
{
return Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius)
.Select(t => tilemap[t])
.Select(node => node.ConnectedTo)
.Sum(connected => Extensions.Directions.Count(direction
=> connected.Includes(direction)
&& connected.Includes(direction.Next())));
var edges = Tilemap.EnumerateTilemapWith(tilemap.Radius)
.SelectMany(
t => tilemap[t].ConnectedTo.Enumerate()
.Where(rightFacingDirections.Contains)
.Select(dir => t.Edge(dir)));

var penalty = 0;

foreach (var (from, to) in edges.Select(e => e.AdjacentTiles))
{
if (isConnectedIndirectly(from, to, out var tilesConnectedToFrom))
{
continue;
}

penalty += 3;

if (!anyTagsPresent(tilesConnectedToFrom) ||
(!isConnectedIndirectly(to, from, out var tilesConnectedToTo)! &&
anyTagsPresent(tilesConnectedToTo)))
{
penalty += 15;
}
}

return penalty;

bool isConnectedIndirectly(
Tile start, Tile target, [NotNullWhen(false)] out ImmutableHashSet<Tile>? connectedTiles)
{
var q = new Queue<Tile>();
var seen = new HashSet<Tile>();

q.Enqueue(start);
seen.Add(start);

while (q.TryDequeue(out var currTile))
{
var neighborTiles = tilemap[currTile].ConnectedTo.Enumerate().Select(currTile.Neighbor);
foreach (var neighborTile in neighborTiles)
{
if (neighborTile == target)
{
// Don't explore tiles across from our direct connection.
if (currTile == start)
{
continue;
}

connectedTiles = default;
return true;
}

if (seen.Contains(neighborTile))
{
continue;
}

q.Enqueue(neighborTile);
seen.Add(neighborTile);
}
}

connectedTiles = ImmutableHashSet.CreateRange(seen);
return false;
}

bool anyTagsPresent(IEnumerable<Tile> tiles) =>
tiles.SelectMany(t => tilemap[t].Blueprint?.AllTags ?? Enumerable.Empty<NodeTag>()).Any();
}
}

private sealed class ConnectedComponents : FF
{
public override string Name => "Connected Components";

protected override double CalculateFitness(Tilemap tilemap)
protected override double CalculateFitness(LogicalTilemap tilemap)
{
var componentCount = 0;
var seen = new HashSet<Tile>();
foreach (var tile in Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius))
foreach (var tile in Tilemap.EnumerateTilemapWith(tilemap.Radius))
{
if (seen.Contains(tile) || tilemap[tile].Blueprint == null)
continue;
Expand Down Expand Up @@ -184,7 +250,7 @@ private IEnumerable<TileCorner> enumerateCorners(LogicalTilemap tilemap)
{
var virtualRadius = tilemap.Radius + 1;

foreach (var tile in Tiles.Tilemap.EnumerateTilemapWith(virtualRadius))
foreach (var tile in Tilemap.EnumerateTilemapWith(virtualRadius))
{
if (tile.Neighbor(Direction.UpRight).Radius > virtualRadius)
continue;
Expand All @@ -211,15 +277,15 @@ protected override double CalculateFitness(LogicalTilemap tilemap)
var componentCounts = componentCountsByBiome(tilemap);
var totalExcessComponents = componentCounts.Sum(kvp => kvp.Value - 1);

return totalExcessComponents * 200;
return totalExcessComponents * 50;
}

private static ImmutableDictionary<IBiome, int> componentCountsByBiome(LogicalTilemap tilemap)
{
var result = ImmutableDictionary.CreateBuilder<IBiome, int>();
var seen = new HashSet<Tile>();

foreach (var tile in Tiles.Tilemap.EnumerateTilemapWith(tilemap.Radius))
foreach (var tile in Tilemap.EnumerateTilemapWith(tilemap.Radius))
{
if (seen.Contains(tile) || tilemap[tile].Biome == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ private sealed record Settings(
LogicalTilemapFitness.ConnectedComponentsCount,
LogicalTilemapFitness.DisconnectedCrevices,
LogicalTilemapFitness.ConnectedTrianglesCount,
LogicalTilemapFitness.CriticalConnectionCount,
LogicalTilemapFitness.NodeBehaviorFitness,
LogicalTilemapFitness.ConnectionDegreeHistogramDifference(
new[] {0, /*1*/ 0.15, /*2*/ 0.2, /*3*/ 0.45, /*4*/ 0.2, 0, 0}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
behaviors: [
{ id: "core" },
{ id: "forceToCenter" },
{ id: "avoidTagProximity", parameters: { tagToAvoid: "spawner", steps: 2 } },
{ id: "avoidTagProximity", parameters: { tagToAvoid: "spawner", steps: 2, penaltyFactor: 300 } },
{ id: "avoidTagProximity", parameters: { tagToAvoid: "spawner", steps: 3, penaltyFactor: 100 } },

{ id: "setTiles", parameters: { type: "floor" } },

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
radius: 2,
explorable: false,
behaviors: [
{ id: "forceDeadEnd", parameters: { penaltyFactor: 200 } },
{ id: "avoidTagAdjacency", parameters: { tagToAvoid: "spawner", penaltyFactor: 50 } },
{ id: "forceDeadEnd", parameters: { penaltyFactor: 400 } },
{ id: "avoidTagAdjacency", parameters: { tagToAvoid: "spawner", penaltyFactor: 40 } },
{ id: "avoidTagProximity", parameters: { tagToAvoid: "spawner", steps: 2, penaltyFactor: 20 } },

{ id: "spawner" },
{ id: "setTiles", parameters: { type: "floor" } },
Expand Down

0 comments on commit ebf266d

Please sign in to comment.