ルービックキューブを解くソフトウェアを開発している場合、キューブをどのように表現しますか?
これは ACM Paper がルービックキューブを表すために使用したいくつかの代替方法を説明し、それらを相互に比較します。悲しいことに、私は全文を入手するためのアカウントを持っていませんが、説明は次のように述べています:
ルービックキューブの7つの代替表現を示し、比較します。3桁の整数の3行3列3列の配列。 6 x 3 x 3のリテラル配列。 5行12列のリテラル行列。 ll行ll列のスパースリテラル行列。 54要素のベクトル。 4次元配列。 3行3行3列のネストされた配列。 APL関数は、向きの移動と1/4回転に加えて、立方体を解くためのいくつかの便利なツールを提供します。
また、この RubiksCube.Java ファイルには、セクションを回転するための関連コードと共に、かなりクリーンな表現が含まれています(実際のコードを探している場合)。セルと面の配列を使用します。
1つの方法は、視覚的な外観に焦点を当てることです。
立方体には6つの面があり、各面は3 x 3の正方形の配列です。そう
Color[][][] rubik = new Color[6][3][3];
次に、各移動は、特定の色の正方形のセットを並べ替えるメソッドです。
エシュー最適化;オブジェクト指向にする。私が使用した疑似コードクラスの概要は次のとおりです。
class Square
+ name : string
+ accronym : string
class Row
+ left_square : square
+ center_square : square
+ right_square : square
class Face
+ top_row : list of 3 square
+ center_row : list of 3 square
+ bottom_row : list of 3 square
+ rotate(counter_clockwise : boolean) : nothing
class Cube
+ back_face : face
+ left_face : face
+ top_face : face
+ right_face : face
+ front_face : face
+ bottom_face : face
- rotate_face(cube_face : face, counter_clockwise : boolean) : nothing
特にコードの使いやすさを犠牲にする場合、使用されるメモリの量は非常に少なく、処理も非常に少ないため、最適化は完全に不要です。
キューブを表現する興味深い方法は、ソフトウェア「Cube Explorer」によって使用されます。多くの巧妙な数学を使用して、そのメソッドは5つの整数のみを使用してキューブを表すことができます。著者は website で彼のプログラムの背後にある数学を説明しています。著者によると、この表現は高速ソルバーの実装に適しています。
これを行うには多くの方法があります。いくつかの方法は、他よりもメモリをより効率的に使用します。
私は人々が3 x 3 x 3の直方体オブジェクトの配列を使用するのを見てきました。直方体オブジェクトは色情報を格納する必要があります(そうです、その中心オブジェクトは使用されません)。私は人々が6つの配列を使用するのを見てきました。各配列は立方体の3 x 3配列です。 3 x 18の立方体の配列を見ました。多くの可能性があります。
おそらく、より大きな懸念は、さまざまな変換をどのように表すかです。物理的な立方体の1つの面の回転(すべての立方体の移動は、基本的には1つの面の回転です)は、多数の直方体オブジェクトを交換することによって表す必要があります。
あなたの選択はあなたが書いているどんなアプリケーションにとっても意味のあるものでなければなりません。キューブをレンダリングしているだけかもしれません。 UIがない可能性があります。キューブを解いている可能性があります。
3 x 18のアレイを選択します。
重要な20の立方体があります。したがって、これを行う1つの方法は、20個の文字列の配列としてです。文字列は、色を示す2文字または3文字を保持します。 1回の移動で7つのキュビに影響します。したがって、6つの側面それぞれにリマッパーが必要です。
注:このソリューションでは、白い中央にあるロゴステッカーの向きを覚えられません。
ちなみに、ルービックキューブのソフトウェアの作成を1回、おそらく15年前に手助けしましたが、それをどのように表現したか思い出せません。
簡単に言えば、キューブをどのように解決するかによって異なります。ソルバーがレイヤーごとのアプローチやフリドリッヒ法などの人間の方法を使用する場合、基礎となるデータ構造は大きな違いはありません。最も遅いプログラミング言語であっても、コンピューターは人間の方法を使用してキューブをほとんど無視できる時間(1秒未満)で解くことができます。しかし、Thistlethwaiteの52移動アルゴリズム、Reidの29移動アルゴリズム、またはKorfの20移動アルゴリズムなど、より計算集約的な方法を使用してキューブを解く場合は、データ構造とプログラミング言語が最も重要です。
OpenGLを使用してキューブをレンダリングするルービックキューブプログラムを実装しました。このプログラムには、2つの異なるタイプのソルバーが組み込まれています(シスルスウェイトとコーフ)。ソルバーは数十億の動きを生成し、各キューブの状態を数十億回比較する必要があるため、基礎となる構造は高速でなければなりません。私は次の構造を試しました:
上記の方法(3)を拡張すると、立方体の各面は9枚のステッカーで構成されていますが、中央は静止しているため、8個だけを保存する必要があります。そして、6つの色があるので、各色は1バイトに収まります。これらの色の定義を考えると:
enum class COLOR : uchar {WHITE, GREEN, RED, BLUE, ORANGE, YELLOW};
顔は次のようになり、単一の64ビット整数に格納されます。
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
これは次のようにデコードされます:
WGR
G B
WYO
この構造を使用する利点は、rolq
およびrorq
ビット演算子を使用して面を移動できることです。 16ビットずつ回転すると、90度回転します。 32ビットずつ回転すると、180度回転します。隣接するピースは手動で更新する必要があります。上面を回転させた後、正面、左面、背面、右面の最上層も移動する必要があります。この方法で顔を向けることは本当に速いです。たとえば、ローリング
00000000 00000001 00000010 00000011 00000100 00000101 00000000 00000001
16ビットで
00000000 00000001 00000000 00000001 00000010 00000011 00000100 00000101
デコードすると、次のようになります。
WGW
Y G
OBR
別の利点は、キューブの状態の比較が、いくつかのインスタンスでは、いくつかの巧妙なビットマスクと標準の整数比較を使用して実行できることです。これは、ソルバーにとってかなり大きなスピードアップになる可能性があります。
とにかく、私の実装はgithubにあります: https://github.com/benbotto/rubiks-cube-cracker/tree/2.2. See Model/RubiksCubeModel.{h,cpp}
。
上記の方法(4)を拡張すると、ルービックキューブをプログラムで解決するためのアルゴリズムの一部は、パターンデータベースをヒューリスティックとして使用して、A *で反復深化深さ優先検索を使用します。たとえば、Korfのアルゴリズムは3つのパターンデータベースを利用します。1つは8つのコーナーキューブのインデックスと方向を保存します。 1つは12個のエッジピースの6個のインデックスと方向を格納します。最後は、他の6つのエッジのインデックスと方向を格納します。パターンデータベースを使用する場合の高速なアプローチは、キューブをインデックスと方向のセットとして格納することです。
規則を任意に定義すると、エッジキューブは次のようにインデックスを作成できます。
0 1 2 3 4 5 6 7 8 9 10 11 // Index.
UB UR UF UL FR FL BL BR DF DL DB DR // Position (up-back, ..., down-right).
RY RG RW RB WG WB YB YG OW OB OY OG // Colors (red-yellow, ..., orange-green).
したがって、赤黄色のエッジキューブはインデックス0にあり、白緑色のエッジキューブはインデックス4にあります。同様に、コーナーキューブは次のようにインデックスが付けられます。
0 1 2 3 4 5 6 7
ULB URB URF ULF DLF DLB DRB DRF
RBY RGY RGW RBW OBW OBY OGY OGW
したがって、赤、青、黄色のコーナーキューブはインデックス0にあり、オレンジ、緑、黄色のコーナーキューブはインデックス6にあります。
各キュービーの向きも維持する必要があります。エッジピースは2つの方向(方向付けまたは反転)のいずれかにすることができ、コーナーピースは3つの異なる方向(方向付け、1回回転、または2回回転)にすることができます。ピースの向きの詳細については、こちらをご覧ください。 http://cube.crider.co.uk/zz.php?p=eoline#eo_detection このモデルでは、顔を回転させるとインデックスが更新されますと向き。人間が(少なくとも私にとっては)インデックス番号と方向番号の大きな塊を見て、その正確さを確認するのは難しいため、この表現は最も困難です。とはいえ、このモデルは、上記の他のモデルの1つを使用して動的にインデックスと方向を計算するよりもはるかに高速であるため、パターンデータベースを使用する場合に最適です。このモデルの実装をここで見ることができます: https://github.com/benbotto/rubiks-cube-cracker/tree/2.2.0/Model (RubiksCubeIndexModel.{h,cpp}
を参照)。
前述のように、プログラムは立方体もレンダリングします。その部分には別の構造を使用しました。私は「cubie」クラスを定義しました。これは、センター、エッジ、およびコーナーピースのそれぞれに1、2、または3つのカラー面を持つ6つの正方形です。ルービックキューブは、26個のキューブで構成されます。面はクォータニオンを使用して回転されます。キューブとキューブのコードは次のとおりです: https://github.com/benbotto/rubiks-cube-cracker/tree/2.2.0/Model/WorldObject
私のルービックキューブソルバープログラムに興味がある場合は、YouTubeに概要ビデオがあります: https://www.youtube.com/watch?v=ZtlMkzix7Bw&feature=youtu.be
キューブは、3つの水平リンクリストと交差する3つの垂直円形リンクリストと考えることができます。
キューブの特定の行が回転するときはいつでも、対応するポインターを回転させるだけです。
次のようになります。
struct cubeLinkedListNode {
cubedLinkedListNode* nextVertical;
cubedLinkedListNode* lastVertical;
cubedLinkedListNode* nextHorizontal;
cubedLinkedListNode* lastHorizontal;
enum color;
}
実際には2つの「最後の」ポインターは必要ないかもしれません。
[Cでこれを行いましたが、JavaまたはC#で、cubeLinkedListNodeの単純なクラスを使用して、各クラスが他のノードへの参照を保持するだけで使用できます。)
6つの連動する循環リンクリストがあることに注意してください。 3垂直3水平。
回転ごとに、対応する循環リンクリストをループし、回転する円のリンクと接続する円を順番にシフトします。
そのようなもの、少なくとも...
他の人は物理的な立方体の説明にうまく対応しましたが、立方体の状態について...ベクトル変換の配列を使用して立方体の変化を説明してみます。そうすれば、変更が加えられてもルービックキューブの履歴を保持できます。そして、あなたはベクトルを変換行列に掛けて最も簡単な解決策を見つけることができるだろうか?
動く48面の順列として。基本的な回転も順列であり、順列を構成することができ、グループを形成します。
プログラムでは、そのような順列は0から47までの数値を含む48要素の配列で表されます。数値に対応する色は固定されているため、順列から視覚的表現を計算でき、逆も同様です。