「コンピュータ プログラミング」第 3 回課題

課題の内容

黒マスはどこだ(通称:黒どこ)というパズルを扱う。 黒どこは,N×N のマスに,次の条件に従って 黒マスを入れていくパズルである。

例題(9x9の場合)

例題1 例題2

解答

解答1 解答2

黒どこの解き方のヒント

以下のレベルのいずれか1つを選んで解答せよ。

Level 1:Minimum

9x9の黒どこを出題して遊べるプログラムを作成せよ。 以下の点に注意すること。

ヒント

Level 2:Fair

5x5の黒どこの問題を自動的に解答し,すべての解を報告するプログラムを作りなさい。つまり、

レポートに実行結果として添付するのは,Level 1の要領でランダムに生成した いくつかの問題例とする

ヒント

Level 3:Ambitious

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に対して、以下のように入出力仕様を規定する。

参考文献など