最終回。↓のつづき。
プログラムがパワーアップした後の要点は、
ここ↑で書いたcalc.c
の計算部分と
ここ↑で書いたfileio.c
のファイル入出力です。
今回は、なんとなく作ったログ書き出しプログラムについて書きます。あと、makefileについて。
全体のプログラムはこちら↓
GitHub - oha-yashi/sudoku: ナンプレ攻略プログラム
(追記@2020/5月) これをJavaScriptに移植したwebバージョンができてます!詳しくは ↓
log.c
動作
githubからcloneしたあと(詳細はプログラムにナンプレを解かせたい - その4 - おはやし日記)
$ make log
でコンパイル。
logdata
フォルダに、盤面データtest
↓をいれて
%1d 000 400 065 080 000 000 700 090 000 000 000 120 065 008 000 004 000 000 000 600 009 100 000 700 000 005 000
$ ./log test (auto)
で実行。(auto
を加えるとステップごとにEnterを叩く必要がなくなる)
Enterを叩いていくとこのように表示され、logdata/test_log
が作成される。中身は↓のようになります(クソ長い)
gistbeaa9476c970a13069f85a74f521a2d5
解答ステップごとに、全ての候補が書き出されています。さらに、前のステップから変更があったマスについてはマスの下の線が
^^^^^
となって示されています。
雑に解説
log.cはなんとなくあったらいいかも知れんと思って突貫で作ったので割と作りが雑です。
write_log()
- 数字の書き込み
for(i=0;i<9;i++){ fprintf(fp, "%d:@", i); for(j=0;j<3;j++){ roop = i*9 + j*3; fprintf(fp, "|%c %c %c|%c %c %c|%c %c %c|@", PUT_LOG(roop , 1), PUT_LOG(roop , 2), PUT_LOG(roop , 3), PUT_LOG(roop+1, 1), PUT_LOG(roop+1, 2), PUT_LOG(roop+1, 3), PUT_LOG(roop+2, 1), PUT_LOG(roop+2, 2), PUT_LOG(roop+2, 3) ); } fprintf(fp, "\n "); fprintf(fp, "%d:@", i); for(j=0;j<3;j++){ roop = i*9 + j*3; fprintf(fp, "|%c %c %c|%c %c %c|%c %c %c|@", PUT_LOG(roop , 4), PUT_LOG(roop , 5), PUT_LOG(roop , 6), PUT_LOG(roop+1, 4), PUT_LOG(roop+1, 5), PUT_LOG(roop+1, 6), PUT_LOG(roop+2, 4), PUT_LOG(roop+2, 5), PUT_LOG(roop+2, 6) ); } fprintf(fp, "\n "); fprintf(fp, "%d:@", i); for(j=0;j<3;j++){ roop = i*9 + j*3; fprintf(fp, "|%c %c %c|%c %c %c|%c %c %c|@", PUT_LOG(roop , 7), PUT_LOG(roop , 8), PUT_LOG(roop , 9), PUT_LOG(roop+1, 7), PUT_LOG(roop+1, 8), PUT_LOG(roop+1, 9), PUT_LOG(roop+2, 7), PUT_LOG(roop+2, 8), PUT_LOG(roop+2, 9) ); } fprintf(fp, "\n ");
roop
はマスの番号。PUT_LOG
はマクロ。数字or空白の表示なのでfprintf
の%c
に突っ込む。
#define PUT_LOG(n, i) FLAG(data[n], i) ? i+'0' : ' '
- 枠線(横)の書き込み
if(i==2||i==5||i==8){ fprintf(fp, "@@@@"); AT_LINE(i*9+0);AT_LINE(i*9+1);AT_LINE(i*9+2); fprintf(fp, "@@"); AT_LINE(i*9+3);AT_LINE(i*9+4);AT_LINE(i*9+5); fprintf(fp, "@@"); AT_LINE(i*9+6);AT_LINE(i*9+7);AT_LINE(i*9+8); fprintf(fp, "@\n "); }else{ fprintf(fp, "----"); DASH_LINE(i*9+0);DASH_LINE(i*9+1);DASH_LINE(i*9+2); fprintf(fp, "--"); DASH_LINE(i*9+3);DASH_LINE(i*9+4);DASH_LINE(i*9+5); fprintf(fp, "--"); DASH_LINE(i*9+6);DASH_LINE(i*9+7);DASH_LINE(i*9+8); fprintf(fp, "@\n "); }
3列ごとに@
で太い線を、その他は-
で細い線を引く。AT_LINE
とDASH_LINE
はマクロ。
#define AT_LINE(n) data[n]==buf[n] ? fprintf(fp, "@@@@@@") : fprintf(fp, "^^^^^@") #define DASH_LINE(n) data[n]==buf[n] ? fprintf(fp, "------") : fprintf(fp, "^^^^^-")
さっきみたいにfprintfの中身だけ変えればよかったな、まあええわ。要は、前ステップのデータbuf[]
と操作後のデータdata[]
が違っていれば何かしら変更があったということなので横線を^^^^^
にして示す。
menu_log()
前に作ったmenu.c/menu()
をログ書き込みに特化させた
void menu_log(){ int cnt = 1, ssK = sumsumKouho(); while(cnt < LIMIT){ if(ssK==81) break; /* 判定処理 */ only_two_pair_all(); if(ssK > sumsumKouho()){ /* 処理で候補を減らせたら */ write_log(cnt, 1, "two pairs -> delete num except pair"); move_data(data, buf); ssK = sumsumKouho(); }if(ssK==81) break; findPairAll(); if(ssK > sumsumKouho()){ write_log(cnt, 2, "two pairs -> delete pair in LineRowBlock"); move_data(data, buf); ssK = sumsumKouho(); }if(ssK==81) break; read_and_delete(); if(ssK > sumsumKouho()){ write_log(cnt, 3, "read LineRowBlock and delete"); move_data(data, buf); ssK = sumsumKouho(); }if(ssK==81) break; findAllOnlyOne(); if(ssK > sumsumKouho()){ write_log(cnt, 4, "onlyone in LineRowBlock -> input"); move_data(data, buf); ssK = sumsumKouho(); }if(ssK==81) break; checkNumAll(); if(ssK > sumsumKouho()){ write_log(cnt, 5, "onlyone in data -> input"); move_data(data, buf); ssK = sumsumKouho(); }if(ssK==81) break; if(isauto){}else getch(); cnt++; } }
# define LIMIT 30
回まで処理。用意した処理で対応できずに詰んだら無限ループになってしまうので。ssk=sumsumKouho()
は、盤面全体で候補のフラグが立っている数。全マスが埋まればssK=81
となって終了。
isauto
はグローバル変数でisauto=0
。ここ、if(!isauto)getch();
でよかったな…………。コマンドライン引数の3つ目にauto
を入れていればgetch()不要で次のステップに進む。
makefile
make は、コマンドをmakefile
に書き込んでおくと短い呼び出しでそれをやってくれる機能(?多分結構違う)です。
なんか解説することあるかなと思ったけどmakefileにメモってあるから要らんかなw
ファイル構造が
sudoku | |- makefile | |- source | |- calc.c |- calc.h ...
ってなっているので、コンパイルに使うファイルの探し先として
VPATH = source
としています。
まとめ
プログラム君がどう動いているのか知りたかったので作ってみただけです。
おしまい!!!
参考にしたサイト
ここに載せた以外にもあるんですけど、大学や高専の情報科か何かのページが多いのでリンク貼っていいのかわからんのもあったり…………まあ検索すれば出て来ます。
ncurses
ビット演算
- ビット演算 (bit 演算) の使い方を総特集! 〜 マスクビットから bit DP まで 〜 - Qiita https://qiita.com/drken/items/7c6ff2aa4d8fce1c9361
makefile
トリビアなmakefile入門 http://www.jsk.t.u-tokyo.ac.jp/~k-okada/makefile/
GNU make 日本語訳(Coop編) - 目次 https://www.ecoop.net/coop/translated/GNUMake3.77/make_toc.jp.html
Makefileの書き方に関する備忘録 - minus9d's diary https://minus9d.hatenablog.com/entry/20140203/1391436293