数独パズルを解くSASプログラム 知平 菜美子 兵庫県立大学・経済学部 4 回生 周防 節雄 兵庫県立大学・学術情報館 Sudoku Solving System Coded in SAS Namiko Chihira Faculty of Economics, the University of Hyogo Setsuo Suoh Systems Information Centre, the University of Hyogo 要旨 数独パズルを解く SAS プログラム(Sudoku Solving System: SSS)を開発した。数独パズルの局面を SAS デ ータセットに表現しようとすると、9×9 のマトリックスの形状を採用するのが一般的である。つまり、9 変 数、9 オブザベーションの SAS データセットとなる。パズルのルール上、横 1 列、縦 1 列、3×3 の 9 個のブ ロックのそれぞれに、1~9 の数字を当てはめていくことになるが、SAS では原則的に横一列、つまりオブザ ベーションごとにしか計算処理できないので、本来 SAS で解くには不向きな問題である。本論文では、初期 のマトリックス状の SAS データセットからパズルを解くのに必要な複数の SAS データセットを作成し、必要 な処理を施した上で、それらのデータセットの情報を統合することで、パズルを解き進めていく手法を採用 した。局面が進展するにつれて、同じ解法プログラムを繰り返し実行する必要があり、%include を使うこと によってそれを自動的に行うことを可能にした。SAS 言語には副プログラムの概念はないので、マクロ言語 を実質的にその代用品として活用した。今回開発したプログラムは、ほとんどの数独パズルを解くことに成 功している。 キーワード:データハンドリング、SAS マクロ言語、%include 文、再帰的プログラミング 1.はじめに 我々は数独パズルを解く SAS プログラム(Sudoku Solving System: SSS)を開発した。このパズルのルール 上、横 1 列、縦 1 列、3×3 の 9 個のブロックのそれぞれに、1~9 の数字を当てはめていく作業が必要になる が、SAS では原則的に横一列、つまりオブザベーションごとにしか計算処理できないので、本来 SAS で解く には大変不向きな問題である。更に、SAS にはサブルーティンの概念がない上に、プログラム全体を繰り返 し処理することも普通にはできない言語構造である。これらの難点を克服するために、SAS マクロ言語を最 大限に活用して、一種の再帰的プログラミング技法を採用した結果、極めて興味深い構造の SAS プログラム を作成することができた。 2.数独の簡単な説明 8 数独(日本のパズル制作会社ニコリ 6 の登録商標)とは、日本では「ナンバー プレイス(ナンプレ) 」とも呼ばれて いるペンシルパズルである。数独問題 は図 2.1 に例示する。世界的にも有名 なパズルであり、その問題は様々な雑 9 7 6 3 7 5 2 2 4 6 箱 7 4 3 8 5 8 1 誌や新聞などにも掲載されている。ま 4 3 9 2 8 図 2.1 数独問題 た、世界パズル連盟の主催する、パズ ルの国際大会である世界パズル選手 1 3 5 8 4 6 1 2 9 3 7 9 2 7 3 8 4 6 5 1 3 6 1 7 5 9 2 8 4 8 7 9 1 2 5 4 6 3 6 3 5 9 4 7 8 1 2 1 4 2 8 6 3 5 7 9 2 9 8 5 3 1 7 4 6 4 5 3 2 7 6 1 9 8 7 1 6 4 9 8 3 2 5 行 列 図 2.2 数独解答 出典: (株式会社ビデオ出版、SUPER ナンプレポータブル vol.1) 権にも毎年出題されている。このパズ ルは 9×9 の空いているマス目に 1~9 の数字を入れていく。基本ルールは図 2.2 で示している「行」 「列」 「箱」 のそれぞれに 1~9 の全ての数字を入れていかなければならず、グループ内で数字が重複してはいけない。 「行」は横列、 「列」は縦列、 「箱」(box)は 3×3 で囲まれた 9 個のマス目であり、全部で 9 個ずつある。 3.SAS で数独を解く上での問題点 SAS で数独を解く際の問題点は、SAS では原則的には同一オブザベーション内での演算しか行うことがで きないという点である。数独という問題の性質上、行・列・箱という3つのグループについてそれぞれ演算 を行い、解き進めていかなくてはならない。SSS では、問題を解き始める前にオリジナルのデータセットか ら行・列・箱ごとに容易に処理が可能となるデータセットを作成し、これらのグループの処理結果を合成し て、各マス目の候補ナンバーを見つける方針を採用した。 4.SAS プログラムの解説 今回の SSS は次の 4 つのプログラムからなる。 ①sudoku_macro.sas ②puzzle_make_original_data.sas 数独問題の テキストファイル ③puzzle_solve_final.sas ④reconstruct.sas これらのプログラムの詳細は 4.3 で述べる。 ORIGINAL CELL ROW COL BOX 図 4.1 SAS データセット作成手順 000801000 006030900 070000030 607000504 000206000 200070008 000405000 308000402 010309080 図 4.2 テキストファイル データ表現方法 4.1 まず、SAS で数独を解くためには、図 4.1 に示す様に、問 数・9 オブザベーション)に変換する(図 4.3)。空いたマス目に OBS a1 a2 a3 a4 a5 a6 a7 a8 a9 1 0 0 0 8 0 1 0 0 0 2 0 0 6 0 3 0 9 0 0 3 0 7 0 0 0 0 0 3 0 4 6 0 7 0 0 0 5 0 4 5 0 0 0 2 0 6 0 0 0 6 2 0 0 0 7 0 0 0 8 7 0 0 0 4 0 5 0 0 0 8 3 0 8 0 0 0 4 0 2 9 0 1 0 3 0 9 0 8 0 数字が確定されるたびに ORIGINAL に追加され、次なる処理 図 4.3 データセット ORIGINAL 題を入力し必要な SAS データセットを作成する。 はじめに、9 行 9 列の初期局面をテキストファイルに入力 する。例えば、先の図 2.1 の問題は図 4.2 に示すようにテキス トエディタで作成する。「0」は空いているマス目を表す。こ のテキストファイルを SAS データセット(ORIGINAL:9 変 に引き渡される。この ORIGINAL から、81 個の全てのマス 目の位置情報(行ナンバー、列ナンバー、箱ナンバー)と数字の値を変数とするデータセット CELL(81 オブ ザベーション)を作成する(図 4.4 中央)。各マス目の箱(box)番号は図 4.4(左端)に示す。この CELL を使 って、同一の行・列・箱に属するセルを同じオブザベーションにまとめて、それぞれ 3 つのデータセット ROW、 COL、BOX に保存する(図 4.4 右)。これら図 4.4 にある 4 つのデータセットは SAS プログラム reconstruct.sas により作成される。このプログラムは sudoku_macro.sas のプログラムの中で定義されている SAS マクロのう ち、all_filter と verify の中で%include で組み込まれており、ORIGINAL が更新されるたびに、自動的にこの 4 つのデータセットも更新される。 データセット ROW 1 1 1 4 4 4 7 7 7 1 1 1 4 4 4 7 7 7 1 1 1 4 4 4 7 7 7 2 2 2 5 5 5 8 8 8 2 2 2 5 5 5 8 8 8 2 2 2 5 5 5 8 8 8 3 3 3 6 6 6 9 9 9 3 3 3 6 6 6 9 9 9 3 3 3 6 6 6 9 9 9 マス目の箱番号 OBS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 row_no col_no box_no 1 1 1 1 2 1 1 3 1 1 4 2 1 5 2 1 6 2 1 7 3 1 8 3 1 9 3 2 1 1 2 2 1 2 3 1 2 4 2 2 5 2 2 6 2 2 7 3 2 8 3 2 9 3 v 0 0 0 8 0 1 0 0 0 0 0 6 0 3 0 9 0 0 データセット CELL 81 オブザベーションのうち 最初の 18 オブザベーションだけ表示 セ ル の 値 OBS 1 2 3 4 5 6 7 8 9 a1 a2 a3 a4 a5 a6 a7 a8 a9 0 0 0 8 0 1 0 0 0 0 0 6 0 3 0 9 0 0 0 7 0 0 0 0 0 3 0 6 0 7 0 0 0 5 0 4 0 0 0 2 0 6 0 0 0 2 0 0 0 7 0 0 0 8 0 0 0 4 0 5 0 0 0 3 0 8 0 0 0 4 0 2 0 1 0 3 0 9 0 8 0 データセット COL OBS 1 2 3 4 5 6 7 8 9 a1 a2 a3 a4 a5 a6 a7 a8 a9 0 0 0 6 0 2 0 3 0 0 0 7 0 0 0 0 0 1 0 6 0 7 0 0 0 8 0 8 0 0 0 2 0 4 0 3 0 3 0 0 0 7 0 0 0 1 0 0 0 6 0 5 0 9 0 9 0 5 0 0 0 4 0 0 0 3 0 0 0 0 0 8 0 0 0 4 0 8 0 2 0 データセット BOX OBS 1 2 3 4 5 6 7 8 9 a1 a2 a3 a4 a5 a6 a7 a8 a9 0 0 0 0 0 7 0 6 0 8 0 0 0 3 0 1 0 0 0 9 0 0 0 3 0 0 0 6 0 2 0 0 0 7 0 0 0 2 0 0 0 7 0 6 0 5 0 0 0 0 0 4 0 8 0 3 0 0 0 1 0 8 0 4 0 3 0 0 0 5 0 9 0 4 0 0 0 8 0 2 0 解きたい 数独問題 図 4.4 作成されたデータセット 4.2 フィルタ SSS では始めにマス目毎に対応する数値変数 filter を作成し、 それを基に正解の数字の特定作業が行われる。 つまり filter とは思考のキーとなる最も重要な情報であると言える。具体的には、filter は空いているマス目が 所属する行・列・箱のグループのいずれかで既に使用されている数字を使って最大 9 ケタの整数で表現した ものであり、そこに含まれている数字はそのマス目では使えない。filter は [ ]と表され、 ま たは i となる。例えば filter の値が「123406780」の場合、5 と 9 が使用できる、つまり候補ナンバーになる。 4.3 プログラムの構造 SSS を構成する 4 つの SAS プログラムの関係は図 4.5 に示す通りである。 START ① sudoku_macro.sas ② puzzle_make_original_data.sas SSS を保存するドライブ名を指定 解法に必要な全てのマクロを定義 マクロの中で%include によって④ reconstruct.sas が実行される %let で解きたい数独問題のテキス トファイル名の指定 X コマンドで必要なフォルダを自 動作成 データセット ORIGINAL を作成 ③ puzzle_solve_final.sas YES %let でマクロ変数 loop_no を指定 正解が出るか、あるいは最後の候 補の局面が制限回数を超えるまで 実行される 別の問題を 解くかどうか? NO END 図 4.5 プログラム実行手順 ① sudoku_macro.sas ここには数独の解法に必要なアルゴリズムが役割別に SAS のマクロ言語で記述されており、29 個のマクロ を定義している。利用者はこのプログラムの冒頭で%let によって SSS を構成する 4 つの SAS プログラムを保 存するドライブ名を指定しなければならない。このプログラムは SAS セッションの始めに一度実行するだけ でよい。詳細は周防・知平(2011)を参照されたい。これらのマクロの実行は③puzzle_solve_final.sas において 行われる。 ② puzzle_make_original_data.sas(付録 1 参照) このプログラムでは解きたい数独問題をあらかじめテキストエディタで作成したテキストファイルを読み 込んで、データセット ORIGINAL を作成する。そのためにプログラム冒頭で%let によって解きたい数独問題 のテキストファイル名を指定する(拡張子は指定しなくてよい) 。また、X コマンドで、DOS 命令が実行さ れ、①sudoku_macro.sas で指定したドライブ(例えば C ドライブ)に、次の 2 つのフォルダが自動的に新規 作成される。 (1) アウトプット画面に出力される情報のうち、ODS 機能を使って html 形式で保存する情報を格納 するフォルダ[C:¥sudoku¥output_window] (2) ログ画面の全情報(log.txt)、及び(1)以外のアウトプット画面の情報(output.txt)を保存するための フォルダ[C:¥sudoku¥log_window] 一般的に SAS プログラムを実行すると、 ログ情報が LOG 画面に、 処理結果が OUTPUT 画面に表示される。 SSS の実行をこの通常の方法で行うと、%include 文で何度も同じプログラムを書き加えていくので、LOG 情 報の量が表示限度を軽く超えてしまい、あふれの警告情報が頻繁に出現して、実行の中断が起きる。しかし LOG 情報はプログラム開発中は貴重なディバッグ用情報として不可欠である。そのため、proc printto を使っ て上の(2)のフォルダの中に外部のテキストファイル log.txt として自動的に出力・保存している。 OUTPUT 画面の情報も、プログラム開発中は動作の確認のため必要となる。その情報の中には、数独を解 いている際のポイントとなるいくつかの局面だけを別個保存して、解法の際の進行状況を容易に確認できる ようにしたい情報もある。また、SSS のエンドユーザの立場では、途中結果は重要ではなく、最後の結果の 解答だけを見たい場合もある。従って、OUTPUT 画面の情報は 3 種類の異なる形で保存している。解法の際 の局面の進行状況を確認できる情報は、上の(1)に保存している。最終結果の解答だけは、OUTPUT 画面(図 4.6)に直接表示している。その他の情報は(2)のフォルダに output.txt として保存した。上の(1)で html 形式で保 存する際は、マクロ変数 round、which、new_which の値をファイル名に使い、実行中のどのタイミングで作 成された OUTPUT 画面情報であるかが分かるようにした。例えば「round5_4_3.xls」(実際は html ファイル) はマクロ変数 round=5、which=4、new_which=3 の際に出力した局面を表している。この局面はラウンド5を 実行中に現れた局面であることが分かる。which と new_which は作戦③と作戦④においてそれぞれ候補局面 を設定するために使用している変数で、新しく局面を設定すると1増えるので、実際はその数字から1少な い値の時に出現したことを意味する。つまり、which=3(作戦③の第 3 番目の局面)から更に作戦④に進んだ時 の new_which=2(作戦④の第 2 番目の局面)を表示している。 ③ puzzle_solve_final.sas(付録 2 参照) このプログラムの冒頭の%let でマクロ変数 loop_no をユーザーが指定する。敢えて指定しない場合のデフ ォルト値は 15 である。このマクロ変数 loop_no の値は各局面においてこのプログラムの実行を繰り返す回数 の上限値を意味している。この値が小さすぎると、正解に近づいているにもかかわらず、回数制限のために 途中で打ち切られる可能性がある。実際に数独を SSS に解かせた実験結果からデフォルト値 15 あたりが妥当 と思われる。 このプログラムの冒頭では、%eval 関数によってマクロ変数 new_round と round の値も自動的に 1 ずつ増や される。マクロ変数 new_round はこのプログラムの実行の開始から終了までにこのプログラムが繰り返し実 行された総回数であり、マクロ変数 round は各局面においてこのプログラムを繰り返し実行した回数を表し ている。4.5 節で述べる作戦③や作戦④で探索の対象となる複数の候補局面(正解の局面かもしれないし、不 正解の局面かもしれない)をそれぞれデータセット ORIGINAL としてセットする度にマクロ変数 round はリ セットされる。 このプログラムは%include によって自動的に繰り返し実行されるので、各局面において無限ループに陥ら ないように実行を繰り返す回数をマクロ変数 round で数えておき、その値が loop_no の値を超えるとそれ以 上の探索は中止して、次の候補の局面の探索に移る。従ってこのプログラムの実行が始まると、正解が出る か、あるいは最後の候補の局面が制限回数を超えるまで%include で自分自身のプログラムを組み込むことに より、自動的に繰り返し実行される。 ④ reconstruct.sas(付録 3 参照) このプログラムは、引き渡されたデータセット ORIGINAL から 4 つのデータセット CELL、ROW、COL、 BOX を作成する。このプログラムは①sudoku_macro.sas の中の SAS マクロ all_filter と verify の中で%include により自動的に組み込まれて実行される。 4.4 プログラムの利用法 SSS を利用する時の手順を以下に示す。 ① sudoku_macro.sas の冒頭で%let でプログラムを保存するドライブ名を指定後、サブミットする。 ② puzzle_make_original_data.sas の冒頭で%let で、数独問題のテキストファイル名(拡張子不要)を指定 し、サブミットする。 (データセット ORIGINAL が作成される。) ③ puzzle_solve_final.sas の冒頭で%let によりマクロ変数 loop_no を指定後、サブミットする。 loop_no は指定しなければデフォルト値 15 が設定される。 上記の①②③を行った後、正解が得られれば、アウトプット画面に正解の最終局面が表示される(図 4.6 左) 。正解が得られなかった場合は、途中結果として、作戦③で複数の候補局面を作る直前の局面、つまり 正解であると確定している数字のみが入った局面が表示される(図 4.6 右) 。 引き続き別の数独問題を解く場合は②と③を繰り返す。 正解が得られました ここまでしか出来ませんでした OBS a1 a2 a3 a4 a5 a6 a7 a8 a9 OBS a1 a2 a3 a4 a5 a6 a7 a8 a9 1 5 9 3 8 6 1 2 4 7 1 0 0 5 3 0 0 0 0 0 2 8 2 6 7 3 4 9 5 1 2 8 0 0 0 5 0 0 2 0 3 4 7 1 9 5 2 8 3 6 3 0 7 0 0 1 0 5 0 0 4 6 3 7 1 9 8 5 2 4 4 4 0 0 0 0 5 3 0 0 5 1 8 5 2 4 6 3 7 9 5 0 1 0 0 7 3 0 0 6 6 2 4 9 5 7 3 1 6 8 6 0 0 3 2 0 0 0 8 0 7 9 6 2 4 8 5 7 1 3 7 0 6 0 5 0 0 0 0 9 8 3 5 8 6 1 7 4 9 2 8 0 0 4 0 0 0 0 3 0 9 7 1 4 3 2 9 6 8 5 9 0 0 0 0 0 9 7 0 0 図 5.2 の問題の実行結果のアウトプット画面 図 2.1 の問題の実行結果のアウトプット画面 図 4.6 4.5 実行結果のアウトプット画面 4 つの作戦の解説 現在までに開発した SSS では 4 種類の作戦を採用 初期局面 している。実行する作戦は図 4.7 に示すように、作戦 Give up ! ①から順次適用していき、その結果、新しいマス目に 数字を確定することができなかった場合には次の作 戦に移る。そこで新たに確定できる数字を見つけた場 合は次の作戦に移らず、データセット ORIGINAL を アップデートした後、再び作戦①に戻って実行するよ うに設計した。なぜならば、新たに確定できたマス目 i i=1 = ≠ 作戦番号 (1~4) i:5 再 帰 的 に 繰 り 返 し 現局面 i=i+1 作戦 i を適用 NO マス目が新たに 埋まったか? YES が 1 つでも増えることによって、その情報が他の行・ 現局面の更新作業 列・箱に波及効果を与え、フィルタの更新が行われ、 その結果として新たなマス目に数字が確定できる可 能性が高くなるからである。 NO 全てのマス目が 埋まったか? YES まず作戦①を実行する前に、局面探索のキーとなる 正解 変数 filter を作成しておく。 図 4.7 4 つの作戦の流れ 作戦① この作戦①では数字の特定の方法は 2 つある。 1 つ目は、空のマス目に候補ナンバーが 1 個しか残っていない場合である。この場合は当然その数字が確 定する。図 4.8 の(1)のマス目の filter は[123456089]であり、7 以外の数字はこのマス目が所属する行・列・箱 のいずれかで使用されている。つまり候補ナンバーが 1 つしかない。従って、この時点でこのマス目の数字 は 7 に確定する。 2 つ目は、1つのマス目に複数の候補ナンバーがあ る場合でも、行・列・箱のグループごとに見た時に或 る数字がそのマス目だけに候補ナンバーとして残って いる場合にも、その数字は確定になる。図 4.8 の(2)の マス目では候補ナンバーは複数あるが、この(2)のマス 目のある行を見てみると、(2)のマス目以外の空いたマ 123 006 780 023 006 709 023 006 700 6 023 006 700 2 ス目の filter には全て 2 が入っていることが分かる。つ 123 456 080 まりこの行において、2 を入れることができるのは(2) 3 のマス目だけだということになる。従ってこのマス目 123 006 089 の数字は 2 で確定する。 100 006 780 103 006 709 100 006 780 6 003 006 780 7 103 000 780 8 123 406 089 123 400 780 02 3 456 780 120 456 700 120 006 700 120 006 780 103 450 780 123 400 780 020 006 780 020 006 780 103 456 780 023 406 780 8 023 450 089 1 103 006 789 7 (1) 2 103 450 089 103 056 089 103 103 003 000 056 450 780 789 709 023 12 0 456 456 700 709 023 020 006 456 700 089 120 020 056 450 789 789 003 020 450 450 709 089 023 123 450 456 789 089 103 123 450 450 789 089 3 9 5 6 4 7 5 3 4 9 図 4.8 この 2 種類の方法により新たに数字が見つかった場 1 103 000 089 003 006 089 3 003 456 780 023 456 080 023 450 780 023 450 080 023 400 080 8 123 400 089 023 406 089 023 400 789 4 020 456 080 (2) 8 020 450 080 2 123 400 089 作戦① 合は、空のマス目にその数字を追加した後、ORIGINAL を更新し、プログラム puzzle_solve_final.sas の先頭に 戻る。この方法で新しい数字が見つからなくなるまで繰り返した後、次の作戦②へ移る。 作戦② この作戦は、作戦①で新たな数字が確定できなくなった場合に、filter 情報だけのアップデートを試みる。 まず候補ナンバーが 2 つしかないマス目を探す。そしてそのマス目が所属する行・列・箱のグループの中で 同じ組み合わせの数字のマス目、つまり同じ filter 情報を持つマス目を探す。同じ数字の組み合わせのマス目 が 2 つあった場合はそのグループの中ではもうその数字は他のマス目では使えない。そこでそのグループ内 の他マス目の filter にさらにその 2 つの数字を追加し、filter をアップデートする。例えば、図 4.9 で黒いマス 目 2 つは同じ行にあり、かつ候補ナンバーが共に 1 と 6 である。つまりこの 2 つのマス目のどちらかに 1 が 入り、もう 1 つには 6 が入ることは確定している。従って、この行の他のマス目では 1 と 6 が候補になるこ とはないので、同一行の他のマス目の filter には 1 と 6 を追加することができる(図 4.9 右) 。 123 006 780 023 006 709 023 006 780 123 006 780 103 006 709 7 3 8 123 400 780 6 7 3 003 006 780 123 450 780 023 456 780 123 400 780 023 456 780 6 3 7 023 406 700 123 406 700 123 056 780 103 450 780 123 400 780 023 406 780 023 056 780 103 456 780 2 123 456 080 3 123 006 089 1 8 123 006 789 1 103 056 789 103 056 789 8 2 4 6 5 7 3 4 8 023 450 789 023 450 789 3 2 5 123 000 089 023 006 789 2 9 8 3 123 400 089 023 406 789 023 400 789 123 006 780 023 006 709 023 006 780 123 006 780 103 006 709 7 3 8 123 400 780 6 7 3 003 006 780 123 450 780 023 456 780 123 400 780 023 456 780 5 2 4 6 3 7 020 456 089 023 450 789 020 450 089 023 456 080 023 450 780 023 450 080 023 400 780 020 456 080 023 406 700 123 406 700 123 056 780 103 450 780 123 406 780 023 406 780 023 056 780 103 456 780 7 4 9 123 450 089 8 8 2 020 450 080 123 456 080 2 3 123 400 089 123 006 089 1 8 123 006 789 作戦②適用前 123 400 780 1 103 056 789 103 056 789 8 2 4 6 5 7 3 2 9 8 5 2 4 023 456 080 023 450 780 023 450 080 123 406 780 020 456 080 4 8 5 023 450 789 7 4 9 123 450 089 2 3 8 作戦②適用後 023 400 780 図 4.9 123 406 780 作戦②適用の前と後のフィルタ情報の変化 123 400 089 023 406 789 023 400 789 020 456 089 023 450 789 020 450 089 023 450 789 3 123 000 089 023 006 789 123 406 780 8 020 450 080 2 123 400 089 この確認を行・列・箱の全てに対して行った後、新しくなった filter を使って作戦①を再実行する。その結 果、新しい数字が見つかればその数字を追加した後にまた作戦①に戻り、見つからなければ作戦②に進む。 作戦②の実行にも関わらず、新しい数字が見つからなければ次の作戦③に移る。 作戦③ 作戦②を実行した後でも新たな数字が見 000 450 089 100 400 089 000 400 789 つからなかった場合には、 正解が必ず含まれ る複数の候補局面を作り、 それらを一つずつ チェックしていく。候補を作るために、現在 4 の局面から候補ナンバーが 2 個あるマス目 を行・列・箱のグループとは関わりなく任意 の 2 個を取り出す。その取り出した候補ナン バーの全ての組み合わせ、 つまり4通りの組 (1) み合わせの候補局面を作成する。この 4 通り の局面のいずれか1つは必ず正解なので、 そ れぞれの候補局面に逐次、 作戦①と作戦②を 020 456 009 9 020 406 709 6 8 2 020 406 089 020 450 780 100 450 080 003 450 080 020 406 089 020 056 789 120 456 089 023 056 089 実行する。図 4.10 の場合、黒色のマス目を 2 000 450 089 100 450 089 4 9 023 456 089 020 456 089 020 450 789 8 5 103 450 709 103 450 709 7 123 406 709 123 056 780 103 400 789 123 000 700 1 3 図 4.10 000 450 709 100 450 709 000 450 700 120 406 709 023 056 080 000 400 089 123 000 700 103 400 780 103 050 780 5 9 4 1 000 450 700 120 456 709 023 456 780 000 450 789 120 406 789 7 6 103 450 089 103 400 089 103 400 789 003 456 789 100 450 009 100 450 709 003 456 789 3 5 4 4 8 9 7 2 023 400 780 103 450 780 103 450 780 120 406 789 4 8 023 450 080 020 450 789 120 450 089 023 450 089 (2) 作戦③ つ選び、この 2 つのマス目の候補の全ての組み合わせ、つまり(1)のマス目には 1 か 7、(2)のマス目には 3 か 5 の数字を入れた 4 つの候補局面を作成し実行する。 その際、途中で誤答が判明するか、局面に進展がなくなった場合はそこで中止して、残りの局面を順次試 していく。4 つの局面全てを試しても、正解に達しない場合は次の作戦④に移る。 作戦④ 作戦③で試みた 4 つの局面それぞれに対して、更に候補ナンバーが 2 個ある任意のマス目を取り出し、新 しく候補の局面を作成する。作戦④では候補ナンバーが 2 個あるマス目が 1 つしかない場合も想定し、マス 目を 1 つだけ使用する場合と、2 つ使用する場合のどちらかを実行する。作戦③で作成した 4 通りの組み合 わせの局面を 1 つ取り出し、候補ナンバーが 2 個のマス目を列挙する。その様なマス目が 2 つ以上ある場合 には、それから任意にマス目を 2 つ取り出し候補ナンバーの組み合わせで 4 つの新しい局面を作る。マス目 が 1 つしかない場合はそのマス目のみ使用し 2 つの新しい局面を作る。新しい局面を作成したらそれぞれの 局面について作戦①から実行する。これを作戦③の 4 通りの局面すべてについてそれぞれ試す。従って、作 戦④では最高 16 個の新しい局面を作成し、試すことができる。 5.プログラムの性能とバージョンアップの可能性 数独の市販本やインターネット上に難問として紹介されている問題をいくつか試した結果、現時点では 1 つを除き正解を出すことに成功しているので、SSS はほとんどの数独の問題について解くことができるとい っても過言ではない。解けた難問の2例を図 5.1 に示す。 (解答は付録4を参照) 現プログラムで解くことのできない唯一の難問を図 5.2 に示す。この問題が掲載されているサイトによる と「科学と応用数学の博士号を持つフィンランド人の環境科学者 Arto Inkala 博士が、解が一つだけ存在し「当 てずっぽう」ではなく「論理」のみですべての 5 9 4 1 9 マスを埋めることができる「正しい数独」の中 4 7 6 9 8 2 で限りなく難しい、「世界一難しい数独」を作 り出すことに成功した」という記述がある。 この問題を SSS に解かせてみると、作戦② 8 1 5 3 まで適用して図 5.3 にあるシャドウのかかった 2 つのマス目の数字、5 と 3 を見つけた後、SSS は作戦③作戦④を適用したが、局面の進展はそ 1 5 8 3 5 4 8 7 2 4 (難問 1) 出典: (http://robohei.jugem.cc/?eid=1689) れ以上得られなかった。 図 5.1 時間的制約を考慮しなければ、 「しらみつぶ 4 8 5 1 7 3 8 7 4 5 9 1 3 2 5 8 8 2 4 6 9 8 4 3 (難問 2) 出典: (http://kaka8.blog.so-net.ne.jp/ archive/20110416) 解けた難問例 し法」で全ての組み合わせについてチェックし ていけば正解は必ず得られるが、feasible でない。つまり、組み合わせの爆発が起こり、計算時間がかかりす ぎて正解にたどりつけない。 図 5.3 は、数字が確定していないマス目について、9 桁の数字から成る filter 情報を書き出している。filter の中にある 0 に対応する場所にある数字が候補ナンバーである。従って、そのマス目の 0 の個数が候補ナン バーの個数になり、その個数を全て掛け合わせた数字がこの局面から出現しうる総局面の数である。 実際に、図 5.3 からのその総局面数を計算してみると、 通りになる。これは、仮に 1 秒間に 1 億個の局面をチェックできたとしても 1000 兆年以上かかる計算になり、実行不可能である。 現在のバージョンでは作戦③と④において候補ナンバーが 2 つに限定されている 4 つのマス目を使用して 16 個の候補の局面を作成した後、それぞれを初期局面として作戦①から再開している。それにもかかわらず 最後までは解けないので、今後の計画としては、さらに使用するマス目を1つ増やして 32 個の局面を作成し て、作戦①から実行を再開できるようにプログラムのバージョンアップをするつもりである。この程度の局 面数の増加は実行時間の点で実行可能範囲である。 5 3 8 2 7 1 1 7 4 5 5 3 6 3 2 6 5 4 8 9 3 9 7 図 5.2 解けなかった難問 出典: (http://gigazine.net/news/20100822_ hardest_sudoku/) 003 103 450 056 780 780 120 8 056 780 100 450 7 780 103 4 456 700 103 406 1 780 123 123 400 406 080 780 000 456 6 089 003 103 406 406 080 700 000 100 406 406 789 709 5 3 023 450 780 103 450 780 103 450 000 103 456 700 123 050 080 123 050 700 023 450 700 123 056 700 3 2 003 456 009 5 023 4 450 009 003 023 456 050 709 709 103 103 023 023 050 050 050 050 700 009 700 080 123 023 5 050 050 2 089 780 103 123 1 050 5 050 709 780 123 023 450 5 3 456 700 080 103 123 7 3 056 006 780 780 123 023 023 050 050 056 8 780 789 780 100 003 003 023 056 056 056 056 709 009 709 789 103 003 003 450 450 450 3 709 009 709 100 023 050 9 7 000 709 789 023 056 009 020 056 089 120 056 709 003 456 089 6 023 006 089 9 003 406 709 003 006 709 図 5.3 フィルタ情報の表示 参考文献 周防節雄・知平菜美子(2011) 本論文集収録 SAS マクロ言語を使った数独パズルを解くプログラムの構造と制御方法、 付録1.puzzle_make_original_data.sas /* puzzle_make_original_data.sas */ *★以下のマクロ変数を設定してください。; %let Q=Q113; *数独問題の dat ファイル名の指定(拡 張子は不要); *以下の設定は変更不要; %let round=0; *各局面ごとに繰り返した回数; %let which=1; *作戦③で4つの候補局面(original_1 ~original_4)の設定; %let new_which=0; *作戦④で 2 つの候補局面 (original1・original2)の設定; %let new_round=0; *puzzle_solve_final.sas を実行した 回数; %let select_sw=0; *作戦④で候補が2つか4つかの 判定; options noxwait; x "cd &drive:¥"; x "md sudoku"; *&drive にフォルダ sudoku を作成; x "cd sudoku"; x "md output_window"; *&drive:¥sudoku の下にフォル ダ output_window 作成; x "md log_window"; *&drive:¥sudoku の下にフォ ルダ log_window 作成; x "exit"; %let log=&drive:¥sudoku¥log_window; %let output=&drive:¥sudoku¥output_window; options nocenter nodate nonumber ls=90; filename in1 "&problem_folder¥&Q..dat"; data original; drop i; infile in1; array a {9} $ 1; do i=1 to 9; input @i a{i} @@; end; input; /* Release current data line.*/ run; ods listing close; ods html file="&output¥&Q..xls"; proc print data=original; title "data=original"; run; ods html close; ods listing; 付録2.puzzle_solve_final.sas /* puzzle_solve_final.sas */ *Before this program is run, "puzzle_make_original_data.sas" must be run.; options mprint SPOOL; %let loop_no=15; *各局面の繰り返し回数の上限を指 定してください; *以下は設定不要; %let star=*; /* blank=Valid ODS, "*"=Stop ODS;*/ %let round=%eval(&round+1); %let wrong=0; /*0=Not Wrong Answer,1=Wrong Answer*/ %let new_round=%eval(&new_round+1); data original_before; *this dataset will be compared with "new" original at the bottom; set original; run; ods listing close; ods html file="&output¥ROUND&round._&which._&new_which ..xls"; proc print data=original; title "ROUND &round:&new_round. data=original"; run; ods html close; ods listing; PROC PRINTTO log="&log¥logROUND&round._&which._&new_which ..txt" NEW; RUN; PROC PRINTTO print="&log¥outputROUND&round._&which._&new_w hich..txt" NEW; RUN; %all; *解法エンジン; 付録3.reconstruct.sas /* reconstruct.sas */ proc print data=row; title "data=row"; run; data cell; keep v row_no col_no box_no; array a {9} $ 1; *array row_no {9}; *array col_no {9}; *array box_no {9}; *-------------------------------------------; proc sort data=cell; by col_no; run; set original; do i=1 to 9; row_no=_n_; col_no=i; box_no=MAX(INT((_n_-1)/3),0)+INT( (i-1)/3)+2*INT((_n_-1)/3)+1; v=a{i}; output;; end; run; data col; keep a1-a9; array a {9} $ 1; retain a1-a9; set cell; by col_no; a{row_no}=v; if last.col_no then output; run; proc print data=col; title "data=col"; run; proc print data=cell; title "data=cell"; run; *-------------------------------------------; *-------------------------------------------; proc sort data=cell; by row_no; run; proc sort data=cell; by box_no; run; data box; keep a1-a9; array a {9} $ 1; retain a1-a9 i; data row; keep a1-a9; array a {9} $ 1; retain a1-a9; set cell; by box_no; if first.box_no then i=1; a{i}=v; i+1; if last.box_no then output; set cell; by row_no; a{col_no}=v; if last.row_no then output; run; run; options nocenter ps=100; proc print data=box; title "data=box"; run; 付録4.図 5.1 の難問の解答 7 5 6 4 8 3 9 2 1 8 9 1 6 2 5 3 7 4 3 2 4 9 7 1 6 8 5 2 8 7 5 9 6 4 1 3 1 6 9 3 4 7 8 5 2 5 4 3 8 1 2 7 9 6 9 1 5 7 6 4 2 3 8 6 7 2 1 3 8 5 4 9 4 3 8 2 5 9 1 6 7 (難問 1) 3 1 4 9 8 2 7 6 5 6 5 8 1 4 7 3 9 2 2 7 9 3 5 6 1 8 4 9 2 5 4 7 3 8 1 6 4 6 1 8 9 5 2 7 3 8 3 7 2 6 1 4 5 9 5 4 3 6 1 8 9 2 7 7 8 2 5 3 9 6 4 1 1 9 6 7 2 4 5 3 8 (難問 2)
© Copyright 2024 Paperzz