安徽科技学院 信网学院网络文化节 张乐

#include <stdio.h>
#include <windows.h>

//获取标准输出、入句柄
HANDLE hOut = NULL;
HANDLE hIn = NULL;

int box[9][9] = { 0 }; //定义一个二维数组储存数独
int box99[9][9]; //定义一个99标记数组,1表示对应位置不能再填某个数,
int box33[3][3]; //定义一个3
3标记数组,1表示所在宫格不能再填某个数
int sum = 0; //数独解的个数
int MouseNum=0; //鼠标左键按下代表的值

void gotoxy(int x,int y);
void color(int x);
void clear(); //清屏
void intro(); //使用说明
void Drawbg(); //绘制界面
int MouseR(int* posx, int* posy); //返回数与鼠标的坐标
void Clearbox(); //清空数组
void Putbox(); //输出数组
void Putnum(int n,int x,int y); //在正确位置输出指定数
int Check(int x, int y); //检查对应位置数字是否合适
int Check1(); //检查数独有无重复数字的错误
int Check2(); //检查不存在可填数字的错误
void Tofalse(); //将标记数组全部置为 false
int Tobox33(int n); //给box33数组赋值
int Tobox99(int n); //给box99数组赋值
int start(int x, int y); //开始计算

int main()
{
COORD wsize = {60, 40};
SMALL_RECT rc = {0,0,60-1,40-1};
DWORD mode;
CONSOLE_CURSOR_INFO cursorInfo;
int ix, iy, number;

hOut=GetStdHandle(STD_OUTPUT_HANDLE);
hIn=GetStdHandle(STD_INPUT_HANDLE);
//设置控制台窗口属性 
SetConsoleTitle("Sudoku"); 
SetConsoleScreenBufferSize(hOut, wsize);
SetConsoleWindowInfo(hOut,1,&rc);
GetConsoleMode(hIn, &mode);  
mode &= ~ENABLE_QUICK_EDIT_MODE; 	//移除快速编辑模式
SetConsoleMode(hIn, mode);
cursorInfo.dwSize = 25;
cursorInfo.bVisible = 0;
SetConsoleCursorInfo(hOut, &cursorInfo);

intro();
Drawbg();							// 绘制背景 

while (1)
{
	while (1)
	{	
		number = MouseR(&ix, &iy);
		if (number == 10)			//按下开始键 
		{
			MouseNum = 0;
			if (!Check1())
				continue;
			else
				break;
		}
		Putnum(number,ix,iy);
		gotoxy(6,33);
		if(!Check1())
			printf("输入有误,请检查!");
		else
			printf("                            ");
	}
	if (Check2())
		start(0, 0);
	else
		sum = 0;
		
	gotoxy(6,33);
	printf("                        ");
	gotoxy(6,33);
	switch(sum)
	{
		case 0:printf("该数独无解!");break;
		default:printf("求得数独的解!");break;
	}
	sum = 0;
}
return 0;

}

void gotoxy(int x,int y)
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(hOut,c);
}

void color(int x)
{
SetConsoleTextAttribute(hOut,x);
}

//使用说明
void intro()
{
color(12);
printf("\n\n\n");
printf(" ssss u u d d o o k k u u\n");
printf(" s s u u d d o o k k u u\n");
printf(" s u u d d o o k k u u\n");
printf(" s u u d d o o k u u\n");
printf(" s u u d d o o k k u u\n");
printf(" s s u u d d o o k k u u\n");
printf(" ssss u u u d d o o k k u u u \n");
color(14);
printf("\n\n\n 使用说明\n\n");
printf(" * * * * * * * * * * * * * * *\n");
printf(" * 1. 鼠标选中要填入的数字 *\n");
printf(" * 2. 点击相应空格填入数字 *\n");
printf(" * 3. 检查无误点击开始求解 *\n");
printf(" * * * * * * * * * * * * * * *\n");
color(3);
printf("\n\n\n按enter继续…");
getchar();
}

//用空格填满窗口
void clear()
{
int i;
gotoxy(0,0);
for(i=0;i<100;i++)
printf(" ");
}

