您的当前位置:首页正文

大数据开发工程师的周末:关于数独的生成

来源:华拓网

关于数独的生成

这次从深圳回来的火车上,由于过于无聊,玩了一下数独游戏,和吕政委(同学)讨论了下数独的生成方法,这篇日志算是对车上思路的一个实现。即使是一个简单的问题,也可以引申出很多有趣的东西,这种乐趣只有写代码的时候才能发现,只可意会不可言传……

以前其实写过一个数独游戏,但是重装了无数次系统之后源代码不知道哪去了,估计是让猫给吃了;《编程之美》里面貌似有一篇文章是讲数独的生成的,而且不止一种方法,不过我的这本书估计也让猫给吃了……我这里是用回溯法生成完整的数独。

哈哈哈,周末时光翻看到了高中时期写的这篇文章,感叹一下(逝去的我的高中时光)

现在从事着大数据开发工作,依旧喜欢写代码。
拥有自己的大数据学习交流群:606859705
喜欢代码的伙伴可以一起交流经验

其实有很多地方可以说的,但是还是算了,贴上代码:

/*

* Name:        main.c

* Purpose:     数独生成

* Author:      HSZ @ HNU

* Created:     2013/7/11 星期四 17:42:56

* LastChange:  2013/7/11 星期四 17:42:56

* History: 

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#define MAX_NUM 9

#define MAP_H MAX_NUM

#define MAP_W MAX_NUM

// 可选数字缓冲区

struct num_list {

int nums[MAX_NUM];

int size;

};

// 随机打乱数组

static void randomize(int nums[], int size);

// 初始化可选数字缓冲区

static void init_num_list(struct num_list *list, const int map[MAP_H][MAP_W], int row, int col);

// 初始化地图

static void init_map(int map[MAP_H][MAP_W]);

int main(int argc, char *argv[])

{

int map[MAP_H][MAP_W] = {0};

int i, k;

srand(time(NULL));

init_map(map);

for (i = 0; i < MAP_H; ++i) {

for (k = 0; k < MAP_W; ++k) {

printf("%d, ", map[i][k]);

}

printf("\n");

}

return 0;

}

void init_map(int map[MAP_H][MAP_W])

{

int i, k;

struct num_list list[MAP_H][MAP_W] = {0};

// 遍历地图,填充合适的数字

i = 0;

while (i < MAP_H) {

k = 0;

while (k < MAP_W) {

// 如果map[i][k] == 0,说明这个格对应的可选数字列表没有初始化过

if (map[i][k] == 0) {

// 初始化

init_num_list(list[i] + k, map, i, k);

// 打乱

randomize(list[i][k].nums, list[i][k].size);

}

// 如果此时map[i][k]不为0,说明是回溯,清0,否则继续回溯会出错

map[i][k] = 0;

if (list[i][k].size == 0) {

// 如果没有可选的数字,回溯

--k;

if (k < 0) {

k = 8;

--i;

}

continue;

} else {

// 否则,填充地图,移除可选数字列表中的一个数字

map[i][k] = list[i][k].nums[list[i][k].size - 1];

--list[i][k].size;

}

++k;

}

++i;

}

}

void randomize(int nums[], int size)

{

int i, k;

int tmp;

for (i = 0; i < size; ++i) {

// 令k = [i, size-1)区间随机的一个数

k = (i + rand() % (size - i));

// 交换nums[i]与nums[k]

tmp = nums[i];

nums[i] = nums[k];

nums[k] = tmp;

}

}

void init_num_list(struct num_list *list, const int map[MAP_H][MAP_W], int row, int col)

{

int i, k;

// 初始可选数字1~9,0是一个占位符

int allow_nums[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

// 去除横纵两个方向上已经存在的数字,这里其实可以稍稍优化一下

for (i = 0; i < 9; ++i) {

allow_nums[map[row][i]] = 0;

allow_nums[map[i][col]] = 0;

}

// 定位到这个九宫格的左上角坐标

row = row - (row % 3);

col = col - (col % 3);

// 遍历这个九宫格

for (i = row; i < row + 3; ++i) {

for (k = col; k < col + 3; ++k)

allow_nums[map[i][k]] = 0;

}

// 遍历剩下的数字填充数字缓冲区

list->size = 0;

for (i = 1; i < 10; ++i) {

if (allow_nums[i] != 0) {

list->nums[list->size] = allow_nums[i];

++list->size;

}

}

}