数独计算小程序开发(一)
2009-12-22 15:46
357 查看
前些日子,女朋友给了我一个数独游戏,弄了好久没弄出来。计算量有点大,于是就想通过编程来计算了,就做了这么个东西来玩玩。
首先数独规则:
在9*9的方格矩阵中,根据已知数字填入1-9数字。最后满足在每行、每列、每个3*3宫中的9个格中不重复的存在1-9的所有数。OVER!
说说实现吧,数独的数据信息的是记录在一个二维数组中的。每个元素为如下数据结构
其中nValue存储元素的值,因为要计算和存储可能值(有多个值)而且为了计算的方便和效率,元素的值是通过设置位来表示的。如值为5时nValue = B10000;可能值为5、7、8时nValue = B11010000;通过这样的表达方式,在实际的判定算法中也可以很方便的计算,且效率很高。
首先有个最基本的算法(互斥性算法)。因为每行每列每宫中不能有相同数,所以可以由此原则和数独初始的已知数来算出每格的可能值。
然后还有个必须值算法,根据的是每行每列每宫中的值必须1~9都有(因为互斥而且有9格),通过这种算法也能找出某些值。
计算一次就是调用上面的两个算法:
在这里我没有实现迭代计算,因为现在的打算是通过算法将结果分析出来,而不是遍历试出来(虽然这样也不错),以后会实现的,但这不是重点。
值得一说的是,每格元素是通过行号和列好来指定坐标的。因为数独有9*9个输入框,edit空间很多,为了能够方便输入输出,我在resource.h头文件中更改了每个控件的ID值,如位于第3行5列(行从上向下,列从左向右,都以0开始)的元素ID为IDC_NUM35 = 0x1135,还写了了几个宏来实现从二维数组坐标和控件ID间进行相互转换的操作:
现在还是alpha版,功能还不完善,尚未添加:对原始输入数据正确性的检测、新计算出的值的高亮显示等,因为没有实现迭代,所以每次计算后,要用户手动将新计算出的值输入到输入区,然后进行第二次计算,直至全部计算完毕。
完整代码下载: 数独辅助程序源码_0.5Alpha版
感兴趣的可以看看,如果有什么意见和建议就留言,希望多多交流。欢迎转载,请保留原始链接:
http://blog.csdn.net/zha_1525515/archive/2009/12/22/5056282.aspx
首先数独规则:
在9*9的方格矩阵中,根据已知数字填入1-9数字。最后满足在每行、每列、每个3*3宫中的9个格中不重复的存在1-9的所有数。OVER!
说说实现吧,数独的数据信息的是记录在一个二维数组中的。每个元素为如下数据结构
typedef struct shuduelement { BOOL bKnown; /* 次元素值是否为已知 */ /* bKnown为TRUE时则为已知值,为FALSE时则为可能值或初始的0, 按相应的bit位存储*/ unsigned int nValue; } SDElement;
其中nValue存储元素的值,因为要计算和存储可能值(有多个值)而且为了计算的方便和效率,元素的值是通过设置位来表示的。如值为5时nValue = B10000;可能值为5、7、8时nValue = B11010000;通过这样的表达方式,在实际的判定算法中也可以很方便的计算,且效率很高。
首先有个最基本的算法(互斥性算法)。因为每行每列每宫中不能有相同数,所以可以由此原则和数独初始的已知数来算出每格的可能值。
]/* * 计算指定元素的可能值,若其值已知则退出不计算 */ void calcPossibleValue(SDElement rgnShuDu[][MAX_COL_NUM],const int row,const int col) { int startRow, startCol; /* 所在宫的起始位置 */ int i, j; unsigned int num = 0; if(!rgnShuDu[row][col].bKnown) //值未知 { startRow = (row / PALACE_LEN) * PALACE_LEN; startCol = (col / PALACE_LEN) * PALACE_LEN; /* 统计所在宫已知数 */ for(i = startRow; i < startRow + PALACE_LEN; i++) for(j = startCol; j < startCol + PALACE_LEN; j++) { if(rgnShuDu[i][j].bKnown) num |= rgnShuDu[i][j].nValue; } /* 统计所在行和列的已知数 */ for(i = 0; i < MAX_COL_NUM; i++) if(rgnShuDu[row][i].bKnown) num |= rgnShuDu[row][i].nValue; for(i = 0; i < MAX_ROW_NUM; i++) if(rgnShuDu[i][col].bKnown) num |= rgnShuDu[i][col].nValue; rgnShuDu[row][col].nValue = num ^ ALL_POSSIBILITY; } }
然后还有个必须值算法,根据的是每行每列每宫中的值必须1~9都有(因为互斥而且有9格),通过这种算法也能找出某些值。
/** * (局部函数)计算一个元素的必须的值,已知元素直接返回,如一个宫内 *其余的元素都不能为某值(已知数也不是那个值),则此元素一定为此某值, *因为一个宫内必须有1~9的所有数。此算法人实际使用较多(我老婆), * 前提条件,所有未知元素已根据互斥性算出了可能值 * 输入: rgnShuDu要操作和保存数的二维数组 * row,col分别指定要计算的元素的行列数 * 注意:元素可以算出必须值的可能性不大,故可能有效可能会浪费时间 */ static void calcMustValue(SDElement rgnShuDu[][MAX_COL_NUM], const int row, const int col) { int startRow, startCol; /* 所在宫的起始位置 */ int i, j; unsigned int num = 0; if(!rgnShuDu[row][col].bKnown) { startRow = (row / PALACE_LEN) * PALACE_LEN; startCol = (col / PALACE_LEN) * PALACE_LEN; /* 统计所在宫内所有非指定元素的值,包括已知数 */ for(i = startRow; i < startRow + PALACE_LEN; i++) for(j = startCol; j < startCol + PALACE_LEN; j++) { if(i != row || j != col) num |= rgnShuDu[i][j].nValue; } /* 不为零则这个元素比为某个值,这样此元素值已知 */ if((num = num ^ ALL_POSSIBILITY) != 0) { rgnShuDu[row][col].bKnown = TRUE; rgnShuDu[row][col].nValue = num; } } }
计算一次就是调用上面的两个算法:
void calcAllPossibleValue(SDElement rgnShuDu[][MAX_COL_NUM]) { int i = 0, j = 0; for(i = 0; i < MAX_ROW_NUM; i++) for(j = 0; j < MAX_COL_NUM; j++) calcPossibleValue(rgnShuDu, i, j); for(i = 0; i < MAX_ROW_NUM; i++) for(j = 0; j < MAX_COL_NUM; j++) calcMustValue(rgnShuDu, i, j); }
在这里我没有实现迭代计算,因为现在的打算是通过算法将结果分析出来,而不是遍历试出来(虽然这样也不错),以后会实现的,但这不是重点。
值得一说的是,每格元素是通过行号和列好来指定坐标的。因为数独有9*9个输入框,edit空间很多,为了能够方便输入输出,我在resource.h头文件中更改了每个控件的ID值,如位于第3行5列(行从上向下,列从左向右,都以0开始)的元素ID为IDC_NUM35 = 0x1135,还写了了几个宏来实现从二维数组坐标和控件ID间进行相互转换的操作:
]/** * 输入控件很多为了能够更好的之间处理,调整了resource.h中的各输入控件 *的值,ID皆为IDC_NUMxx的形式,如:IDC_NUM35 = 0x1135,表示的是第3行第5列 *的输入控件,由此,可以容易由一控件ID获取其行列数:()前面的11是为了避免 *和别的ID值重复) */ #define ROW_MASK 0xF0 /* 获取行数的掩码 */ #define COL_MASK 0x0F /* 获取列数的掩码 */ /* 由控件获取行数 */ #define GET_ROW(IDC_NUMxx) ((IDC_NUMxx & ROW_MASK) >> 4) /* 由控件获取列数 */ #define GET_COL(IDC_NUMxx) (IDC_NUMxx & COL_MASK) /* 由行数列数获取控件ID */ #define GET_ID(row,col) (0x1100 | col | (row<<4))这样子在输入输出就会很方便, 而且为以后的添加的一些功能能够奠定基础。
现在还是alpha版,功能还不完善,尚未添加:对原始输入数据正确性的检测、新计算出的值的高亮显示等,因为没有实现迭代,所以每次计算后,要用户手动将新计算出的值输入到输入区,然后进行第二次计算,直至全部计算完毕。
完整代码下载: 数独辅助程序源码_0.5Alpha版
感兴趣的可以看看,如果有什么意见和建议就留言,希望多多交流。欢迎转载,请保留原始链接:
http://blog.csdn.net/zha_1525515/archive/2009/12/22/5056282.aspx
相关文章推荐
- 高速公路坐标高程计算程序开发之后记
- c#开发-计算一段程序运行的时间
- 适用于ATI卡的GPU计算MD5的小程序源码,基于AMD APP SDK开发
- Android开发--身高体重指数(BIM)计算--完成BMI程序
- iOS入门开发计算器小程序,包括button、label、image的使用
- 微信小程序开发常用技巧(2)——页面view高度计算
- 程序开发: Oracle各种日期计算方法(收藏)
- 第七周项目2-自选图形用户界面程序开发(计算活了多少天)
- Android开发环境搭建和SAP安装KEY计算程序
- 开始准备跨平台的数独程序开发
- 浅谈数值计算程序开发中性能分析的重要性--valgrind工具使用简介及可恶的std::pow
- 量子计算程序开发环境搭建
- 适用于ATI卡的GPU计算MD5的小程序源码,基于AMD APP SDK开发
- 全民数独游戏自动计算程序(1)
- 程序开发: Oracle各种日期计算方法(收藏)
- 计算数独的小程序-.-
- 数独计算程序
- 数独计算程序
- 5、使用JAX-WS注解开发WebService程序
- Chrome扩展程序开发调试简明教程