static IFastImage Visualize(CellBoard board, bool showOnlyLargestArea, int scale = 1) { if (showOnlyLargestArea) { var(area, size) = ConnectedAreaAnalyzer .FindForegroundAreas(board.Dimensions, p => board[p] == CellType.Dead) .MaxBy(component => component.Area) ?.TrimExcess(1) ?? throw new InvalidOperationException("This can't happen"); return(GenericVisualizer.RenderBinary(size, isTrue: area.Contains, trueColor: SKColors.White, falseColor: SKColors.Black, scale: scale)); } else { return(GenericVisualizer.RenderBinary(board.Dimensions, isTrue: p => board[p] == CellType.Dead, trueColor: SKColors.White, falseColor: SKColors.Black, scale: scale)); } }
public static MapData Create(int seed, TextureQueue textureQueue) { GC.KeepAlive(textureQueue); // SHUT UP ABOUT UNUSED PARAMETER!! var random = new Random(seed); CellBoard geometryBoard = GenerateGeometryBoard(random); (ConnectedArea playableSpace, Size boardSize) = geometryBoard.TrimToLargestDeadConnectedArea(); var internalDistances = playableSpace.DetermineInteriorEdgeDistance(Neighborhood.Moore); var sideDefCache = new ModelSequence <SideDef, SideDef>(s => s); // Seems silly, but what should be abstracted about it? var vertexCache = new ModelSequence <LatticePoint, Vertex>(ConvertToVertex); var sectorCache = new ModelSequence <SectorDescription, Sector>(ConvertToSector); var lineCache = new ModelSequence <LineDescription, LineDef>(ld => ConvertToLineDef(ld, sectorCache, sideDefCache)); var edges = GetEdges(boardSize, internalDistances); DrawEdges(edges, vertexCache, lineCache); var playerLogicalSpot = FindPlayerSpot(geometryBoard); return(new MapData( NameSpace: "Doom", LineDefs: lineCache.GetDefinitions().ToImmutableArray(), SideDefs: sideDefCache.GetDefinitions().ToImmutableArray(), Vertices: vertexCache.GetDefinitions().ToImmutableArray(), Sectors: sectorCache.GetDefinitions().ToImmutableArray(), Things: ImmutableArray.Create( Actor.Player1Start.MakeThing( x: playerLogicalSpot.X * LogicalUnitSize + LogicalUnitSize / 2, y: playerLogicalSpot.Y * LogicalUnitSize + LogicalUnitSize / 2, angle: 90)))); }
void Initialize(CellBoard cellBoard) { Cells = TwoDimensionalArrayExtension.Create <CellView>(cellBoard.ActualCells.Size()); cellBoard.ActualCells.ForEach((point, cell) => { var cellView = new CellView { Point = point, DataContext = cell }; cellView.IndexChanged += OnCellViewIndexChanged; Cells.Set(point, cellView); }); }
void Awake() { //Ensureses that the cell manager has started if (instance == null) { instance = this; } else if (instance != this) { Destroy(gameObject); } cellB = GetComponent <CellBoard>();//Gets the cell board component }
static void Main(string[] args) { var grid = new CellBoard(10, 10); grid.Randomize(); ShowGrid(grid.CurrentCellState); while (Console.ReadLine() != "q") { grid.UpdateState(); ShowGrid(grid.CurrentCellState); } }
public void Setup() { var random = new Random(3); var board = new CellBoard(new Size(256, 256)) .Fill(random, probabilityAlive: 0.5) .MakeBorderAlive(thickness: 1) .GenerateStandardCave() .ScaleAndSmooth(times: 3) .TrimToLargestDeadArea(); _area = ConnectedAreaAnalyzer .FindForegroundAreas(board.Dimensions, p => board[p] == CellType.Dead) .MaxBy(a => a.Area); }
public void ScaleBoard() { var dir = OutputLocation.CreateDirectory("Cellular Automata Scaling"); foreach (var file in dir.GetFiles()) { file.Delete(); } var path = dir.FullName; void Save(CellBoard board, string name, int scale) { using var img = Visualize(board, false, scale); img.Save(Path.Combine(path, $"{name}.png")); } var random = new Random(0); var board = new CellBoard(new Size(128, 128)) .Fill(random, probabilityAlive: 0.5) .MakeBorderAlive(thickness: 1) .GenerateStandardCave(); Save(board, "1. board", 8); const int scalingIterations = 3; CellBoard last = board; foreach (var noise in new[] { 0, 0.05, 0.1, 0.15, 0.2 }) { CellBoard scaled = board; foreach (int scalingIteration in Enumerable.Range(1, scalingIterations)) { scaled = scaled.Quadruple().AddNoise(random, noise).RunGenerations(1); Save(scaled, $"{scalingIteration + 1}. board {1 << scalingIteration}x - noise {noise:F2}", 8 / (1 << scalingIteration)); last = scaled; } } }
public void RenderABunchOfOptions() { var dir = OutputLocation.CreateDirectory("Cellular Automata Trials"); foreach (var file in dir.GetFiles()) { file.Delete(); } var path = dir.FullName; var trials = (from seed in Enumerable.Range(0, 3) from size in new[] { 96, 128 } from probAlive in new[] { 0.48, 0.5, 0.52 } select(seed, size, probAlive)).ToArray(); Parallel.ForEach(trials, trial => { var random = new Random(trial.seed); var board = new CellBoard(new Size(trial.size, trial.size)) .Fill(random, probabilityAlive: trial.probAlive) .MakeBorderAlive(thickness: 1) .GenerateStandardCave() .TrimToLargestDeadArea() .ScaleAndSmooth() .ScaleAndSmooth(); using var img = Visualize(board, showOnlyLargestArea: false); img.Save(Path.Combine(path, $"Size {trial.size}" + $" - ProbAlive {trial.probAlive:F2}" + $" - Seed {trial.seed}" + $".png")); }); }
static IFastImage Visualize(CellBoard board, int scale = 1) => GenericVisualizer.RenderBinary(board.Dimensions, isTrue: p => board[p] == CellType.Dead, trueColor: SKColors.White, falseColor: SKColors.Black, scale: scale);
public static MapData Create(int seed, string texturePrefix, TextureQueue textureQueue) { var random = new Random(seed); var caveBoard = new CellBoard(new Size(128, 128)) .Fill(random, probabilityAlive: 0.5) .MakeBorderAlive(thickness: 3) .GenerateStandardCave(); var(caveArea, size) = ConnectedAreaAnalyzer .FindForegroundAreas(caveBoard.Dimensions, p => caveBoard[p] == CellType.Dead) .OrderByDescending(a => a.Area) .First() .TrimExcess(border: 1); var interior = caveArea.DetermineInteriorEdgeDistance(Neighborhood.VonNeumann); var alternateFloor = new CellBoard(new Size(size.Width + 1, size.Height + 1)) .Fill(random, probabilityAlive: 0.5) .RunGenerations(6); var alternateCeiling = new CellBoard(new Size(size.Width + 1, size.Height + 1)) .Fill(random, probabilityAlive: 0.5) .RunGenerations(6); var lightRange = new LightRange(DarkLevels: 15, LightLevels: 5); var lights = CaveThingPlacement.RandomlyPlaceLights( interior.Where(pair => pair.Value == 2).Select(pair => pair.Key).ToList(), random, lightRange, percentAreaToCover: 0.05, varyHeight: true) .ToArray(); var(floorLighting, ceilingLighting) = LightTracer.Trace(size, p => !caveArea.Contains(p), lightRange, lights); var(planeMap, sectors, tiles) = CreateGeometry( size, caveArea, alternateFloor, alternateCeiling, floorLighting, ceilingLighting, textureQueue, texturePrefix); var playerPosition = caveArea.First(); var things = lights.Select(light => new Thing( Type: light.Height == LightHeight.Ceiling ? "CeilingCrystal" : "FloorCrystal", X: light.Center.X + 0.5, Y: light.Center.Y + 0.5, Z: 0, Angle: 0, Ambush: false, Skill1: true, Skill2: true, Skill3: true, Skill4: true)).ToList(); things.Add(new Thing( Type: Actor.Player1Start.ClassName, X: playerPosition.X + 0.5, Y: playerPosition.Y + 0.5, Z: 0, Angle: 0, Ambush: false, Skill1: true, Skill2: true, Skill3: true, Skill4: true)); return(new MapData( NameSpace: "Wolf3D", TileSize: 64, Name: "Procedural Cave", Width: size.Width, Height: size.Height, Tiles: tiles, Sectors: sectors, Zones: ImmutableArray.Create(new Zone()), Planes: ImmutableArray.Create(new Plane(Depth: 64)), PlaneMaps: ImmutableArray.Create(planeMap), Things: things.ToImmutableArray(), Triggers: ImmutableArray <Trigger> .Empty)); }
static (ImmutableArray <MapSquare>, ImmutableArray <Sector>, ImmutableArray <Tile>) CreateGeometry( Size size, ConnectedArea cave, CellBoard alternateFloor, CellBoard alternateCeiling, LightMap floorLight, LightMap ceilingLight, TextureQueue textureQueue, string texturePrefix) { var planeMap = new Canvas(size); double minLight = 0.2; double darkStep = (1 - minLight) / ceilingLight.Range.DarkLevels; double maxLight = 1.1; double lightStep = (maxLight - 1) / ceilingLight.Range.LightLevels; double GetAlpha(int light) => light switch { 0 => 0, int pos when pos > 0 => pos * lightStep, int neg when neg < 0 => - neg * darkStep, _ => throw new InvalidOperationException("Impossible") }; string GetTextureName(Corners corners, int light, bool isEastWest = false) { string name = $"t{(int)corners:D2}{light:+#;-#;#}{(isEastWest ? "dark" : "")}"; var patches = ImmutableArray.CreateBuilder <Patch>(); if (light > 0) { patches.Add( new Patch( $"{texturePrefix}{(int)corners:D2}", 0, 0, Blend: new ColorBlend("FFFFFF", GetAlpha(light)))); } else if (light < 0) { patches.Add( new Patch( $"{texturePrefix}{(int)corners:D2}", 0, 0, Blend: new ColorBlend("000000", GetAlpha(light)))); } else { patches.Add( new Patch( $"{texturePrefix}{(int)corners:D2}", 0, 0)); } if (isEastWest) { patches.Add( new Patch( $"{texturePrefix}{(int)corners:D2}", 0, 0, Blend: new ColorBlend("000000"), Style: RenderStyle.Translucent, Alpha: 0.075)); } textureQueue.Add(new CompositeTexture(name, 256, 256, patches.ToImmutable(), XScale: 4, YScale: 4)); return(name); } Corners GetCorners(CellBoard board, Position pos) => Corner.CreateFromUpperLeft( upperLeft: pos, on: p => board[p] == CellType.Dead); Corners GetSideCorners(Position left, Position right) => Corner.Create( topLeft: alternateCeiling[left] == CellType.Dead, topRight: alternateCeiling[right] == CellType.Dead, bottomLeft: alternateFloor[left] == CellType.Dead, bottomRight: alternateFloor[right] == CellType.Dead ); int GetSideLight(Position p) => (ceilingLight[p] + floorLight[p]) / 2; var sectorSequence = new ModelSequence <SectorDescription, Sector>(description => new Sector( TextureCeiling: GetTextureName(description.Ceiling, description.CeilingLight), TextureFloor: GetTextureName(description.Floor, description.FloorLight))); var tileSequence = new ModelSequence <TileDescription, Tile>(description => new Tile( TextureEast: GetTextureName(description.EastCorners, description.EastLight, isEastWest: true), TextureNorth: GetTextureName(description.NorthCorners, description.NorthLight), TextureWest: GetTextureName(description.WestCorners, description.WestLight, isEastWest: true), TextureSouth: GetTextureName(description.SouthCorners, description.SouthLight), TextureOverhead: GetTextureName(description.FloorCorners, 0))); for (int y = 0; y < size.Height; y++) { for (int x = 0; x < size.Width; x++) { var pos = new Position(x, y); int tileId = -1; if (!cave.Contains(pos)) { tileId = tileSequence.GetIndex(new TileDescription( NorthCorners: GetSideCorners(left: pos + Offset.Right, right: pos), EastCorners: GetSideCorners(left: pos + Offset.DownAndRight, right: pos + Offset.Right), SouthCorners: GetSideCorners(left: pos + Offset.Down, right: pos + Offset.DownAndRight), WestCorners: GetSideCorners(left: pos, right: pos + Offset.Down), FloorCorners: GetCorners(alternateFloor, pos), NorthLight: GetSideLight(pos + Offset.Up), EastLight: GetSideLight(pos + Offset.Right), SouthLight: GetSideLight(pos + Offset.Down), WestLight: GetSideLight(pos + Offset.Left))); } int sectorId = sectorSequence.GetIndex(new SectorDescription( Floor: GetCorners(alternateFloor, pos), Ceiling: GetCorners(alternateCeiling, pos), FloorLight: floorLight[pos], CeilingLight: ceilingLight[pos])); planeMap.Set(x, y, tile: tileId, sector: sectorId, zone: 0); } } return( planeMap.ToPlaneMap(), sectorSequence.GetDefinitions().ToImmutableArray(), tileSequence.GetDefinitions().ToImmutableArray()); }
//script used upon awakening private void Awake() { cellB = GameManager.instance.GetComponent <CellBoard>(); //Sets an instance of the cell board cellMatrix = cellB.cellMatrix; //Declares a cell matrix to establish a position for each individual cell spriteRenderer = GetComponent <SpriteRenderer>(); //Sets a sprite renderer to create visuals }