// 绘制背景界面
void Drawbg()
{
int i,j,x = 1,y =1;

clear();//先清屏 
for (i = 0; i < 27; i++)
{
	for(j=0;j<=9;j++)
	{
		if(j%3==0) color(14);
		gotoxy(x+j*6,y);
		printf("|");
		color(7);
		if(y%3==1&&j<9)
		{
			if(i%9==0) color(14);
			gotoxy(x+j*6+1,y-1);
			printf("_____");
			color(7);
		}
		if(y==27&&j<9)
		{
			color(14);
			gotoxy(x+j*6+1,y);
			printf("_____");
			color(7);
		}
	}
	y+=1;
}
for(i=0;i<9;i++)
{
	color(i+1);
	gotoxy(x+i*6,30);
	printf("|");
	gotoxy(x+3+i*6,30);
	printf("%d",i+1);
}
color(14);
gotoxy(15,32);
printf("[置零]");
gotoxy(25,32);
printf("[清空]");
gotoxy(35,32);
printf("[开始]");
printf("\n提示:\n\n当前选中的数字:\n\n\n点击空格填入当前选中的数字,点击开始按钮计算数独的解。"); 

}

//处理鼠标事件
int MouseR(int* mx, int* my)
{
INPUT_RECORD mRecord; //定义输入事件结构体
DWORD res; //用于存储读取记录
COORD pos; //用于存储鼠标当前位置
int flag=1;
while (flag)
{
ReadConsoleInput(hIn, &mRecord, 1, &res); //读取输入事件
if (mRecord.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) //如果是左键单击
{
pos = mRecord.Event.MouseEvent.dwMousePosition; //获取鼠标当前位置
if (pos.X >=1 && pos.X <= 55 && pos.Y30) //选择数字
{
MouseNum=(pos.X-2)/6+1;
}
if (pos.X >= 1 && pos.X <= 55 && pos.Y >= 1 && pos.Y <= 27) // 坐标点在九宫格内就将给点坐标按地址值传出
{
*mx=pos.X;
*my=pos.Y;
flag=0;
}
if(pos.X > 15 && pos.X < 20 && pos.Y
32) //按下置零键
{
MouseNum=0;
}
if (pos.X > 25 && pos.X < 30 && pos.Y32) //按下清空键
{
Clearbox();
Putbox();
gotoxy(6,33);
printf(" ");
}
if (pos.X > 35 && pos.X < 40 && pos.Y
32) //按下开始键
{
MouseNum = 10;
gotoxy(16,35);
printf(“0”);
return MouseNum;
}
gotoxy(16,35);
printf("%d",MouseNum);
}
}
return MouseNum;
}

//在正确位置输出指定的数
void Putnum(int n,int x,int y)
{
int sx,sy;
sx=(y-1)/3;
sy=(x-2)/6;
box[sx][sy]=n;
gotoxy(sy6+4,sx3+2);
if(box[sx][sy]>0) printf("%d",box[sx][sy]);
else printf(" ");
}

//输出数组
void Putbox()
{
int i,j,x=4,y=2;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
gotoxy(x+j6,y+i3);
if(box[i][j]>0)
{
color(box[i][j]);
printf("%d",box[i][j]);
}
else printf(" ");
}
}
color(14);
}

//数组内的数清空
void Clearbox()
{
int i,j;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
box[i][j] = 0;
}
}
MouseNum = 0;
}

//检查box[x][y]是否合适
int Check(int x, int y)
{
int i,j,xx,yy,flag = 1;
for (i = 0; i<9; i++)
{
if (box[x][i] == box[x][y] && i != y)
{
flag = 0;
}
if (box[i][y] == box[x][y] && i != x)
{
flag = 0;
}
}
xx = x / 3;
yy = y / 3;
for (i = xx * 3; i<(xx + 1) * 3; i++)
{
for (j = yy * 3; j<(yy + 1) * 3; j++)
{
if (i != x && j != y && box[i][j] == box[x][y])
{
flag = 0;
}
}
}
return flag;
}

