[ 簡単な説明 ]
「数独」と呼ばれるパズルを解くプログラム例です。 |
/* sudoku.c */ #include <stdio.h> #include <stdlib.h> /* #define CROSS /* 対角要素の制限を付加するオプション */ */ #define N 1 void printmatrix(void); int datain(int mn, int point); void determine(void); void printans(int mn, int *ans); void save(int *rs, int *cs, int *vs); int assume(int *i, int *j, int *rr, int *cc, int rs, int cs, int vs); void nestup(int *rk, int i, int j, int rr, int cc, int v, int *cs, int *vs); void nestdown(int *rk, int *rs, int *cs, int *vs); void load(int rk); int data[N][81] = { /* { 0,0,4, 5,0,0, 0,8,0, 0,3,0, 0,6,0, 7,0,4, 0,2,0, 0,7,8, 0,5,0, 1,0,0, 0,0,0, 4,0,0, 9,8,7, 0,0,0, 5,6,0, 0,0,6, 0,0,0, 0,0,7, 0,0,3, 6,5,0, 0,0,8, 0,0,0, 0,4,0, 1,9,0, 0,0,0, 0,3,2, 0,0,0}, { 0,0,4, 5,0,7, 8,0,0, 0,3,0, 0,6,0, 0,9,0, 0,2,0, 8,0,4, 0,1,0, 1,0,0, 0,5,0, 0,0,2, 0,0,0, 0,0,0, 0,0,0, 5,4,0, 0,2,0, 0,7,6, 0,6,0, 0,0,0, 0,5,0, 0,7,9, 0,1,0, 2,4,0, 0,0,8, 9,0,2, 3,0,0} /* { 0,6,0, 2,0,4, 0,5,0, 4,7,0, 0,6,0, 0,8,3, 0,0,5, 0,7,0, 1,0,0, 9,0,0, 1,0,3, 0,0,2, 0,1,2, 0,0,0, 3,4,0, 6,0,0, 7,0,9, 0,0,8, 0,0,6, 0,8,0, 7,0,0, 1,4,0, 0,9,0, 0,2,5, 0,8,0, 3,0,5, 0,9,0}, { 0,0,0, 3,0,0, 0,1,0, 0,9,4, 0,0,1, 0,0,7, 2,0,0, 7,0,0, 4,0,0, 0,0,0, 0,5,0, 3,0,0, 5,8,0, 0,0,0, 0,6,9, 0,0,3, 0,8,0, 0,0,0, 0,0,7, 0,0,5, 0,0,6, 6,0,0, 4,0,0, 2,8,0, 0,1,0, 0,0,6, 0,0,0}, { 0,0,3, 0,4,0, 8,0,0, 0,0,0, 1,0,9, 0,0,0, 2,0,9, 0,0,0, 3,0,7, 0,5,0, 0,0,0, 0,4,0, 8,0,0, 0,2,0, 0,0,9, 0,1,0, 0,0,0, 0,6,0, 5,0,1, 0,0,0, 4,0,6, 0,0,0, 2,0,5, 0,0,0, 0,0,6, 0,8,0, 7,0,0}, */ { 0,2,0, 0,7,5, 0,1,0, 1,0,0, 0,0,4, 5,0,8, 0,5,6, 8,0,0, 2,0,0, 8,1,0, 0,0,0, 7,0,0, 9,0,0, 0,0,0, 0,0,3, 0,0,2, 0,0,0, 0,4,5, 0,0,9, 0,0,1, 4,3,0, 3,0,1, 7,0,0, 0,0,9, 0,7,0, 3,9,0, 0,2,0} /* { 0,0,1, 0,0,0, 8,0,0, 0,2,0, 0,1,0, 0,7,0, 3,0,0, 0,2,0, 0,0,6, 0,0,2, 0,3,0, 7,0,0, 4,0,0, 2,0,7, 0,0,5, 0,0,0, 0,6,0, 0,0,0, 5,0,0, 0,7,0, 0,0,4, 0,6,0, 0,8,0, 0,3,0, 0,0,7, 6,0,3, 2,0,0} */ }; static int nstack = 50; int cq, rq, iq, jq; int ds, dss; int D[10], R[9], C[9], Mat[3][3]; int AR[9], AC[9], AM[3][3]; int V[9][9]; int AV[9][9]; int *RS, *CS, *VS; #ifdef CROSS int X1, X2, AX1, AX2; #endif void printmatrix(void) { int i, j, k; for(j = 0; j < 3; j++) { printf("+"); for(k = 0; k < 3; k++) printf("---"); } printf("+\n"); for(i = 0; i < 9;) { printf("|"); for(j = 0; j < 9;) { printf("%2d ", V[i][j]); if(++j % 3 == 0) printf("|"); } printf("\n"); if(++i % 3 == 0) { for(j = 0; j < 3; j++) { printf("+"); for(k = 0; k < 3; k++) printf("---"); } printf("+\n"); } } } void printans(int mn, int *ans) { printf("*** answer %d - %d ***\n", mn, (*ans)++); printmatrix(); } int datain(int mn, int point) { int c, i, ii, j, jj, p, r, s, v; p = 0; if(point >= N) return 0; for(i = 0; i < 9; i++) R[i] = C[i] = 511; for(i = 0; i < 3; i++) for(j = 0; j < 3; j++) Mat[i][j] = 511; #ifdef CROSS X1 = X2 = 511; #endif ds = r = 0; for(i = 0; i < 3; i++) { for(ii = 0; ii < 3; ii++, r++) { c = 0; for(j = 0; j < 3; j++) { for(jj = 0; jj < 3; jj++, c++) { V[r][c] = v = data[point][p++]; if(v == 0) continue; ds++; s = D[v]; R[r] -= s; C[c] -= s; Mat[i][j] -= s; } } } } #ifdef CROSS for(p = 0; p < 9; p++) { if(V[p][p]) X1 -= D[V[p][p]]; if(V[p][9 - p]) X2 -= D[V[p][9 - p]]; } #endif printf("*** problem %d ***\n", mn); printmatrix(); return 1; } void determine(void) { int rc, rm, cc, cm, mm, mr, s; int c, f, i, ii, j, jj, nc, r, v; do { f = 0; for(v = 1; v <= 9; v++) { s = D[v]; #ifdef CROSS if(X1 == s) { f++; for(r = 0; r < 9; r++) { if(V[r][r]) continue; V[r][r] = v; R[r / 3] -= s; C[r / 3] -= s; Mat[r / 3][r / 3] -= s; break; } } if(X2 == s) { f++; for(r = 0; r < 9; r++) { c = 9 - r; if(V[r][c]) continue; V[r][c] = v; R[r / 3] -= s; C[c / 3] -= s; Mat[r / 3][c / 3] -= s; break; } } #endif r = 0; for(i = 0; i < 3; i++) { for(ii = 0; ii < 3; ii++, r++) { rc = R[r]; if((rc & s) == 0) continue; nc = 0; for(j = 0; j < 3; j++) { if((s & Mat[i][j]) == 0) continue; c = j * 3; rm = rc & Mat[i][j]; for(jj = 0; jj < 3; jj++, c++) { if(V[r][c] > 0 || (s & C[c]) == 0) continue; if((s ^ (rm & C[c])) == 0) { nc = 1; cq = c; jq = j; goto next1; } nc++; if(nc == 1) { cq = c; jq = j; } } } next1: if(nc == 1) { f++; V[r][cq] = v; R[r] -= s; C[cq] -= s; Mat[i][jq] -= s; #ifdef CROSS if(r == cq) X1 -= s; if(r == 3 - cq) X2 -= s; #endif } } } c = 0; for(j = 0; j < 3; j++) { for(jj = 0; jj < 3; jj++, c++) { cc = C[c]; if((cc & s) == 0) continue; nc = 0; for(i = 0; i < 3; i++) { if((s & Mat[i][j]) == 0) continue; r = i * 3; cm = cc & Mat[i][j]; for(ii = 0; ii < 3; ii++, r++) { if(V[r][c] > 0 || (s & R[r]) == 0) continue; if((s ^ (cm & R[r])) == 0) { nc = 1; rq = r; iq = i; goto next2; } nc++; if(nc == 1) { rq = r; iq = i; } } } next2: if(nc == 1) { f++; V[rq][c] = v; R[rq] -= s; C[c] -= s; Mat[iq][j] -= s; #ifdef CROSS if(rq == c) X1 -= s; if(rq == 3 - c) X2 -= s; #endif } } } for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { if((Mat[i][j] & s) == 0) continue; nc = 0; r = i * 3; mm = Mat[i][j]; for(ii = 0; ii < 3; ii++, r++) { if((R[r] & s) == 0) continue; c = j * 3; mr = mm & R[r]; for(jj = 0; jj < 3; jj++, c++) { if(V[r][c] > 0 || (s & C[c]) == 0) continue; if((s ^ (mr & C[c])) == 0) { nc = 1; rq = r; cq = c; goto next3; } nc++; if(nc == 1) { rq = r; cq = c; } } } next3: if(nc == 1) { f++; V[rq][cq] = v; R[rq] -= s; C[cq] -= s; Mat[i][j] -= s; #ifdef CROSS if(rq == cq) X1 -= s; if(rq == 3 - cq) X2 -= s; #endif } } } } ds += f; #ifdef CROSS }while(ds < 83 && f > 0); #else }while(ds < 81 && f > 0); #endif } void save(int *rs, int *cs, int *vs) { int c, r; dss = ds; *rs = *cs = *vs = 0; for(r = 0; r < 9; r++) { AR[r] = R[r]; AC[r] = C[r]; for(c = 0; c < 9; c++) AV[r][c] = V[r][c]; } for(r = 0; r < 3; r++) for(c = 0; c < 3; c++) AM[r][c] = Mat[r][c]; #ifdef CROSS AX1 = X1; AX2 = X2; #endif } int assume(int *i, int *j, int *rr, int *cc, int rs, int cs, int vs) { int rmc; int c, k, r; for(r = rs; r < 9; r++) { for(c = cs; c < 9; c++) { if(V[r][c] > 0) cs = vs = 0; else { *i = r / 3; *j = c / 3; rmc = (R[r] & C[c]) & Mat[*i][*j]; for(k = vs + 1; k <= 9; k++) { if((D[k] & rmc) > 0) { *rr = r + 1; *cc = c + 1; return k; } } return 0; } } } return 0; } void nestup(int *rk, int i, int j, int rr, int cc, int v, int *cs, int *vs) { int s; int *wc, *wr, *wv; int k, n; (*rk)++; if(*rk >= nstack) { n = nstack + 20; wr = (int *)malloc(n * sizeof(int *)); wc = (int *)malloc(n * sizeof(int *)); wv = (int *)malloc(n * sizeof(int *)); if(wr == NULL || wc == NULL || wv == NULL) { fprintf(stderr, "Error : memory allocation error.\n"); exit(-1); } for(k = 0; k < nstack; k++) { wr[k] = RS[k]; wc[k] = CS[k]; wv[k] = VS[k]; } free((char *)RS); free((char *)CS); free((char *)VS); RS = wr; CS = wc; VS = wv; nstack = n; } RS[*rk] = rr; CS[*rk] = cc; VS[*rk] = v; ds++; V[rr-1][cc-1] = v; s = D[v]; R[rr-1] -= s; C[cc-1] -= s; Mat[i][j] -= s; (*cs)++; *vs = 0; } void nestdown(int *rk, int *rs, int *cs, int *vs) { *rs = RS[*rk] - 1; *cs = CS[*rk] - 1; *vs = VS[*rk]; (*rk)--; } void load(int rk) { int s; int c, k, r, v; ds = dss; for(r = 0; r < 9; r++) { R[r] = AR[r]; C[r] = AC[r]; for(c = 0; c < 9; c++) V[r][c] = AV[r][c]; } for(r = 0; r < 3; r++) for(c = 0; c < 3; c++) Mat[r][c] = AM[r][c]; for(k = 0; k <= rk; k++) { r = RS[k]-1; c = CS[k]-1; v = VS[k]; ds++; V[r][c] = v; s = D[v]; R[r] -= s; C[c] -= s; Mat[r / 3][c / 3] -= s; } #ifdef CROSS X1 = AX1; X2 = AX2; #endif determine(); } int main(void) { int jj; int mn = 1, ans = 1, point = 0; int i, j, rk, rr, cc, v; int rs, cs, vs; RS = (int *)malloc(nstack * sizeof(int)); CS = (int *)malloc(nstack * sizeof(int)); VS = (int *)malloc(nstack * sizeof(int)); if(RS == NULL || CS == NULL || VS == NULL) { fprintf(stderr, "Error : memory allocation error.\n"); exit(-1); } jj = 1; for(i = 1; i <= 9; i++) { D[i] = jj; jj *= 2; } while(datain(mn, point++)) { ans = 1; determine(); #ifdef CROSS if(ds >= 83) printans(mn, &ans); #else if(ds >= 81) printans(mn, &ans); #endif else { save(&rs, &cs, &vs); rk = -1; while(1) { while(1) { v = assume(&i, &j, &rr, &cc, rs, cs, vs); if(v == 0) break; nestup(&rk, i, j, rr, cc, v, &cs, &vs); determine(); #ifdef CROSS if(ds >= 83) #else if(ds >= 81) #endif { printans(mn, &ans); break; } } if(rk == -1) break; nestdown(&rk, &rs, &cs, &vs); load(rk); } } mn++; } return 1; } |
*** problem 1 *** +---------+---------+---------+ | 0 6 0 | 2 0 4 | 0 5 0 | | 4 7 0 | 0 6 0 | 0 8 3 | | 0 0 5 | 0 7 0 | 1 0 0 | +---------+---------+---------+ | 9 0 0 | 1 0 3 | 0 0 2 | | 0 1 2 | 0 0 0 | 3 4 0 | | 6 0 0 | 7 0 9 | 0 0 8 | +---------+---------+---------+ | 0 0 6 | 0 8 0 | 7 0 0 | | 1 4 0 | 0 9 0 | 0 2 5 | | 0 8 0 | 3 0 5 | 0 9 0 | +---------+---------+---------+ *** answer 1 - 1 *** +---------+---------+---------+ | 8 6 1 | 2 3 4 | 9 5 7 | | 4 7 9 | 5 6 1 | 2 8 3 | | 3 2 5 | 9 7 8 | 1 6 4 | +---------+---------+---------+ | 9 5 8 | 1 4 3 | 6 7 2 | | 7 1 2 | 8 5 6 | 3 4 9 | | 6 3 4 | 7 2 9 | 5 1 8 | +---------+---------+---------+ | 5 9 6 | 4 8 2 | 7 3 1 | | 1 4 3 | 6 9 7 | 8 2 5 | | 2 8 7 | 3 1 5 | 4 9 6 | +---------+---------+---------+ |
*** problem 2 *** +---------+---------+---------+ | 0 0 0 | 3 0 0 | 0 1 0 | | 0 9 4 | 0 0 1 | 0 0 7 | | 2 0 0 | 7 0 0 | 4 0 0 | +---------+---------+---------+ | 0 0 0 | 0 5 0 | 3 0 0 | | 5 8 0 | 0 0 0 | 0 6 9 | | 0 0 3 | 0 8 0 | 0 0 0 | +---------+---------+---------+ | 0 0 7 | 0 0 5 | 0 0 6 | | 6 0 0 | 4 0 0 | 2 8 0 | | 0 1 0 | 0 0 6 | 0 0 0 | +---------+---------+---------+ *** answer 2 - 1 *** +---------+---------+---------+ | 7 6 5 | 3 4 9 | 8 1 2 | | 8 9 4 | 5 2 1 | 6 3 7 | | 2 3 1 | 7 6 8 | 4 9 5 | +---------+---------+---------+ | 1 4 6 | 9 5 7 | 3 2 8 | | 5 8 2 | 1 3 4 | 7 6 9 | | 9 7 3 | 6 8 2 | 1 5 4 | +---------+---------+---------+ | 3 2 7 | 8 1 5 | 9 4 6 | | 6 5 9 | 4 7 3 | 2 8 1 | | 4 1 8 | 2 9 6 | 5 7 3 | +---------+---------+---------+ |
*** problem 3 *** +---------+---------+---------+ | 0 0 3 | 0 4 0 | 8 0 0 | | 0 0 0 | 1 0 9 | 0 0 0 | | 2 0 9 | 0 0 0 | 3 0 7 | +---------+---------+---------+ | 0 5 0 | 0 0 0 | 0 4 0 | | 8 0 0 | 0 2 0 | 0 0 9 | | 0 1 0 | 0 0 0 | 0 6 0 | +---------+---------+---------+ | 5 0 1 | 0 0 0 | 4 0 6 | | 0 0 0 | 2 0 5 | 0 0 0 | | 0 0 6 | 0 8 0 | 7 0 0 | +---------+---------+---------+ *** answer 3 - 1 *** +---------+---------+---------+ | 1 6 3 | 7 4 2 | 8 9 5 | | 7 8 5 | 1 3 9 | 6 2 4 | | 2 4 9 | 6 5 8 | 3 1 7 | +---------+---------+---------+ | 6 5 7 | 9 1 3 | 2 4 8 | | 8 3 4 | 5 2 6 | 1 7 9 | | 9 1 2 | 8 7 4 | 5 6 3 | +---------+---------+---------+ | 5 2 1 | 3 9 7 | 4 8 6 | | 4 7 8 | 2 6 5 | 9 3 1 | | 3 9 6 | 4 8 1 | 7 5 2 | +---------+---------+---------+ |
*** problem 4 *** +---------+---------+---------+ | 0 2 0 | 0 7 5 | 0 1 0 | | 1 0 0 | 0 0 4 | 5 0 8 | | 0 5 6 | 8 0 0 | 2 0 0 | +---------+---------+---------+ | 8 1 0 | 0 0 0 | 7 0 0 | | 9 0 0 | 0 0 0 | 0 0 3 | | 0 0 2 | 0 0 0 | 0 4 5 | +---------+---------+---------+ | 0 0 9 | 0 0 1 | 4 3 0 | | 3 0 1 | 7 0 0 | 0 0 9 | | 0 7 0 | 3 9 0 | 0 2 0 | +---------+---------+---------+ *** answer 4 - 1 *** +---------+---------+---------+ | 4 2 8 | 9 7 5 | 3 1 6 | | 1 9 3 | 2 6 4 | 5 7 8 | | 7 5 6 | 8 1 3 | 2 9 4 | +---------+---------+---------+ | 8 1 5 | 4 3 9 | 7 6 2 | | 9 4 7 | 5 2 6 | 1 8 3 | | 6 3 2 | 1 8 7 | 9 4 5 | +---------+---------+---------+ | 2 8 9 | 6 5 1 | 4 3 7 | | 3 6 1 | 7 4 2 | 8 5 9 | | 5 7 4 | 3 9 8 | 6 2 1 | +---------+---------+---------+ *** answer 4 - 2 *** +---------+---------+---------+ | 4 2 8 | 9 7 5 | 3 1 6 | | 1 9 3 | 6 2 4 | 5 7 8 | | 7 5 6 | 8 1 3 | 2 9 4 | +---------+---------+---------+ | 8 1 5 | 4 3 9 | 7 6 2 | | 9 4 7 | 2 5 6 | 1 8 3 | | 6 3 2 | 1 8 7 | 9 4 5 | +---------+---------+---------+ | 2 8 9 | 5 6 1 | 4 3 7 | | 3 6 1 | 7 4 2 | 8 5 9 | | 5 7 4 | 3 9 8 | 6 2 1 | +---------+---------+---------+ |
sudoku.c | 確定サーチを用いて数独を解くプログラム (メインルーチン) |
disp.c | 数独の表示ルーチン |
conio.c | 表示の低レベルルーチン |
/* file = sudoku2.c * * 【使用法】 * * A>SUDOKU2 入力ファイル名 * * 各数値を足し合わせた数を指定することにより、それぞれの動作をあわ * 行います。このフラグを省略した場合は、7が指定されたものとみまします。 * (すべての確定サーチを行う) * * 入力ファイルのフォーマットは、問題の空欄を0として、数字を並べるだけ * です。例として問題3を挙げておきます。 * * * A>TYPE MONDAI3.INP * 0 0 1 0 0 0 6 0 0 * 0 8 0 2 0 6 0 5 0 * 6 0 0 0 3 0 0 0 1 * 0 9 0 0 0 4 0 7 0 * 0 0 2 0 0 0 5 0 0 * 0 4 0 9 0 0 0 6 0 * 1 0 0 0 8 0 0 0 7 * 0 2 0 7 0 3 0 1 0 * 0 0 9 0 0 0 4 0 0 * * 松田 晋 */ #include <stdio.h> #include <stdlib.h> int col[9], row[9], mas[3][3]; /* 行、列、マスの許容値テーブル */ int bit[] = {0 /* dummy */, 1, 2, 4, 8, 16, 32, 64, 128, 256}; typedef struct masu masu_t; struct masu { masu_t *next; /* 順方向ポインタ */ masu_t *prev; /* 逆方向ポインタ */ char col; /* 列 */ char row; /* 行 */ char num; /* 数字 */ }; masu_t board[9][9], head; void pause(void); void disp_num(int c, int r, int n, int mode); void display_board(void); void usage(void); void flush(void); /* 後始末 */ void sudoku(int n); /* 引数(ひきすう)nは残りの空欄の個数 */ int search_f; /* 確定サーチを制御するフラグ */ void set_num(int b, int r, int c, masu_t *p, int f) { p->num = b; /* ボードに数を置く */ row[r] &= ~bit[b]; /* 許容値テーブルのクリア */ col[c] &= ~bit[b]; mas[r / 3][c / 3] &= ~bit[b]; p->prev->next = p->next; /* 双方向リストから */ p->next->prev = p->prev; /* 要素を取り除く */ disp_num(c, r, b, f); /* 数字の表示 */ } /* set_num */ void erase_num(int b, int r, int c, masu_t *p) { p->num = 0; /* ボードをもとに戻す */ row[r] |= bit[b]; /* 許容値テーブルを戻す */ col[c] |= bit[b]; mas[r / 3][c / 3] |= bit[b]; p->prev->next = p; /* 双方向リストを */ p->next->prev = p; /* 元に戻す */ disp_num(c, r, 0, 0); /* 数字をはがす */ } /* erase_num */ void init_pointers(void) { /* ポインタの初期化 */ masu_t *p; for (p = &board[0][0]; p <= &board[8][8]; p++) { p->prev = p - 1; p->next = p + 1; } board[0][0].prev = &head; board[8][8].next = &head; head.next = &board[0][0]; head.prev = &board[8][8]; } /* init_pointers */ void init_table(void) /* 許容値テーブルの初期設定 */ { int i, j; /* 初期状態ではなにを置いても良い */ for (i = 0; i < 9; i++) { col[i] = 0777; /* 行、列の許容値テーブルを */ row[i] = 0777; /* 111111111bで初期設定する */ } for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) mas[i][j] = 0777; /* マスについても同じ */ } /* init_table */ int read_board(FILE *f) /* 問題の読み込みと */ { /* ボード及びテーブルの設定 */ int r, c, b, n; masu_t *p; n = 0; p = &board[0][0]; for (r = 0; r < 9; r++) for (c = 0; c < 9; c++, p++) { p->col = c; p->row = r; fscanf(f, "%d", &b); /* 問題の読み込み */ if (b) /* 読み込んだ数字が0以外ならば */ set_num(b, r, c, p, 0); /* 確定設定 */ else { /* 読み込んだ数字が0ならば */ n++; /* それを数える */ p->num = 0; /* ボードのクリア */ } } return n; /* 戻り値は空欄の個数 */ } /* read_board */ int search_masu(int n) /* 各マスについての確定サーチ */ { int b, r, c, nk; int rr, cc, r_save, c_save; masu_t *p; for (rr = 0; rr < 3; rr++) for (cc = 0; cc < 3; cc++) for (b = 1; b <= 9; b++) if (mas[rr][cc] & bit[b]) { nk = 0; for (r = rr * 3; r < rr * 3 + 3; r++) for (c = cc * 3; c < cc * 3 + 3; c++) if (row[r] & col[c] & bit[b] && board[r][c].num == 0) { nk++; r_save = r; c_save = c; } if (nk == 1) { /* bを置得る場所が1個なら確定 */ p = &board[r_save][c_save]; set_num(b, r_save, c_save, p, 1); /* 確定設定 */ sudoku(n - 1); /* 次のマスを埋める */ erase_num(b, r_save, c_save, p); return 1; } else if (nk == 0) /* 置得る場所が0個なら戻る */ return 1; } return 0; } /* search_masu */ int search_row(int n) /* 各行についての確定サーチ */ { int b, r, c, nk, c_save; masu_t *p; for (r = 0; r < 9; r++) for (b = 1; b <= 9; b++) if (row[r] & bit[b]) { nk = 0; for (c = 0; c < 9; c++) if (col[c] & mas[r / 3][c / 3] & bit[b] && board[r][c].num == 0) { nk++; c_save = c; } if (nk == 1) { /* bを置得る場所が1個なら確定 */ p = &board[r][c_save]; set_num(b, r, c_save, p, 1); /* 確定設定 */ sudoku(n - 1); /* 次のマスを埋める */ erase_num(b, r, c_save, p); return 1; } else if (nk == 0) /* 置得る場所が0個なら戻る */ return 1; } return 0; } /* search_row */ int search_col(int n) /* 各桁についての確定サーチ */ { int b, r, c, nk, r_save; masu_t *p; for (c = 0; c < 9; c++) for (b = 1; b <= 9; b++) if (col[c] & bit[b]) { nk = 0; for (r = 0; r < 9; r++) if (row[r] & mas[r / 3][c / 3] & bit[b] && board[r][c].num == 0) { nk++; r_save = r; } if (nk == 1) { /* bを置得る場所が1個なら確定 */ p = &board[r_save][c]; set_num(b, r_save, c, p, 1); /* 確定設定 */ sudoku(n - 1); /* 次のマスを埋める */ erase_num(b, r_save, c, p); return 1; } else if (nk == 0) /* 置得る場所が0個なら戻る */ return 1; } return 0; } /* search_col */ void sudoku(int n) /* nは残りの空欄の個数 */ { int r, c, s, b; masu_t *p; if (n == 0) { /* もう空欄が無ければ、解が求められている */ pause(); return; } /* 確定サーチ */ if ((search_f & 1) && search_masu(n)) return; if ((search_f & 2) && search_row(n)) return; if ((search_f & 4) && search_col(n)) return; /* 以下、バックトラック */ p = head.next; /* 未確定の場所を求める */ r = p->row; c = p->col; /* 許容値テーブルのビット積により、この欄に置ける数の集合を求める */ s = row[r] & col[c] & mas[r / 3][c / 3]; for (b = 1; b <= 9; b++) /* 1〜9の各数字について */ if (s & bit[b]) { /* bが未使用であれば */ set_num(b, r, c, p, 2); /* 仮設定 */ sudoku(n - 1); /* バックトラック */ erase_num(b, r, c, p); /* 仮設定を元に戻す */ } } /* sudoku */ int init(int argc, char *argv[]) /* 初期化 */ { /* 空欄の個数を返す */ int n; FILE *f; if (argc < 2) { usage(); exit(1); } f = fopen(argv[1], "r"); if (f == NULL) { fprintf(stderr, "オープン・エラー:%s\n", argv[1]); exit(1); } init_pointers(); /* ポインタの初期設定 */ init_table(); /* 許容値テーブルの初期設定 */ display_board(); /* 数独盤の作成 */ n = read_board(f); /* 入力データの読み込み */ fclose(f); pause(); return n; /* 空欄の個数を返す */ } int main(int argc, char *argv[]) { int n; n = init(argc, argv); /* nは空欄の個数 */ if (argc < 3) search_f = 7; else search_f = atoi(argv[2]); sudoku(n); /* n個の空欄を埋める */ flush(); /* 後始末 */ return 0; } /* main */ |
/* file = disp.c * * 目的:数独の表示を行う * * 作成:松田晋 */ #include <stdio.h> void locate(int x, int y); /* カーソルを移動する */ void reverseVideo(void); /* リバース表示 */ void normalVideo(void); /* 通常表示 */ void cls(void); /* 画面消去 */ void bell(void); /* ブザーを鳴らす */ /* 関数 disp_num * * 引数:int c : 列 * int r : 行 * int n : 数字(0は数字が入っていないことを示す) * int mode : 表示フラグ * 0 → 入力データ(ノーマル・全角) * 1 → 確定(リバース・全角) * 2 → 仮設定(リバース・半角) */ void disp_num(int c, int r, int n, int mode) { static char *num_tbl[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; locate(c * 4 + 3, r * 2 + 2); if (mode == 0) normalVideo(); else reverseVideo(); if (n == 0) printf(" "); else if (mode == 2) /* 仮設定の場合は半角表示 */ putchar('0' + n); else /* 確定の場合は全角表示 */ printf(num_tbl[n]); } /* disp_num */ void display_board(void) { cls(); printf("・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n" "・ ・ ・ ・ ・ ・ ・ ・ ・ ・\n" "・・・・・・・・・・・・・・・・・・・\n"); } /* display_board */ void usage(void) { fprintf(stderr, "使用法:SUDOKU 入力ファイル名 [確定サーチフラグ]\n" "\n" "確定サーチフラグは、0〜7の数値で、" "下記のように設定します。\n" "\n" "\bit1 = 各マスについて、確定サーチを行う。\n" "\bit2 = 各列について、確定サーチを行う。\n" "\bit4 = 各桁について、確定サーチを行う。\n" "\n" " 各数値を足し合わせた数を指定することにより、" "それぞれの動作をあわせて\n" "行います。このフラグを省略した場合は、" "7が指定されたものとみまします。\n" "(すべての確定サーチを行う)\n"); } void pause(void) { normalVideo(); locate(1, 23); printf("Hit return key!"); bell(); (void) getchar(); locate(1, 23); printf(" "); } /* pause */ void flush(void) /* 後始末 */ { locate(3, 24); reverseVideo(); printf("====探索終了===="); normalVideo(); } |
/* file = conio.c * * 目的:表示の低レベルルーチン * ANSIエスケープシーケンス利用 * * 作成:松田晋 */ #include <stdio.h> #include <stdlib.h> #include <conio.h> void locate(int x, int y) /* カーソルを移動する */ { printf("\033[%d;%dH", y, x); } void reverseVideo(void) /* リバース表示 */ { printf("\033[7m"); } /* reverseVideo */ void normalVideo(void) /* 通常表示 */ { printf("\033[m"); } /* normalVideo */ void cls(void) /* 画面消去 */ { printf("\033[2J"); } void bell(void) /* ブザーを鳴らす */ { putchar('\007'); } |