メニエスの名のもとに

プログラミング関係を中心としたぐだぐだブログ

ナンプレ(数独)問題作成プログラム その2

プログラミング言語を決める

プログラムを書き始める前には、どのプログラミング言語で記述するかを決定する必要がある。しかし、この世には星の数ほどプログラミング言語があるし、今この瞬間にも新しいプログラミング言語が誕生しているかも知れない。
既に知っているプログラミング言語で書いてもいいし、知らないプログラミング言語を勉強しながら書いてもいい。しかし、目的を見失ってはいけない。いまするべきことはプログラミング言語の学習ではなく、ナンプレの問題を作成することなのだ。
そう考えるならば、知っているプログラミング言語を使う方が無難である。そうなると、オブジェクト指向以前の古いプログラミング言語か、オブジェクト指向かという二択になる。幸いにも私は関数型言語を使いこなすほどには知っていないので、二択で済むのである。
オブジェクト指向言語を知っていると言っても、息をするようにクラス設計が出来るという程知っているわけではない。いつもこのクラス設計でいいのだろうかと悩みながらプログラムを書いている。まあ、そうやって人は成長するわけだが、目的を見失ってはいけない。いまするべきことは、オブジェクト指向の勉強ではなく、ナンプレの問題を作成することなのだ。
人間の能力には限りがあるのである。対象とする問題をよく知っている場合や、対象とする問題が簡単な場合は、勉強をしながらプログラミングをするのもいい。また、GUIアプリのようにオブジェクト指向を使用しないでプログラムを作成するのが困難な場合は、仕方がない。
しかし、対象とする問題がよくわからない場合は、プログラミング言語はよく知っている言語を使うべきである。というわけで、C言語でナンプレ問題作成プログラムを作成することに決定した。
このように、プログラミングを始める前にしっかりと考えておくべきである。一度、別の言語でプログラミングを始めてしまい、うまくいかなくてC言語に戻ったりするのはやるべきではない。格好悪いからね。くれぐれも注意するように。
なお、stdint.h を使用するので c99 でやる。

データ構造を決める

まず1つのマスとなる cell_t を次のように決める。

 typedef struct {
    unsigned symbol : 9;
    unsigned fixed : 1;
  } cell_t;

symbol にそのマスに入る候補となる数字が入る。何も入っていなければ0, 1 だけなら 1, 1 と2 が入っていれば 3である。数字nを2n-1(上付き文字指定supがうまく表示されない。どうしたらいいんだ?)で表すのである。このビット表現とビット操作がナンプレプログラムの基本になる。fixed はそのマスが最初に見えているマスかどうかを示す。
fixed なら見えているマス、パズルを解くときにユーザーが変更することが出来ないマスである。実は、もう一つフラグがあるのだが、使わないことにしたので、ここではデータ構造に入れない。そのフラグというのは、そのマスに入っている候補が一つだけであることを示すフラグであった。それは冗長な情報である。symbol を見ればいつでも分かるから。一方、一つだけならそれは問題を解くプログラムによって確定した数字ということであり、その数字をもとに他のマスの候補を絞ることができるという点で重要である。
これは、オブジェクト指向でも問題となることで、冗長な情報を持つか、それとも毎回計算するかというのは判断に悩む問題である。冗長性はメモリの無駄と言うよりも、情報が矛盾するという危険となる。で、以前はフラグを持っていたが、今回はフラグを持たないという決定をした。今流行りの関数型言語(さらに遅延評価)ならば、このフラグはもたないであろう。このフラグは持たない方がプログラミングスタイルとして正しいのだ。というよりも、フラグの立て忘れによるバグが怖いのである。より正確に言えば、バグが出る度に、このフラグの立て忘れではないかと毎回疑って、ソースを見直すことを繰り返して嫌になったからである。ただし、そういうことを書くと格好悪いので書かない方がいい。
今日の分はこのくらいで。

次回予告

今日の続きで、SIMD within a register (SWAR)から