おはやし日記

テーマ……バイク←プログラミング←旅

プログラムにナンプレを解かせたい - その3

ナンプレプログラム途中経過。ひとまず最終回メニュー操作、メイン関数、makefileについて。 前回はセッティング、というかncursesの仕様について振り返った

o-treetree.hatenablog.com

メニュー

sudoku/ver.1/menu

ヘッダファイル

なんでグローバル変数を置いたのか…………いる?要らなくない?

int LS[9] = {0,1,2,4,5,6,8,9,10};
int RS[9] = {1,5,9,15,19,23,29,33,37};

なぜかここにもあるグローバル変数。せめてまとめろ。これは表示の時に使う。区切り線も勘案した表示上の座標。

後々わかったが、インクルードファイルの方に配列を初期化して書くとコンパイルできない。menu.cとmain.cの両方にmenu.hをインクルードしているので両方で展開されて衝突する。

  • void menu()

ループを回して、

findAllOnlyOne(); //menu.c内、確定できるところを見つける
showAllTest(); //calc.c内、表示処理
markNow(now); //menu.c内、現在地を表示
printmenu(); //メニュー画面を表示
ch = getch();
/* chにキーを入れ、それにより分岐 */
checkNumAll(); /calc.c内/全マスで確定するか判断
refresh(); //ncurses.h 表示。

findAllOnlyOne();はループの後ろで良かったのでは

  • void print menu() 冒頭のprintw("now(%d, %d, in %d): ", LINE(now), ROW(now), BLOCK(now));要らん、ていうか上書きされるやん。デバッグの時に表示してたところだ

  • void udrl(int ch) 入力が方向キーだった時の動作

  • markNow(int n) 現在地のマスn$ $で強調表示する

  • findAllOnlyOne()

for(i: 全マス)
    for(j: 0~8)
        if(マスiの候補jが存在するなら)
            if(ifOnlyOne(i, j)) //jで確定できるなら
               inputNum(i, j+1) //マスiに数字jを確定

二重のifは&&でよかった

  • void changeKouho() まだ自動化できてない分、手動で候補のフラグを変更する関数。これで候補を削ると確定するところがあったりする。
//changeに変更する候補を入れた後
masu[now].kouho[change] = masu[now].kouho[change] ? 0 : 1;

これは三項演算子。以下のif文と同値。

if(masu[now].kouho[change]){
    masu[now].kouho[change] = 0;
}else{
    masu[now].kouho[change] = 1;
}

要は0と1の反転なんだけど別の書き方ないかね

  • -1して絶対値をとる(0 -> |-1| = 1, 1 -> 0
  • 1とのXOR^をとる(1^1 = 0, 0^1 = 1)こっちの方がスマートだ

メイン・makefile

sudoku/ver.1/main.c-makefile

main.c

メイン関数。

int main(void){
    startGame(); //開始時設定
    reset(); //盤面リセット
    getch(); //何かしらのキー入力まで待機
    menu(); //これでゲームループが始まる
    showAllTest(); //終了前に全マス開示……いる?
    getch(); //キー操作待機
    endGame(); //終了処理
    return 0;
}

特に言うことなし。

makefile

これを置いておけば簡単なコマンドでコンパイルができる。

基本的な構造
{ターゲット}: 素材を列挙
{tab}{コマンド} //{tab}はタブ文字。空白ではいけない

例えば

main: main.c
{tab}gcc -o main main.c

と作っておけばターミナルでmake mainと打つとそれがgcc -o main main.cに変換されて実行される。便利やね。実際にはもっと細かいが、まあ。

実際
  • マクロ
MAKE_O = gcc -c $<

MAKE_Ogcc -c $<に置き換わる

  • solveSudoku
solveSudoku: main.o setting.o calc.o menu.o
    gcc -lncurses -o $@ $^

$@はターゲット名を示すマクロ。$^はすべての素材を示すマクロ。つまり上記のコマンドは

gcc -lncurses -o solveSudoku main.o setting.o calc.o menu.o

と解釈される。ちなみに-lncursesは、ncurses.hを利用するために必要なオプション。

  • main.oその他
calc.o: calc.c calc.h
    $(MAKE_O)

hogehoge.oをつくるためのコマンド。マクロを展開して

calc.o: calc.c calc.h
    gcc -c $<

さらに、$<は素材の先頭のものを示すマクロ。素材の先頭に.cのファイルを置くことで

calc.o: calc.c calc.h
    gcc -c calc.c

と解釈される。

  • clean 要らんファイルを消すのにcleanを使ったりするらしいが適当にやっているので参考にはならん

  • do ./solveSudokuを打つのがめんどいのでこのコマンドでmake doで置き換える

まとめ

ビット演算を活用したい

ビット 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
unsigned short x 1 0 0 1 0 0 1 0 1 0 1 0 1 0 1 0
用途 a a a a 0 0 b b b b b b b b b c
  • a : 確定した数字 0001 ~ 1001 x>>12で取り出せる
  • b : i=1~9の候補フラグ x>>i & 1 で取り出せる
  • c : 確定したか1/0 x&1で取り出せる

う〜む良さげ!

あとは、手動で潰している候補をある程度自動で潰せるようにしたい。 ま、とりあえず洗い出せた改善点を改良してver.2を作ってみようと思う。おしまい。

追記:改良版ができてます ↓

o-treetree.hatenablog.com

よろしくどうぞ!

プライバシーポリシー ・お問い合わせはこちら