nigoblog

技術系会社のCEOブログ~私的編~

ルービックキューブの実装をPHPでしてみた~ルービックキューブクラス~

前回ルービックキューブにハマる~そしてアルゴリズムへ~ - nigoblog
ルービックキューブにハマったということを書いたのですが、今回そのアルゴリズムを実装するべくチャレンジすることにしました。

まずはアルゴリズムを記述する前に色々な動作を書く必要があると思ったのでそこから書いて行きました。

  1. ルービックキューブクラス
  2. ルービックキューブを配列で表す
  3. 入れ替え関数
  4. 回転処理関数
  5. まとめ

という流れでみていきます。

ルービックキューブクラス

まずは動作とデータモデルを表すためのクラスを設計します。
実装は次章以降で。

データモデル

これはルービックキューブをどういう風にデータ構造として表すか。
今回はPHPを用いたので、配列の中でも連想配列を用いました。

入れ替え

キューブの回転処理の際に発生する入れ替えを行うクラス。単純にスワップです。

回転処理

ここがメインです。ルービックキューブは回転させるという動作を組み合わせて遊ぶものです。
なので回転させ、その結果どうなったかを記述します。
回転の要素は3種類あって

  1. 方向
  2. 位置
  3. 回転角

がそれぞれ回転のパラメータです。
ある面を上に見た時に、
縦回転、横回転、高さ回転
それぞれ
右、中、左 (縦)
手前、中、奥 (横)
上、中、下 (高さ)
さらに
90, 180, 270 (単位: deg)
というわけで全27の動作があります。様々な書き方があると思いますが、方向を関数で、位置と回転角を引数で表します。

ルービックキューブを配列で表す

ルービックキューブクラス自体は次のようになります。

class Cube{
}

ここにフィールド変数という形でcubeモデルを作成します。
すると

class Cube{
    private $cube = array(
        '1' => array('Y1', 'Y2', 'Y3', 'Y4', 'Y5', 'Y6', 'Y7', 'Y8', 'Y9'),
	'2' => array('G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'),
	'3' => array('O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O7', 'O8', 'O9'),
	'4' => array('R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', 'R9'),
	'5' => array('B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'),
	'6' => array('W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8', 'W9')
    );
}

という感じで表します。この時、YやらGやらは色を表しております。
またサイコロのように連想配列を設定します。
今回、ベクトルを2つ用意するか、一つのベクトルかで迷い、結局ベクトルは一つで表現することにしました。

入れ替え関数

これは単純にスワップなのですが、データ構造上、4つの引数が必要ということで次のようになりました。

public function swap($key1, $value1, $key2, $value2){
	$tmp = $this->cube[$key1][$value1];
	$this->cube[$key1][$value1] = $this->cube[$key2][$value2];
	$this->cube[$key2][$value2] = $tmp;
}

本当にただのスワップです。

回転処理関数

今回ここがメインとなります。
先程にも書きましたが、回転方向で関数を分け、位置と回転角を引数で表現します。すると次のようになります。

//position => right, center, left
public function verticalRotate($position, $deg){
	if($position == 'right'){
		if($deg == 90){
			$this->swap(1, 2, 5, 2);
			$this->swap(1, 5, 5, 5);
			$this->swap(1, 8, 5, 8);
			$this->swap(1, 2, 6, 2);
			$this->swap(1, 5, 6, 5);
			$this->swap(1, 8, 6, 8);
			$this->swap(1, 2, 2, 2);
			$this->swap(1, 5, 2, 5);
			$this->swap(1, 8, 2, 8);
		}elseif($deg == 180){
			$this->swap(1, 2, 6, 2);
			$this->swap(1, 5, 6, 5);
			$this->swap(1, 8, 6, 8);
			$this->swap(2, 2, 5, 2);
			$this->swap(2, 5, 5, 5);
			$this->swap(2, 8, 5, 8);
		}elseif($deg == 270){
			$this->swap(1, 2, 2, 2);
			$this->swap(1, 5, 2, 5);
			$this->swap(1, 8, 2, 8);
			$this->swap(1, 2, 6, 2);
			$this->swap(1, 5, 6, 5);
			$this->swap(1, 8, 6, 8);
			$this->swap(1, 2, 5, 2);
			$this->swap(1, 5, 5, 5);
			$this->swap(1, 8, 5, 8);
		}	
	}
}

長々と書いておりますが、今回は簡単のため
回転方向 縦
位置 右
角度 90, 180, 270
の3つのパターンの回転の動作を書きました。同様のものをあと24個書いて動作は完了です。(多い…)

まとめ

以上をまとめとして、実行部分のコードを示します。

        $new_cube = new Cube();
	$origin = $new_cube->getCube();
	echo '<pre>';
	print_r($origin);
	echo '</pre>';
	$new_cube->verticalRotate('right', 270);
	$after_swap = $new_cube->getCube();
	echo '<pre>';
	print_r($after_swap);
	echo '</pre>';

まずはCubeクラスのインスタンスを作成します。
ちなみにこれまで説明しませんでしたが、ゲッターもあります。
まずはオリジナルを表示。つまり全部が揃っている状態。
次に縦方向に右の位置で270度回転させ、
それを表示しています。

結果は大量になるので載せませんが無事成功してました。

そんな感じで、
次は残りの動作を全て作成。
その後、問題をセットするなどをやっていきたいと思います。

ではでは