ヘキソミノ完全解へのシナリオ
ver. 0.34 2010/03/03 daichinアットexcite.co.jp
   http://hexomino.hp.infoseek.co.jp/

 部分解への分割方法の検討ver.0.15に合わせて全面改訂になりますが、まだ当分落書き、備忘録レベルです。
構想検討 -> 文書化 -> 図示化 -> コーディング それぞれに結構な時間がかかるので、まあ、少しずつ進めて行きます。

解数分布の大雑把な推定

 縦中央線を重複境界として左右に2分割。

 縦中央線の組み合わせは、1E11程度と推定。
  中央の出っ張りに置けるピースは、35ピース中、32ピース。置けないのは左の3つ。
  向きを含めると110通り
  ピース#0を置いた場合の組み合わせは1.5E91,462,102,922 2010/2/22)
 

 一つの中央線組み合わせに対して、右側半分がどのピースを使うかという組み合わせが平均1E7程度、それぞれのピースの組み合わせに平均1E3

 左側は、残りのピースでの組み合わせになるので、平均1E3程度。

 全解はこれらの組み合わせになるので、1E11 x 1E7 x 1E3 x 1E3 = 1E24 となりで今までの推定の範囲に収まる。

 それぞれの要素は、ピースの組み合わせにより、乗数が±2(0.01〜100倍)程度は平気でバラつくと思われることも加味して、計算時間,パーツリストの構造、サイズ等を検討する。

 計算時間の推定

  2分割のパーツ・リストがすべてできた状態を仮定すると、1E11(右) x 1E7(左) = 1E18 の組み合わせに対して、検索して、それぞれの重みを掛け算して、その総和を取ることになります。1CPUでの1秒あたりの処理数は1E7程度になるのではと想定してます。そうすると、1E18 / 1E7 = 1E11秒・CPU = 1E6日・CPU1000個のCPUをフルに使って3年かかることになります。

  かろうじて実現可能な推定になりますが、前提に2分割パーツ・リストが完成しているということがあり、それでもこれだけの処理が必要になるということです。この後、推定するパーツ・リストの作成にはこれ以上の膨大な処理時間が必要になるはずですので、いずれにしろ、すべてうまくいったとしても10年後の2020年でも厳しいだろうという話だということです。

  特に、ここ数年で顕著になった消費電力に対する制限というのが非常にインパクトが大きいように思います。スパコンでさえ、消費電力が性能の指標になる時代ですから、人類にとってなんの役にも立たないこの計算の為に、多数のCPU時間(=電力消費)を提供していただくというのは、なかなか難しい時代になりました。


ピースの数値表現

 35ピースの定義に6ビット、最大8通りの向きに3ビット、最大6段の位置に3ビットで、合計12ビット必要になり 、16ビット変数(short)を使うと4ビット余ります。 パーツを定義する場合、複数のピース並びを定義するので、4ビットの空きを作らず圧縮して保存することも可能ですが、その後の処理を考えると、各ピース毎に16ビット(2バイト)にするのがシンプルです。ストレージ容量はまだまだこれからも増加しそうですので、とりあえずこれで進めてみます。バイトの区切りで分ける右側のパターンも使いやすそうですが、左側のパターンでまずはコーディングしてみます。

    空き  ピース#  向きoffset        空き ピース#  空き 向きoffset
   0 0 0 0 p p p p p p r r r o o o         0 0 p p p p p p 0 0 r r r o o o


....0.....
....0.....
....0.....
....0.....
....0.....
....0.....
....11111.
...222221.
.333332...
...34444..
..8855544.
..8888555.

000000 001 000
000001 000 000
000002 000 001 000003 000 003 000004 000 000
000005 000 000
000008 002 002

 一番はじめに求まる左図のパーツは、このように14バイトで表現できます。

  各ピースの向き番号リスト


....0.....
....0*....
....0*....
....0*....
....0*....
....0*....
....11111.
........1.


