3Dボクセルベースの部屋が効率的に密閉されているかどうかを判断する方法


10

ボクセルベースの3Dルームで大きな部屋が密閉されているかどうかを効率的に判断する際に、いくつか問題がありました。私は助けを求めずに問題を解決するために全力を尽くしましたが、あきらめるのに十分なほど試みなかったので、助けを求めています。

明確にするために、部屋に穴が開いていないことを密封しています。部屋が密閉されているかどうかを確認する酸素シーラーと、酸素入力レベルに応じて密閉する酸素シーラーがあります。

今、これが私がやっている方法です:

  • シーラータイルの上のブロックから始まり(ベントはシーラーの上面にあります)、6つの隣接する方向すべてに再帰的にループします
  • 隣接するタイルが完全な非真空タイルである場合は、ループを続行します
  • 隣接するタイルがいっぱいではない場合、またはバキュームタイルである場合、隣接するブロックが再帰的に満たされているかどうかを確認します。
  • タイルがチェックされるたびに、カウンターをデクリメントします
  • カウントが0に達した場合、最後のブロックがバキュームタイルに隣接している場合は、領域がシールされていないことを返します
  • カウントがゼロになり、最後のブロックがバキュームタイルではない場合、またはカウンターがゼロになる前に再帰ループが終了する(バキュームタイルが残っていない)場合、領域はシールされます。

エリアがシールされていない場合は、いくつかの変更を加えてループを再度実行します。

  • 真空タイルの代わりに「通気性のある」タイルの隣接ブロックをチェックする
  • 減少するカウンターを使用する代わりに、隣接する「通気性のある」タイルが見つからなくなるまで続けます。
  • ループが終了したら、チェックされた各ブロックをバキュームタイルに設定します。

これが私が使用しているコードです:http : //pastebin.com/NimyKncC

問題:

私は3秒ごとにこのチェックを実行しています。シーラーは数百のブロックをループする必要がある場合があり、酸素シーラーが多い大きな世界では、数秒ごとにこれらの複数の再帰ループがCPUで非常に困難になる場合があります。

最適化の経験が豊富な方が私に手を貸してくれないか、少なくとも私を正しい方向に向けられるかどうか疑問に思っていました。本当にありがとう。


物事がいつ変化するかを確認することから始めればよいでしょう。3秒ごとにチェックするのはやり過ぎのようです。ボクセルが変化すると、シールが壊れる可能性があるからです。密閉された部屋を構成するボクセルが変更された場合、その部屋を再チェックするようにマークできます。そうでない場合は、気にしないでください。
MichaelHouse

この3秒間に数百のボクセルが変更される可能性があるため、近くで何か変更があったかどうかを確認するよりも、定期的にボクセルを変更する方が効率的だと思いました。私はそれで実験します。
NigelMan1010 2013年

まあ、数百のボクセルが3秒の時間枠で変化する可能性がある場合は、パフォーマンスに多くの問題が発生する可能性があります。コードのプロファイリングを開始して、非効率を見つけます。幸運を!
MichaelHouse

回答:


3

最良のソリューションは、予想される部屋のサイズなど、複数の要素に依存します。

  1. 何かが実際に変化しているときにのみ、このチェックを行います。

アプローチ1:

A *を使用して、通気孔から通気孔の上のタイル/通気孔自体、または真空と呼ばれるタイルまでのパスを見つけることができます。パスが見つかった場合、部屋は封印されていません。これは現在のアプローチとそれほど変わらないが、より高速になるはずです。見つかったら、「塗りつぶし」を行って、タイルを真空に設定します。

アプローチ2:

多分あなたの外側の構造はそれほど複雑ではありません-部屋の下に表面があることを考えると、6方向すべてに移動する必要はないので、表面に沿って移動し、すべてのタイルを真空としてマークする必要があります。


0

再帰的な検索を行うとき、同じボクセルを複数回チェックしていないことを確認していますか?アルゴリズムの説明からはわかりませんが、ボクセルを既に再帰的に展開したかどうかを示すためのフラグがあるはずです。

また、Byte56が言ったように、物事が変化したときにのみリークをチェックする必要もあります。これにより、変更の頻度に応じて、行う作業量を大幅に最小限に抑えることができます。アルゴリズムの連続する呼び出し間で情報をキャッシュすることもできます。これにより、最初の呼び出し後に実行する計算量を簡単にすることができます。

編集:

私はあなたのコードのいくつかを見ました。最初の段落のように、LinkedListを使用してボクセルが既にチェックされているかどうかを示しているようです。これにLinkedList以外のものを使用すると、より良い結果が得られる場合があります。おそらくHashSetなどを試してみませんか?これにより、チェックメソッドの複雑さがO(n)からO(1)に削減されます。


はい、それを "checked"というLinkedListに追加し、チェックする前にそのリストに位置が含まれているかどうかをチェックしています。何百ものボクセルがその3秒間に変更された可能性があるため、何かが変更されたかどうかを確認することも、CPUに非常に負担がかかると思いました。この状況で、ハッシュセットがリンクリストとどのように比較されるかはわかりますが、ありがとうございます。
NigelMan1010 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.