Come dovrebbe essere implementato un circuito o un sistema di alimentazione (come la pietra rossa in Minecraft)


8

Voglio implementare un sistema di alimentazione come il sistema redstone in Minecraft.

Ho n fonti di alimentazione e m cavi. Se scollego la fonte di alimentazione o un cavo, il circuito dovrebbe spegnersi. modello di sistema via cavo

Come posso evitare le cerchie? Se ogni cavo con lo stato "on" alimenta i cavi vicini, posso creare cerchi infiniti in cui non è coinvolta alcuna fonte di alimentazione (vedi immagine). Inoltre il sito è che funziona in T = m

Potrei inviare la scarica di energia attraverso il grafico a partire da ogni fonte di alimentazione e in ogni chiamata di aggiornamento spengo ogni cavo. Il problema è che funziona in T = n * m.

Esiste una buona pratica? In Minecraft il sistema di pietra rossa era molto lento, quindi penso di aver trascurato qualcosa.

EDIT: il sistema dovrebbe funzionare senza un decadimento basato sulla distanza.


Questo dipende dal modello che stai tentando di implementare. Ad esempio, una fonte di alimentazione potrebbe fornire x unità di potenza che vengono consumate durante l'uso. Un altro modello è che la tua fonte di energia ha un potenziale che limita il carico che puoi posizionare sul circuito che funziona fintanto che fornisci energia alla tua fonte di energia.
user3730788

Risposte:


7

Propagazione ricorsiva. Ad esempio, hai una lampada collegata da oggetti cavo N a una batteria. La lampada chiede all'ennesimo cavo se è alimentata (questo è il cavo collegato direttamente alla lampada). L'ennesimo cavo chiede quindi al cavo N-1 se è alimentato e così via. Ogni volta che viene chiesto a un oggetto se è alimentato o meno, imposta una lastEvaluatedvariabile sul tempo di frame corrente. La ricorsione finisce in fondo su un nodo finale, come una batteria, o quando raggiunge un oggetto che è già stato valutato in quel frame (questo evita la ricorsione infinita). Queste propagazioni si verificano solo quando il sistema cambia. Le modifiche includono l'aggiunta / rimozione di parti o interruttori da attivare.

Non vi è alcuna riduzione della distanza o restrizioni simili con questo sistema. L'ho usato per creare un simulatore di gate logici e funziona per vari esempi logici come un flip-flop.


Questo. Inoltre aggiungerei un riferimento alla fonte di energia. Se un elemento viene modificato, dire all'origine di riferimento di aggiornare la rete che sta alimentando. In questo modo non solo devi aggiornare quando qualcosa cambia, ma sai anche quali elementi sono interessati. I cambiamenti nella tua rete possono anche essere identificati facilmente: un cambiamento richiederebbe una rivalutazione o meno, ecc.
Felsir,

@Felsir Potresti farlo, ma non lo consiglierei. Aumenta la complessità senza molto guadagno. Possono esserci più fonti di energia e più lavandini per fonte. Sarebbe più semplice fidarsi solo della valutazione, e in realtà non richiede molte risorse.
MichaelHouse

Penso che la soluzione manchi di una cosa: se hai un cavo nel mezzo e uno ha potenza e l'altra estremità non solo uno otterrà il cambiamento. Fondamentalmente hai creato un albero con la variabile "lastEvauluated" rimuovendo i cerchi. Ora il cambiamento si propaga verso l'alto nell'albero ma non verso il basso. Lo proverò nella mia implementazione spingendo le modifiche verso il basso dopo averle tirate su.
Benedikt S. Vogler,

Ho aggiunto la soluzione alla tua risposta in una modifica perché la mia aggiunta all'algoritmo funziona.
Benedikt S. Vogler,

