回路または電源システム(Minecraftのレッドストーンなど)を実装する方法


8

Minecraftにレッドストーンシステムのような電源システムを実装したい。

n個の電源とm個のケーブルがあります。電源またはケーブルを外すと、回路がオフになります。 ケーブルシステムのモデル

サークルを回避するにはどうすればよいですか?ステータスが「オン」の各ケーブルが近くのケーブルに電力を供給している場合、電源が含まれていない無限の円を作成できます(画像を参照)。プラスのサイトはT = mで実行されるということです

すべての電源から開始してグラフを介してパワーバーストを送信でき、各更新コールですべてのケーブルをオフにしました。問題は、T = n * mで実行されることです。

ベストプラクティスはありますか?Minecraftではレッドストーンシステムが非常に遅いため、見落としがあったと思います。

編集:システムは、距離ベースの減衰なしで動作するはずです。


これは、実装しようとしているモデルによって異なります。たとえば、電源は使用時に消費されるx単位の電力を提供できます。別のモデルは、電源に電源を供給している限り機能する回路にかけることができる負荷を制限する可能性がある電源であるということです。
user3730788

回答:


7

再帰的な伝播。たとえば、N個のケーブルオブジェクトによってランプがバッテリーに接続されているとします。ランプは、電源が入っているかどうかをN番目のケーブルに問い合わせます(これはランプに直接接続されているケーブルです)。N番目のケーブルは、電源が入っているかどうかなどをN-1ケーブルに尋ねます。オブジェクトに電源が入っているかどうかが尋ねられるたびに、lastEvaluated変数は現在のフレーム時間に設定されます。再帰は、バッテリーなどのエンドノードで終了するか、すでにそのフレームで評価されているオブジェクトに到達すると終了します(これにより、無限再帰が回避されます)。これらの伝播は、システムが変更されたときにのみ発生します。変更には、切り替えられるパーツまたはスイッチの追加/削除が含まれます。

このシステムでは、距離の減衰や同様の制限はありません。私はそれを使用して論理ゲートシミュレーターを作成し、フリップフロップのようなさまざまな論理例で機能します。


この。さらに、電源への参照を追加します。要素が変更された場合、参照されているソースに、それが電力を供給しているネットワークを更新するように伝えます。これにより、何かが変更されたときに更新する必要があるだけでなく、影響を受ける要素もわかります。ネットワークの変更も簡単に特定できます。変更には再評価が必要かどうかなど
Felsir

@Felsirできますが、お勧めしません。それは多くの利益なしで複雑さを増やします。複数の電源があり、ソースごとに複数のシンクがあります。評価を信頼するだけの方が簡単であり、リソースをそれほど消費しません。
MichaelHouse

解決策には、私が考える1つ欠けている点があります。ケーブルが真ん中にあり、1つに電力があり、もう一方の端にケーブルがある場合、1つだけでは変更が行われません。基本的に、円を取り除いて「lastEvauluated」変数を持つツリーを作成しました。これで、変更はツリーの上方に伝搬しますが、下方には伝搬しません。私の実装では、プルアップした後、変更をプッシュダウンして試してみます。
Benedikt S. Vogler

アルゴリズムへの私の追加が機能するため、私は1つの編集で回答にソリューションを追加しました。
Benedikt S. Vogler

1
@Benedikt予想される動作について説明します。それは、私のシステムが入力と出力を使用しているためです。ANDゲートとORゲートは双方向ではありません(これらはダイオード実装を使用しています)。そのため、Bノードを超えて何かに移動する力が必要な場合は、出力をその方向に向けます。あなたの双方向システムを説明するために新しい答えを作成することをお勧めします。
MichaelHouse

2

Minecraftでは、非常に短い減衰距離(16ブロックの範囲)の距離ベースの減衰があります。

あなたはそれ必要なものグラフ間の接続性テストです。

これを行う1つの方法は、各エッジを繰り返し取得し、接続されたノードを1つのノードに結合することです。すべてのエッジがなくなると、各ネットワークのノードになります。そうすれば、電力を送るのは簡単です。


ノードにサブグラフを保存することは非常に賢明に思えますが、この解決策のかなり重要な部分であると思われる「グラフ間の接続テスト」についてのみこの回答が少し曖昧に感じられるため、具体的な実装について少し考える必要があります。
Benedikt S. Vogler、2015年

実際、その説明は、最小カットを見つけるためのKargerのアルゴリズムの変形です。しかし、代わりに、収縮するエッジがなくなるまで続けます。
ラチェットフリーク

1

パワードブロックには複数の入力/出力接続がありますが、最初は、それが入力または出力であるかどうかはわかりません。

各ブロックには、そこに到達するエネルギーから失われた/使用されたエネルギーを差し引いた「電圧」があります。

給電ブロックは周囲のすべてのブロックに電力を供給し、各ブロックは周囲のブロックからのより高い電圧を入力として受け取ります。強度を定義してシステムを複雑にすることもできますが、ここでは単純にするために電圧のみを使用します。

ブロックを追加/削除することにより、または回路自体によって回路に変更が行われるたびに、変更は安定するまですべての回路に伝播する必要があります。

動力を与えられたオブジェクト(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;
};

したがって、addSiblingとremoveSiblingを実装するとすると、最も重要な部分は伝搬関数です。

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

再帰的な解決策として、各ブロックはエネルギーを少し減らし、決して増やしてはなりません。動力源は固定値を設定できますが、入力に基づいて増加することはありません。すべての「実際の」システムがこのように機能するため、これは問題になりません。


ただし、このソリューションでは、シャットダウンする前に各ループで「n = 1 /減少」の呼び出しが必要です。これは少し高価ではありませんか?
Benedikt S. Vogler、2015年

いいえ、変更時にのみ更新します。ブロックを作成/削除/編集するとき、またはブロックがアクティブな変更を生成するとき。コードを見ると、ほとんどの変更は数ブロックしか伝播しません。もちろん、@ BenediktS.Voglerが言うようにグラフを簡略化することもできますが、私見では、すでにかなり高速です。すでに巨大なメカニズムであるアクティブゾーンで1000のアクティブブロックを想定します。完全更新の最悪の場合でも、それは数回の操作* 1000のみであり、短いです。通常、更新されるブロックはごくわずかです
Adrian Maire
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.