/// <summary> /// 移除指定的全部信号接收器 /// </summary> /// <param name="nSignalID">N signal I.</param> public void RemoveAllHandler(SignalID nSignalID) { if (this.m_HandlerMap.ContainsKey(nSignalID)) { var mhc = this.m_HandlerMap[nSignalID]; mhc.Dispose(); this.m_HandlerMap.Remove(nSignalID); } }
/// <summary> /// 向所有注册的接收器分发指定信号 /// </summary> /// <param name="nSignalID">消息ID</param> /// <param name="oSender">消息发送者</param> /// <param name="oParam">消息参数</param> public void DispatchSignal(SignalID nSignalID, object oSender, object oParam = null) { if (!this.m_HandlerMap.ContainsKey(nSignalID)) { return; } var m = new _Signal() { ID = nSignalID, Sender = oSender, Param = oParam }; this.m_SignalQueue.Enqueue(m); }
/// <summary> /// 移除指定的信号接收器 /// </summary> /// <param name="nSignalID">消息ID</param> /// <param name="pCallback">添加时的回调</param> public void RemoveHandler(SignalID nSignalID, SignalCallback pCallback) { if (pCallback == null) { return; } if (this.m_HandlerMap.ContainsKey(nSignalID)) { var mhc = this.m_HandlerMap[nSignalID]; mhc.RemoveHandler(pCallback); if (mhc.Count == 0) { this.m_HandlerMap.Remove(nSignalID); } } }
/// <summary> /// 添加一个信号接收器 /// </summary> /// <param name="pMsgID">消息ID</param> /// <param name="pCallback">接受到消息的回调</param> public void AddHandler(SignalID nSignalID, SignalCallback pCallback) { if (pCallback == null) { return; } if (this.m_HandlerMap.ContainsKey(nSignalID)) { this.m_HandlerMap[nSignalID].AddHandler(pCallback); } else { var mhc = new _SignalHandlerCollection(); mhc.AddHandler(pCallback); this.m_HandlerMap.Add(nSignalID, mhc); } }
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 }); }
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 }); }
public static Blueprint Generate(RamConfiguration configuration) { var width = configuration.Width ?? 16; var height = configuration.Height ?? 16; var baseAddress = configuration.BaseAddress ?? 0; var signal = configuration.Signal ?? '0'; var includePower = configuration.IncludePower ?? true; const int entitiesPerCell = 3; const int cellHeight = 6; const int writerEntityOffset = -1; const int readerEntityOffset = 1; var gridWidth = width + (includePower ? ((width + 7) / 16 + 1) * 2 : 0); var gridHeight = height * cellHeight; var xOffset = -gridWidth / 2; var yOffset = -gridHeight / 2; var entities = new List <Entity>(); for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++) { var address = row * width + column + baseAddress + 1; var memoryCellEntityNumber = (row * width + column) * entitiesPerCell + 2; var memoryCellX = column + (includePower ? (column / 16 + 1) * 2 : 0) + xOffset; var memoryCellY = (height - row - 1) * cellHeight + 2.5 + 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 && column == 0) .Select(offset => memoryCellEntityNumber + offset * width * entitiesPerCell) ) .ToList(); // Memory cell entities.Add(new Entity { Entity_number = memoryCellEntityNumber, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Check), Constant = address, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to writer input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }, // Connection to reader input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + readerEntityOffset, Circuit_id = CircuitId.Input } }, Green = new List <ConnectionData> { // Connection to own output (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output }, // Connection to writer output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Output } } }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to own input (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input }, // Connection to reader input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + readerEntityOffset, Circuit_id = CircuitId.Input } } }) }); // Memory cell writer entities.Add(new Entity { Entity_number = memoryCellEntityNumber + writerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY - 2 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Check), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent writer input (address line) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to memory cell input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } }).ToList(), // Connection to adjacent writer input (data in) Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).ToList() }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to memory cell input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, 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 + 2 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Info), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to memory cell input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } }, Green = new List <ConnectionData> { // Connection to memory cell output (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output } } }, new ConnectionPoint { // Connection to adjacent reader output (data out) Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + readerEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); } } if (includePower) { var substationWidth = (width + 7) / 16 + 1; var substationHeight = (gridHeight + 3) / 18 + 1; entities.AddRange(CreateSubstations(substationWidth, substationHeight, xOffset, gridHeight % 18 - 4 + yOffset, width * height * entitiesPerCell + 1)); } return(new Blueprint { Label = $"{width}x{height} RAM", Icons = new List <Icon> { new Icon { Signal = SignalID.Create(ItemNames.AdvancedCircuit) } }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
public override int GetHashCode() { return(this == null ? 0 : TimeStamp.GetHashCode() ^ SignalID.GetHashCode() ^ Phase.GetHashCode()); }
public override int GetHashCode() { return(this == null ? 0 : SignalID.GetHashCode()); }
public static Blueprint Generate(ScreenConfiguration configuration) { var width = configuration.Width ?? 18; var height = configuration.Height ?? 18; const int cycle = 2; const int parallelCycle = 32; var entities = new List <Entity>(); var pixels = new Entity[height, width]; var columnControllers = new Controller[width]; var rowControllers = new Controller[height]; // Pixels for (var row = 0; row < height; row++) { for (var column = 0; column < width; column++) { var relativeRow = row % 18; var relativeColumn = column % 18; // Don't place lights that intersect the substations if (relativeRow > 15 && relativeColumn > 15) { continue; } var pixel = new Entity { Name = ItemNames.Lamp, Position = new Position { X = column + 2, Y = row + 2 }, Control_behavior = new ControlBehavior { Circuit_condition = new CircuitCondition { First_signal = SignalID.Create(ScreenUtil.PixelSignals[row]), Comparator = Comparators.GreaterThan, Constant = 0 }, Use_colors = true } }; pixels[row, column] = pixel; entities.Add(pixel); } } // Column controllers for (var column = 0; column < width; column++) { var controllerX = column + 2; var controllerY = height + 4; var memory = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 0.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Constant = 0, Comparator = Comparators.GreaterThan, Output_signal = SignalID.Create(VirtualSignalNames.Each), Copy_count_from_input = false } } }; entities.Add(memory); var writer = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 2.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(writer); var addressMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 4.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = column + 1, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(addressMatcher); var cyclicWriter = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 6.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(cyclicWriter); var cyclicMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 8.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = column % cycle + 1, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(cyclicMatcher); var parallelWriter = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 14.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(parallelWriter); var parallelAddressRangeLow = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 10.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = column + 1, Comparator = Comparators.LessThan, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(parallelAddressRangeLow); var parallelAddressRangeHigh = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 12.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = column + parallelCycle + 1, Comparator = Comparators.GreaterThanOrEqualTo, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(parallelAddressRangeHigh); var isOdd = column % 2 == 1; var parallelHorizontalLink1 = new Entity { Name = column % 18 == 16 ? ItemNames.Substation : ItemNames.BigElectricPole, Position = new Position { X = controllerX + 0.5, Y = controllerY + 16.5 + (isOdd ? 2 : 0) } }; entities.Add(parallelHorizontalLink1); var parallelHorizontalLink2 = new Entity { Name = ItemNames.BigElectricPole, Position = new Position { X = controllerX + 0.5, Y = controllerY + 20.5 + (isOdd ? 2 : 0) } }; entities.Add(parallelHorizontalLink2); var videoEnabler = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = controllerX, Y = controllerY + 24.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(videoEnabler); var videoReferenceSignalSubtractor = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = controllerX, Y = controllerY + 26.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = -3, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(videoReferenceSignalSubtractor); var videoValueSpreader = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = controllerX, Y = controllerY + 28.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = 2, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(videoValueSpreader); var videoBitIsolator = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = controllerX, Y = controllerY + 30.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = 1, Operation = ArithmeticOperations.And, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(videoBitIsolator); var videoBitShifter = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = controllerX, Y = controllerY + 32.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_signal = SignalID.CreateLetterOrDigit('W'), Operation = ArithmeticOperations.RightShift, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(videoBitShifter); columnControllers[column] = new Controller { Memory = memory, Writer = writer, AddressMatcher = addressMatcher, Cyclic = new CyclicInput { Writer = cyclicWriter, Matcher = cyclicMatcher }, Parallel = new ParallelInput { Writer = parallelWriter, AddressRangeLow = parallelAddressRangeLow, AddressRangeHigh = parallelAddressRangeHigh, HorizontalLink1 = parallelHorizontalLink1, HorizontalLink2 = parallelHorizontalLink2 }, Video = new VideoInput { Enabler = videoEnabler, ReferenceSignalSubtractor = videoReferenceSignalSubtractor, ValueSpreader = videoValueSpreader, BitIsolator = videoBitIsolator, BitShifter = videoBitShifter } }; } // Row controllers for (var row = 0; row < height; row++) { var controllerY = row + 2; var memory = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = -1.5, Y = controllerY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Constant = 0, Comparator = Comparators.LessThan, Output_signal = SignalID.Create(VirtualSignalNames.Each), Copy_count_from_input = true } } }; entities.Add(memory); var writer = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = -3.5, Y = controllerY }, Direction = Direction.Right, 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 addressMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = -5.5, Y = controllerY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = row + 1, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(addressMatcher); var cyclicWriter = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = -7.5, Y = controllerY }, Direction = Direction.Right, 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(cyclicWriter); var cyclicMatcher = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = -9.5, Y = controllerY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Info), Constant = row % cycle + 1, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.Create(VirtualSignalNames.Check), Copy_count_from_input = false } } }; entities.Add(cyclicMatcher); rowControllers[row] = new Controller { Memory = memory, Writer = writer, AddressMatcher = addressMatcher, Cyclic = new CyclicInput { Writer = cyclicWriter, Matcher = cyclicMatcher } }; } BlueprintUtil.PopulateEntityNumbers(entities); var substationWidth = (width + 8) / 18 + 1; var substationHeight = (height + 8) / 18 + 1; var substations = CreateSubstations(substationWidth, substationHeight, 0, 0, entities.Count + 1, GridConnectivity.Top | GridConnectivity.Vertical); entities.AddRange(substations); var substations2 = CreateSubstations(substationWidth, 1, 0, height + 38, entities.Count + 1); entities.AddRange(substations2); // Pixel connections for (var row = 0; row < height; row++) { for (var column = 0; column < width; column++) { var pixel = pixels[row, column]; if (pixel == null) { continue; }
public bool Equals(SignalID other) => type == other.type && name == other.name;
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(PixelSignalsConfiguration configuration) { var signalCount = configuration.SignalCount ?? ScreenUtil.PixelSignals.Count; const int maxFilters = 20; var entities = new List <Entity>(); var signalConstants = new Entity[(signalCount + maxFilters - 1) / maxFilters]; // Signal constants for (var index = 0; index < signalConstants.Length; index++) { var outputSignalMap = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = index + 1, Y = 0 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Filters = ScreenUtil.PixelSignals.Skip(index * maxFilters).Take(Math.Min(maxFilters, signalCount - index * maxFilters)).Select((signal, signalIndex) => new Filter { Signal = SignalID.Create(signal), Count = 1 }).ToList() } }; signalConstants[index] = outputSignalMap; entities.Add(outputSignalMap); } BlueprintUtil.PopulateEntityNumbers(entities); // Signal constant connections for (var index = 1; index < signalConstants.Length; index++) { var outputSignalMap = signalConstants[index]; var adjacentOutputSignalMap = signalConstants[index - 1]; AddConnection(CircuitColor.Red, outputSignalMap, null, adjacentOutputSignalMap, null); } return(new Blueprint { Label = $"Pixel signals", Icons = new List <Icon> { new Icon { Signal = SignalID.Create(ItemNames.Lamp) }, new Icon { Signal = SignalID.Create(ItemNames.ConstantCombinator) } }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }
public static Blueprint Generate(SpeakerConfiguration configuration) { const int numberOfInstruments = 12; var speakersPerConfiguration = configuration.SpeakersPerConfiguration ?? 6; var volumeLevels = configuration.VolumeLevels ?? 1; var minVolume = configuration.MinVolume ?? 0; var maxVolume = configuration.MaxVolume ?? 1; var baseAddress = configuration.BaseAddress ?? 0; var reverseAddressX = configuration.ReverseAddressX ?? false; var reverseAddressY = configuration.ReverseAddressY ?? false; var signal = configuration.Signal ?? '0'; var includePower = configuration.IncludePower ?? true; var speakersPerVolumeLevel = speakersPerConfiguration * numberOfInstruments; var speakerCount = speakersPerVolumeLevel * volumeLevels; var width = configuration.Width ?? speakerCount / (configuration.Height ?? 16); var height = configuration.Height ?? speakerCount / width; const int entitiesPerCell = 6; const int cellHeight = 11; const int writerEntityOffset = -1; const int clearerEntityOffset = -2; const int readerEntityOffset = 1; const int playerEntityOffset = 2; const int speakerEntityOffset = 3; var gridWidth = width + (includePower ? ((width + 7) / 16 + 1) * 2 : 0); var gridHeight = height * cellHeight; var xOffset = -gridWidth / 2; var yOffset = -gridHeight / 2; var entities = new List <Entity>(); for (int row = 0; row < height; row++) { for (int column = 0; column < width; column++) { var relativeAddress = (reverseAddressY ? (height - row - 1) : row) * width + (reverseAddressX ? (width - column - 1) : column); var address = relativeAddress + baseAddress + 1; var memoryCellEntityNumber = (row * width + column) * entitiesPerCell + 3; var memoryCellX = column + (includePower ? (column / 16 + 1) * 2 : 0) + xOffset; var memoryCellY = (height - row - 1) * cellHeight + 4.5 + 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 && column == 0) .Select(offset => memoryCellEntityNumber + offset * width * entitiesPerCell) ) .ToList(); // Memory cell entities.Add(new Entity { Entity_number = memoryCellEntityNumber, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Check), Constant = address, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to writer input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }, // Connection to reader input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + readerEntityOffset, Circuit_id = CircuitId.Input } }, Green = new List <ConnectionData> { // Connection to own output (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output }, // Connection to writer output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Output } } }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to own input (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input }, // Connection to reader input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + readerEntityOffset, Circuit_id = CircuitId.Input } } }) }); // Memory cell writer entities.Add(new Entity { Entity_number = memoryCellEntityNumber + writerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY - 2 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Check), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent writer input (address line) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to memory cell input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } }).ToList(), // Connection to adjacent writer input (data in) Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).ToList() }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to memory cell input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input }, // Connection to memory cell clearer output (data in/out) new ConnectionData { Entity_id = memoryCellEntityNumber + clearerEntityOffset, Circuit_id = CircuitId.Output } } }) }); // Memory cell clearer entities.Add(new Entity { Entity_number = memoryCellEntityNumber + clearerEntityOffset, Name = ItemNames.ArithmeticCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY - 4 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.CreateLetterOrDigit(signal), Second_signal = SignalID.CreateVirtual(VirtualSignalNames.Dot), Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.CreateLetterOrDigit(signal) } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent clearer input (clear signal) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + clearerEntityOffset, Circuit_id = CircuitId.Input }).ToList(), Green = new List <ConnectionData> { // Connection to own output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + clearerEntityOffset, Circuit_id = CircuitId.Output } } }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to own input (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + clearerEntityOffset, Circuit_id = CircuitId.Input }, // Connection to memory cell writer output (data in/out) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Output } } }) }); // Memory cell reader entities.Add(new Entity { Entity_number = memoryCellEntityNumber + readerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY + 2 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Info), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to memory cell input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } }, Green = new List <ConnectionData> { // Connection to memory cell output (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output }, // Connection to player input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + playerEntityOffset, Circuit_id = CircuitId.Input } } }, new ConnectionPoint { // Connection to adjacent reader output (data out) Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + readerEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); // Player entities.Add(new Entity { Entity_number = memoryCellEntityNumber + playerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY + 4 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateVirtual(VirtualSignalNames.Dot), Constant = 0, Comparator = Comparators.GreaterThan, Output_signal = SignalID.CreateLetterOrDigit(signal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent player input (play signal) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + playerEntityOffset, Circuit_id = CircuitId.Input }).ToList(), Green = new List <ConnectionData> { // Connection to reader input (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + readerEntityOffset, Circuit_id = CircuitId.Input } } }, new ConnectionPoint { Green = new List <ConnectionData> { // Connection to speaker (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + speakerEntityOffset } } }) }); // Speaker entities.Add(new Entity { Entity_number = memoryCellEntityNumber + speakerEntityOffset, Name = ItemNames.ProgrammableSpeaker, Position = new Position { X = memoryCellX, Y = memoryCellY + 5.5 }, Control_behavior = new ControlBehavior { Circuit_condition = new CircuitCondition { First_signal = SignalID.CreateLetterOrDigit(signal) }, Circuit_parameters = new CircuitParameters { Signal_value_is_pitch = true, Instrument_id = relativeAddress % speakersPerVolumeLevel / speakersPerConfiguration } }, Connections = CreateConnections(new ConnectionPoint { Green = new List <ConnectionData> { // Connection to player output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + playerEntityOffset, Circuit_id = CircuitId.Output } } }), Parameters = new SpeakerParameter { Playback_volume = maxVolume - (double)(relativeAddress / speakersPerVolumeLevel) / (volumeLevels - 1) * (maxVolume - minVolume), Playback_globally = true, Allow_polyphony = true }, Alert_parameters = new SpeakerAlertParameter { Show_alert = false } }); } } if (includePower) { var substationWidth = (width + 7) / 16 + 1; var substationHeight = (gridHeight + 3) / 18 + 1; entities.AddRange(CreateSubstations(substationWidth, substationHeight, xOffset, yOffset + 2, width * height * entitiesPerCell + 1)); } return(new Blueprint { Label = $"{width}x{height} Speaker", Icons = new List <Icon> { new Icon { Signal = SignalID.Create(ItemNames.ProgrammableSpeaker) } }, 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 Blueprint Generate(SpriteShifterConfiguration configuration) { var signalCount = configuration.SignalCount ?? ScreenUtil.PixelSignals.Count; const int maxFilters = 20; const int shifterCount = 32; const int inputSignalCount = 32; var inputSignals = ComputerSignals.OrderedSignals.Take(inputSignalCount).ToList(); var offsetSignal = VirtualSignalNames.Dot; var entities = new List <Entity>(); var inputMaps = new Entity[inputSignalCount]; var shifters = new Shifter[shifterCount]; // Input maps for (var processorIndex = 0; processorIndex < inputSignalCount; processorIndex++) { var inputSignal = inputSignals[processorIndex]; var y = processorIndex * 4 + 3; if (y % 18 == 8) { y--; } else if (y % 18 == 9) { y++; } var inputMap = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = 1, Y = y }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Filters = new List <Filter> { Filter.Create(offsetSignal, processorIndex + 1) } } }; inputMaps[processorIndex] = inputMap; entities.Add(inputMap); } // Shifters for (var shifterIndex = 0; shifterIndex < shifterCount; shifterIndex++) { var shifterX = shifterIndex * 2 + shifterIndex / 8 * 2 + 2; var outputLink = new Entity { Name = ItemNames.BigElectricPole, Position = new Position { X = 0.5 + shifterX, Y = -1.5 } }; entities.Add(outputLink); var inputSquared = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = shifterX, Y = 0.5 }, Direction = Direction.Down, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = 2, Operation = ArithmeticOperations.Exponentiation, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(inputSquared); var bufferedInput = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 0.5 + shifterX, Y = 2 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = 1, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(bufferedInput); var negativeInputSquared = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 1 + shifterX, Y = 0.5 }, Direction = Direction.Up, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_constant = -1, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(negativeInputSquared); // Input signal processors var signalProcessors = new SignalProcessor[inputSignalCount]; for (var processorIndex = 0; processorIndex < inputSignalCount; processorIndex++) { var inputSignal = inputSignals[processorIndex]; var y = processorIndex * 4 + 3; var inputChecker = new Entity { Name = ItemNames.DeciderCombinator, Position = new Position { X = 0.5 + shifterX, Y = y }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_signal = SignalID.Create(offsetSignal), Comparator = Comparators.IsEqual, Output_signal = SignalID.Create(VirtualSignalNames.Each), Copy_count_from_input = false } } }; entities.Add(inputChecker); var inputBuffer = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 0.5 + shifterX, Y = 1 + y }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(inputSignal), Second_constant = 1, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(inputSignal) } } }; entities.Add(inputBuffer); var outputGenerator = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 0.5 + shifterX, Y = 2 + y }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(VirtualSignalNames.Each), Second_signal = SignalID.Create(inputSignal), Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(VirtualSignalNames.Each) } } }; entities.Add(outputGenerator); var outputCleaner = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 0.5 + shifterX, Y = 3 + y }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Arithmetic_conditions = new ArithmeticConditions { First_signal = SignalID.Create(inputSignal), Second_constant = -1, Operation = ArithmeticOperations.Multiplication, Output_signal = SignalID.Create(offsetSignal) } } }; entities.Add(outputCleaner); signalProcessors[processorIndex] = new SignalProcessor { InputChecker = inputChecker, InputBuffer = inputBuffer, OutputGenerator = outputGenerator, OutputCleaner = outputCleaner }; } // Output signal maps var outputMaps = new Entity[(signalCount + maxFilters - 1) / maxFilters]; for (var index = 0; index < outputMaps.Length; index++) { var outputSignalMap = new Entity { Name = ItemNames.ConstantCombinator, Position = new Position { X = index % 2 + shifterX, Y = index / 2 + inputSignalCount * 4 + 3 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Filters = ScreenUtil.PixelSignals.Skip(index * maxFilters).Take(Math.Min(maxFilters, signalCount - index * maxFilters)).Select((signal, signalIndex) => new Filter { Signal = SignalID.Create(signal), Count = index * maxFilters + signalIndex + 1 }).ToList() } }; outputMaps[index] = outputSignalMap; entities.Add(outputSignalMap); } var offsetBuffer = new Entity { Name = ItemNames.ArithmeticCombinator, Position = new Position { X = 0.5 + shifterX, Y = outputMaps[^ 1].Position.Y + 1
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 override int GetHashCode() { return(this == null ? 0 : SignalID.GetHashCode() ^ TimeStamp.GetHashCode() ^ EventCode.GetHashCode() ^ EventParam.GetHashCode()); }
public Blueprint Generate(IConfigurationRoot configuration) { var registerCount = int.TryParse(configuration["RegisterCount"], out var registerCountValue) ? registerCountValue : 16; const char memorySignal = 'A'; const char writeSignal = '1'; const char leftOperandSignal = '2'; const char rightOperandSignal = '3'; const char conditionSignal = '4'; const int writerEntityOffset = -1; const int autoIncrementEntityOffset = -2; const int leftOperandEntityOffset = 1; const int rightOperandEntityOffset = 2; const int conditionEntityOffset = 3; const int entitiesPerRegister = 6; const int cellWidth = 8; const int cellHeight = 2; var gridHeight = registerCount * 2; var xOffset = -cellWidth / 2; var yOffset = -gridHeight / 2; var entities = new List <Entity>(); for (int row = 0; row < registerCount; row++) { var address = row + 1; var memoryCellEntityNumber = row * entitiesPerRegister + 3; var memoryCellX = 2.5 + xOffset; var memoryCellY = row * cellHeight + 1 + yOffset; List <int> GetAdjacentMemoryCells(params int[] offsets) => offsets .Where(offset => row + offset >= 0 && row + offset < registerCount) .Select(offset => memoryCellEntityNumber + offset * entitiesPerRegister) .ToList(); var previousMemoryCell = GetAdjacentMemoryCells(-1); var nextMemoryCell = GetAdjacentMemoryCells(1); var adjacentMemoryCells = GetAdjacentMemoryCells(-1, 1); // Memory cell entities.Add(new Entity { Entity_number = memoryCellEntityNumber, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(writeSignal), Constant = address, Comparator = Comparators.IsNotEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to own output (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output }, // Connection to auto-increment output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + autoIncrementEntityOffset, Circuit_id = CircuitId.Output } }, // Connection to next writer input (address line) Green = nextMemoryCell.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to writer input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Input } }).ToList() }, new ConnectionPoint { Red = new List <ConnectionData> { // Connection to own input (data feedback) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input }, // Connection to writer output (data in) new ConnectionData { Entity_id = memoryCellEntityNumber + writerEntityOffset, Circuit_id = CircuitId.Output }, // Connection to right operand input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + rightOperandEntityOffset, Circuit_id = CircuitId.Input } } }) }); // Memory cell writer entities.Add(new Entity { Entity_number = memoryCellEntityNumber + writerEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX, Y = memoryCellY - 1 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(writeSignal), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent writer input (data in) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + writerEntityOffset, Circuit_id = CircuitId.Input }).ToList(), // Connection to previous memory cell input (address line) Green = previousMemoryCell.Select(entityNumber => new ConnectionData { Entity_id = entityNumber, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to memory cell input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } }).ToList(), }, new ConnectionPoint { Red = new List <ConnectionData> { // Connection to memory cell output (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output } } }) }); // Auto-increment writer entities.Add(new Entity { Entity_number = memoryCellEntityNumber + autoIncrementEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX - 2, Y = memoryCellY - 1 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(leftOperandSignal), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { // Connection to adjacent auto-increment input (address line/data in) Green = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + autoIncrementEntityOffset, Circuit_id = CircuitId.Input }).ToList(), }, new ConnectionPoint { Red = new List <ConnectionData> { // Connection to memory cell input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Input } } }) }); // Left operand reader entities.Add(new Entity { Entity_number = memoryCellEntityNumber + leftOperandEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX + 2, Y = memoryCellY - 1 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(leftOperandSignal), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to right operand input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + rightOperandEntityOffset, Circuit_id = CircuitId.Input }, // Connection to condition input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + conditionEntityOffset, Circuit_id = CircuitId.Input } }, // Connection to previous right operand input (address line) Green = previousMemoryCell.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + rightOperandEntityOffset, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to right operand input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + rightOperandEntityOffset, Circuit_id = CircuitId.Input }, // Connection to condition input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + conditionEntityOffset, Circuit_id = CircuitId.Input } }).ToList() }, new ConnectionPoint { // Connection to adjacent left operand output (data out) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + leftOperandEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); // Right operand reader entities.Add(new Entity { Entity_number = memoryCellEntityNumber + rightOperandEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX + 2, Y = memoryCellY }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(rightOperandSignal), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to memory cell output (data out) new ConnectionData { Entity_id = memoryCellEntityNumber, Circuit_id = CircuitId.Output } }, // Connection to next left operand input (address line) Green = nextMemoryCell.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + leftOperandEntityOffset, Circuit_id = CircuitId.Input }).Concat(new List <ConnectionData> { // Connection to left operand input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + leftOperandEntityOffset, Circuit_id = CircuitId.Input } }).ToList() }, new ConnectionPoint { // Connection to adjacent right operand output (data out) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + rightOperandEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); // Condition reader entities.Add(new Entity { Entity_number = memoryCellEntityNumber + conditionEntityOffset, Name = ItemNames.DeciderCombinator, Position = new Position { X = memoryCellX + 4, Y = memoryCellY - 1 }, Direction = Direction.Right, Control_behavior = new ControlBehavior { Decider_conditions = new DeciderConditions { First_signal = SignalID.CreateLetterOrDigit(conditionSignal), Constant = address, Comparator = Comparators.IsEqual, Output_signal = SignalID.CreateLetterOrDigit(memorySignal), Copy_count_from_input = true } }, Connections = CreateConnections(new ConnectionPoint { Red = new List <ConnectionData> { // Connection to left operand input (data out) new ConnectionData { Entity_id = memoryCellEntityNumber + leftOperandEntityOffset, Circuit_id = CircuitId.Input } }, Green = new List <ConnectionData> { // Connection to left operand input (address line) new ConnectionData { Entity_id = memoryCellEntityNumber + leftOperandEntityOffset, Circuit_id = CircuitId.Input } } }, new ConnectionPoint { // Connection to adjacent condition output (data out) Red = adjacentMemoryCells.Select(entityNumber => new ConnectionData { Entity_id = entityNumber + conditionEntityOffset, Circuit_id = CircuitId.Output }).ToList() }) }); } return(new Blueprint { Label = $"{registerCount} Registers", Icons = new List <Icon> { new Icon { Signal = SignalID.Create(ItemNames.ProcessingUnit) } }, Entities = entities, Item = ItemNames.Blueprint, Version = BlueprintVersions.CurrentVersion }); }