ヒントの位置が指定された ナンプレの高速な生成法
Download
Report
Transcript ヒントの位置が指定された ナンプレの高速な生成法
パズル問題自動生成時代
株式会社タイムインターメディア
知識工学センターパズル推進室
稲葉 直貴
発表内容について
様々な種類のパズルに応用できる汎用的な
問題自動生成アルゴリズムの紹介。
NumberPlace,CrossSumと呼ばれるパズル
への本アルゴリズムの適用について説明し
それらを通じてより一般的なパズルに対する
問題自動生成アルゴリズム設計手法を提案。
発表の流れ
NumberPlace自動生成アルゴリズムの紹介
他のパズルにも応用できそうな部分を抽出
CrossSumの自動生成アルゴリズムを構築
NumberPlaceとは?
(1)縦横の全ての列に1から9を一つずつ入れる
(2)太線で囲まれた3×3のブロック内にも1から9を一つずつ入れる
●問題●
4
3
★解答★
5
1
2
4
3
6
8
9
5
1
7
9
2
5
4
9
7
1
2
3
5
6
8
4
5
4
7
3
5
6
8
4
1
7
2
9
3
7
3
2
1
4
6
9
5
8
6
8
5
3
9
2
7
4
1
4
1
9
7
5
8
3
6
2
3
1
2
9
9
3
5
6
8
9
1
5
8
2
7
9
6
1
4
3
5
1
5
3
6
1
3
9
5
4
6
5
8
7
2
3
4
8
1
2
7
6
9
5
6
1
7
今回考える問題について
入力:ヒント座標の集合
出力:入力座標に数字が配置された
ユニークな解を持つ問題図
4
3
5
1
9
2
5
4
5
4
7
3
ヒント
3
2
9
5
1
9
3
6
8
9
1
5
1
5
3
6
5
6
1
7
与えられた
ヒント配置で
問題を作成
問題作成の流れ
ヒントの位置を決める
問題作成の流れ
ヒントの位置を決める
解答盤面を作成する
7
4
3
8
6
9
5
1
2
9
6
1
2
3
5
7
8
4
5
8
2
4
1
7
6
9
3
6
3
7
9
2
8
4
5
1
4
1
5
3
7
6
9
2
8
2
9
8
1
5
4
3
6
7
8
7
4
6
9
1
2
3
5
1
3
2
5
9
6
5
7
4
8
3
2
8
1
7
4
6
9
問題作成の流れ
ヒントの位置を決める
解答盤面を作成する
ヒント以外を除去する
7
4
3
8
6
9
5
1
2
9
6
1
2
3
5
7
8
4
5
8
2
4
1
7
6
9
3
6
3
7
9
2
8
4
5
1
4
1
5
3
7
6
9
2
8
2
9
8
1
5
4
3
6
7
8
7
4
6
9
1
2
3
5
1
3
2
5
9
6
5
7
4
8
3
2
8
1
7
4
6
9
これで唯一解になっていれば完成!
問題作成の流れ
このヒントで解いてみる
7
4
3
5
1
2
9
1
2
3
5
4
5
2
4
1
7
3
3
7
1
5
9
8
5
6
1
1
3
5
3
6
5
3
6
3
8
5
4
3
5
6
1
4
空きマスの数:37
問題作成の流れ
このヒントで解いてみる
7
4
3
5
1
2
9
1
2
3
5
4
5
2
4
1
7
3
3
7
1
9
5
3
1
9
8
ヒント数字を変更する
4
1
5
3
8
6
1
1
3
5
3
5
6
5
6
3
5
6
1
4
空きマスの数:37→35
★この操作を繰り返して全マスが確定する状態にする
タネとなる初期解答図の生成
まず一つのパターンを用意
7
4
3
8
6
9
5
1
2
9
6
1
2
3
5
7
8
4
5
8
2
4
1
7
6
9
3
6
3
7
9
2
8
4
5
1
4
1
5
3
7
6
9
2
8
2
9
8
1
5
4
3
6
7
8
7
4
6
9
1
2
3
5
1
3
2
5
9
6
5
7
4
8
3
2
8
1
7
4
6
9
解答パターンの生成
同じブロック内の列を
ランダムに選ぶ
まず一つのパターンを用意
解答盤面の性質を壊さず
数字をシャッフルする
7
3
4
3
7
8
6
9
5
1
2
9
6
1
2
3
5
7
8
4
5
8
2
4
1
7
6
9
3
6
7
3
7
6
9
2
8
4
5
1
4
1
5
3
7
6
9
2
8
2
9
8
1
5
4
3
6
7
8
7
4
6
9
1
2
3
5
1
3
6
2
5
9
6
3
5
7
4
8
3
2
8
1
7
4
6
9
この処理を全マスに対して行う
解答アルゴリズム(ソルバー)について
★状態が「確定」する箇所だけを埋める
解答処理を高速に行うために…
解くために用いる「手筋」の制限
(確定する全ての箇所が埋まるわけではない)
再帰的な手続きを使用
(変化があった箇所だけをチェック)
問題を解く上で扱う要素
数字
候補
盤面の数字
4
6
1
5
2
3
2
1
2
9
9
5
3
8
6
2
5
5
4
2
8
7
6
9
8
4
5
7
5
7
5
3
1
7
9
盤面に入る数字の候補
9
4
3
1
2
3
2
1
8
6
5
7
1
4
6
9
1
2
3
1
2
3
4
5
6
4
5
6
7
8
9
7
8
9
1
2
3
1
2
3
4
5
6
4
5
6
7
8
9
7
8
9
「手筋」について
NumberPlaceの手筋には二種類が存在する
「数字」を入れる規則
(どういうとき数字を入れられるか)
「候補」を消す規則
(どういうとき候補が消せるか)
数字を入れる三つの規則
あるブロックで3が入る候補が一つしか
存在しなければ、そのマスに3が入る
3
X X
X
X X
X
X X
ある列で6が入る候補が一つしか
存在しなければ、そのマスに6が入る
X
X X X X 6
あるマスに入る候補が7しかなければ
そのマスに7が入る
1 2 3 4 5
6 7 8 9
7
X X X
候補を消す三つの規則
あるマスに数字5が入るとき
そのマスから5以外の候補を消す
同じブロック内から5の候補を消す
同じ列内から5の候補を消す
5
ここでは以上の規則だけを用いる
(全ての問題を解くには不十分)
用いる手続き
数字を入れる手続き
位置(x,y)に値zを代入
候補を消す手続き
位置(x,y)の候補から値zを消去
「数字を入れる手続き」の実行
数字を代入すると、その影響を受ける範囲で
「候補を消す手続き」が直ちに呼び出される
5
(2,4)に5を入れたことにより
赤く図示された範囲に対して
候補を消す手続きが実行される
「候補を消す手続き」の実行
候補を消すと、その影響を受ける範囲で
新たに数字が確定するかチェックされる
★数字を入れる三つの規則を調べる
数字が確定する場合は再び
「数字を入れる手続き」が呼ばれる
(6,4)から候補5が消されたことで、
青く図示された範囲がチェックされる
5
解答アルゴリズム
数字が一つも入ってない状態から開始し、
既に数字が明かされている全ての箇所で
「数字を入れる手続き」を実行する
盤面の一辺の長さをNとしたとき
「数字を入れる手続き」の実行回数:N^2
「候補を消す手続き」の実行回数:N^3
★全体ではO(N^3)で終了
実行時間:O(N)
実行時間:O(1)
問題生成アルゴリズム(ジェネレータ)
について
貪欲法に基づいている
「解答後の空きマスの数」が少なくなるよう
問題盤面(ヒントの数字)を変更していく
生成は確率的
常に成功するとは限らない
ヒント数字の変更手順
全てのマスを順に見ていく
ヒント位置であれば1から9まで変更
解答後の空きマス数をチェック
前より空きマス数が下がれば
そのヒントを残し最初に戻る
下がらない、もしくは「解なし」
ならば数字を元に戻し次へ
空きマスが0になる(成功)か
最後の数に到達(失敗)したら終了
4
3
5
1
9
2
5
4
5
4
7
3
3
7
4
5
9
8
3
6
8
6
1
5
1
5
3
6
5
6
1
4
変更を効率良く行うために
一箇所のヒントの変更に対し、毎回最初から
解き直すのは効率が悪いので段階を踏む
★この目的のため「局所ソルバー」が使われる
7
7
5
9
2
5
4
9
5
4
7
3
5
3
7
9
5
1
8
4
3
5
8
6
1
1
5
3
3
5
6
5
6
3
1
4
4
3
1
55 1
2
3
5
2
4
4
1
7
3
3
7
9
5 3
8
1
4
1
1
3
5
5
8
6
1
6
1
5
3
3
5
6
5
6
3
5
6
1
4
アルゴリズムの終了
成功した場合
最終的なヒントと解答後の盤面を出力
(成功時には全てのマスに数字が入っている)
失敗した場合
あるヒント位置に対し唯一解となる問題図が
存在するかどうかを判定するのは困難なので
再チャレンジするか否かは人が判断する
(ヒントの数を増やす、位置を変える 等)
問題作成の流れ (まとめ)
解パターン生成
作成成功 作成失敗
ヒントを代入
空きマス0
解く
もう下がらない
空きマスを数える
減少
ヒントの変更
増加(orイコール)
ヒントを元に戻す
CrossSumとは?
(1) 白マスに1から9のいずれかの数字を入れる
(2) 三角マスの数字はそこから一列に連続している
白マスに入れられる数字の合計を表す
(3) 一列に連続する白マスに同じ数字は入らない
●問題●
4
★解答★
15
4
3
3
16
20
20
12
15
1 2 16
3 8 9
12
5 7
アルゴリズムの入出力
入力 : 三角マス(ヒント)のパターン
出力 : 上のパターンを持つ問題&解答図
入力
出力
4
3
20
15
1 2 16
3 8 9
12
5 7
問題作成の流れ
解パターン生成
作成成功 作成失敗
ヒントを代入
空きマス0
解く
時間切れ
空きマスを数える
減少
ヒントの変更
増加(orイコール)
ヒントを元に戻す
解パターン生成 その1
適当な1から9の順列を用意
7 5 2 3 8 1 9 6 4
この繰り返しで盤面を覆う
9 6 4 7
9 6 4
9 6
9
5
7
4
6
9
2
5
7
4
6
3
2
5
7
4
8
3
2
5
7
1
8
3
2
5
9
1
8
3
2
6
9
1
8
3
4
6
9
1
8
7
4
6
9
1
5
7
4
6
9
2
5
7
4
6
2
5 2
7 5 2
4 7 5 2
…
この上から三角マスをかぶせれば数字の重複は起こらない!
解パターン生成 その2
これだけでは
ランダム度が低い
上下左右を確認して
変更できる箇所を
適当に入れ替える
7
4
6
9
1
8
3
2
5
7
4
5
7
4
6
9
1
8
3
2
5
7
2
5
8
7
4
6
9
1
8
3
2
5
3
2
5
7
4
6
9
1
8
3
2
8
3
2
5
7
4
6
9
1
8
3
1
8
3
2
5
7
4
6
9
1
8
9
1
8
3
2
5
7
4
6
9
1
6
9
1
8
3
2
5
7
4
6
9
4
6
9
1
8
3
2
5
7
4
6
7
4
6
9
1
8
3
2
5
7
4
5
7
4
6
9
1
8
3
2
5
7
ヒントの代入
解答から一意に
ヒントが定まるので
それを代入する
8 1 9 276 4
7 5 262 3
7
9
20
3
24
19
6
4 187 8 6 5 8 111 3 1 2
22
29
6 8 7 3 4 213 6 9 2 5
14
23
13
9 9 5 237 3 9 5 6 111 8
20
18
1 1 4 2 8 3 242 5 2 9
6
17
8 1 2 4 254 2 6 4 5 198
26
4
3 8
1 9 2 7 8 165 1 3
26
8
21
23
2 1 5 8 7 116 7 8 3 1
11
14
13
5 5 6 168 4 6 3 1 127 6
26
18
7 2 7 9 3 5 9 4 7 5
24
12
4 7 8 7 9 8 1 3 5 4
5
7
16
7
5
4
1
8
13
4
7
2
7
問題作成の流れ
解パターン生成
作成成功 作成失敗
ヒントを代入
空きマス0
解く
時間切れ
空きマスを数える
減少
ヒントの変更
増加(orイコール)
ヒントを元に戻す
CrossSumソルバーの構成
★3つの要素が互いに関係し合っている
盤面に入る数字
数字
その列に入る
数字の組み合わせ
盤面に入る
数字の候補
候補
ヒント
数字が入った場合の処理
可能な組の更新
4
{389}
{479}
{569}
{578}
その列から3の候補を消す
15
3
16
20
3
12
そのマスから他の候補を消す
候補が消された場合の処理
可能な組の更新1
マスで候補が一つなら入れる
※仮に列から3の候補が消えたら
3を含む組を消す
4
3
可能な組の更新2
※仮にマスからある組の候補が
全て消されたらその組を消す
3
15
16
20
12
列で候補が一箇所なら入れる
可能な組が更新された場合の処理
{159}
{168}
{249}
{258}
{267}
入らない候補を消す
※3,4,6,7は入らない
4
15
3
16
20
12
※5は必ず入る
入る数の候補が一箇所なら入れる
解答アルゴリズム
全ヒントに対し可能な数字の組み合わせの更新を行う
4
15
3
16
20
12
★最終的な結果は更新の適用順序にはよらない
問題作成の流れ
解パターン生成
作成成功 作成失敗
ヒントを代入
空きマス0
解く
時間切れ
空きマスを数える
減少
ヒントの変更
増加(orイコール)
ヒントを元に戻す
ヒントの変更
背景にある解を介してヒントを変更してやる
4
3
12
4
12
1 2
3
3
12
13
全部埋まらない
12
7
12
1 2 12
3 4 5
13
8
1
6 7
「解」を変更
★少なくとも一つ解の存在が保証される
変更手順(例)
※左上のマスから順次数字を入れ替えていく。
4
3
12
12
1 2 12
3 4 5
13
6 7
※数字の変更は同時に
一箇所にのみ行われる。
入れ換えた結果space(解答後の空きマス数)が
下がったら、その数を残し、再び左上に戻る。
全てのマスが埋まる(成功)か、どの数字を変更しても
spaceが下がらず右下に到達(失敗)したら実行終了。
失敗後の処理
ナンプレでは失敗した盤面を捨ててやり直していたが‥
7 5 262 133 208 1 9 326 144 307
24
4 777
4
8 161 9 8 7
18
32
6 1
9
3 9 7 6 8
20
13
29
13
9 4 9 237
7 8 301 9
21
32
1 2
2 5 9 6
11
14
12
8 1
4
3 6 218
16
11
14
3 168 111
5 8 6
18
10
17
2 4
6
7 1
17
12
19
4
5 9 3 178 4 9
3
7
17
23
26
3
9
8
9
7
19
19
4 7 5 8 6 8 1
5
77
2
4
1
1
8
7
1
7
問題点:盤面が大きくなると
面積に対して指数関数的に
成功確率が低下する。
問題作成の流れ (改良版)
解パターン生成
盤面の再生処理
ヒントを代入
作成成功 作成失敗
空きマス0
解く
時間切れ
空きマスを数える
減少
ヒントの変更
増加(orイコール)
ヒントを元に戻す
新たな解パターン生成
7 5 262 133 208 1 9 326 144 307
24
7
2 4 2
1 8 161 9 8 7
4 77 1
18
32
5 9 6
7 203 9 7 6 8
6 1 2
13
29
13
9 9
5 7 8 301 9
9 4 9 237 5
21
32
7 9
5 7
8 8
1 112 5 9 6
1 2 6
14
12
1 6
4 164 2
7 1
9 3 6 218
8 1 8
11
9 3 1
2 2
6 18514 8 6
3 168 111 5
10
17
1
3
2
2
7
8 4
3 7 1
2 4
6 3
17
12
19
5 9 3 178 4 9 5 1 1774 3
23
26
5 8 9 6
2 9
1 7
4
7 3 2 9 1
19
19
8 8
6 4
9
4 7 5 8 6 8 1 7
5
77
2
4
1
1
8
7
2
4
1
4
3
7
背後にある解に注目
解けなかった部分を除く
ランダムに再配置
これを種に再び問題生成
全てのマスが埋まるまで繰り返す
★完成図★
新たな種から生成される問題は
より唯一解に近づいている
(と期待される)
この操作を問題が完成するか
納得のいくまで繰り返す。
7 5 182 123 258 1 9 326 144 307
24
7
2
1
4 127
4
8 161 9 8 7
29
32
6 9 5 8 7 153 9 7 6 8
29
13
94 1 3 127 9 5 7 8 181 9
21
23
1 2 7 5 8 1 282 5 9 6
5
25
8 1 1 4 254 7 9 3 6 258
12
3 188 111 1 3 2 6 1456 1 5
10
15
2 3 1 2 4 176 5 3 2 1
12
23
5 9 3 178 5 9 8 1 377 6
32
10
7 6 2 9 7 8 9 2 1 4
19
19
4 7 5 8 6 8 1 8 2 9
5
77
2
4
1
1
8
8
4
1
3
7
考えるべきことのまとめ
初期盤面をどう作るか
ソルバーの構成
問題盤面の変更方法
失敗時の盤面再生処理
初期盤面をどう作るか
解を保障する状態からのスタートが望ましい
用いるソルバーが完全でないと盤面が矛盾をはらんでも
検出できず、解答不能状態に落ち込む場合がある。
これを回避するためには「※解の存在を保証し」つつ、
問題盤面を変更していく必要がある。
※ナンプレの生成過程はこの条件を満たしていない
(そうすることは可能だが却って遅くなる)
ソルバーの構成を考える
基本となる要素は何か?
盤面の状態、候補、その他の制約条件など
それらが変化したとき影響を受ける範囲は?
変化があった箇所だけ再帰的に解くように設計
★局所的な盤面変更を行う今回の手法に有効
どこまで簡素化するか
解答能力と計算量のトレードオフを考慮
一般に「完全ソルバー」を作るのは困難
問題盤面の変更方法
解の存在を保証するように変更
解を変更し、それに合わせて問題盤面を変更する
部分的に解いたものを保存しておく
変更の度に一から解き直すのは非効率的
唯一解までの「距離」をどう計るか
空きマス、候補数の総和
失敗時の盤面再生処理
既に「できている」部分を残してシャッフル
どこまでを「できている」と見なすか
壊しすぎる→収束しない
残しすぎる→閉塞状況を打開できない
今後の予定
いくつかのパズルに対して適用してみる
各々について難度を制御できるようにする
私事
もっと仲間を増やす
パズル界をルール設計中心の方向へ