public static Blueprint Generate(SpriteMemoryConfiguration configuration) { var spriteCount = configuration.SpriteCount ?? 16; var baseAddress = configuration.BaseAddress ?? 1; var rowSignals = ComputerSignals.OrderedSignals.Take(36).ToList(); var inputSignal = VirtualSignalNames.LetterOrDigit('0'); var entities = new List <Entity>(); var sprites = new Sprite[spriteCount]; var rowFilters = new RowFilter[rowSignals.Count + 1]; for (var index = 0; index < spriteCount; index++) { var reader = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 0.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Check), Constant = 0, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(reader); var drawSelector = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 2.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Dot), Constant = index + 1, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(drawSelector); var memory = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 4.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = 0, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(memory); var writer = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 6.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Check), Constant = 0, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(writer); var spriteSelector = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 8.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = index + 1, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(spriteSelector); sprites[index] = new Sprite { Reader = reader, DrawSelector = drawSelector, Memory = memory, Writer = writer, SpriteSelector = spriteSelector }; } for (var index = 0; index < rowFilters.Length; index++) { var renamer = new Entity { Name = index == 0 ? ItemNames.DeciderCombinator : ItemNames.ArithmeticCombinator, Position = new Position { X = 10.5, Y = index }, Direction = Direction.Left, Control_behavior = index == 0 ? new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(inputSignal), Constant = 1, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Info), Copy_count_from_input = false } } : new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(inputSignal), Second_constant = 1, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(rowSignals[index - 1]) } } }; entities.Add(renamer); var addressMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 12.5, Y = index }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Check), Constant = baseAddress + index, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(inputSignal), Copy_count_from_input = true } } }; entities.Add(addressMatcher); rowFilters[index] = new RowFilter { Renamer = renamer, AddressMatcher = addressMatcher }; } BlueprintUtil.PopulateEntityNumbers(entities); AddConnection(CircuitColor.Green, sprites[0].Writer, CircuitId.Input, rowFilters[0].Renamer, CircuitId.Output); for (var index = 0; index < spriteCount; index++) { var sprite = sprites[index]; AddConnection(CircuitColor.Green, sprite.Reader, CircuitId.Input, sprite.DrawSelector, CircuitId.Input); AddConnection(CircuitColor.Green, sprite.DrawSelector, CircuitId.Input, sprite.Memory, CircuitId.Output); AddConnection(CircuitColor.Green, sprite.Memory, CircuitId.Output, sprite.Memory, CircuitId.Input); AddConnection(CircuitColor.Red, sprite.Memory, CircuitId.Input, sprite.Writer, CircuitId.Output); AddConnection(CircuitColor.Red, sprite.Reader, CircuitId.Input, sprite.Writer, CircuitId.Input); AddConnection(CircuitColor.Red, sprite.Writer, CircuitId.Input, sprite.SpriteSelector, CircuitId.Output); if (index > 0) { var adjacentSprite = sprites[index - 1]; AddConnection(CircuitColor.Green, sprite.Reader, CircuitId.Output, adjacentSprite.Reader, CircuitId.Output); AddConnection(CircuitColor.Green, sprite.DrawSelector, CircuitId.Output, adjacentSprite.DrawSelector, CircuitId.Output); AddConnection(CircuitColor.Red, sprite.DrawSelector, CircuitId.Input, adjacentSprite.DrawSelector, CircuitId.Input); AddConnection(CircuitColor.Green, sprite.Writer, CircuitId.Input, adjacentSprite.Writer, CircuitId.Input); AddConnection(CircuitColor.Green, sprite.SpriteSelector, CircuitId.Input, adjacentSprite.SpriteSelector, CircuitId.Input); } } for (var index = 0; index < rowFilters.Length; index++) { var rowFilter = rowFilters[index]; AddConnection(CircuitColor.Green, rowFilter.Renamer, CircuitId.Input, rowFilter.AddressMatcher, CircuitId.Output); if (index > 0) { var adjacentRowFilter = rowFilters[index - 1]; AddConnection(CircuitColor.Green, rowFilter.Renamer, CircuitId.Output, adjacentRowFilter.Renamer, CircuitId.Output); AddConnection(CircuitColor.Green, rowFilter.AddressMatcher, CircuitId.Input, adjacentRowFilter.AddressMatcher, CircuitId.Input); AddConnection(CircuitColor.Red, rowFilter.AddressMatcher, CircuitId.Input, adjacentRowFilter.AddressMatcher, CircuitId.Input); } } return(new Blueprint { Label = $"Sprite Memory", Icons = new List <Icon> { Icon.Create(ItemNames.DeciderCombinator), Icon.Create(ItemNames.Lamp) }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
private static Filter CreateFilter(char signal, int count) { return(Filter.Create(VirtualSignalNames.LetterOrDigit(signal), count)); }
public static Blueprint Generate(VideoMemoryConfiguration configuration, List <bool[, ]> frames = null) { var width = configuration.Width ?? 32; var height = configuration.Height ?? 2; var baseAddress = configuration.BaseAddress ?? 1; var frameHeight = frames?.ElementAtOrDefault(0)?.GetLength(0) ?? 0; const int framesPerRow = 32; const int maxFilters = 20; var entities = new List <Entity>(); var memoryRows = new MemoryRow[height]; var metadata = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = 2, Y = 0 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Filters = new List <Filter> { Filter.Create(VirtualSignalNames.LetterOrDigit('Z'), frames?.Count ?? 0) } } }; entities.Add(metadata); for (var row = 0; row < height; row++) { var cellY = row * 9 - (row % 2 == 1 ? 1 : 0) + 2; var rowFrames = frames?.Skip(row * framesPerRow).Take(framesPerRow).ToList(); var addressMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 1, Y = cellY + 0.5 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = row + baseAddress, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(addressMatcher); var memoryCells = new MemoryCell[width]; for (var column = 0; column < width; column++) { var cellX = column + 2; var enabler = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = cellX, Y = cellY + 0.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Check), Constant = 0, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(enabler); var pixelFilters = Enumerable.Range(0, frameHeight) .Select(frameRow => { var pixel = rowFrames .Select((frame, frameOffset) => frame[frameRow, column] ? 1 << frameOffset : 0) .Sum(); return(Filter.Create(ScreenUtil.PixelSignals[frameRow], pixel)); }) .Where(pixelFilter => pixelFilter.Count != 0) .ToList(); var subCellCount = column % 18 >= 16 ? 6 : 7; var subCells = new Entity[subCellCount]; for (var subCellIndex = 0; subCellIndex < subCellCount; subCellIndex++) { var subCell = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = cellX, Y = subCellIndex < 6 || row % 2 == 1 ? cellY + subCellIndex + 2 : cellY - 1 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Filters = pixelFilters.Skip(subCellIndex * maxFilters).Take(maxFilters).ToList() } }; entities.Add(subCell); subCells[subCellIndex] = subCell; } memoryCells[column] = new MemoryCell { Enabler = enabler, SubCells = subCells }; } memoryRows[row] = new MemoryRow { AddressMatcher = addressMatcher, Cells = memoryCells }; } BlueprintUtil.PopulateEntityNumbers(entities); var substationWidth = (width + 9) / 18 + 1; var substationHeight = height / 2 + 1; entities.AddRange(CreateSubstations(substationWidth, substationHeight, 0, 0, entities.Count + 1)); for (var row = 0; row < height; row++) { var memoryRow = memoryRows[row]; AddConnection(CircuitColor.Red, memoryRow.AddressMatcher, CircuitId.Output, memoryRow.Cells[0].Enabler, CircuitId.Input); var adjacentRow = row - 1; if (adjacentRow >= 0) { var adjacentMemoryRow = memoryRows[adjacentRow]; AddConnection(CircuitColor.Green, memoryRow.AddressMatcher, CircuitId.Input, adjacentMemoryRow.AddressMatcher, CircuitId.Input); for (var column = 0; column < width; column++) { var memoryCell = memoryRow.Cells[column]; var adjacentMemoryCell = adjacentMemoryRow.Cells[column]; AddConnection(CircuitColor.Green, memoryCell.Enabler, CircuitId.Output, adjacentMemoryCell.Enabler, CircuitId.Output); } } for (var column = 0; column < width; column++) { var memoryCell = memoryRow.Cells[column]; AddConnection(CircuitColor.Green, memoryCell.SubCells[0], null, memoryCell.Enabler, CircuitId.Input); for (var subCellIndex = 1; subCellIndex < memoryCell.SubCells.Length; subCellIndex++) { var subCell = memoryCell.SubCells[subCellIndex]; var adjacentSubCell = memoryCell.SubCells[subCellIndex < 6 || row % 2 == 1 ? subCellIndex - 1 : 0]; AddConnection(CircuitColor.Green, subCell, null, adjacentSubCell, null); } var adjacentColumn = column - 1; if (adjacentColumn >= 0) { var adjacentMemoryCell = memoryRow.Cells[adjacentColumn]; AddConnection(CircuitColor.Red, memoryCell.Enabler, CircuitId.Input, adjacentMemoryCell.Enabler, CircuitId.Input); } } } return(new Blueprint { Label = $"Video ROM", Icons = new List <Icon> { Icon.Create(ItemNames.Lamp), Icon.Create(ItemNames.ConstantCombinator) }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
public static Blueprint Generate(RomConfiguration configuration, IList <MemoryCell> program = null, IList <MemoryCell> data = null) { var snapToGrid = configuration.SnapToGrid ?? false; var xOffset = configuration.X ?? 0; var yOffset = configuration.Y ?? 0; var width = configuration.Width ?? 16; var height = configuration.Height ?? 16; var cellSize = configuration.CellSize ?? 1; var programRows = configuration.ProgramRows ?? (program != null ? (program.Count - 1) / width + 1 : height / 2); var programName = configuration.ProgramName; var iconNames = configuration.IconNames ?? new List <string> { ItemNames.ElectronicCircuit }; if (program != null && program.Count > programRows * width) { Console.WriteLine($"Program too large to fit in ROM ({program.Count} > {programRows * width})"); programRows = (program.Count - 1) / width + 1; height = Math.Max(height, programRows + ((data?.Count ?? 0) - 1) / width + 1); } if (data != null && data.Count > (height - programRows) * width) { Console.WriteLine($"Data too large to fit in ROM ({data.Count} > {(height - programRows) * width})"); height = programRows + (data.Count - 1) / width + 1; } const int maxFilters = 20; var entitiesPerCell = cellSize + 1; var cellHeight = cellSize + 2; var blockHeightInCells = 64 * 3 / (cellSize + 2); var blockGapHeight = 8; var readerEntityOffset = cellSize; var gridWidth = width + ((width + 7) / 16 + 1) * 2; var gridHeight = height * cellHeight + (height - 1) / blockHeightInCells * blockGapHeight; var entities = new List <Entity>(); for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++) { var memoryCell = row < programRows ? program?.ElementAtOrDefault(row *width + column) ?? new MemoryCell { Address = -1, IsEnabled = false } : data?.ElementAtOrDefault((row - programRows) * width + column) ?? new MemoryCell { Address = -1, IsEnabled = false }; var memoryCellEntityNumber = (row * width + column) * entitiesPerCell + 1; var memoryCellX = column + (column / 16 + 1) * 2 + xOffset; var memoryCellY = gridHeight - (row + 1) * cellHeight - row / blockHeightInCells * blockGapHeight + yOffset; var adjacentMemoryCells = new List <int> { -1, 1 } .Where(offset => column + offset >= 0 && column + offset < width) .Select(offset => memoryCellEntityNumber + offset * entitiesPerCell) .Concat(new List <int> { -1, 1 } .Where(offset => row + offset >= 0 && row + offset < height && (row < programRows == row + offset < programRows) && column == 0) .Select(offset => memoryCellEntityNumber + offset * width * entitiesPerCell) ) .ToList(); // Memory sub-cells for (var subCell = 0; subCell < cellSize; subCell++) { entities.Add(new Entity { Entity_number = memoryCellEntityNumber + subCell, Name = ItemNames.ConstantCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY + cellSize - subCell - 1 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Filters = memoryCell.Filters?.Skip(subCell * maxFilters).Take(maxFilters).ToList(), Is_on = memoryCell.IsEnabled ? (bool?)null : false }, Connections = CreateConnections(new ConnectionPoint { Green = new List <ConnectionData> { // Connection to reader input or previous memory sub-cell new ConnectionData { Entity_id = memoryCellEntityNumber + (subCell == 0 ? readerEntityOffset : subCell - 1), Circuit_id = CircuitId.Input } } }) }); } // Memory cell reader entities.Add(new Entity { Entity_number = memoryCellEntityNumber + readerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY + cellSize + 0.5 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Info), Constant = memoryCell.Address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateVirtual(VirtualSignalNames.Everything), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent reader input (address line) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + readerEntityOffset, Circuit_id = CircuitId.Input }).ToList(), Green = new List <ConnectionData> { // Connection to memory cell new ConnectionData { Entity_id = memoryCellEntityNumber } } }, new ConnectionPoint { // Connection to adjacent reader output Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + readerEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); } } // Timestamp entities.Add(new Entity { Entity_number = entities.Count + 1, Name = ItemNames.ConstantCombinator, Position = new Position { X = 1 + xOffset, Y = gridHeight - 2 + yOffset }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Filters = new List <Filter> { Filter.Create(VirtualSignalNames.LetterOrDigit('0'), (int)(DateTime.Now.Ticks / 10000)) } } }); var substationWidth = (width + 7) / 16 + 1; var substationHeight = (gridHeight + 2) / 18 + 1; entities.AddRange(CreateSubstations(substationWidth, substationHeight, xOffset, gridHeight % 18 - 4 + yOffset, entities.Count + 1)); return(new Blueprint { Label = $"{width}x{height} ROM{(programName != null ? $": {programName}": "")}", Icons = iconNames.Select(name => Icon.Create(name)).ToList(), Entities = entities, SnapToGrid = snapToGrid ? new SnapToGrid { X = (ulong)gridWidth, Y = (ulong)gridHeight } : null, AbsoluteSnapping = snapToGrid ? true : null, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
public static SignalID CreateLetterOrDigit(char letterOrDigit) { return(CreateVirtual(VirtualSignalNames.LetterOrDigit(letterOrDigit))); }
public static Blueprint Generate(FontConfiguration configuration) { var fontImageFile = configuration.FontImage; var combinatorsPerRow = configuration.CombinatorsPerRow ?? 5; var useOneSignalPerRow = configuration.UseOneSignalPerRow ?? false; var inputSignal = configuration.InputSignal ?? VirtualSignalNames.Dot; var widthSignal = configuration.WidthSignal; var heightSignal = configuration.HeightSignal; var signals = configuration.Signals.Contains(',') ? configuration.Signals.Split(',').ToList() : configuration.Signals.Select(signal => VirtualSignalNames.LetterOrDigit(signal)).ToList(); const int maxFilters = 20; var font = FontUtil.ReadFont(fontImageFile); var characters = font.Characters; var entities = new List <Entity>(); var characterEntities = new List <(Entity Matcher, List <Entity> Glyph)>(); if (heightSignal != null) { characters.Add(new FontUtil.Character { CharacterCode = '\n', GlyphPixels = new bool[font.Height, 0] }); } var combinatorX = 0; for (var characterIndex = 0; characterIndex < characters.Count; characterIndex++) { var character = characters[characterIndex]; var glyphPixels = character.GlyphPixels; var height = glyphPixels.GetLength(0); var width = glyphPixels.GetLength(1); if (characterIndex % combinatorsPerRow == 0) { combinatorX = 0; } var glyphFilters = new List <Filter>(); if (widthSignal != null) { glyphFilters.Add(Filter.Create(widthSignal, width)); } if (heightSignal != null) { glyphFilters.Add(Filter.Create(heightSignal, height)); } for (int y = 0; y < height; y++) { if (useOneSignalPerRow) { var rowSignal = 0; for (int x = 0; x < width; x++) { if (glyphPixels[y, x]) { rowSignal |= 1 << x; } } glyphFilters.Add(Filter.Create(signals[y], rowSignal)); } else { for (int x = 0; x < width; x++) { if (glyphPixels[y, x]) { glyphFilters.Add(Filter.Create(signals[y * width + x])); } } } } var combinatorY = characterIndex / combinatorsPerRow; var matcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = (characterIndex % combinatorsPerRow - combinatorsPerRow) * 2 + 0.5, Y = combinatorY }, Direction = Direction.Left, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(inputSignal), Constant = character.CharacterCode, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Everything), Copy_count_from_input = true } } }; entities.Add(matcher); var glyph = new List <Entity>(); for (int index = 0; index < (glyphFilters.Count + maxFilters - 1) / maxFilters; index++) { var glyphPart = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = combinatorX++, Y = combinatorY }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Filters = glyphFilters.Skip(index * maxFilters).Take(maxFilters).ToList() } }; glyph.Add(glyphPart); entities.Add(glyphPart); } characterEntities.Add((matcher, glyph)); } BlueprintUtil.PopulateEntityNumbers(entities); for (int characterIndex = 0; characterIndex < characterEntities.Count; characterIndex++) { var(matcher, glyph) = characterEntities[characterIndex]; AddConnection(CircuitColor.Green, matcher, CircuitId.Input, glyph[0], null); // Connect to constant combinators holding glyphs var adjacentCharacterIndex = characterIndex - (characterIndex / combinatorsPerRow == 0 ? 1 : combinatorsPerRow); if (adjacentCharacterIndex >= 0) { var adjacentMatcher = characterEntities[adjacentCharacterIndex].Matcher; AddConnection(CircuitColor.Red, matcher, CircuitId.Input, adjacentMatcher, CircuitId.Input); // Connect inputs together AddConnection(CircuitColor.Green, matcher, CircuitId.Output, adjacentMatcher, CircuitId.Output); // Connect outputs together } // Connections between glyph parts for (int index = 1; index < glyph.Count; index++) { AddConnection(CircuitColor.Green, glyph[index], null, glyph[index - 1], null); } } return(new Blueprint { Label = $"{font.Width}x{font.Height} Font", Icons = new List <Icon> { Icon.Create(ItemNames.ConstantCombinator), Icon.Create(VirtualSignalNames.LetterOrDigit('A')), Icon.Create(VirtualSignalNames.LetterOrDigit('B')), Icon.Create(VirtualSignalNames.LetterOrDigit('C')) }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
public static Blueprint Generate(DemuxConfiguration configuration) { var signalCount = configuration.SignalCount ?? ComputerSignals.OrderedSignals.Count; var width = configuration.Width ?? 1; var addressSignal = configuration.AddressSignal ?? VirtualSignalNames.Dot; var outputSignal = configuration.OutputSignal ?? VirtualSignalNames.LetterOrDigit('A'); var entities = new List <Entity>(); var signalFilters = new SignalFilter[signalCount]; for (int index = 0; index < signalCount; index++) { var filterX = index % width * 4; var filterY = index / width; var addressChecker = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 0.5 + filterX, Y = filterY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(addressSignal), Constant = index + 1, Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Dot), Copy_count_from_input = false } } }; entities.Add(addressChecker); var signalRenamer = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 2.5 + filterX, Y = filterY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(ComputerSignals.OrderedSignals[index]), Second_signal = SignalID.Create(VirtualSignalNames.Dot), Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(outputSignal) } } }; entities.Add(signalRenamer); signalFilters[index] = new SignalFilter { AddressChecker = addressChecker, SignalRenamer = signalRenamer }; } BlueprintUtil.PopulateEntityNumbers(entities); for (var index = 0; index < signalCount; index++) { var signalFilter = signalFilters[index]; AddConnection(CircuitColor.Red, signalFilter.AddressChecker, CircuitId.Output, signalFilter.SignalRenamer, CircuitId.Input); if (index > 0) { var adjacentSignalFilterIndex = index / width == 0 ? index - 1 : index - width; var adjacentSignalFilter = signalFilters[adjacentSignalFilterIndex]; AddConnection(CircuitColor.Red, signalFilter.AddressChecker, CircuitId.Input, adjacentSignalFilter.AddressChecker, CircuitId.Input); AddConnection(CircuitColor.Green, signalFilter.SignalRenamer, CircuitId.Input, adjacentSignalFilter.SignalRenamer, CircuitId.Input); AddConnection(CircuitColor.Red, signalFilter.SignalRenamer, CircuitId.Output, adjacentSignalFilter.SignalRenamer, CircuitId.Output); } } return(new Blueprint { Label = $"Demultiplexer", Icons = new List <Icon> { Icon.Create(ItemNames.DeciderCombinator), Icon.Create(ItemNames.ArithmeticCombinator) }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }