Logikraft/circuits.lua
2024-05-20 14:18:52 +02:00

304 lines
9.3 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- component {
-- inputs: ["in1": bit, "in2": bit, "inB": byte],
-- outputs: ["out": byte],
-- name: alu0,
-- optiCompute: fun
-- contents: {
--
-- }
-- }
function logikraft.computeCircuit(circuit, input)
end
local function has_value (tab, len, val)
for i = 1, len do
if tab[i].x == val.x and tab[i].y == val.y and tab[i].z == val.z then
return true
end
end
return false
end
function logikraft.discoverBlocks(pos)
local i = 2
local j = 1
local poz = {}
poz[1] = pos
while (j<i)
do
local p = poz[j]
j = j+1
local neighbourhood = {
{x = p.x+1, y = p.y, z = p.z},
{x = p.x-1, y = p.y, z = p.z},
{x = p.x, y = p.y+1, z = p.z},
{x = p.x, y = p.y-1, z = p.z},
{x = p.x, y = p.y, z = p.z+1},
{x = p.x, y = p.y, z = p.z-1}
}
for p2=1,6
do
local n = neighbourhood[p2]
if((not has_value(poz,i-1,n)) and (minetest.get_item_group(minetest.get_node(n).name,"circuitry")==1))
then
poz[i] = n
i = i+1
end
end
end
minetest.chat_send_all("Discovered ".. (i-1) .. " blocks")
return poz
end
local function collapseConnectionsStep(connz)
for k,conna in ipairs(connz)
do
for l,connb in ipairs(connz)
do
if k<l
then
local match = table.findMatch1(conna.conn,connb.conn)
if match
then
-- we add connb\m[2] to conna\m[1], and then we remove connb
table.remove(conna.conn,match[1])
for i,x in pairs(connb.conn) do
if i ~= match[2] then table.insert(conna.conn,x) end
end
-- And we merge the node lists
for i,x in ipairs(connb.nodes) do
table.insert(conna.nodes,x)
end
table.remove(connz,l)
return true
end
end
end
end
return false
end
function logikraft.collapseConnections(connz)
while collapseConnectionsStep(connz)
do end
end
-- {x,y,z,d=0 if x+, 1 if z+}
function logikraft.compileCircuit(poz)
local components = {}
local connections = {}
for i,pos in ipairs(poz)
do
local node = minetest.get_node(pos)
if logikraft.cablenodes[node.name]
then
-- It is a cable
local conns = logikraft.cables[logikraft.cablenodes[node.name]].conns
for j,c in ipairs(conns)
do
if not (c == 1 or c == 2 or c == 4 or c == 8 or c == 17 or c == 18 or c == 20 or c == 24)
then
local newconn = {}
if math.fmod(math.floor(c/1),2)==1
then table.insert(newconn,{x=pos.x-1,y=pos.y,z=pos.z,d=0}) end
if math.fmod(math.floor(c/2),2)==1
then table.insert(newconn,{x=pos.x,y=pos.y,z=pos.z-1,d=1}) end
if math.fmod(math.floor(c/4),2)==1
then table.insert(newconn,{x=pos.x,y=pos.y,z=pos.z,d=0}) end
if math.fmod(math.floor(c/8),2)==1
then table.insert(newconn,{x=pos.x,y=pos.y,z=pos.z,d=1}) end
local pos2 = table.copy(pos)
pos2.conn = j
table.insert(connections,{nodes = {pos2},conn = newconn})
end
end
elseif logikraft.componentnodes[node.name]
then
-- It is a component
local cpblock = logikraft.componentnodes[node.name]
if cpblock.x == 1 and cpblock.y == 1
then
local component = logikraft.components[cpblock.name]
local cp = {type = cpblock.name, ports = {}, pos = pos}
-- Left
if component.ports.left
then
for j,n in pairs(component.ports.left)
do
if n
then
cp.ports[n] = {x=pos.x-1,y=pos.y,z=pos.z+j-1,d=0}
end
end
end
-- Right
if component.ports.right
then
for j,n in pairs(component.ports.right)
do
if n
then
cp.ports[n] = {x=pos.x+component.width-1,y=pos.y,z=pos.z+j-1,d=0}
end
end
end
-- Top
if component.ports.top
then
for j,n in pairs(component.ports.top)
do
if n
then
cp.ports[n] = {x=pos.x+j-1,y=pos.y,z=pos.z+component.height-1,d=1}
end
end
end
-- Bottom
if component.ports.bottom
then
for j,n in pairs(component.ports.bottom)
do
if n
then
cp.ports[n] = {x=pos.x+j-1,y=pos.y,z=pos.z-1,d=1}
end
end
end
-- If we have a meta name, we save it
local meta = minetest.get_meta(pos)
if meta:get_string("logikraft:name") ~= ""
then cp.name = meta:get_string("logikraft:name")
end
table.insert(components,cp)
-- We do everything in the 0 0 block, we ignore the others
end
-- else we just ignore
end
end
logikraft.collapseConnections(connections)
-- We replace the index of the connection in the components
for k,cmp in pairs(components)
do
for pn,x in pairs(cmp.ports)
do
-- We find the connection with this port
local theconn = 0
for i,connz in ipairs(connections)
do
if table.getkey1(connz.conn,x) -- if x in connz
then theconn = i end
end
cmp.ports[pn] = theconn
end
end
-- We remove conn data from the connections, the index in now enough
for k,conn in ipairs(connections)
do
connections[k] = connections[k].nodes
end
-- We remove inputs and outputs, as we only store ports
local inputs = {}
local outputs = {}
local cleanedComponents = {}
for i,cmp in ipairs(components)
do
local name = cmp.name or cmp.type.."_unknown_"..tostring(i)
if cmp.type == "input"
then
inputs[name] = {
conn = cmp.ports["out"],
pos = cmp.pos
}
elseif cmp.type == "output"
then
outputs[name] = {
conn = cmp.ports["in"],
pos = cmp.pos
}
else
table.insert(cleanedComponents,cmp)
end
end
-- TODO sort components in inferred components order, for faster computing
--[[
print("Discovered:")
print(dump(cleanedComponents))
print(dump(inputs))
print(dump(outputs))
print(dump(connections))
--]]
return {components = cleanedComponents, inputs=inputs, outputs=outputs, connections = connections}
end
local function computeStep(circuit,connvals,computed)
local effective = false
for i,cmp in pairs(circuit.components)
do
if not computed[i]
then
-- We check that all the inputs have a value
local allvalue = true
local inputs = {}
for k,name in pairs(logikraft.components[cmp.type].inputs)
do
allvalue = allvalue and (cmp.ports[name] and connvals[cmp.ports[name]] and true)
inputs[name] = allvalue and connvals[cmp.ports[name]]
end
if allvalue
then
local output = logikraft.components[cmp.type].compute(inputs)
print("Component "..cmp.type)
print(dump(inputs))
print(dump(output))
for name,v in pairs(output)
do
if cmp.ports[name] and connvals[cmp.ports[name]]
then
-- Already set
minetest.chat_send_all("Le composant "..cmp.type.." ne peut pas écrire")
else
connvals[cmp.ports[name]] = v
end
end
computed[i] = true
effective = true
end
end
end
return effective
end
function logikraft.compute(circuit,inz)
local connvals = {}
local computed = {}
-- We read the inputs components
for name,x in pairs(circuit.inputs)
do
if x.conn and inz[name]
then connvals[x.conn] = inz[name]
end
end
while computeStep(circuit,connvals,computed)
do end
-- We read the output components
local outz = {}
for name,x in pairs(circuit.outputs)
do
if x.conn
then outz[name] = connvals[x.conn]
end
end
return outz
end