Create StoneRed.LogicSimulator.Api project

This commit is contained in:
Stone_Red
2023-10-13 12:24:15 +02:00
parent 4a43a1d2ef
commit 2cd4168cfd
27 changed files with 77 additions and 60 deletions
@@ -0,0 +1,12 @@
namespace StoneRed.LogicSimulator.Api.Attributes;
[AttributeUsage(AttributeTargets.Class)]
public class LogicGateDescriptionAttribute : Attribute
{
public string Description { get; }
public LogicGateDescriptionAttribute(string description)
{
Description = description;
}
}
@@ -0,0 +1,12 @@
namespace StoneRed.LogicSimulator.Api.Attributes;
[AttributeUsage(AttributeTargets.Class)]
public class LogicGateNameAttribute : Attribute
{
public string Name { get; }
public LogicGateNameAttribute(string name)
{
Name = name;
}
}
@@ -0,0 +1,8 @@
using Microsoft.Xna.Framework;
namespace StoneRed.LogicSimulator.Api.Interfaces;
internal interface IColorable
{
public Color Color { get; }
}
@@ -0,0 +1,8 @@
using Microsoft.Xna.Framework.Graphics;
namespace StoneRed.LogicSimulator.Api.Interfaces;
internal interface IDrawable
{
Texture2D Texture { get; }
}
@@ -0,0 +1,10 @@
using MonoGame.Extended.Input;
namespace StoneRed.LogicSimulator.Api.Interfaces;
internal interface IInteractable
{
public string Info { get; }
public void OnInteraction(MouseStateExtended mouseState, MouseStateExtended previousMouseState, KeyboardStateExtended keyboardStateExtended);
}
@@ -0,0 +1,181 @@
using Microsoft.Xna.Framework.Graphics;
using StoneRed.LogicSimulator.Api.Utilities;
namespace StoneRed.LogicSimulator.Api.Interfaces;
#pragma warning disable S112 // General exceptions should never be thrown
internal abstract class LogicGate
{
private readonly List<LogicGateConnection> logicGateConnections = new();
private bool logicGateConnectionsChnaged = false;
private int currentInput;
private int newInput;
private int output;
private int cachedOutput;
private LogicGateConnection[] logicGateConnectionsArray = Array.Empty<LogicGateConnection>();
public abstract int OutputCount { get; set; }
public abstract int InputCount { get; set; }
internal IReadOnlyList<LogicGateConnection> LogicGateConnections => logicGateConnections.AsReadOnly();
internal GraphicsDevice? GraphicsDevice { get; set; }
internal LogicGateWorldData WorldData { get; init; } = new LogicGateWorldData();
internal ulong Id { get; set; }
public override bool Equals(object? obj)
{
return obj is LogicGate gate &&
Id == gate.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
internal void NextTick()
{
currentInput = newInput;
newInput = 0;
output = 0;
}
internal void SetInput(int value, int index)
{
if (index >= InputCount)
{
throw new IndexOutOfRangeException();
}
// Inputs should act as or gates
if (value == 1)
{
newInput.SetBit(1, index);
}
}
internal void Connect(LogicGate logicGate, int inputIndex, int outputIndex)
{
if (inputIndex >= logicGate.InputCount)
{
throw new IndexOutOfRangeException();
}
if (outputIndex >= OutputCount)
{
throw new IndexOutOfRangeException();
}
lock (logicGateConnections)
{
logicGateConnections.Add(new LogicGateConnection(logicGate, inputIndex, outputIndex));
logicGateConnectionsChnaged = true;
}
}
internal bool IsConnectedTo(LogicGate logicGate, int? inputIndex = null, int? outputIndex = null)
{
lock (logicGateConnections)
{
return logicGateConnections.Exists(c =>
c.LogicGate.Id == logicGate.Id
&& (!inputIndex.HasValue || c.InputIndex == inputIndex)
&& (!outputIndex.HasValue || c.OutputIndex == outputIndex));
}
}
internal void Disconnect(LogicGate logicGate, int? inputIndex = null, int? outputIndex = null)
{
lock (logicGateConnections)
{
int index = logicGateConnections.FindIndex(c =>
c.LogicGate.Id == logicGate.Id &&
(!inputIndex.HasValue || c.InputIndex == inputIndex) &&
(!outputIndex.HasValue || c.OutputIndex == outputIndex));
logicGateConnections.RemoveAt(index);
logicGateConnectionsChnaged = true;
}
}
internal void Update()
{
Execute();
cachedOutput = output;
PublishOutput();
}
internal int GetCachedOutputBit(int index)
{
if (index < 0 || index >= OutputCount)
{
throw new IndexOutOfRangeException();
}
return cachedOutput.GetBit(index);
}
protected internal virtual void Initialize()
{ }
protected abstract void Execute();
protected int GetInputBit(int index)
{
if (index < 0 || index >= InputCount)
{
throw new IndexOutOfRangeException();
}
return currentInput.GetBit(index);
}
protected void SetOutputBit(int value, int index)
{
if (index < 0 || index >= OutputCount)
{
throw new IndexOutOfRangeException();
}
output.SetBit(value, index);
}
protected Texture2D CreateTexture(int width, int height)
{
return new Texture2D(GraphicsDevice, width, height);
}
private void PublishOutput()
{
if (logicGateConnectionsChnaged)
{
lock (logicGateConnections)
{
logicGateConnectionsArray = logicGateConnections.ToArray();
logicGateConnectionsChnaged = false;
}
}
for (int i = 0; i < logicGateConnectionsArray.Length; i++)
{
LogicGateConnection connection = logicGateConnectionsArray[i];
connection.LogicGate.SetInput(output.GetBit(connection.OutputIndex), connection.InputIndex);
}
}
}
#pragma warning restore S112 // General exceptions should never be thrown
internal class LogicGateConnection
{
public LogicGate LogicGate { get; }
public int InputIndex { get; }
public int OutputIndex { get; }
public LogicGateConnection(LogicGate logicGate, int inputIndex, int outputIndex)
{
LogicGate = logicGate;
InputIndex = inputIndex;
OutputIndex = outputIndex;
}
};
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="StoneRed.LogicSimulator" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Extended" Version="3.8.0" />
<PackageReference Include="MonoGame.Extended.Input" Version="3.8.0" />
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
</ItemGroup>
</Project>
@@ -0,0 +1,34 @@
namespace StoneRed.LogicSimulator.Api.Utilities;
#pragma warning disable S112 // General exceptions should never be thrown
internal static class BitHelper
{
public static void SetBit(this ref int input, int value, int index)
{
if (index >= 32)
{
throw new IndexOutOfRangeException();
}
if (value == 1)
{
input |= 1 << index;
}
else
{
input &= ~(1 << index);
}
}
public static int GetBit(this int input, int index)
{
if (index >= 32)
{
throw new IndexOutOfRangeException();
}
return (input >> index) & 1;
}
}
#pragma warning restore S112 // General exceptions should never be thrown
@@ -0,0 +1,11 @@
using Microsoft.Xna.Framework;
namespace StoneRed.LogicSimulator.Api.Utilities;
internal record LogicGateWorldData
{
public Vector2 Position { get; set; }
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}