304 lines
9.3 KiB
Lua
304 lines
9.3 KiB
Lua
-- 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
|