C#でエイト・クイーン問題を解いてみましょう。

チェスの駒・クイーンは、上下左右斜めの8方向に遮る物がない限り進むことができます。将棋の飛車と角行を合わせた動きです。さてチェスの盤上に8個のクイーンをお互いに他の駒に取られないような位置においていきます。置き方は何通りあるのでしょうか?

縦列だけに注目すると同じ列にはひとつのクイーンしか置けません。そこで各列について上から何番目の位置にクイーンを置くかを数値で表し、要素数8の整数のリストをつくります。

また横列もひとつのクイーンしか置けません。ということは要素数8のリストのなかに同じ整数は含まれないということになります。1~8の順列を作って斜めのチェックをすれば答えを得ることができそうです。

以下は1~8の順列を得るためのメソッドです。

あとは斜めのラインだけチェックします。

各列に置かれているクイーンからみて取ることができるクイーンがあるかどうか調べます。

ボタンが押されたら処理を開始します。0~7までの順列をすべて取得します。これで縦横でお互い他のクイーンに取られることはない配置が得られますが、斜めはそうではないのでチェックします。解が得られたらリストに格納します。

解が格納されたリストを文字列に変換して結果を表示します。

これは結果をリッチテキストボックスに表示するためのメソッドです。

この方法は斜めに取ることができるクイーンがある配置であってもとりあえず取得するという無駄な処理をしています。そこで一列ずつ置くことができる場所があるかどうか調べながら処理をします。置くことができない場合は、それ以上考えません。これで処理にかかる時間を短縮できるかもしれません。

GetPositionCanPut(List<int> vs)メソッドは、すでに要素が1以上存在するリストを渡して、クイーンを置くことができる位置のリストを求めるメソッドです。

GetQueensPositions(List<int> parentList, List newPositions)メソッドは、すでに決定しているクイーンの位置に対して新しいクイーンの位置のリストを追加するメソッドです。

ボタンが押されたら処理を開始します。

すでに置かれているクイーンに対して新しいクイーンを配置できる場所を調べて追加していきます。配置できない場合はその配置は捨てられます。最後に得られた結果をShowResultメソッドで表示します。

実際に処理時間に違いはあるのでしょうか? ShowResultメソッドの部分は同じなので、それ以外の部分の処理にかかる時間を計測します。

前者では100ミリ秒以上かかりますが、後者であれば数ミリ秒で終わることがわかりました。