C程序计算对角线数独源代码

C程序计算对角线数独源代码

使用简单语法编写的C程序,仅在Linux环境下运行过。
顺便问一下C语言大佬们一个问题:
while循环中运行到scanf函数为什么循环直接就结束了?
希望大佬们提出建议!

运行原理

九宫格对应二维数组,给每个格子分类:空格、定格、虚格、暂废格。
空格:即数独中的空格子,程序中用0表示
定格:即数独中一开始就给定的格子
虚格:程序分析中已经赋予过数值的空格
暂废格:程序为空格赋予的值用尽的格子
1.用户输入九宫格
2.赋值函数将适合的数值赋予一维数组
3.格子函数将每个格子的状态赋予二维数组
4.给九宫格中的空格赋值并判断是否有重复
如果不重复进行下一个格子
否则
用虚格函数将格子中的数值更换,返回第4步
如果更换所有值仍然重复
返回上一个空格,运行第4步
结束

更换用尽返回上一个格子
成功更换数值
输入九宫格
给一维数组二维数组函数赋值
给九宫格赋值
判断是否有重复
虚格函数
结束
注意事项

程序在Windows平台下运行可能出现内存溢出的情况,我在Linux下完美运行
程序在结尾while循环中运行到scanf函数时会出现直接跳出循环的情况,不影响程序计算
在输入九宫格的时候务必准确输入,否则会计算错误,输入后无法更改
输入时空格用0代替,直接回车会卡死

