For a few weeks now I’ve began writing a system to process a table into a runnable Logic Gate sequence.
How the compiler runs:
The base of every logic gate in my simulation is AND, NOT and OR gates. They use these types:
export type InputOutputObject =
{
['gate']: string,
['index']: string,
}
export type Gate =
{
['outputs']: {InputOutputObject},
['inputs']: {InputOutputObject},
['proccessFunction']: ({[string]:boolean})->({[string]:boolean})
}
InputOutputObject is a unique “address” for the output, each address in an entire set of gates has to be unique, as its used as an index.
Gate simply contains an array of InputOutputObjects with the inputs and outputs table. The index “proccessFunction” is a function that takes in a dictionary with the inputs and returns a dictionary with the outputs.
More complex gates
In the simulation, a feature borrowed from Sebastian Lague’s Digital Logic Sim, you can make your own gates based on a table of Gate objects, and a table containing all the “wires/connections” between the gates and the ports.
export type CustomGate =
{
['gates']: {Gate},
['inputs']: {string},
['outputs']: {string},
['gateName']: string,
['gateColor']: Color3,
['gateConnections']: {[string]: {InputOutputObject}}
}
gates contains the table of Gate objects in the customGate.
inputs contains the list of inputs into the customGate
outputs contains the list of outputs from the customGate
gateName is the name of the gate (declared by player)
gateColor is simply the RGB colour of the gate object
gateConnections contains a dictionary referrencing the relations between the gates and the ports.
The compiler itself
The compiler takes the list of gates, the inputs into the simulation, and the outputs.
local function CompileBoard(allGates:{CustomGate},inputs:{string},outputs:{string})
local storedConnections = {}
local storedValues = {}
for _, inputName in pairs(inputs) do
storedConnections[inputName..'.base'] = signal.new()
storedValues[inputName..'.base'] = false
end
for index, cGate in pairs(allGates) do
local inp = cGate.inputs
local out = cGate.outputs
for _, outputName in pairs(storedConnections) do
local conver = outputs..cGate.gateName
if not storedConnections[conver] then storedConnections[conver] = signal.new()
end
end
for _, gate in pairs(cGate.gates) do
for _, out in pairs(gate.outputs) do
storedConnections[conv(out)] = signal.new()
storedValues[conv(out)] = false
end
end
for index, cGate in pairs(allGates) do
for _, gate in pairs(cGate.gates) do
for _, inp in pairs(gate.inputs) do
local aSig = storedConnections[conv(inp)]
if aSig then
aSig.Connect(function(s:true?)
local function getInputs()
local c = {}
for i, v in pairs(gate.inputs) do
local v = storedValues[conv(v)]
c[v.index] = v
end
return c
end
local outputs = gate.proccessFunction(getInputs())
for i, v in pairs(outputs) do
storedValues[i] = v
if s then
storedConnections[i]:Fire(true)
end
end
end)
end
end
end
end
end
local editFuncs = {}
function editFuncs:StartUp()
for i, v in pairs(storedConnections) do
v:Fire()
end
for i, v in pairs(storedValues) do
storedValues[i] = nil
end
end
function editFuncs:SetToInput(inputIndex,newvalue:boolean)
storedValues[inputIndex..'.base'] = newvalue
storedConnections[inputIndex..'.base']:Fire(true)
end
function editFuncs:kill()
for i, v in pairs(storedConnections) do
v:Destroy()
end
end
return editFuncs
end
So what’s the problem?
CustomGates can only be made with a combination of the basic Gate objects of AND, NOT and OR, meaning that custom gates can’t be used in custom gates, which would mean difficulties when making 4BIT+ gates.
I’ve tried to see what format I could use to store this, but I got no clue. I’ve even tried using GPT, still no clear answer.
If anyone who has an idea on how I could format it, please inform!