-- ============================================================================ -- CONTROLLO REATTORE IC2 CON LOGICA GATE INTEGRATA -- ============================================================================ -- Questo programma gestisce automaticamente il reattore IC2 per l'arricchimento -- del materiale, con logica di controllo integrata che sostituisce i gate hardware. -- -- LOGICA GATE INTEGRATA (non servono più gate fisici): -- - RS Latch: Gestisce la commutazione tra modalità normale e rifornimento -- con isteresi per evitare oscillazioni (soglie: 10s per Set, 15s per Reset) -- - XNOR: Garantisce che arancione e bianco non siano mai attivi contemporaneamente -- -- COLORI BUNDLED REDSTONE: -- - Arancione (2): Modalità normale - Input/output materiale da arricchire ATTIVI -- - Bianco (1): Modalità rifornimento - Input/output cellule uranio ATTIVI -- - Nessuno (0): Sistema fermo/errore -- ============================================================================ -- Funzione per verificare che il peripheral sia valido function getPeripheral() local success, s = pcall(function() return peripheral.wrap("bottom") end) if not success or not s then return nil, "Peripheral non disponibile" end return s, nil end -- Funzione per ottenere il monitor (prova più lati) function getMonitor() local sides = {"top", "left", "right", "front", "back"} for _, side in ipairs(sides) do local success, monitor = pcall(function() local m = peripheral.wrap(side) if m and m.setCursorPos then return m, side end return nil, nil end) if success and monitor then return monitor, side, nil end end return nil, nil, "Monitor non trovato" end -- Funzione per aggiornare il monitor con i dati del reattore function updateMonitor(monitor, uuid, state, title, tab, isRefueling, errorMsg) if not monitor then return false end local success, err = pcall(function() -- Ottieni dimensioni del monitor local width, height = monitor.getSize() if not width or not height then -- Fallback se getSize non disponibile width, height = 26, 9 end -- Configura il monitor monitor.setTextScale(0.5) -- Testo più piccolo per monitor 2x3 monitor.clear() monitor.setCursorPos(1, 1) -- Header monitor.setTextColor(colors.white) local header = "=== REATTORE IC2 ===" if string.len(header) > width then header = string.sub(header, 1, width) end monitor.write(header) monitor.setCursorPos(1, 2) monitor.setTextColor(colors.gray) monitor.write(string.rep("=", width)) local line = 3 -- Mostra errori se presenti if errorMsg then monitor.setCursorPos(1, line) monitor.setTextColor(colors.red) monitor.write("ERRORE:") line = line + 1 monitor.setCursorPos(1, line) monitor.setTextColor(colors.orange) -- Tronca messaggio se troppo lungo local msg = string.sub(tostring(errorMsg), 1, width - 1) monitor.write(msg) line = line + 2 elseif tab and tab.timeLeft then -- Stato del reattore monitor.setCursorPos(1, line) monitor.setTextColor(colors.cyan) monitor.write("Stato: ") if isRefueling then monitor.setTextColor(colors.yellow) monitor.write("RIFORNIMENTO") else monitor.setTextColor(colors.green) monitor.write("ATTIVO") end line = line + 1 -- Tempo rimanente local hours = math.floor(tab.timeLeft / 3600) local minutes = math.floor((tab.timeLeft % 3600) / 60) local seconds = tab.timeLeft % 60 monitor.setCursorPos(1, line) monitor.setTextColor(colors.lightBlue) monitor.write("Tempo:") line = line + 1 monitor.setCursorPos(1, line) monitor.setTextColor(colors.white) local timeStr if hours > 0 then timeStr = string.format("%02d:%02d:%02d", hours, minutes, seconds) else timeStr = string.format("%02d:%02d", minutes, seconds) end monitor.write(timeStr) line = line + 1 -- Barra di avanzamento (adattata alla larghezza) monitor.setCursorPos(1, line) monitor.setTextColor(colors.gray) monitor.write("[") local barWidth = math.min(width - 4, 18) -- Lascia spazio per [ e ] local timePercent = math.min(tab.timeLeft / 3600, 1) * 100 -- Percentuale basata su 1 ora local filled = math.floor((timePercent / 100) * barWidth) if timePercent > 50 then monitor.setTextColor(colors.green) elseif timePercent > 20 then monitor.setTextColor(colors.yellow) else monitor.setTextColor(colors.red) end for i = 1, barWidth do if i <= filled then monitor.write("=") else monitor.setTextColor(colors.gray) monitor.write("-") end end monitor.setTextColor(colors.gray) monitor.write("]") line = line + 1 -- Avviso se tempo basso if tab.timeLeft < 60 and not isRefueling then monitor.setCursorPos(1, line) monitor.setTextColor(colors.red) monitor.write("! ATTENZIONE !") if line < height - 1 then line = line + 1 monitor.setCursorPos(1, line) monitor.setTextColor(colors.orange) local warning = "Uranio in esaurimento" if string.len(warning) > width then warning = string.sub(warning, 1, width) end monitor.write(warning) end end else -- Nessun dato disponibile monitor.setCursorPos(1, line) monitor.setTextColor(colors.orange) monitor.write("Dati non disponibili") end -- Footer if line < height then monitor.setCursorPos(1, height) monitor.setTextColor(colors.gray) monitor.write(string.rep("=", width)) end return true end) if not success then return false end return true end -- Funzione per ottenere lo stato del reattore in modo sicuro function getReactorState(s) if not s then return nil, nil, nil, nil, "Peripheral non valido" end local success, uuid, state, title, tab = pcall(function() return s.get(1) end) if not success then return nil, nil, nil, nil, "Errore nella lettura del reattore: " .. tostring(uuid) end if not tab or type(tab) ~= "table" then return uuid, state, title, nil, "Dati reattore non validi" end if tab.timeLeft == nil or type(tab.timeLeft) ~= "number" then return uuid, state, title, tab, "timeLeft non valido" end return uuid, state, title, tab, nil end -- Costanti per la logica RS Latch con isteresi (sostituisce i gate hardware) local REFUEL_THRESHOLD_LOW = 10 -- Soglia per attivare rifornimento (Set) local REFUEL_THRESHOLD_HIGH = 15 -- Soglia per disattivare rifornimento (Reset) - isteresi -- Costanti per i colori bundled redstone local COLOR_ORANGE = 2 -- Arancione: modalità normale (input/output materiale da arricchire) local COLOR_WHITE = 1 -- Bianco: modalità rifornimento (input/output cellule uranio) local COLOR_NONE = 0 -- Nessun colore: sistema fermo -- Funzione che implementa la logica RS Latch integrata -- Gestisce la commutazione tra arancione (normale) e bianco (rifornimento) con isteresi -- Sostituisce il gate RS Latch hardware function updateReactorMode(timeLeft, currentMode) -- currentMode può essere: "normal" (arancione), "refuel" (bianco), o nil (inizializzazione) if not timeLeft or timeLeft < 0 then return COLOR_NONE, "error" -- Errore: dati non validi end -- Logica RS Latch con isteresi: -- - Set (rifornimento): quando timeLeft < REFUEL_THRESHOLD_LOW -- - Reset (normale): quando timeLeft >= REFUEL_THRESHOLD_HIGH -- - Isteresi: tra LOW e HIGH mantiene lo stato corrente (evita oscillazioni) if timeLeft < REFUEL_THRESHOLD_LOW then -- Set: attiva modalità rifornimento (bianco) return COLOR_WHITE, "refuel" elseif timeLeft >= REFUEL_THRESHOLD_HIGH then -- Reset: attiva modalità normale (arancione) return COLOR_ORANGE, "normal" else -- Zona di isteresi (tra LOW e HIGH): mantieni lo stato corrente if currentMode == "refuel" then return COLOR_WHITE, "refuel" else -- Se non c'è uno stato corrente, usa il valore più vicino alla soglia -- Se siamo appena scesi sotto HIGH, rimani in normale -- Se siamo appena saliti sopra LOW, vai in rifornimento -- Per sicurezza, se non c'è stato, considera normale return COLOR_ORANGE, "normal" end end end -- Funzione che implementa la logica XNOR integrata -- Garantisce che arancione e bianco non siano mai attivi contemporaneamente -- (già gestito automaticamente da setBundledOutput, ma questa funzione verifica la logica) function validateOutput(outputValue) -- Verifica che l'output sia valido (solo arancione, bianco o nessuno) if outputValue == COLOR_ORANGE or outputValue == COLOR_WHITE or outputValue == COLOR_NONE then return true, outputValue else -- Output non valido: spegni tutto per sicurezza return false, COLOR_NONE end end -- Funzione di compatibilità per bundled redstone (ComputerCraft 1.5 vs versioni più recenti) local function setBundledOutputCompat(side, color) -- Prova prima con rs (versioni recenti) if rs and rs.setBundledOutput then return rs.setBundledOutput(side, color) -- Fallback a redstone (ComputerCraft 1.5 per Minecraft 1.4.7) elseif redstone and redstone.setBundledOutput then return redstone.setBundledOutput(side, color) else error("API bundled redstone non disponibile") end end -- Funzione per impostare output redstone in modo sicuro con logica gate integrata function setOutputSafely(outputValue, errorMsg) -- Valida l'output (logica XNOR: solo un colore alla volta) local isValid, safeValue = validateOutput(outputValue) if not isValid then print("ATTENZIONE: Output non valido, uso valore sicuro") outputValue = safeValue end local success, err = pcall(function() setBundledOutputCompat("back", outputValue) end) if not success then print("ERRORE: Impossibile impostare output redstone: " .. tostring(err)) if errorMsg then print(errorMsg) end return false end return true end function clear() term.clear() term.setCursorPos(1, 1) end clear() -- Rilevamento versione ComputerCraft e API disponibile local ccVersion = "sconosciuta" local bundledAPI = "nessuna" if rs and rs.setBundledOutput then bundledAPI = "rs.setBundledOutput (ComputerCraft recente)" ccVersion = "recente" elseif redstone and redstone.setBundledOutput then bundledAPI = "redstone.setBundledOutput (ComputerCraft 1.5 - MC 1.4.7)" ccVersion = "1.5" else bundledAPI = "NON DISPONIBILE" print("ATTENZIONE: API bundled redstone non trovata!") print("Il programma potrebbe non funzionare correttamente") end print("Versione ComputerCraft rilevata: " .. ccVersion) print("API bundled redstone: " .. bundledAPI) print("") -- Inizializzazione sicura local s, err = getPeripheral() if not s then print("ERRORE CRITICO: " .. err) print("Premere un tasto per riprovare...") os.pullEvent("key") os.reboot() end -- Inizializzazione monitor local monitor, monitorSide, monitorErr = getMonitor() if monitor then print("Monitor trovato sul lato: " .. monitorSide) else print("ATTENZIONE: " .. (monitorErr or "Monitor non trovato")) print("Il programma continuera' senza monitor") end -- Lettura iniziale dello stato local uuid, state, title, tab, err = getReactorState(s) if err then print("ERRORE: " .. err) print("Verificare la connessione del reattore") if monitor then updateMonitor(monitor, nil, nil, nil, nil, false, err) end print("Premere un tasto per continuare...") os.pullEvent("key") end if tab and tab.timeLeft == 0 then print("Caricare il reattore e premere un tasto") if monitor then updateMonitor(monitor, uuid, state, title, tab, false, "Reattore vuoto - caricare uranio") end os.pullEvent("key") clear() end print("Pronto") print("Sistema di sicurezza attivo") print("Logica gate integrata (XNOR + RS Latch) attiva") -- Variabili per il controllo di sicurezza e logica gate integrata local lastTimeLeft = nil local consecutiveErrors = 0 local maxErrors = 5 local currentReactorMode = nil -- "normal", "refuel", o nil (inizializzazione) local lastOutputValue = COLOR_NONE -- Traccia l'ultimo output per evitare cambi inutili -- Inizializzazione stato iniziale basato sul timeLeft corrente if tab and tab.timeLeft then local initOutput, initMode = updateReactorMode(tab.timeLeft, nil) currentReactorMode = initMode lastOutputValue = initOutput -- Imposta l'output iniziale if initMode == "normal" then setOutputSafely(COLOR_ORANGE, "Impossibile impostare modalità iniziale normale") print("Stato iniziale: MODALITA' NORMALE (arancione)") elseif initMode == "refuel" then setOutputSafely(COLOR_WHITE, "Impossibile impostare modalità iniziale rifornimento") print("Stato iniziale: MODALITA' RIFORNIMENTO (bianco)") else setOutputSafely(COLOR_NONE, "Impossibile impostare stato iniziale") print("Stato iniziale: ERRORE") end else -- Se non ci sono dati, inizia in modalità normale currentReactorMode = "normal" lastOutputValue = COLOR_ORANGE setOutputSafely(COLOR_ORANGE, "Impossibile impostare stato iniziale") print("Stato iniziale: MODALITA' NORMALE (dati non disponibili)") end if monitor then local isRefueling = (currentReactorMode == "refuel") updateMonitor(monitor, uuid, state, title, tab, isRefueling, nil) end while true do clear() print("Caricamento automatico materiale da arricchire in funzione") -- Verifica periodica della connessione del peripheral if consecutiveErrors > 3 then print("Riconnessione al peripheral...") s, err = getPeripheral() if not s then print("ERRORE: " .. err) print("Attesa 5 secondi prima di riprovare...") sleep(5) consecutiveErrors = 0 else consecutiveErrors = 0 print("Riconnesso con successo") end end -- Verifica e riconnessione monitor se necessario if not monitor or not pcall(function() monitor.getSize() end) then monitor, monitorSide, monitorErr = getMonitor() if monitor then print("Monitor riconnesso sul lato: " .. monitorSide) end end -- Lettura sicura dello stato uuid, state, title, tab, err = getReactorState(s) if err then consecutiveErrors = consecutiveErrors + 1 print("ERRORE: " .. err) print("Tentativo " .. consecutiveErrors .. "/" .. maxErrors) -- Aggiorna monitor con errore (mantieni lo stato corrente) if monitor then local isRefuelingMonitor = (currentReactorMode == "refuel") updateMonitor(monitor, uuid, state, title, tab, isRefuelingMonitor, err) end if consecutiveErrors >= maxErrors then print("ERRORE CRITICO: Troppi errori consecutivi") print("Arresto sistema per sicurezza") -- In caso di errore critico, spegni tutto (COLOR_NONE) setOutputSafely(COLOR_NONE, "Sistema fermato per sicurezza") currentReactorMode = "error" lastOutputValue = COLOR_NONE if monitor then updateMonitor(monitor, uuid, state, title, tab, false, "SISTEMA FERMATO - Troppi errori") end print("Premere un tasto per riprovare...") os.pullEvent("key") consecutiveErrors = 0 -- Ripristina lo stato iniziale dopo l'errore currentReactorMode = nil else sleep(2) end else consecutiveErrors = 0 -- Validazione dei dati if tab and tab.timeLeft then -- Verifica coerenza dei dati (timeLeft non dovrebbe aumentare) if lastTimeLeft ~= nil and tab.timeLeft > lastTimeLeft + 5 then print("ATTENZIONE: Rilevato incremento anomalo del tempo") print("Possibile errore di lettura, attesa...") sleep(3) else lastTimeLeft = tab.timeLeft end local hours = math.floor(tab.timeLeft / 3600) local minutes = math.floor((tab.timeLeft % 3600) / 60) local seconds = tab.timeLeft % 60 print("Tempo rimanente: " .. hours .. " ore, " .. minutes .. " minuti, " .. seconds .. " secondi") -- LOGICA GATE INTEGRATA (sostituisce XNOR e RS Latch hardware) -- Determina la modalità del reattore basandosi sul timeLeft local outputValue, newMode = updateReactorMode(tab.timeLeft, currentReactorMode) -- Aggiorna lo stato solo se è cambiato if newMode ~= currentReactorMode then local oldMode = currentReactorMode currentReactorMode = newMode if newMode == "refuel" then clear() print("ATTENZIONE: Uranio in esaurimento") print("Modalità RIFORNIMENTO attivata (bianco)") print("Input/output materiale da arricchire: DISATTIVATI") print("Input/output cellule uranio: ATTIVI") elseif newMode == "normal" then if oldMode == "refuel" then print("Rifornimento completato") end print("Modalità NORMALE attivata (arancione)") print("Input/output materiale da arricchire: ATTIVI") print("Input/output cellule uranio: DISATTIVATI") end end -- Imposta l'output solo se è cambiato (ottimizzazione) if outputValue ~= lastOutputValue then local modeName = "normale" if newMode == "refuel" then modeName = "rifornimento" elseif newMode == "error" then modeName = "errore" end setOutputSafely(outputValue, "Impossibile impostare modalità " .. modeName) lastOutputValue = outputValue if outputValue == COLOR_ORANGE then print("Output: ARANCIONE (normale)") elseif outputValue == COLOR_WHITE then print("Output: BIANCO (rifornimento)") elseif outputValue == COLOR_NONE then print("Output: SPENTO (errore)") end end -- Aggiorna monitor con dati attuali local isRefueling = (newMode == "refuel") if monitor then updateMonitor(monitor, uuid, state, title, tab, isRefueling, nil) end else print("ERRORE: Dati reattore non validi") consecutiveErrors = consecutiveErrors + 1 end end sleep(1) end