源代码
#include<stdio.h>
unsigned short One_Pocket[800]={0},One_Pocket_Basic = 0,A;
unsigned short Two_Pocket[9][9]={0};//坐标值对应九宫格的坐标值,用于存入相应的九宫格是什么状态,一次函数调用,永久使用
unsigned short X = 0,Y = 0,Nine_Pocket[9][9] = 
{ //申明坐标X,Y,九宫格二维数组,空值用0代替
	{0 , 0 , 0 ,   7 , 0 , 9 ,   0 , 1 , 0},

	{6 , 0 , 8 ,   0 , 0 , 0 ,   9 , 0 , 0},

	{0 , 9 , 0 ,   3 , 0 , 0 ,   0 , 7 , 0},


	{0 , 0 , 0 ,   0 , 5 , 0 ,   4 , 0 , 7},

	{0 , 0 , 0 ,   9 , 0 , 6 ,   0 , 0 , 0},

	{3 , 0 , 6 ,   0 , 7 , 0 ,   0 , 0 , 0},


	{0 , 4 , 0 ,   0 , 0 , 2 ,   0 , 8 , 0},

	{0 , 0 , 5 ,   0 , 0 , 0 ,   2 , 0 , 1},

	{0 , 3 , 0 ,   5 , 0 , 8 ,   0 , 0 , 0}
};
short For_Gong()//判断坐标对应的相应值在第几宫格中,方法:GN=For_Gong()
{
if(Y <= 2)
	{
	if(X <= 2)
		{
			return 1;
		}
	if(X<= 5)
		{
			return 2;
		}
	if(X <= 8)
		{
			return 3;
		}
	}
else if(Y <= 5 )
	{
	if(X <= 2)
		{
			return 4;
		}
	if(X <= 5)
		{
			return 5;
		}
	if(X <= 8)
		{
			return 6;
		}
	}
else if(Y <= 8)
	{
	if(X <= 2)
		{
			return 7;
		}
	if(X <= 5)
		{
			return 8;
		}else
		{
			return 9;
		}
	}

}
void Nine_Pocket_Return_For()//判断相应坐标值是什么状态,空格返回1,定格返回2,虚格返回3。存入对应的二维数组中
{
	short SA,i;
	for(Y = 0 ; Y <= 8 ; Y++)
	{
		for(X = 0 ; X <=8 ; X++)
		{
			if(Nine_Pocket[Y][X] != 0)//如果坐标值不等于零
			{
	  			SA = One_Pocket_Basic;//记录原始一维数组底值
	   			for(i = 0 ;  i <=8 ; i++)//逐次增加一维数组的底值并判断所有的值是否为0
				{
	       			if(One_Pocket[One_Pocket_Basic] == 0)//如果第一个一维数组值为零
					{
	       				One_Pocket_Basic = One_Pocket_Basic + 1; //将底值加1
					}
        			if(i == 8)//如果加到到最后还是等于零,则是定格
					{
						Two_Pocket[Y][X] = 2;
        				One_Pocket_Basic = SA;  //恢复一维数组的坐标底
					}
					One_Pocket_Basic = One_Pocket_Basic + 9;
				}
			}
    		else//否则这个是空格或者是虚格
			{
				Two_Pocket[Y][X] = 3;
				One_Pocket_Basic = One_Pocket_Basic + 9;
			}
		}
	}
 	X = 0;
    Y = 0;
    One_Pocket_Basic = 0; 
}
short Two_Pocket_Return()//给需要的函数返回九宫格是什么状态
{
	if(Nine_Pocket[Y][X] == 0)
	{
		return 1;
	}
	else
	{
		return Two_Pocket[Y][X];
	}
	
}
void Pocket_Add()//增值函数,增值函数的意义在于将坐标值增加到下一位虚格中,方便分析使用。
{
    short Forcast;
    if(X == 8 )
    {
        Y = Y + 1;
        X = 0;
        One_Pocket_Basic = One_Pocket_Basic + 9;
        for(short i = 1; i < 81 ; i++)//根据要求,增值后的坐标必须是空值
		{
        	Forcast = Two_Pocket_Return(); //1空,2定,3虚
        	if(Forcast == 1 || Forcast == 3)
			{
        		break;
			}
        	else
			{
        		if(X == 8 )
				{
        			Y = Y + 1;
        			X = 0;
        			One_Pocket_Basic = One_Pocket_Basic + 9;
				}
    			else
				{
        			X = X + 1;
        			One_Pocket_Basic = One_Pocket_Basic + 9;
				}
			}
		}
	}
    else
	{
	   X = X + 1;
	   One_Pocket_Basic = One_Pocket_Basic + 9;
	   for(short i = 1 ; i < 81 ; i++)//根据要求,增值后的坐标必须是空值
        {
        	Forcast = Two_Pocket_Return();
    		if(Forcast == 1)
			{
    			break;
			}    
    		else
			{
                if(X == 8 )
				{
    				Y = Y + 1;
    				X = 0;
    				One_Pocket_Basic = One_Pocket_Basic + 9;
                }
                else
                {
			     	X = X + 1;
			     	One_Pocket_Basic = One_Pocket_Basic + 9;
				}
			}
		}
	}
}
void Pocket_Reduce()//降值函数
{
    unsigned short Forcast;
    if(X == 0 )
	{
        Y = Y - 1;
        X = 8;
        One_Pocket_Basic = One_Pocket_Basic - 9;
        for(unsigned short i = 1 ; i < 81 ; i++)//根据要求,降值后的坐标必须是虚值
        {
        	Forcast = Two_Pocket_Return();
            if(Forcast == 3)
			{
    			break;
			}
    		else
            {
     			if(X == 0)
				{
    				Y = Y - 1;
    				X = 8;
    				One_Pocket_Basic = One_Pocket_Basic - 9;
				}  
    			else
                {
    				X = X - 1;
    				One_Pocket_Basic = One_Pocket_Basic - 9;
				}			
			}
		}
	}
    else
	{
	   	X = X - 1;
	   	One_Pocket_Basic = One_Pocket_Basic - 9;
    	for(unsigned short i = 1 ; i < 81 ; i++)//根据要求,降值后的坐标必须是虚值
		{
            Forcast = Two_Pocket_Return();
            if(Forcast == 3)
			{
		      	break;
			}
		    else
			{
		      	if(X == 0)
				{
		      		Y = Y - 1;
		      		X = 8;
		      		One_Pocket_Basic = One_Pocket_Basic - 9;
				}
				else
				{
		      		X = X - 1;
		      		One_Pocket_Basic = One_Pocket_Basic - 9;
				}			
			}
		}
	}
}
short Return_For_X()//判断坐标参数X轴是否有重复,重复返回1,不重复返回2,以下函数同理
{
    for(unsigned short i = 0 ; i < 9 ; i++)
	{
        if( i == X)
		{
			continue;
		}
        else
		{
        	if(Nine_Pocket[Y][i] == Nine_Pocket[Y][X])
			{
    			return 1;
			}
		}
	}
	return 2;
}
short Return_For_Y()
{
    for(unsigned short i = 0 ; i < 9 ; i++)
	{
        //<>判断Y轴
        if(i == Y)
		{
    		continue;
		}
       	else
		{
    		if(Nine_Pocket[i][X] == Nine_Pocket[Y][X])
			{
    			return 1;
			}
		}
	}
	return 2;
}
short Return_For_L()
{
    for(unsigned short i = 0 ; i < 9 ; i++)
	{
    	if(i == X || i == Y)
    	{
    		continue;
		}
        else
		{
        	if(Nine_Pocket[i][i] == Nine_Pocket[Y][X])
			{	
        		return 1;
			}
		}
	}
	return 2;
}
short Return_For_R()
{
    for(unsigned short i = 0 ; i < 9 ; i++)
	{
    	if( i == X)
		{
    		continue;
		}
		else
        {
            if(Nine_Pocket[8-i][i] == Nine_Pocket[Y][X])
			{
				return 1;
			}
        }
	}
	return 2;
}
short Return_For_G(short A)
{
    switch(A)
	{
    	case 1://<代码分析>  判断此坐标在第一宫中是否有重复,以下for判断皆如此
    		for(unsigned short j = 0 ; j < 3 ; j++)
			{
    			for(unsigned short i = 0 ; i < 3 ; i++)
				{
    				if(i == X && j == Y)
					{
    					continue;
					}
        				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
					{
    					return 1;
					}
				}
			}
	break;
	case 2:
		for(unsigned short j = 0 ; j < 3 ; j++)
		{
			for(unsigned short i = 3 ; i < 6 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;
	case 3:
		for(unsigned short j = 0 ; j < 3 ; j++)
		{
			for(unsigned short i = 6 ; i < 9 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;
	case 4:
		for(unsigned short j = 3 ; j < 6 ; j++)
		{
			for(unsigned short i = 0 ; i < 3 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
		      		return 1;
				}
			}
		}
	break;
	case 5:
		for(unsigned short j = 3 ; j < 6 ; j++)
		{
			for(unsigned short i = 3 ; i < 6 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;
	case 6:
		for(unsigned short j = 3 ; j < 6 ; j++)
		{
            for(unsigned short i = 6 ; i < 9 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}	
			}	
		}
	break;
	case 7:
		for(unsigned short j = 6 ; j < 9 ; j++)
		{
			for(unsigned short i = 0 ; i < 3 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;
	case 8:
		for(unsigned short j = 6 ; j < 9 ; j++)
		{
			for(unsigned short i = 3 ; i < 6 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;
	case 9:
		for(unsigned short j = 6 ; j < 9 ; j++)
		{
			for(unsigned short i = 6 ; i < 9 ; i++)
			{
				if(i == X && j == Y)
				{
					continue;
				}
				if(Nine_Pocket[j][i] == Nine_Pocket[Y][X])
				{
					return 1;
				}
			}
		}
	break;		
	}
return 2;
}
short Return_For()//判断相应的坐标值是否有重复,重复返回1,不重复返回2
{
    short Forcast;
    Forcast = Return_For_X();
    if(Forcast == 1)
    {
        return 1;
	}
    Forcast = Return_For_Y();
    if(Forcast == 1)
    {
        return 1;
	}
    Forcast = For_Gong();
    Forcast = Return_For_G(Forcast);
    if(Forcast == 1)
	{
        return 1;
	}
    //对于斜轴的判断是有条件的,左轴条件是X=Y,右轴条件是Y==(8-X),并且要分开判断,
    if(X == Y)
	{
        Forcast = Return_For_L(); //左右斜上轴的判断是有条件的,不是一直使用
        if(Forcast == 1)
		{
        	return 1;
		}
	}
    if(Y == (8-X))
	{
        Forcast = Return_For_R(); 
        if(Forcast == 1 )
		{
        	return 1;
		}
	}
    return 2;
}
void Print_Nine_Pocket()//将九宫格打印
{
    for(unsigned short i=0 ; i<9 ; i++)
	{
    	for(unsigned short j=0 ; j<9 ; j++)
		{
    		printf(" %d ",Nine_Pocket[i][j]);
    		if ( j==2  ||  j == 5)
			{
    			printf(" ");
			}
    		if( i==2 && j == 8 )
			{
    			printf("\n");
			}
    		if( i == 5 && j == 8 )
			{
    			printf("\n");
			}
        	if( j == 8)
			{
				printf("\n");
			}
		}
	}
}

void Give_For()//给一维数组赋预测值,自动匹配符合每个格子的数值,写入一维数组中
{
    short Forcast,SA;
    for(Y = 0 ; Y <= 8 ; Y++)
    {
        	for(X = 0 ; X <= 8 ; X++)
    	   {
	       	if(Nine_Pocket[Y][X] == 0)
            {
                for(SA = 1 ; SA <= 9 ; SA++)//从1-9开始依次增加数字
                {
				    Nine_Pocket[Y][X] = SA;    //将预测数字写入九宫格
				    Forcast = Return_For();//判断相应的坐标值中的预测值是否重复//将是否重复的值存入变量中
				    if(Forcast == 2)		//如果没有重复
				    {						
					   One_Pocket[One_Pocket_Basic] = SA;//将预测值写入一维数组中
				    }
				    Nine_Pocket[Y][X] = 0;
				    One_Pocket_Basic = One_Pocket_Basic + 1;
                }
            }
			else
			{
			One_Pocket_Basic = One_Pocket_Basic + 9;
			}
        }
    }
    X = 0;
    Y = 0;
    One_Pocket_Basic = 0; 
}
short Nine_Pocket_Xu_For()//对虚格的坐标进行赋值判断,如果成功更换此格子,返回1,否则为暂废格返回2
{
    short SA,Max,Forcast;
    SA = One_Pocket_Basic; //记录底值原始数值
    Max = One_Pocket_Basic + 9; //记录原始数值的最大值
    for(One_Pocket_Basic ; One_Pocket_Basic < Max ; One_Pocket_Basic++) //判断出格子里的值在一维数组中是第几位
	{
        if(One_Pocket[One_Pocket_Basic] ==0)
		{
		}
        else
		{
        	if(One_Pocket[One_Pocket_Basic] != Nine_Pocket[Y][X])//如果此时的一维数组不等于相应格子值
			{
			}
        	else//否则格子里的值等于一维数组的值
			{
        		break;
			}
		}
	    if(One_Pocket_Basic == (Max-1))//如果进行第八次计算还是没有结果,则是暂废格
		{
		  One_Pocket_Basic = SA; //恢复原坐标底值,一维数组坐标底值紧跟XY变化
		  printf("虚格操作:此格是暂废格");
		  return 2;			
		}
	}
    for(One_Pocket_Basic ; One_Pocket_Basic < Max ; One_Pocket_Basic++)//以记录后的底值为开始,逐渐加1,如果一维数组为0,就加1,否则就赋值格子
	{
        if(One_Pocket[One_Pocket_Basic] == 0 || One_Pocket[One_Pocket_Basic]==Nine_Pocket[Y][X])
		{
		}
        else//如果不等于0
		{
        	Nine_Pocket[Y][X] = One_Pocket[One_Pocket_Basic]; //将不等于0的数重新赋值到原先的九宫格中
    		Forcast=Return_For(X ,Y); //将是否重复的值存入变量中
			if(Forcast == 1)
			{//如果重复
				Nine_Pocket[Y][X] = 0;
			}
			else
			{//否则没有重复,则成功更换数值
				One_Pocket_Basic = SA; //恢复原坐标底值,一维数组坐标底值紧跟XY变化	
				return 1;
			}
		}
		if(One_Pocket_Basic == (Max-1) || One_Pocket_Basic == Max)//如果进行最后一次判断一维数组值都还为零,则此格为暂废格,需要XY坐标底值降值函数
		{
			One_Pocket_Basic = SA;//恢复原坐标底值,一维数组坐标底值紧跟XY变化
			return 2;
		}
	}
}
short Nine_Pocket_Add_For()//用一维数组的预测值给九宫格赋值并判断
{
	short Forcast,SA;
	for(Y = 0 ; Y <= 8 ; Y++)
	{
		for(X = 0 ;  X <= 8  ; X++)
		{
			Label:
			Forcast = Two_Pocket_Return(); //获取二维数组中相应的格子是什么状态,1空格,2定格,3虚格
			if(Forcast == 1)//如果是空格进行赋值判断操作
			{ 
			}
			if(Forcast == 2)//如果是定格跳过本次循环
			{ 
				One_Pocket_Basic = One_Pocket_Basic + 9; //一维数组底值紧跟XY坐标值变化
				continue;
			}
			if(Forcast == 3)//如果是虚格,则进入虚格函数
			{
				Forcast = Nine_Pocket_Xu_For();//1为虚格并成功更换了此格预测数,2为所有预测数已用尽,需要返回上一个虚格中更换相应的虚格数,
				if(Forcast == 1)
				{
					Pocket_Add(); //成功更换当前格子值后,应当将坐标换回原来的值
					goto Label;	
				}
				if(Forcast == 2)
				{
					Nine_Pocket[Y][X] = 0; //将当前的坐标值恢复成0,然后降值坐标返回上一个虚值坐标并重复本函数
					Pocket_Reduce(); //将坐标值降到上一个虚格中
					goto Label;
				}
			}
			//剩余是对空格子里的值赋值并判断,如果赋值成功并不重复,此次循环顺利结束,如果重复,则使用降值函数返回上一级虚值并使用goto标签
			SA = One_Pocket_Basic; //记录原始底值
			for(short i = 0  ; i < 9  ; i++)
			{
				if(One_Pocket[One_Pocket_Basic] == 0)
				{
				    One_Pocket_Basic = One_Pocket_Basic+1;
				}
				else
				{
					Nine_Pocket[Y][X] = One_Pocket[One_Pocket_Basic];
					Forcast = Return_For(X ,Y); //将是否重复的值存入变量中
					if(Forcast == 1)//返回1重复,否则不重复
					{
						Nine_Pocket[Y][X] = 0;
						One_Pocket_Basic = One_Pocket_Basic + 1; //如果重复则把一维数组的底值加1再次进行计算
					}
					else
					{
						One_Pocket_Basic = SA;//底值归位
						One_Pocket_Basic = One_Pocket_Basic + 9; //本次循环结束,一维数组底值紧跟坐标XY变化
						break;
					}
				}	
				if(i == 8)//如果进行第8次计算则说明这个格子是暂废格,降值处理
				{
					Nine_Pocket[Y][X] = 0;
					One_Pocket_Basic = SA;
					Pocket_Reduce();
					goto Label; 
				}
			}	
		}	
	}
}
void inget()
{
	for(short i = 0; i < 9 ; i++)
	{
		for(short j = 0 ; j < 9 ; j++ )
		{
			printf("\n请输入坐标为Y=%d,X=%d的数值:",i+1,j+1);
			scanf("%d",&Nine_Pocket[i][j]);
		}
	}
}
void Print_Two_Pocket()//将九宫格打印
{
    for(unsigned short i=0 ; i<9 ; i++)
	{
    	for(unsigned short j=0 ; j<9 ; j++)
		{
    		printf(" %d ",Two_Pocket[i][j]);
    		if ( j==2  ||  j == 5)
			{
    			printf(" ");
			}
    		if( i==2 && j == 8 )
			{
    			printf("\n");
			}
    		if( i == 5 && j == 8 )
			{
    			printf("\n");
			}
        	if( j == 8)
			{
				printf("\n");
			}
		}
	}
}
void main()
{
	char m;
	printf("程序准备完成,请确认是否开始(y输入表格,n结束)\a\n"); 
	scanf("%c",&m);
	while(m == 'y' || m == 'Y')
	{
		printf("请输入新的表格:\n");
		inget();//用户输入数独表格     
    	Print_Nine_Pocket();//将九宫格打印
		printf("\n请确认无误后进行下一步操作(y重新输入,n开始分析)\n");
		fflush(stdin);
		scanf("%c",&m);
	}
	Give_For();//给一维数组赋值,输入坐标参数X,Y,给一维数组返回预测值
	Nine_Pocket_Return_For();
	//Print_Two_Pocket();
	Nine_Pocket_Add_For();//用一维数组的预测值给九宫格赋值并判断
	printf("\n");
	Print_Nine_Pocket();//将九宫格打印		
}
数独法说明:用三个二维数组记录数独每个点的状态,SD(i, j)显示数值,也是真实数值(1到9)。ST(i, j)状态,1可由用户输入,2是题目给定的,不能改。SY(i, j)这符串,记录每个点中可能的值。 1、在进行自动计算时,只计算ST(i, j)为1的点,首先将所有状态为1的点的SY(i, j)值全部设为"123456789",SD(i, j)值全部设为0 2、逐点扫描,找到一个点,然后将该点所在的行、列、区域中已存在的SD(x, y)值从SY(i, j)中删除,因为数独规则是一个数值,在行、列、区域都不重复。 3、经第二步处理后,SY(i, j)为空,说明题目错误,SY(i, j)值为一位数字,就说明该点的值是唯一的,可以确定了。 4、剩余的SY(i, j)值最少也是二个数字的,或更多位数。随机从这些两位数的SY(i, j)中选取一个点。取其中的一位确定为该点的值后,重复第2步。如果错误遇错,则重复执行第4步。直到所有点都被确定。 注意:第2步是需要多次重复执行的,所有可用递归函数完成。如果执行结果出现错误(某数出现重复,或某点无值),需要对该过程所执行的所有操作进行回退。 第4步也是需要重复执行的。本和序用Goto跳转方式实现多次执行。 简单的数独,要么所有的点都具有独一值,第1步执行完成后,就已全部完成。或者具有多个解,随意猜测一个二位数的SY(i, j)的值都能成功。 难的数独,是可唯一确定的点很少,大部分点都有两种或多种可能的值,但最终正确答案只有一种或很少种解。 软件在自动计算过程中,具有很大的偶然性,对于骨灰级的数独题目在计算过程中,时间短的可能不到1秒就能完成,长的可能要几分钟,需要将各种可能性都测试一遍才有结果。 只要题目正确,多计算几次就能得到答案。 程序只处理有两种可能值的情况,对只存在三种可能值的情况未进一步处理,该情况非常极端了。 软件中包含网上下载的200个数独题目。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值