....v.....  
..8888555. 
..8855544.
...34444..
.333332*..
...222221.
....11111.

 上と下を半分に分けると左の2つの分割され、*印の部分を含めて、現在考えている最小サイズのパーツになります。

 右側のパターンは分割方法の検討の時には想定していなかったパターンです。このように境界が隣り合わせていない場合もあることを考慮に入れる必要が出てきました。

 部分解への分割方法の検討


右上パーツの検討
 

#0#####
.0*....
.0*....
.0*....
.0*....
.0*....
.11111.
.....1.


#0######
.O22222.
.O5552..
.Oee555.
.Oe.....
.Oeee...
.11111..
.....1..

No.1

#0######
.Oyy....
.Oyytt..
.Oyyt...
.Ottt...
.Ot.....
.11111..
.....1..

No.1049
 一番左の条件を満たす組み合わせは1049通り。 ctr21.c

 これは、汎用性のないセンター上部専用パーツ



..22222.
..5552..
..ee555.
..e*....
..eee...
.11111..
.....1..




..22222..
..5552...
..ee555..
..e000000
..eee....
.11111...
.....1...

No.1


..22222..
..5552...
..ee555..
..e33333.
..eee3...
.11111...
.....1...

No.2


..22222..
..5552...
..ee555..
..e8888..
..eee88..
.11111...
.....1...

No.3
 これが今回初めて求まった、汎用パーツ。たった3通り。 ctr30.c

 ちなにみNo.1は、すでに使用しているピース#0を含むので、このケース使えるのは2通り。

 パーツリストを作成する時に、以降の利用を考えて、すべてのピースの組み合わせを含む汎用的なものにするか、その時点で必要な組み合わせに限定するかは、要検討。



..22222..
..5552*..
..ee555..
..e33333.
..eee3*..
.11111*..
.....1...



..22222.....
..55524444..
..ee555..44.
..e33333....
..eee3666...
.111117666..
.....177....
......77....
......7.....

No.1

..222224444
..555244...
..ee555....
..e33333...
..eee3666..
.111117666.
.....177...
......77...
......7....

No.1998
 No.1は汎用パーツとしては、有効だけれど、このケースでは、ピース#4が右端の壁に接して、上にできるスペースが5個の為無効となる。使えるのはNo.1998以降。 

 ctr40.c:ピース#0も含む汎用 35,286通り 
 ctr40_0.c:今回のケース用に、ピース#0を除外 31,295通り 

※ いずれの結果も途中での空きスペースチェックをしていない
  ため、連続スペースが2個と4個が独立してあるなどの、
  実際には無効な組み合わせを含んでいる。
  => 毎回チェックの有無のどちらがトータルとして時間短縮に
      なるか、要検討。
  => 連続スペース・チェックの高速化チューニング
 


..222224444
..555244...
....555*...
...33333...
.....3666..
......7666.
......77...
......77...
......7....



..222224444
..555244aaa
....555aa.a
...33333...
.....3666..
......7666.
......77...
......77...
......7....

No.3
 ctr50.c: 16通り

 No.1、2はそれぞれピース#0、#1を使用しているため、No.3 が最初。


.......4444
......44aaa
.......aa.a
...33333*..
.....3666..
.......666.
...........
...........
...........
...........
...........



.......4444
......44aaa
.......aaga
...33333ggg
.....3666gg
.......666.
...........
...........
...........
...........
...........

 焦ったあまり、1ステップ飛ばして求めたことにあとで気づく。

 ctr60.c: 31通り


.......4444
......44aaa
.......aaga
...33333ggg
.....3666gg
.......666*
...........
...........
...........
...........
...........


.......4444
......44aaa
.......aaga
...33333ggg
.....3666gg
.......6668
..........8
.........88
.........88
...........
...........

No.8

.0222224444
.0555244aaa
.0ee555aaga
.0e33333ggg
.0eee3666gg
.1111176668
.....177..8
......77.88
......7..88
...........
...........
 ここまでのパーツを合わせて、やっと1個の4分割パーツの完成。

 ここまでは、各パーツの特性に合わせて、直接ハードコーディングで調整してきたわけですが、その中で、どうやったら汎用のコーディングになるかがだいぶ見えてきました。

