Bagaimana seharusnya sirkuit atau sistem tenaga (seperti redstone di Minecraft) diimplementasikan

8

Saya ingin menerapkan sistem tenaga seperti sistem redstone di minecraft.

Saya memiliki n sumber daya dan kabel m. Jika saya mencabut sumber listrik atau kabel, sirkuit akan mati. model sistem kabel

Bagaimana cara menghindari lingkaran? Jika setiap kabel dengan status "aktif" menyalakan kabel di dekatnya, saya dapat membuat lingkaran tanpa batas di mana tidak ada sumber daya yang terlibat (lihat gambar). Situs Plus adalah bahwa ia berjalan di T = m

Saya dapat mengirim daya meledak melalui grafik mulai dari setiap sumber daya dan di setiap panggilan pembaruan saya mematikan setiap kabel. Masalahnya adalah itu berjalan di T = n * m.

Apakah ada praktik terbaik? Di Minecraft sistem redstone sangat lambat jadi saya pikir saya mengabaikan sesuatu.

EDIT: Sistem harus bekerja tanpa kerusakan berbasis jarak.

Benedikt S. Vogler
sumber
Ini tergantung pada model apa yang Anda coba implementasikan. Misalnya, sumber daya dapat menyediakan x unit daya yang dikonsumsi saat digunakan. Model lain adalah bahwa sumber daya Anda memiliki potensi yang membatasi beban yang dapat Anda tempatkan pada rangkaian yang berfungsi selama Anda memasok daya ke sumber daya Anda.
user3730788

Jawaban:

7

Perambatan rekursif. Misalnya, Anda memiliki lampu yang dihubungkan oleh benda kabel N ke baterai. Lampu menanyakan kabel ke-N apakah kabel menyala (ini kabel yang terpasang langsung ke lampu). Kabel Nth kemudian menanyakan kabel N-1 apakah itu aktif dan sebagainya. Setiap kali suatu objek ditanya apakah itu diaktifkan atau tidak, itu menetapkan lastEvaluatedvariabel ke waktu bingkai saat ini. Rekursi itu keluar pada simpul ujung, seperti baterai, atau ketika mencapai objek yang sudah dievaluasi bingkai itu (ini menghindari rekursi tak terbatas). Propagasi ini hanya terjadi ketika sistem berubah. Perubahan termasuk menambah / menghapus bagian atau sakelar yang sedang di-toggle.

Tidak ada pembusukan jarak atau pengekangan serupa dengan sistem ini. Saya menggunakannya untuk membuat simulator gerbang logika dan berfungsi untuk berbagai contoh logika seperti flip-flop.

MichaelHouse
sumber
Ini. Plus saya akan menambahkan referensi ke sumber daya. Jika suatu elemen diubah, beri tahu sumber yang dirujuk untuk memperbarui jaringan yang dihidupkannya. Dengan cara ini Anda tidak hanya harus memperbarui ketika sesuatu berubah, Anda juga tahu elemen apa yang terpengaruh. Perubahan dalam jaringan Anda juga dapat diidentifikasi dengan mudah: apakah perubahan memerlukan evaluasi ulang atau tidak, dll.
Felsir
@Felsir Anda bisa melakukan itu, tetapi saya tidak akan merekomendasikannya. Ini meningkatkan kompleksitas tanpa banyak keuntungan. Mungkin ada beberapa sumber daya dan beberapa sumber per sumber. Akan lebih mudah hanya mempercayai evaluasi, dan itu benar-benar tidak intensif sumber daya.
MichaelHouse
Solusinya tidak memiliki satu hal yang saya pikir: jika Anda memiliki kabel di tengah dan satu memiliki kekuatan dan ujung lainnya tidak hanya satu akan mendapatkan perubahan. Anda pada dasarnya telah membuat pohon dengan variabel "lastEvauluated" dengan melucuti lingkaran. Sekarang perubahan menyebar ke atas di pohon tetapi tidak turun. Saya akan mencobanya dalam implementasi saya dengan mendorong perubahan ke bawah setelah menariknya ke atas.
Benedikt S. Vogler
Saya menambahkan solusi untuk jawaban Anda dalam satu pengeditan karena penambahan saya pada algoritma berfungsi.
Benedikt S. Vogler
1
@ Benedikt Anda menggambarkan perilaku yang diharapkan. Itu karena sistem saya menggunakan input dan output. DAN gerbang dan gerbang ATAU bukan dua arah (ini menggunakan implementasi dioda). Jadi, jika saya ingin kekuatan untuk melakukan perjalanan ke sesuatu di luar simpul B, saya akan mengarahkan output seperti itu. Saya sarankan Anda membuat jawaban baru untuk menggambarkan sistem dua arah Anda.
MichaelHouse
2