1
@Benedikt Descrivi il comportamento previsto. Questo perché il mio sistema utilizza input e output. Le porte AND e le porte OR non sono bidirezionali (utilizzano l'implementazione dei diodi). Quindi, se volessi che il potere viaggiasse verso qualcosa oltre il nodo B, avrei diretto un output in quel modo. Ti suggerirei di creare una nuova risposta per descrivere il tuo sistema bidirezionale.
MichaelHouse

2

In Minecraft c'è un decadimento basato sulla distanza con una distanza di decadimento molto breve (intervallo di 16 blocchi).

Cosa ti serve un test di connettività tra grafici .

Un modo per farlo sarebbe prendere ripetutamente ogni fronte e combinare i nodi collegati e in un singolo nodo. Dopo che tutti i bordi sono stati eliminati, verrà visualizzato un nodo per ciascuna rete. Quindi inviare il potere è banale.


Salvare un sottografo in un nodo sembra molto intelligente, tuttavia devo pensare un po 'a un'implementazione concreta perché questa risposta sembra un po' vaga solo menzionando il "test di connettività tra grafici" che sembra essere una parte piuttosto importante di questa soluzione.
Benedikt S. Vogler,

in realtà quella descrizione è una variante dell'algoritmo di Karger per trovare tagli minimi. Ma invece continui fino a quando non ci sono più bordi da contrarre.
maniaco del cricchetto,

1

Un blocco alimentato ha diverse connessioni input / output, ma a un punto iniziale non sappiamo quando è input o output.

Ogni blocco ha una "Tensione" che è l'energia che arriva ad esso meno il perso / usato.

Un blocco alimentato fornirà energia a tutti i blocchi circostanti e ogni blocco prende come input la tensione più alta dai blocchi circostanti. Potresti anche complicare il sistema definendo un'intensità, ma rimarrò con la tensione solo per semplicità.

Ogni volta che viene eseguita una modifica al circuito, aggiungendo / rimuovendo blocchi o dal circuito stesso, la modifica deve essere propagata a tutto il circuito fino alla stabilità.

Ti suggerirei di progettare un'interfaccia per qualsiasi oggetto alimentato (cubo in MC):

class PowerInterface
{
protected:
    std::vector<shared_ptr<PowerInterface>> sibling;

    double energy=0;
    bool   isActive = false;

    virtual void propagate(double inEnergy) = 0;

    virtual void addSibling(shared_ptr<PowerInterface> newSibling) = 0;
    virtual void removeSibling( shared_ptr<PowerInterface> remSibling) =0;
};

Supponendo quindi di implementare addSibling e removeSibling, la parte più importante è la funzione di propagazione:

void PoweredCube::propagate( double inEnergy ) 
{
    // Define the behaviour
    energy = inEnergy-1.0; // Normal device
    energy = inEnergy-0.1; // Normal cable
    energy = 10.0;         // Normal source of power.

    if (energy<0.0)
    { 
        energy = 0.0;
        isActive = false;
        // No energy, so do not propagate anymore
        return;
    }
    isActive = true;

    // Propagate
    for (auto &s: sibling)
    {
        // Only propagate to sibling with less energy. 
        if (energy > s->energy) s->propagate( energy);
    }
}

Come soluzione ricorsiva, ogni blocco dovrebbe ridurre un po 'l'energia, non aumentarla mai. La fonte di energia può impostare un valore fisso, ma non aumentare mai in base agli input. Questo non dovrebbe essere un problema poiché tutti i sistemi "reali" funzionano in questo modo.


Ma con questa soluzione ogni loop necessita di chiamate "n = 1 / diminuisci" prima di essere chiuso. Non è un po 'costoso?
Benedikt S. Vogler,

No, si aggiorna solo sulle modifiche: quando si crea / elimina / modifica un blocco o quando un blocco produce una modifica attiva. Se si osserva il codice, la maggior parte delle modifiche si propagherà solo per alcuni blocchi. Ovviamente, potresti semplificare il grafico come dice @ BenediktS.Vogler, ma IMHO, sarà già abbastanza veloce. Consente di utilizzare 1000 blocchi attivi nella zona attiva, che è già un meccanismo enorme. Anche nel caso peggiore di un aggiornamento completo sono solo poche operazioni * 1000, che è breve. Di solito vengono aggiornati solo pochi blocchi
Adrian Maire,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.