黒マスはどこだ(通称:黒どこ)というパズルを扱う。 黒どこは,N×N のマスに,次の条件に従って 黒マスを入れていくパズルである。
以下のレベルのいずれか1つを選んで解答せよ。
9x9の黒どこを出題して遊べるプログラムを作成せよ。 以下の点に注意すること。
5x5の黒どこの問題を自動的に解答し,すべての解を報告するプログラムを作りなさい。つまり、
9x9の黒どこの問題を自動的に解答し, (できるだけすべての)解を報告するプログラムを作りなさい。つまり、
なお本課題に対しては,q1.txt〜q20.txt の問題 を自動的に解答するプログラムを作りなさい。 実行結果としては、これらのいくつか(5個以上)の解答例を示すこと。 さらに自分で入力した問題(解の数が不明なもの)に対しても解答できるとなお良い。 ただし、 これらの問題には解がただ 1 つしかないことがわかっている。 また問題は番号が大きいほど難しいので、それらが解けるほどポイントが高い。
Level 2で述べたヒントを参考にすること。最後の段階で 全探索する候補をできるだけ減らす努力が必要となる。
またLevel 3 では,「局面の状態を保持し,仮定を置いて解き進める」ことも必要なる。このためにスタック(stack)と呼ばれるデータ構造を使用するとよい。
スタックは,LIFO(Last-In First-Out)型のバッファで,最後にスタックに入れたものが最初に取り出される。スタックにデータを入れる操作をプッシュ(push),スタックからデータを取り出す操作をポップ(pop)という。
たとえば,int
型変数を保持するスタックは,次のようにコーディングされる。
struct stack_elem { int data; struct stack_elem *prev; }; struct stack_elem *stack_top = NULL; /* x をスタックにプッシュする */ int stack_push(int x) { struct stack_elem *tmp; if ((tmp = (struct stack_elem *)malloc(sizeof(struct stack_elem))) == NULL) { fprintf(stderr, "Memory Error!\n"); exit(-1); } tmp->data = x; tmp->prev = stack_top, stack_top = tmp; return x; } /* スタックトップにあるデータをポップする */ int stack_pop() { struct stack_elem *tmp; int x; if (stack_top == NULL) { fprintf(stderr, "The Stack is Empty.\n"); exit(-1); } x = stack_top->data; tmp = stack_top, stack_top = stack_top->prev; free(tmp); return x; }
この「スタック」を利用したプログラムの例として,「スタックマシン」(stkmacn.c
)という計算機をあげておく。スタックマシンは,レジスタを持たない簡単な計算機モデルであり,オペランド(計算対象)をスタックにプッシュしておき,演算はスタック中の値をポップして行う。
ちなみに,スタックを用いて解の探索を行うと「深さ優先探索(depth-first search)」になる。幅優先探索の場合は,局面を保持するデータ構造に,リストまたは多分木を使うことになる(ここでは,これらについての解説は省略する)。
Level 2およびLevel 3に対して、以下のように入出力仕様を規定する。
stdin
)から行い,与えられたフォーマットで書かれた「問題」を読めるようにしなさい。このとき,ファイルからの入力は,リダイレクションを使用することになる(例:% ./a.out < assign1.txt)。
stdout
)に行う(ファイルへ出力する場合は,% ./a.out < assign1.txt > result1.txt のようにリダイレクションを使用する)。ただし,エラーメッセージなどは標準エラー出力(stderr
)に出力する。