Di minecraft ada peluruhan berbasis jarak dengan jarak peluruhan yang sangat pendek (kisaran 16 blok).

Apa yang Anda butuhkan adalah tes konektivitas antara grafik .

Salah satu cara untuk melakukannya adalah berulang kali mengambil setiap sisi dan menggabungkan node yang terhubung dan menjadi satu node. Setelah semua tepi hilang, Anda akan berakhir dengan simpul untuk setiap jaringan. Maka daya kirim itu sepele.

aneh ratchet
sumber
Menyimpan subgraph dalam sebuah node tampaknya sangat pintar, namun saya harus berpikir sedikit tentang implementasi konkret karena jawaban ini terasa agak kabur hanya menyebutkan "tes konektivitas antar grafik" yang tampaknya menjadi bagian yang agak penting dari solusi ini.
Benedikt S. Vogler
sebenarnya deskripsi itu adalah varian pada algoritma Karger untuk menemukan potongan minimum. Tetapi alih-alih Anda melanjutkan sampai tidak ada lagi tepi untuk berkontraksi.
ratchet freak
1

Blok bertenaga memiliki beberapa koneksi input / output, tetapi pada titik awal, kita tidak tahu kapan itu input atau output.

Setiap blok memiliki "Tegangan" yang merupakan energi yang sampai padanya dikurangi yang hilang / digunakan.

Blok bertenaga akan memberikan daya ke semua blok sekitarnya, dan setiap blok mengambil sebagai input tegangan yang lebih tinggi dari blok sekitarnya. Anda juga dapat menyulitkan sistem dengan mendefinisikan Intensitas, tetapi saya akan tetap menggunakan Voltage hanya untuk kesederhanaan.

Setiap kali perubahan dilakukan ke sirkuit, dengan menambahkan / menghapus blok, atau oleh sirkuit itu sendiri, perubahan harus disebarkan ke semua sirkuit sampai stabilitas.

Saya sarankan Anda untuk mendesain antarmuka untuk objek bertenaga apa pun (kubus dalam 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;
};

Jadi seandainya Anda menerapkan addSibling dan removeSibling, bagian terpenting adalah fungsi merambat:

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);
    }
}

Sebagai solusi rekursif, setiap blok harus mengurangi sedikit energi, tidak pernah meningkatkannya. Sumber daya dapat menetapkan nilai tetap, tetapi tidak pernah meningkat berdasarkan input. Itu seharusnya tidak menjadi masalah karena semua sistem "nyata" bekerja dengan cara ini.

Adrian Maire
sumber
Tetapi dengan solusi ini setiap loop membutuhkan panggilan "n = 1 / pengurangan" sebelum dimatikan. Bukankah ini agak mahal?
Benedikt S. Vogler
Tidak, Anda hanya memperbarui tentang perubahan: ketika Anda membuat / menghapus / mengedit blok, atau ketika sebuah blok menghasilkan perubahan aktif. Jika Anda melihat kode, sebagian besar perubahan hanya akan menyebar beberapa blok. Tentu saja, Anda dapat menyederhanakan grafik sebagai @ BenediktS.Vogler berkata, tapi IMHO, itu sudah cukup cepat. Mari kita bayangkan 1000 blok aktif di zona aktif, yang sudah merupakan mekanisme besar. Bahkan dalam kasus terburuk dari pembaruan penuh hanya beberapa operasi * 1000, yang singkat. Biasanya hanya beberapa blok yang diperbarui
Adrian Maire