ピース組み合わせによる処理の検証用と処理の規模(スケール)見極め用サンプル


#0##########
.0.........[
.0.........[
.0.........[
.0.........[
.0.........[
.11111.....[
.....1.....[
...........[
 赤字境界を埋める4分割パーツを求める。 TopR05.c

 Pen4 2.26Gのマシンで、約50時間 

 singedの32bitの桁あふれを起こして、結果は -2,096,057,601
 行数等から判断して総数は、19,378,778,879 通りと思われる。


処理フロー

  nPattern = 0;

  for (iCtr = 0; iCtr < N_of_CtrParts; iCtr++) {
    for (iRight = 0; iRight < N_of_RightParts[iCtr]; iRight++) {
        nPattern += getPatterns(iCtr, iRight);
    }
  }

 トップレベルはこれだけになります。getPatternsの中で、右と左の2分割パーツがすでにパーツリストにあれば、それらの組み合わせ数を乗算して終わり。パーツリストにない場合は、4分割リストを検索、なければ8分割、それでもなければ最小パーツへと降りて行って、必要なパーツリストだけを作成しながら、解を求めて行きます。

 最初は、すべての階層のパーツリストを作成しながらの処理になりますが、少しずつ既存のパーツリストの再利用率が高くなっていき、解を求める時間が加速度的に早くなっていくことを予想していますが、それが現実的に意味のある時間軸に乗ってくるのかどうかは、かなり怪しいというのが、過去の試行で学んだことです・・・

 複数の方の協力がいただけるような状況になった場合には、パーツリストをネット上に置き、それとローカルのキャッシュとの同期を取りながら進めるような以下プロセスも必要になります。

 パーツリストが
  1.ローカル・キャッシュにあればそれを使う
  2.なければサーバーを確認し、あればそれをダウンロードし使う
  3.サーバーにもなければ、計算を開始するというフラグをサーバーに立てて、計算
    計算が終わったら、パーツリストをサーバーにアップ

 どこかでフローチャートに整理しようと思いますが、いつになるか・・・


バイナリデータの図示化

  各階層パーツリストは、境界上のパーツ並びをバイナリデータで保存しますので、いったいどんな形の組み合わせになっているのかは、人間が見てもわかりません。それではつまらないし、バグも見つけられないので、図示化のツールが必要になります。

 メインのプログラムに組み込めるように修正 test07.c (2010/2/25)
  実際に組み込んだあとで見つかったバグ修正版 test08.c (2010/2/28)
 ※ 並べ方の決め方により、このプログラムも調整が必要。

 とりあえず、上での説明に必要な最小機能でザクっと作ったものがこれ (まだピース番号10以上に対応してないとか、データをmain()にベタ書きしてるとか、上下位置を計算で求めず数値を入れてるとかの未完成品です)


・Version History

 0.34 10/03/03  下層パーツの組み合わせで4分割パーツ1個完成。検証用4分割パーツ結果
 0.33 10/02/28 下層パーツの組み合わせで4分割パーツを作り始める 
 0.32 10/02/24 詰める順番を左上から、右上に変更、各章追記、バイナリデータの図示化追加
 0.31 10/02/22 計算時間の推定、ピースの数値表現、処理フロー書きかけ
 0.30 10/02/20 部分解への分割方法の検討ver.0.15に合わせて全面改訂初稿

 0.20 02/12/24 再度、仕切りなおし。部分解の高速化を進めるのはそのままだが、分割方法を
           使用ピースの種類からサブパーツの形状に変更。
 0.10 02/12/11 原点の「パズルのプログラミングを楽しもう」に戻って、再出発 
 0.05 01/10/09 ヘキソミノ完全解へのシナリオVer. 0.05
 0.04 01/08/24 命題1.1、2.5、2.6の追加。
 0.03 01/08/23 第1期の成果、第2期の方針を追加。
 0.02 01/08/08 早速命題3.5、5.5、5.6の追加。
 0.01 01/08/05 初稿 まだまだ、矛盾だらけ、説明不足だらけですがとりあえずリリース。

 

inserted by FC2 system