日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

徐松亮算法教学-基于C语言的数独(九宫格)多种终盘生成方法(包含矩阵镜像旋转转置等相关算法)

發布時間:2023/12/31 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 徐松亮算法教学-基于C语言的数独(九宫格)多种终盘生成方法(包含矩阵镜像旋转转置等相关算法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

版權聲明:本文為博主徐松亮的原創作品,未經允許不得轉載,多謝支持!QQ:5387603

推薦點擊此鏈接:歡迎進入徐松亮博客一站式導航搜索(隨時更新)


?

目錄

一,前言

二,開發環境

電腦系統

編譯器

編程語言

編輯與工程環境

三,方法

方法概述

生成(或隨機選定)種子矩陣終盤

兩數交換法

非跨界行交換

非跨界列交換

塊行交換

塊列交換

矩陣旋轉

矩陣行鏡像

矩陣列鏡像

矩陣對角線鏡像

四,源碼

五,運行結果演示

運行結果---兩數交換法

運行結果---非跨界行交換

運行結果---非跨界列交換

運行結果---塊行交換

運行結果---塊列交換

運行結果---矩陣旋轉

運行結果---矩陣行鏡像

運行結果---矩陣列鏡像

運行結果---矩陣對角線鏡像

六,引用資料致謝


一,前言

  • 昨天,發布了一篇數獨解題的文章,但是只有解題沒有出題,總是感覺差點意思。
    • 相關鏈接如下:徐松亮算法教學-基于C語言的數獨(九宮格)求解(含多解和解數統計)
  • 網上搜了一些相關資料,大多都是單一方式,流程基本上是填入部分隨機數---產生一個解盤---扣掉一些數。這個方案如果只是用于出題也是可行的,但是這么簡單的話,我真是懶得總結。
  • 本文的矩陣轉換算法都為博主親自編寫調試,都是自身轉換,而不需要建立同樣大小的緩存,尤其是矩陣旋轉相關代碼,還真花費了我一些時間,很是推薦,比目前網上的要好很多,后續我會把矩陣轉換相關的代碼標準化后另建立學習文檔。
  • 偶然在網上發現一篇文章,它講了多種數獨終盤生成辦法,主要是用的矩陣變換,還是那句話:雖然我對數獨本身這個游戲沒什么興趣,但是對它涉及到的計算機數學問題,還是頗有興趣。
  • 做到這,我想到一個問題,接數獨是不是也可以用這篇文章講的矩陣變換方法,經過各種行列兌換,生成一個解,原理有點像擰魔方似的,方法理論上應該是可行的,但不過這個方法不能統計出解的數量。

二,開發環境

  • 電腦系統

    • windows10
  • 編譯器

    • cygwin下的gcc
  • 編程語言

    • C語言
  • 編輯與工程環境

    • VSCode
    • 不了解VSVode安裝配置的請看本人的原創文檔:
      • 徐松亮軟件應用教學-基于Visual Studio Code的C語言開發環境搭建
        ?

三,方法

  • 方法概述

    • 基于一個成型的終盤,經過下列任意變換后,還是一個符合規則的終盤。
  • 生成(或隨機選定)種子矩陣終盤

    • 如果能真正的隨機生成一個終盤,那就不用下面的變換了,所以我們在此用選定的現有矩陣做種子。
    • 真正做可以多做幾個,然后用隨機數來選。
  • 兩數交換法

    • 就是隨機選取兩個數,可以是1和9,也可以是3和5,全局交換后,仍是有效終盤。
    • 下圖舉例,我們已2和8來做交換,如圖所示:
  • 非跨界行交換

    • 以宮為界,即1-3行為一組,4-6行為一組,7-9行為一組,組內可執行行交換,組間不能。符合此規則執行行交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,同色為界,我們執行1與3行的數據交換。

  • 非跨界列交換

    • 以宮為界,即1-3列為一組,4-6列為一組,7-9列為一組,組內可執行行交換,組間不能。符合此規則執列列交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,我們執列1與3列的數據交換。

  • 塊行交換

    • 以宮為界,即1-3行為一組,4-6行為一組,7-9行為一組,組與組交換在此我起名稱作塊行交換。符合此規則交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,我們組1與組2的數據交換。

  • 塊列交換

    • 以宮為界,即1-3列為一組,4-6列為一組,7-9列為一組,組與組交換在此我起名稱作塊列交換。符合此規則交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,我們組1與組2的數據交換。

  • 矩陣旋轉

    • 矩陣旋轉,就是相當于你轉著圈的去看數獨題,你從四個方向看,這個題都是成立的。
    • 下圖舉例,如圖。

  • 矩陣行鏡像

    • 矩陣行鏡像,就好比你看完報紙正面,反過來看報紙背面一樣。符合此規則交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,如圖

  • 矩陣列鏡像

    • 矩陣列鏡像,原理同行鏡像其實是一樣的。符合此規則交換后,終盤仍為符合規則的終盤。
    • 下圖舉例,如圖

  • 矩陣對角線鏡像

    • 矩陣對角線鏡像,原理相當于數學當中的矩陣轉置。
    • 下圖舉例,如圖

四,源碼

/********************************************************************************* @file xsl_game_sudo.c* @author 徐松亮 許紅寧(5387603@qq.com)* @version V1.0.0* @date 2018/11/01******************************************************************************* @attention* 待解決* 1,數獨出題* GNU General Public License (GPL)** <h2><center>&copy; COPYRIGHT 2017 XSLXHN</center></h2>*******************************************************************************//* Includes ------------------------------------------------------------------*/ #include <stdio.h> #include <stdint.h> // 用于計算耗時統計 #include <time.h> /* Private define ------------------------------------------------------------*/ #define XSLGAMESUDO_SUDOKU_LEVEL 9 #define OK 0 #define ERR 1 /* Private typedef -----------------------------------------------------------*/ typedef struct {// 輸入---計算前用戶設定uint8_t cells[XSLGAMESUDO_SUDOKU_LEVEL][XSLGAMESUDO_SUDOKU_LEVEL];//-----最大輸出答案數量(1,為了防止pOutBuf數據溢出;2,為了計算適可而止;)uint32_t MaxOutAnswersCount;// 輸入輸出//-----輸出緩存(NULL---無解輸出)uint8_t *pOutBuf;//-----解最大數量(NULL---不求此值則非全局搜索)uint32_t *pAnswersCount;// 輸出---計算后的統計結果uint32_t OutAnswersCount; } XSLGAMESUDO_S_SUDO; /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ static const uint8_t XslGameSudo_SudoGenerateBuf[XSLGAMESUDO_SUDOKU_LEVEL][XSLGAMESUDO_SUDOKU_LEVEL] = {8, 1, 2, 7, 5, 3, 6, 4, 9,9, 4, 3, 6, 8, 2, 1, 7, 5,6, 7, 5, 4, 9, 1, 2, 8, 3,1, 5, 4, 2, 3, 7, 8, 9, 6,3, 6, 9, 8, 4, 5, 7, 2, 1,2, 8, 7, 1, 6, 9, 5, 3, 4,5, 2, 1, 9, 7, 4, 3, 6, 8,4, 3, 8, 5, 2, 6, 9, 1, 7,7, 9, 6, 3, 1, 8, 4, 5, 2}; // XSLGAMESUDO_S_SUDO XslGameSudo_s_Sudo; /* Extern variables ----------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /*** @brief 格式化打印* @note 打印指定行列的數組* @param *pXslGameSudoS --- 數據指針* mode --- 0-打印問題 1-打印答案 2-只打印數獨不打印字符串* @return null*/ static void XslGameSudo_FormatPrint(XSLGAMESUDO_S_SUDO *pXslGameSudoS, uint8_t mode) {uint8_t i, j, k;uint8_t *pbuf;// 打印問題if ((mode == 0) || (mode == 2)){if (mode == 0){printf("Sudo Questions:\n");}pbuf = (uint8_t *)pXslGameSudoS->cells;for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){for (j = 0; j < XSLGAMESUDO_SUDOKU_LEVEL; j++){printf("%2d", pbuf[i * XSLGAMESUDO_SUDOKU_LEVEL + j]);if (j == (XSLGAMESUDO_SUDOKU_LEVEL - 1))printf("\n");}}}// 打印答案else if (mode == 1){if (pXslGameSudoS->pAnswersCount == 0){printf("Sudo Processor : No Solution!\n");return;}//pbuf = pXslGameSudoS->pOutBuf;for (k = 0; k < pXslGameSudoS->OutAnswersCount; k++){printf("Sudo Answers(%d):\n", k + 1);for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){for (j = 0; j < XSLGAMESUDO_SUDOKU_LEVEL; j++){printf("%2d", pbuf[(k * XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL) + (i * XSLGAMESUDO_SUDOKU_LEVEL + j)]);if (j == (XSLGAMESUDO_SUDOKU_LEVEL - 1))printf("\n");}}}if (pXslGameSudoS->pAnswersCount != NULL){printf("Sudo Answers Count: %d\n", *(pXslGameSudoS->pAnswersCount));}} }uint8_t XslGameSudo_Generate(XSLGAMESUDO_S_SUDO *pXslGameSudoS) {uint8_t num = 1;// 生成種子數獨memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);// 兩數交換法{uint8_t commutation_data_1, commutation_data_2;uint8_t i;uint8_t *pbuf = pXslGameSudoS->cells;// 設定交換數commutation_data_1 = 2;commutation_data_2 = 8;// 執行數據交換for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL; i++){if (pbuf[i] == commutation_data_1){pbuf[i] = commutation_data_2;}else if (pbuf[i] == commutation_data_2){pbuf[i] = commutation_data_1;}else{;}}}printf("Point Exchange method sudoku(point:2,8):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 非跨界行交換{uint8_t commutation_row_1, commutation_row_2;uint8_t i, temp;// 設定交換行(0-8有效)commutation_row_1 = 0;commutation_row_2 = 2;// 執行交換行for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){temp = pXslGameSudoS->cells[commutation_row_1][i];pXslGameSudoS->cells[commutation_row_1][i] = pXslGameSudoS->cells[commutation_row_2][i];pXslGameSudoS->cells[commutation_row_2][i] = temp;}}printf("Row Exchange method sudoku(row:1,3):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 非跨界列交換{uint8_t commutation_col_1, commutation_col_2;uint8_t i, temp;// 設定交換行(0-8有效)commutation_col_1 = 0;commutation_col_2 = 2;// 執行交換行for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){temp = pXslGameSudoS->cells[i][commutation_col_1];pXslGameSudoS->cells[i][commutation_col_1] = pXslGameSudoS->cells[i][commutation_col_2];pXslGameSudoS->cells[i][commutation_col_2] = temp;}}printf("Col Exchange method sudoku(col:1,3):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 塊行交換{uint8_t commutation_blockrow_1, commutation_blockrow_2;uint8_t i, j, temp;// 設定交換行(0-2有效)commutation_blockrow_1 = 0;commutation_blockrow_2 = 1;// 執行交換行for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){for (j = 0; j < 3; j++){temp = pXslGameSudoS->cells[commutation_blockrow_1 * 3 + j][i];pXslGameSudoS->cells[commutation_blockrow_1 * 3 + j][i] = pXslGameSudoS->cells[commutation_blockrow_2 * 3 + j][i];pXslGameSudoS->cells[commutation_blockrow_2 * 3 + j][i] = temp;}}}printf("Block Row Exchange method sudoku(Block Row:1,2):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 塊列交換{uint8_t commutation_blockrow_1, commutation_blockrow_2;uint8_t i, j, temp;// 設定交換行(0-2有效)commutation_blockrow_1 = 0;commutation_blockrow_2 = 1;// 執行交換行for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL; i++){for (j = 0; j < 3; j++){temp = pXslGameSudoS->cells[i][commutation_blockrow_1 * 3 + j];pXslGameSudoS->cells[i][commutation_blockrow_1 * 3 + j] = pXslGameSudoS->cells[i][commutation_blockrow_2 * 3 + j];pXslGameSudoS->cells[i][commutation_blockrow_2 * 3 + j] = temp;}}}printf("Block Col Exchange method sudoku(Block Col:1,2):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 矩陣旋轉(下面是方形矩陣的自旋轉程序(不用額外緩存)){uint8_t i, j, k, n, x;uint8_t temp1, temp2;//設置參數n = XSLGAMESUDO_SUDOKU_LEVEL;x = n / 2;// 一圈一圈處理k = n - 1;for (i = 0; i < x; i++){for (j = 0; j < k; j++){//右列temp1 = pXslGameSudoS->cells[i + j][n - 1 - i];pXslGameSudoS->cells[i + j][n - 1 - i] = pXslGameSudoS->cells[i][i + j];//下行temp2 = pXslGameSudoS->cells[n - 1 - i][n - 1 - i - j];pXslGameSudoS->cells[n - 1 - i][n - 1 - i - j] = temp1;//左列temp1 = pXslGameSudoS->cells[n - 1 - i - j][i];pXslGameSudoS->cells[n - 1 - i - j][i] = temp2;//左上pXslGameSudoS->cells[i][i + j] = temp1;}k -= 2;}}printf("Rotate method sudoku(90 degrees):\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 矩陣行鏡像{uint8_t i, j;uint8_t temp;//for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL / 2; i++){for (j = 0; j < XSLGAMESUDO_SUDOKU_LEVEL; j++){temp = pXslGameSudoS->cells[j][XSLGAMESUDO_SUDOKU_LEVEL - 1 - i];pXslGameSudoS->cells[j][XSLGAMESUDO_SUDOKU_LEVEL - 1 - i] = pXslGameSudoS->cells[j][i];pXslGameSudoS->cells[j][i] = temp;}}}printf("X Mirror sudoku:\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 矩陣列鏡像{uint8_t i, j;uint8_t temp;//for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL / 2; i++){for (j = 0; j < XSLGAMESUDO_SUDOKU_LEVEL; j++){temp = pXslGameSudoS->cells[XSLGAMESUDO_SUDOKU_LEVEL - 1 - i][j];pXslGameSudoS->cells[XSLGAMESUDO_SUDOKU_LEVEL - 1 - i][j] = pXslGameSudoS->cells[i][j];pXslGameSudoS->cells[i][j] = temp;}}}printf("Y Mirror sudoku:\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//----------memcpy((uint8_t *)(pXslGameSudoS->cells), (uint8_t *)&XslGameSudo_SudoGenerateBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);printf("%d,----------Seeds sudoku:\n", num++);XslGameSudo_FormatPrint(pXslGameSudoS, 2);// 矩陣對角線鏡像{uint8_t i, j;uint8_t temp;for (i = 0; i < XSLGAMESUDO_SUDOKU_LEVEL - 1; i++){for (j = 0; j < XSLGAMESUDO_SUDOKU_LEVEL - 1 - i; j++){temp = pXslGameSudoS->cells[i + j + 1][i];pXslGameSudoS->cells[i + j + 1][i] = pXslGameSudoS->cells[i][i + j + 1];pXslGameSudoS->cells[i][i + j + 1] = temp;}}}printf("Transpose sudoku:\n");XslGameSudo_FormatPrint(pXslGameSudoS, 2);//---------- } /*** @brief main函數* @note 主函數入口* @param null* @return null*/ uint8_t MemBuf[1024]; //81個字節存儲一組解,1024可以存儲大于10個解 uint32_t SudoCount; void main(int argc, char **argv) {uint8_t res;uint32_t time1, time2;printf("--------------------------------------------------\n");printf(" XSL Sudo Generate(Normal) \n");printf("--------------------------------------------------\n");XslGameSudo_Generate(&XslGameSudo_s_Sudo); while(1);printf("--------------------------------------------------\n");printf(" XSL Sudo Processor(Normal) \n");printf("--------------------------------------------------\n");// 數據載入memcpy((uint8_t *)(XslGameSudo_s_Sudo.cells), (uint8_t *)&XslGameSudo_SudoBuf[0][0], XSLGAMESUDO_SUDOKU_LEVEL * XSLGAMESUDO_SUDOKU_LEVEL);// 設置配置//---最多解析10個解XslGameSudo_s_Sudo.MaxOutAnswersCount = 5;XslGameSudo_s_Sudo.pOutBuf = MemBuf;XslGameSudo_s_Sudo.pAnswersCount = &SudoCount;// 打印原始數獨XslGameSudo_FormatPrint(&XslGameSudo_s_Sudo, 0);// 啟動數獨測試time1 = GetTickCount();XslGameSudo_Processor(&XslGameSudo_s_Sudo);time2 = GetTickCount();// 打印結果XslGameSudo_FormatPrint(&XslGameSudo_s_Sudo, 1);// 打印耗時printf("Time(ms):%ld\n", time2 - time1);// 定住頁面,否則程序結束直接閃退,延時10秒自動退出time1 = time2 = 0;time1 = GetTickCount();while (((time2 - time1) < 100000) || (time2 == 0)){time2 = GetTickCount();} }

五,運行結果演示

  • 運行結果---兩數交換法

  • 運行結果---非跨界行交換

  • 運行結果---非跨界列交換

  • 運行結果---塊行交換

  • 運行結果---塊列交換

  • 運行結果---矩陣旋轉

  • 運行結果---矩陣行鏡像

  • 運行結果---矩陣列鏡像

  • 運行結果---矩陣對角線鏡像

六,引用資料致謝

  • 感謝如下連接給的思路:
    • https://my.oschina.net/wangmengjun/blog/781984

總結

以上是生活随笔為你收集整理的徐松亮算法教学-基于C语言的数独(九宫格)多种终盘生成方法(包含矩阵镜像旋转转置等相关算法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。