c语言快速数独生成器
生活随笔
收集整理的這篇文章主要介紹了
c语言快速数独生成器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.準備
繼上篇文章《c語言暴力遞歸實現數獨求解》 思路,本章編寫一個數獨生成器,按照數獨的規則生成題目,但不保證題目可解。
2.思路
按照數獨的規則:
水平方向的每一橫行有九格,每一橫行稱為行(Row)
垂直方向的每一縱列有九格,每一縱列稱為列(Column)
三行與三列相交之處有九格,每一單元稱為小九宮(Box、Block)
格子上填入1-9數字,使1-9每個數字在每一行、每一列和每一宮中都只出現一次
所以,我們程序還是使用三個bitmap來進行標記1-9數字是否被使用。
其他的,數獨的表示我們還是用一維數組轉二維數組的思路進行。
3.實現
定義與上篇文章一樣:
#define SIZE_BLK 3 #define SIZE_NUM (SIZE_BLK * SIZE_BLK)#define bit_set(b, n) ((b) |= (0x1 << (n))) #define bit_clr(b, n) ((b) &= ~(0x1 << (n))) #define bit_chk(b, n) (((b) >> (n)) & 0x1)struct instance {unsigned times;unsigned bits_lines[SIZE_NUM];unsigned bits_colum[SIZE_NUM];unsigned bits_block[SIZE_NUM]; };核心邏輯:隨機挑選一個位置,選擇一個合適的、隨機值填入。
int sudoku_roll(struct instance *pinst, char board[SIZE_NUM][SIZE_NUM]) {int rx = rand() % 9; // random valueint ix = rand() % 9;int jx = rand() % 9;int bx = ix / SIZE_BLK * SIZE_BLK + jx / SIZE_BLK;for (int nx = rx; ; nx = (nx + 1) % 9) {if ((nx + 1) % 9 == rx) {printf("Retry\n"); // 實在沒有合適的數值可填了,放棄該位置return -1;}if (bit_chk(pinst->bits_lines[ix], nx)||bit_chk(pinst->bits_colum[jx], nx)||bit_chk(pinst->bits_block[bx], nx)) {printf("Exist[%d, %d, %d] = %d\n", ix, jx, bx, 1 + nx);continue; // 該值違反了數獨規則,重新選取新數值}// 找到了合適的值,標記上去bit_set(pinst->bits_lines[ix], nx);bit_set(pinst->bits_colum[jx], nx);bit_set(pinst->bits_block[bx], nx);board[ix][jx] = '1' + nx;printf("Roll [%d, %d, %d] = %c\n", ix, jx, bx, board[ix][jx]);break;}return 0; }往上一層邏輯,我們就還要考慮填充幾個數字,經驗值上是填充到30~40的時候,題目變得不好求解。
int sudoku_auto(char board[SIZE_NUM][SIZE_NUM], int times) {int ix = 0;int jx = 0;int res = -1;struct instance inst = {0};memset(board, '.', SIZE_NUM * SIZE_NUM);// 循環的考慮:ix是正常填充值// jx是防止數獨無解死循環for (ix = jx = 0;ix < times && jx < SIZE_NUM * SIZE_NUM;jx++) {res = sudoku_roll(&inst, board);if (0 != res) {printf("Retry\n");continue;}ix++;}printf("%s, times: %4d, result: %s\n", "Random ", times, (char *)board);sudoku_display(board);return 0; }為了直觀的顯示,我們加入了打印函數:
void sudoku_display(char board[SIZE_NUM][SIZE_NUM]) {for (int ix = 0; ix < SIZE_NUM; ix++) {if (ix % SIZE_BLK == 0) {printf("+---+---+---+\n");}for (int jx = 0; jx < SIZE_NUM; jx++) {if (jx % SIZE_BLK == 0) {printf("|");}printf("%c", board[ix][jx]);}printf("|\n");}printf("+---+---+---+\n"); }主函數
#define SUDOKU_AUTO(_times) do { \char _input[SIZE_NUM * SIZE_NUM + 1] = {0}; \sudoku_auto((char (*)[SIZE_NUM])_input, _times); \ } while (0)int main(int argc, char *argv[]) {SUDOKU_AUTO(10);SUDOKU_AUTO(20);SUDOKU_AUTO(30);SUDOKU_AUTO(40);exit(EXIT_SUCCESS); }運行結果:
Random , times: 10, result: ..........5......8...............2...............2..8.5.....9..2....6...........1 +---+---+---+ |...|...|...| |.5.|...|..8| |...|...|...| +---+---+---+ |...|...|2..| |...|...|...| |...|.2.|.8.| +---+---+---+ |5..|...|9..| |2..|..6|...| |...|...|..1| +---+---+---+ Random , times: 20, result: 3.1..7...........2.....8..7..3.8.6......6......54...7.8.......9....2.....3....... +---+---+---+ |3.1|..7|...| |...|...|..2| |...|..8|..7| +---+---+---+ |..3|.8.|6..| |...|.6.|...| |..5|4..|.7.| +---+---+---+ |8..|...|..9| |...|.2.|...| |.3.|...|...| +---+---+---+ Random , times: 30, result: .3.8...61.1..769.376.....85......75...7...1...94.....85.6.3...7..1............... +---+---+---+ |.3.|8..|.61| |.1.|.76|9.3| |76.|...|.85| +---+---+---+ |...|...|75.| |..7|...|1..| |.94|...|..8| +---+---+---+ |5.6|.3.|..7| |..1|...|...| |...|...|...| +---+---+---+ Random , times: 40, result: .37...4..9........428..7.358....19.2...3.4..6.92.......7...2.63..1685.24.8...37.. +---+---+---+ |.37|...|4..| |9..|...|...| |428|..7|.35| +---+---+---+ |8..|..1|9.2| |...|3.4|..6| |.92|...|...| +---+---+---+ |.7.|..2|.63| |..1|685|.24| |.8.|..3|7..| +---+---+---+4.結論
該方法能夠簡單快速生成數獨題目,但并不能保證數獨有解。如果要保證生成的有解,那么就需要在sudoku_rand()函數中,引入求解的驗證,但勢必會帶來額外計算量(提高檢測算法也算另外一個調研方向)。
總結
以上是生活随笔為你收集整理的c语言快速数独生成器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jar乱放问题
- 下一篇: 小学生计算机课堂实践的重要性,浅谈小学信