From b4c47b0d793f85377880cb0d59a76a7a4fdd8299 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 16 Feb 2026 12:40:33 -0600 Subject: [PATCH 1/2] TileKnowledge: Optimize GetTilesVisibleToUnit This speeds up the time for the first 100 turns in observer mode from ~40 seconds to ~35 on my chromebook, and brings the printf benchmark from ~250 ms to ~40. --- C7Engine/C7GameData/AIData/TileKnowledge.cs | 33 +++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/C7Engine/C7GameData/AIData/TileKnowledge.cs b/C7Engine/C7GameData/AIData/TileKnowledge.cs index 392dd9081..6f1cb1120 100644 --- a/C7Engine/C7GameData/AIData/TileKnowledge.cs +++ b/C7Engine/C7GameData/AIData/TileKnowledge.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System; +using System.Diagnostics; namespace C7GameData { public class TileKnowledge { @@ -25,6 +26,21 @@ public void AddTilesToKnown(Tile unitLocation, bool recomputeActiveTiles = true) knownTiles.Add(unitLocation); borderTiles.Remove(unitLocation); + // Crude benchmarking tool for GetTilesVisibleToUnit, which can be + // a hot function when profiling. + // { + // Stopwatch stopwatch = new Stopwatch(); + // stopwatch.Start(); + + // for (int i = 0; i < 10000; ++i) { + // foreach (Tile t in GetTilesVisibleToUnit(unitLocation)) { + // knownTiles.Add(t); + // } + // } + + // System.Console.WriteLine($"10k runs took: {stopwatch.ElapsedMilliseconds} milliseconds"); + // } + foreach (Tile t in GetTilesVisibleToUnit(unitLocation)) { knownTiles.Add(t); borderTiles.Remove(t); @@ -44,18 +60,20 @@ public void AddTilesToKnown(Tile unitLocation, bool recomputeActiveTiles = true) } } - private HashSet GetTilesVisibleToUnit(Tile unitLocation) { - HashSet result = new(); + private List GetTilesVisibleToUnit(Tile unitLocation) { + // Space for current tile, 8 inner ring tiles, 12 outer ring tiles + List result = new(21); result.Add(unitLocation); + int unitHeight = unitLocation.overlayTerrainType.height; - foreach (TileDirection a in TileDirection.GetValues(typeof(TileDirection))) { - Tile innerRingNeighbor = unitLocation.neighbors[a]; + foreach (var (innerTileDirection, innerRingNeighbor) in unitLocation.neighbors) { if (innerRingNeighbor == Tile.NONE) { continue; } result.Add(innerRingNeighbor); + int innerHeight = innerRingNeighbor.overlayTerrainType.height; - foreach (TileDirection b in TileDirection.GetValues(typeof(TileDirection))) { + foreach (var (outerTileDirection, outerRingNeighbor) in innerRingNeighbor.neighbors) { // Say we have the following. We are standing on the XX tile // and need to figure out which tiles we can see. We can see // the hill directly to our SW, because we're next to it. @@ -71,16 +89,13 @@ private HashSet GetTilesVisibleToUnit(Tile unitLocation) { // < .. >< Hill >< gg > // < Hill >< gg > // < Hill > - if (((int)a) % 2 == 0 && ((int)b) % 2 == 0) { + if (((int)innerTileDirection) % 2 == 0 && ((int)outerTileDirection) % 2 == 0) { continue; } - Tile outerRingNeighbor = innerRingNeighbor.neighbors[b]; if (outerRingNeighbor == Tile.NONE) { continue; } - int unitHeight = unitLocation.overlayTerrainType.height; - int innerHeight = innerRingNeighbor.overlayTerrainType.height; int outerHeight = outerRingNeighbor.overlayTerrainType.height; // Tiles with a height of at least 2 are visible from 2 tiles From eb4f21e62df1f04ea6267a9984b8054aa5c21971 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 17 Feb 2026 21:44:48 -0600 Subject: [PATCH 2/2] address review comments --- C7Engine/C7GameData/AIData/TileKnowledge.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/C7Engine/C7GameData/AIData/TileKnowledge.cs b/C7Engine/C7GameData/AIData/TileKnowledge.cs index 6f1cb1120..47abc1c42 100644 --- a/C7Engine/C7GameData/AIData/TileKnowledge.cs +++ b/C7Engine/C7GameData/AIData/TileKnowledge.cs @@ -82,7 +82,8 @@ private List GetTilesVisibleToUnit(Tile unitLocation) { // tiles away. We can't see the hill that is SW+SW of us // because we are blocked. To implement this we need to // prevent 90 degree "turns", which we handle by ensuring - // the a+b combo is never a combination of two N/S/E/W dirs. + // the innerTileDirection+outerTileDirection combo is never + // a combination of two N/S/E/W dirs. // // < .. > // < .. >< XX >