//检查box[][]是否正确
int Check1()
{
int a[9]; // 行
int b[9]; // 列
int c[9]; // 宫
int i,j,p,q,n=0,z,w;
//检查行
for (i = 0; i < 9; i++) //此for执行完说明数组的行符合要求
{
for (j = 0; j < 9; j++)
{
a[j] = box[i][j];
if (j == 8)
{
for (q = 0; q < 9; q++) //此for执行完说明一行没有重复的数
{
for (p = q + 1; p < 9; p++)
{
if (p < 9)
{
if (a[q] != 0 && a[p] != 0)
{
if (a[q] == a[p])
return 0;
}
}
}
}
}
}
}

//检查列 
for (i = 0; i < 9; i++)	  //此for执行完说明数组的列符合要求
{
	for (j = 0; j < 9; j++)
	{
		b[j] = box[j][i];
		if (j == 8)
		{
			for (q = 0; q < 9; q++)		//此for执行完说明一列没有重复的数 
			{
				for (p = q + 1; p < 9; p++)
				{
					if (p < 9)
					{
						if (b[q] != 0 && b[p] != 0)
						{
							if (b[q] == b[p])
								return 0;
						}
					}
				}
			}
		}
	}
}

//检查宫 
for (i = 0; i < 3; i++)
{
	for (j = 0; j < 3; j++)
	{
		for (p = 0; p < 3; p++)		// 一个 
		{								// 3*3
			for (q = 0; q < 3; q++)	// 区块 
			{
				c[n] = box[i * 3 + p][j * 3 + q];
				n++;
				if (n == 9)
				{
					for (w = 0; w < 9; w++)		//此for执行完说明宫没有重复的数 
					{
						for (z = w + 1; z < 9; z++)
						{
							if (z < 9)
							{
								if (c[w] != 0 && c[z] != 0)
								{
									if (c[w] == c[z])
										return 0;
								}
							}
						}
					}
					n = 0;
				}
			}
		}
	}
}
return 1;	// 到这说明无重复,返回正确

}

//从1到9依次试数,寻找数独的解
int start(int x, int y)
{
int j;
if (x == 9)
{
Putbox();
sum++;
}
if (sum > 1)
return 0;
if (box[x][y] == 0)
{
for (j = 1; j <= 9; j++) //从1到9依次试数
{
box[x][y] = j;
if (Check(x, y))
{
start(x + (y + 1) / 9, (y + 1) % 9);
}
box[x][y] = 0;
}
}
else
{
start(x + (y + 1) / 9, (y + 1) % 9); //从左到右,从上到下依次确定合适的数
}
return 0;
}

//将标记数组全部置为 false
void Tofalse()
{
int i,j;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
box99[i][j] = 0;
}
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
box33[i][j] = 0;
}
}
}

//对数组box33进行赋值,如果九宫格里有数字n,就将九宫标记数组box33对应位置置为true
int Tobox33(int n)
{
int b[9];
int count = 0;
int i,j,p,q,w;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
for (p = 0; p < 3; p++)
{
for (q = 0; q < 3; q++)
{
b[count] = box[i * 3 + p][j * 3 + q];
count++;
if (count == 9) //将每一宫的数存储到一维数组中进行检查
{
for (w = 0; w < 9; w++)
{
if (b[w] == n)
box33[i][j] = 1;
}
count = 0;
}
}
}
}
}
return 0;
}

//对数组box99进行赋值
int Tobox99(int n)
{
int i,j,p;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
if (box[i][j] == n)
{
for (p = 0; p < 9; p++)
{
box99[i][p] = 1;
box99[p][j] = 1;
}
}
if (box[i][j] != 0)
{
box99[i][j] = 1;
}
}
}
return 0;
}

//依次对数字1~9检查每宫每格
int Check2()
{
int num,i,j,p,q,count;
for (num = 1; num <=9; num++)
{
Tofalse(); // 将标记数组都初始化为false
Tobox33(num); // 将有数num的宫格都赋为true
Tobox99(num); // 将有数num的行列都赋为true

	//检查宫格是否存在数num,存在检查下一宫,不存在就检查有没有空可以填,没有就说明出错了 
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			if (box33[i][j] == 0)
			{
				count = 0;
				for (p = 0; p < 3; p++)
				{
					for (q = 0; q < 3; q++)
					{
						if (box99[i * 3 + p][j * 3 + q] == 0)
						{
							count++;
						}
					}
				}
				if (count>0)
				{
					count = 0;
				}
				else
					return 0;
			}
		}
	}
}
return 1;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值