按我之前产生数独的思路使用matlab产生数独和使用python产生数独游戏python数独游戏的思路,改写成了C++语言的数独游戏,并结合easyx库进行游戏界面输出和交互。(在我之前的博客里都有写,大家可以去看看,这里不多说了)
但是本人对C++的理解还不够深刻,没有用到对象和类的概念,完全是用函数的方式写的,弄得和c没什么区别,许多代码也不够简洁美观,导致虽然功能实现了,但一点也开心不起来,以后慢慢改进吧。
完整代码如下:
#include <iostream>
#include <graphics.h>
//#include <cstdlib>
//#include <ctime>
//#include <algorithm> // std::find
//#include <vector> // std::vector
//#include<cstdlib>
static int wrongtime = 0;
using namespace std;
int iniscreem() //初始化屏幕
{
initgraph(740, 580); // 创建绘图窗口,大小为 740x580 像素
setbkcolor(RGB(222, 213, 176));//设置背景颜色
cleardevice();
settextcolor(0);
settextstyle(70, 0, _T("宋体"));
outtextxy(90, 70, _T("欢迎来到数独游戏"));
settextstyle(40, 0, _T("宋体"));
outtextxy(230, 210, _T("请选择难度等级"));
settextstyle(30, 0, _T("宋体"));
setlinecolor(0);//设定线条颜色为黑
settextcolor(0);
rectangle(330, 300, 410, 340);//在对应位置画矩形
outtextxy(340, 305, _T("普通"));
setlinecolor(GREEN);//设定线条颜色为绿
settextcolor(GREEN);
rectangle(150, 300, 230, 340);
outtextxy(160, 305, _T("简单"));
setlinecolor(RED);//设定线条颜色为绿
settextcolor(RED);
rectangle(510, 300, 590, 340);
outtextxy(520, 305, _T("困难"));
int choice = 0; //代表选择的难度
int correct = 0; //代表鼠标是否点下
while (correct == 0)//correct为0表示鼠标一直没有点下
{
MOUSEMSG m;
if (MouseHit())//判断鼠标是否点下
{
m = GetMouseMsg();
switch (m.uMsg)
{
//检测鼠标左键是否按下
case WM_LBUTTONDOWN:
//如果鼠标点在预先设定的三个矩形内
if (m.x > 150 && m.x < 230 && m.y>300 && m.y < 340)
{
correct = 1;//correct为1表明鼠标点下
choice = 2;//choice为2表示选择简单模式,每行有两个空
}
if (m.x > 330 && m.x < 410 && m.y>300 && m.y < 340)
{
correct = 1;
choice = 4;//choice为4表示选择普通模式,每行有四个空
}
if (m.x > 510 && m.x < 590 && m.y>300 && m.y < 340)
{
correct = 1;
choice = 5;//choice为2表示选择困难模式,每行有五个空
}
break;
default:
break;
}
}
}
//system("pause"); //暂停
//closegraph(); // 关闭绘图窗口
return choice;//返回选择的难度,后面用来生成数独
}
int finish()//数独完成后的显示函数
{
cleardevice();//清屏
settextcolor(0);
settextstyle(70, 0, _T("宋体"));
outtextxy(280, 160, _T("恭喜!"));
outtextxy(140, 250, _T("你获得了胜利!"));
settextstyle(25, 0, _T("宋体"));
outtextxy(280, 350, _T("按任意键关闭"));
return 0;
}
int mysum(int* A[9])//判断数独是否填完
{
int* ptr;
int sum0 = 0;
int count = 0;
for (int i = 0; i < 9; i++)
{
ptr = A[i];//A是一个指针数组,存放数独
for (int j = 0; j < 9; j++)
{
sum0 = sum0 + *ptr;//对数独的所有元素求和
ptr++;
}
}
if (sum0 == 405)
{
count = 1;//如果等于405则填完了,检测方法比较粗糙,但大部分情况下是好用的
}
return count;//返回标志位
}
int* my_getzero(int* arr)//获取一维数组所有非零元素
{
int count = 0;
for (int m = 0; m < 9; m++)
{
if (arr[m] != 0)
{
count++;//先判断有多少个非零元素
}
}
int* p;
int* p1;
p = new int[count + 1];//生成动态数组
//注意这里还没释放内存,主程序里也还没释放,以后可能会有问题
p1 = p;
*p1 = count;
p1++;
for (int n = 0; n < 9; n++)
{
if (arr[n] != 0)
{
*p1 = arr[n];//当元素不为零时,赋值到数组中
p1++;
}
}
return p; //返回数组首地址
}
int** my_getzero_two(int** A) //获取二维数组(数独)中非零元素的坐标
{
int count = 0;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (A[i][j] == 0)
{
count++;//判断有多少个非零元素
}
}
}
static int* arr1 = new int[count + 1];//用来存放行坐标,第一个元素用来存放非零元素的个数,所以数组长度为count+1
static int* arr2 = new int[count + 1]; //用来存放列坐标,第一个元素为零,其余元素为坐标
static int* arr[2] = { arr1,arr2 };
//这些动态数组都没释放,未来要注意
*arr1 = count;//第一个元素为个数
*arr2 = 0;
int* Arr1 = arr1;
int* Arr2 = arr2;
Arr1++;//从第二个元素开始存放
Arr2++;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (A[i][j] == 0)
{
*Arr1 = i;//元素不为零时存放行列坐标
*Arr2 = j;
Arr1++;
Arr2++;
}
}
}
return arr;
}
int* my_union(int* x, int* y)//对两个一维数组的元素取并集,
{
//两个数组的构成都是第一个元素为存放非零元素的个数
//比如[4,2,3,4,5]代表一共4个元素,2,3,4,5,参与取交集运算
int a = *x;
int b = *y;
int count1 = 0;
int count2 = 0;
int p[9] = { 0 };
int* p1 = p;
for (int i = 1; i < a + 1; i++)//
{
for (int j = 1; j < b + 1; j++)
{
if (x[i] != y[j])//x数组的元素分别和y数组中的每一个元素相比较
{
count1++;//若不同则加1
}
}
if (count1 == b)//若没有相同的元素
{
y[0]++;//将不同的元素跟在y数组后面,所以个数会加1
count2++;//用来记录用多少个不同的元素
*p1 = i;//记录不同元素在x数组中的位置
p1++;
}
count1 = 0;//标志位清零
}
int* z = new int[1 + b + count2];//构造相应长度的动态数组
//注意这里动态数组没有释放内存,可能会出现问题
for (int i = 0; i < b + 1; i++)
{
z[i] = y[i];//首先将y数组一一对应粘贴
}
for (int j = 0; j < count2; j++)
{
z[b + j + 1] = x[p[j]];//然后根据坐标将x数组中的元素进行赋值
}
return z;
}
int* my_difference(int* x)//获取一个一维数组与[1,9]等差数列的差集
{
int a = *x;//第一个元素代表x有多少个元素参与比较
int count1 = 0;
int count2 = 0;//记录差集中的元素个数
int p[9] = { 0 };
int* p1 = p;
for (int i = 1; i < 10; i++)//1到9分别进行比较
{
for (int j = 1; j < a + 1; j++)
{
if (i != x[j])//i与x中元素不同则加1
{
count1++;
}
}
if (count1 == a)//i和x中任意一个元素都不同
{
count2++;//找到一个差集元素
*p1 = i;//i就是差集元素,保留下来
p1++;
}
count1 = 0;
}
int* z = new int[1 + count2];
//注意这里动态数组没有释放内存,可能会出现问题
*z = count2;//z的第一个元素代表差集元素个数
for (int i = 1; i < count2 + 1; i++)
{
z[i] = p[i - 1];//从第二个元素开始存放差集元素
}
return z;
}
int* my_random(int a)//产生一个有9个元素的一维数组,元素是1到9随机排列
{
int num[9] = { 0 };
int i = 0;
int seed = a;//a代表随机种子
while (num[8] == 0)
{
srand(50 * (seed * seed * seed + 100 + seed * seed * 5 - 20));//这个表达式是随便写的
//这里要这么写的原因在我另一篇博客里,产生随机数组
int a = (rand() % 9) + 1;//产生一个1到9之间的随机数
int start = 0;
int end = 8;
int* result = find(num + start, num + end, a);//判断数组中是否已经有了这个数字
if (result == num + end)//如果没有就把这个数字加入到数组中
{
num[i] = a;
i++;
}
seed++;//改变随机种子
}
//直到数组最后一位不为0表示都填好了,循环结束
/*for (int i1 = 0; i1 < 9; i1++)
{
cout << num[i1];
}
cout << endl;*/ //测试时候使用看结果
return num;
}
int** answer(int a)//产生数独矩阵,a用来传递随机种子
{
int sum0 = 0;
int N2 = 0;
int seed = a;
static int A1[9] = { 0 };
static int A2[9] = { 0 };
static int A3[9] = { 0 };
static int A4[9] = { 0 };
static int A5[9] = { 0 };
static int A6[9] = { 0 };
static int A7[9] = { 0 };
static int A8[9] = { 0 };
static int A9[9] = { 0 };
/*int A1[9] = { 0 };
int A2[9] = { 0 };
int A3[9] = { 0 };
int A4[9] = { 0 };
int A5[9] = { 0 };
int A6[9] = { 0 };
int A7[9] = { 0 };
int A8[9] = { 0 };
int A9[9] = { 0 };*/
static int* A[9] = { A1,A2,A3,A4,A5,A6,A7,A8,A9 };//创造一个全零的二维矩阵
while (mysum(A) != 1)//用mysum函数判断是否填完
{
int N = 1;//判断状态位
for (int i = 0; i < 9; i++)//每次填数失败以后就把整个数独全部清零
{
for (int j = 0; j < 9; j++)
{
A[i][j] = 0;
}
}
int num[9] = { 0 };
int i = 0;
while (num[8] == 0)//产生一个随机数组,my_random是后来测试时候写的,这里就没改,但原理是一样的
{
//srand((int)time(0)); // 产生随机种子 把0换成NULL也行
srand(50 * (seed * seed * seed + 100 + seed * seed * 5 - 20)); // 产生随机种子
int a = (rand() % 9) + 1;
int start = 0;
int end = 8;
int* result = find(num + start, num + end, a);
if (result == num + end)
{
num[i] = a;
i++;
}
seed++;
}
for (int i1 = 0; i1 < 9; i1++)
{
A1[i1] = num[i1];
//cout << num[i1];
} //随机生成1到9数列作为数独第一行
//cout << endl;
for (int i2 = 1; i2 < 9; i2++) //开始填数
{
for (int j = 0; j < 9; j++)
{
int* x = A[i2];
int x_int[9] = { 0 };
for (int i3 = 0; i3 < 9; i3++)
{
x_int[i3] = *x;
x++;
} //取出所在行
int* y;
int y_int[9] = { 0 };
for (int i4 = 0; i4 < 9; i4++)
{
y = A[i4];
y_int[i4] = *(y + j);
} //取出所在列
int z[9][3];
if (0 <= j && j < 3)
{
for (int m = 0; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z[m][n] = A[m][n];
}
}
}
else if (3 <= j && j < 6)
{
for (int m = 0; m < 9; m++)
{
for (int n = 3; n < 6; n++)
{
z[m][n - 3] = A[m][n];
}
}
}
else if (6 <= j && j < 9)
{
for (int m = 0; m < 9; m++)
{
for (int n = 6; n < 9; n++)
{
z[m][n - 6] = A[m][n];
}
}
}
int z2[3][3];
if (0 <= i2 && i2 < 3)
{
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m][n] = z[m][n];
}
}
}
else if (3 <= i2 && i2 < 6)
{
for (int m = 3; m < 6; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 3][n] = z[m][n];
}
}
}
else if (6 <= i2 && i2 < 9)
{
for (int m = 6; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 6][n] = z[m][n];
}
}
}
int z_int[9];
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z_int[m * 3 + n] = z2[m][n];
}
} //取出所在宫
int* X = my_getzero(x_int);
int* Y = my_getzero(y_int);
int* Z = my_getzero(z_int); //取出行,列,宫的所有非零值
int* t = my_union(X, Y);
t = my_union(t, Z); //所有非零值取并集 ,注意t所指的第一个元素代表非零元素的个数
int* n = my_difference(t); //并集与1到9取差集,判断有些数可以作为被选数
if (*n == 0)
{
N = 2;//*n为0说明没有备选数了,这次填数就失败了,令N = 2
N2++;
//cout << N2 << endl; //记录循环了多少次,测试时候用的
break;//这次填数循环就退出了
}
int s = (rand() % *n) + 1;//如果没退出循环,则说明有数可填
A[i2][j] = n[s];//随机选择第s位的元素进行赋值
}
if (N == 2)
{
break;//退出填数循环
}
}
seed = seed * seed;//修改随机种子
}
//测试时候输出看结果的
/*测试随机生成数组
int num[9] = {0};
int i = 0;
while (num[8] == 0)
{
srand((int)time(0)); // 产生随机种子 把0换成NULL也行
int a = (rand() % 9) + 1; //产生随机数
int start = 0;
int end = 8;
int * result = find(num + start, num + end, a);
if (result == num + end)
{
num[i] = a;
i++;
}
}
for (int i1 = 0; i1 < 9; i1++)
{
A1[i1] = num[i1];
}
sum0 = mysum(A);
cout << sum0 << endl;*/
return A;//返回数独矩阵
}
int** chansheng(int** A, int grade)//随机挖空,产生题面。A是数独矩阵,grade就是iniscreem函数中的choice
{
int k = (int)time(0);
int* a;
for (int i = 0; i < 9; i++)
{
a = my_random(k + i * i * i + 100);//产生随机数组
for (int j = 0; j < grade; j++)
{
A[i][a[j] - 1] = 0; //随机让几个空为0
//产生的a数组是1到9的随机数组,进行赋值下标是0到8,所以要减1
//A[i][a[j]-1] = 1; //测试用
}
}
return A;
}
int test_num(int** A, int x_pos, int y_pos)//检测填数是否正确,x_pos,y_pos表示填数的行列坐标,输出数独的时候使用
{
int right_wrong = 1; //1代表填数正确,2代表填数错误
int num = 0;
int* x = A[x_pos];
int x_int[9] = { 0 };
for (int i3 = 0; i3 < 9; i3++)
{
x_int[i3] = *x;
x++;
} //取出所在行
int* y;
int y_int[9] = { 0 };
for (int i4 = 0; i4 < 9; i4++)
{
y = A[i4];
y_int[i4] = *(y + y_pos);
} //取出所在列
int z[9][3];
if (0 <= y_pos && y_pos < 3)
{
for (int m = 0; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z[m][n] = A[m][n];
}
}
}
else if (3 <= y_pos && y_pos < 6)
{
for (int m = 0; m < 9; m++)
{
for (int n = 3; n < 6; n++)
{
z[m][n - 3] = A[m][n];
}
}
}
else if (6 <= y_pos && y_pos < 9)
{
for (int m = 0; m < 9; m++)
{
for (int n = 6; n < 9; n++)
{
z[m][n - 6] = A[m][n];
}
}
}
int z2[3][3];
if (0 <= x_pos && x_pos < 3)
{
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m][n] = z[m][n];
}
}
}
else if (3 <= x_pos && x_pos < 6)
{
for (int m = 3; m < 6; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 3][n] = z[m][n];
}
}
}
else if (6 <= x_pos && x_pos < 9)
{
for (int m = 6; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 6][n] = z[m][n];
}
}
}
int z_int[9];
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z_int[m * 3 + n] = z2[m][n];
}
} //取出所在宫
for (int k = 0; k < 9; k++)//判断A[x_pos][y_pos]在行数组中出现了几次
{
if (A[x_pos][y_pos] == x_int[k])
{
num++;
}
if (num > 1)//出现超过1次说明填错了
{
right_wrong = 2;//让填错的标志位为2
break;
}
}
num = 0;
if (right_wrong == 1)
{
for (int k = 0; k < 9; k++)
{
if (A[x_pos][y_pos] == y_int[k])//同理判断列数组中出现几次
{
num++;
}
if (num > 1)
{
right_wrong = 2;
break;
}
}
}
num = 0;
if (right_wrong == 1)
{
for (int k = 0; k < 9; k++)
{
if (A[x_pos][y_pos] == z_int[k])//同理判断宫数组中出现几次
{
num++;
}
if (num > 1)
{
right_wrong = 2;
break;
}
}
}
return right_wrong;//返回标志位
}
void test_num_second(int** A, int x_pos, int y_pos, int num2)//检测填数是否正确,记录错误次数时使用
{
//这个函数绝大部分逻辑和上一个函数一模一样,这也是我非常难受的地方,没有想到更好地解决办法
//两个函数的区别在于使用时数独矩阵的状态不同,
//test_num使用时是已经将错误数据填进去了,test_num_second使用时错误数据还没填进去
int num = 0;
int* x = A[x_pos];
int x_int[9] = { 0 };
for (int i3 = 0; i3 < 9; i3++)
{
x_int[i3] = *x;
x++;
} //取出所在行
int* y;
int y_int[9] = { 0 };
for (int i4 = 0; i4 < 9; i4++)
{
y = A[i4];
y_int[i4] = *(y + y_pos);
} //取出所在列
int z[9][3];
if (0 <= y_pos && y_pos < 3)
{
for (int m = 0; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z[m][n] = A[m][n];
}
}
}
else if (3 <= y_pos && y_pos < 6)
{
for (int m = 0; m < 9; m++)
{
for (int n = 3; n < 6; n++)
{
z[m][n - 3] = A[m][n];
}
}
}
else if (6 <= y_pos && y_pos < 9)
{
for (int m = 0; m < 9; m++)
{
for (int n = 6; n < 9; n++)
{
z[m][n - 6] = A[m][n];
}
}
}
int z2[3][3];
if (0 <= x_pos && x_pos < 3)
{
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m][n] = z[m][n];
}
}
}
else if (3 <= x_pos && x_pos < 6)
{
for (int m = 3; m < 6; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 3][n] = z[m][n];
}
}
}
else if (6 <= x_pos && x_pos < 9)
{
for (int m = 6; m < 9; m++)
{
for (int n = 0; n < 3; n++)
{
z2[m - 6][n] = z[m][n];
}
}
}
int z_int[9];
for (int m = 0; m < 3; m++)
{
for (int n = 0; n < 3; n++)
{
z_int[m * 3 + n] = z2[m][n];
}
} //取出所在宫
int* X = my_getzero(x_int);
int* Y = my_getzero(y_int);
int* Z = my_getzero(z_int); //取出行,列,宫的所有非零值
int* t = my_union(X, Y);
t = my_union(t, Z); //所有非零值取并集 ,注意t所指的第一个元素代表非零元素的个数
//得到所有已经填过的数字
for (int k = 1; k < 10; k++)
{
if (t[k] == num2)//num2是准备要填进去的数
{
wrongtime++;//如果数组中出现了这个数字,说明就填错了,错误次数就加一
break;
}
}
}
void show1(int** A)
{
//initgraph(740, 580); // 创建绘图窗口,大小为 740x580 像素
//setbkcolor(RGB(222,213,176));
//cleardevice();
setlinecolor(0);//设定线条颜色为黑
int a = 9; //方格个数
int w = 50; //方格宽度
for (int i = 0; i < a + 1; ++i)//画出数独9*9的方格,1,4,6,8,10条线加粗
{
if (i == 0 || i == 3 || i == 6 || i == 9)
{
setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 5);
line(w, w + w * i, w + w * a, w + w * i); //画横线
line(w + w * i, w, w + w * i, w + w * a); //画竖线
}
else
{
setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 2);
line(w, w + w * i, w + w * a, w + w * i); //画横线
line(w + w * i, w, w + w * i, w + w * a); //画竖线
}
}
settextcolor(0);
settextstyle(16, 0, _T("宋体"));
//outtextxy(11 * w, 3 * w+100, _T("失败次数:"));
for (int k = 0; k < a; k++)
{
for (int j = 0; j < a; j++)
{
if (A[j][k] != 0)//当数据不为0时才输出,数据为0不输出,相当于空白
{
wchar_t num[20];
_itow_s(A[j][k], num, 10);//将数独中的整型数据转化成字符型
//这里这么写的原因在我另一篇博客里,使用outtextxy输出整型
//sprintf_s(num, "%d",A[k][j]);
//char c = *itoa(A[j][k], str, 10);
outtextxy(w + w * k + 21, w + w * j + 17, num);//输出在屏幕上
}
}
}
//system("pause"); //暂停
//closegraph(); // 关闭绘图窗口
}
void show2(int** A, int** arr)//输出数独时判断数据是否正确,正确显示绿色,错误为红色
{
int right_wrong = 0;
setlinecolor(0);//设定线条颜色为黑
int a = 9; //方格个数
int w = 50; //方格宽度
for (int i = 0; i < a + 1; ++i)
{
if (i == 0 || i == 3 || i == 6 || i == 9)
{
setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 5);
line(w, w + w * i, w + w * a, w + w * i); //画横线
line(w + w * i, w, w + w * i, w + w * a); //画竖线
}
else
{
setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 2);
line(w, w + w * i, w + w * a, w + w * i); //画横线
line(w + w * i, w, w + w * i, w + w * a); //画竖线
}
}
settextcolor(0);
settextstyle(16, 0, _T("宋体"));
//outtextxy(11 * w, 3 * w+100, _T("失败次数:"));
for (int k = 0; k < a; k++)
{
for (int j = 0; j < a; j++)
{
if (A[j][k] != 0)//当数据不为0时,判断是否是可以修改的数据
{
wchar_t num[20];
_itow_s(A[j][k], num, 10);
//sprintf_s(num, "%d",A[k][j]);
//char c = *itoa(A[j][k], str, 10);
for (int i = 1; i < arr[0][0] + 1; i++)//arr数组中存放生成题面中为0的位置的行列坐标,也就是可以由玩家填数的位置
{
if (j == arr[0][i] && k == arr[1][i])//当行列坐标都正确
{
right_wrong = test_num(A, j, k);//检测这个数据是否正确
if (right_wrong == 1)
{
settextcolor(GREEN);//正确则为绿色
}
else
{
settextcolor(RED);//错误则为红色
}
}
}
outtextxy(w + w * k + 21, w + w * j + 17, num);//输出数据
}
settextcolor(0);//题面固定数据用黑色输出
}
}
//system("pause"); //暂停
//closegraph(); // 关闭绘图窗口
}
void show3()//显示选择数据区域(就是界面右上角的区域)和错误次数
{
int A[3][3] = { 1,2,3,4,5,6,7,8,9 };
setlinecolor(0);//设定线条颜色为黑
int a = 3; //方格个数
int w = 35; //方格宽度
for (int i = 0; i < a + 1; ++i)
{
setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 2);
line(w + 530, w + w * i + 30, w + w * a + 530, w + w * i + 30); //画横线
line(w + w * i + 530, w + 30, w + w * i + 530, w + w * a + 30); //画竖线
}
settextcolor(0);
settextstyle(26, 0, _T("宋体"));
outtextxy(11 * w + 150, 3 * w + 150, _T("错误次数:"));
wchar_t num3[20];
_itow_s(wrongtime, num3, 10); //失败次数
//sprintf_s(num, "%d",A[k][j]);
//char c = *itoa(A[j][k], str, 10);
settextstyle(26, 0, _T("宋体"));
outtextxy(665, 255, num3);
for (int k = 0; k < a; k++)
{
for (int j = 0; j < a; j++)
{
wchar_t num[20];
_itow_s(A[j][k], num, 10);
//sprintf_s(num, "%d",A[k][j]);
//char c = *itoa(A[j][k], str, 10);
settextstyle(16, 0, _T("宋体"));
outtextxy(w + w * k + 545, w + w * j + 38, num);
}
}
//system("pause"); //暂停
//closegraph(); // 关闭绘图窗口
}
int** answer_test()//测试时候用的函数,真正主函数里没用到
{
static int A1[9] = { 0 };
cout << A1 << endl;
static int A2[9] = { 0 };
static int A3[9] = { 0 };
static int A4[9] = { 0 };
static int A5[9] = { 0 };
static int A6[9] = { 0 };
static int A7[9] = { 0 };
static int A8[9] = { 0 };
static int A9[9] = { 0 };
/*int A1[9] = { 0 };
int A2[9] = { 0 };
int A3[9] = { 0 };
int A4[9] = { 0 };
int A5[9] = { 0 };
int A6[9] = { 0 };
int A7[9] = { 0 };
int A8[9] = { 0 };
int A9[9] = { 0 };*/
static int* A[9] = { A1,A2,A3,A4,A5,A6,A7,A8,A9 };
return A;
}
int** amend(int** A, int correct, int x, int y)//同样,测试用的,主函数里没用到
{
if (correct == 1)
{
A[x][y] = 10;
}
return A;
}
int* test_mouse(int** arr) //检测鼠标点击的格子是否可以修改,可以的话correct为1
{
int num = 0;
int correct = 0;
int x_pos = 0;
int y_pos = 0;
MOUSEMSG m;
if (MouseHit())//检测鼠标是否按下
{
m = GetMouseMsg();
switch (m.uMsg)
{
//检测鼠标左键是否按下
case WM_LBUTTONDOWN:
//如果鼠标点击在数独9*9的区域内
if (m.x > 50 && m.x < 500 && m.y>50 && m.y < 500)
{
x_pos = (m.x - 50) / 50;//x_pos表示点击在在哪一行,可能值为0到8
y_pos = (m.y - 50) / 50;//y_pos表示点击在在哪一列,可能值为0到8
for (int i = 1; i < arr[0][0] + 1; i++)
{
if (y_pos == arr[0][i] && x_pos == arr[1][i])//同样arr内存放可修改的位置坐标
{
correct = 1;//如果可修改,correct为1
break;
}
}
}
break;
default:
break;
}
}
int a[3] = { correct,x_pos,y_pos };//返回数组a,第一个元素表示是否可以修改,二三元素表示点击位置的行列值
return a;
}
int* test_mouse_second(int** daan, int j, int k) //第二次检测鼠标的位置,判断要填入的数字是几
{
int correct = 2; //点击区域的标志位
int x_pos = 0;
int y_pos = 0;
int A[3][3] = { 1,2,3,4,5,6,7,8,9 };
int num = 0;
MOUSEMSG m;
if (MouseHit())
{
m = GetMouseMsg();
switch (m.uMsg)
{
//检测鼠标左键是否按下
case WM_LBUTTONDOWN:
if (m.x > 565 && m.x < 670 && m.y>65 && m.y < 170)
{
correct = 1;//代表点在了选择数字区
x_pos = (m.x - 565) / 35;
y_pos = (m.y - 65) / 35;
num = A[y_pos][x_pos];
test_num_second(daan, j, k, num);//检测填入的数据是否正确,错误的话wrongtime加1
}
else
{
correct = 0;//代表点在了其他地方
}
break;
default:
break;
}
}
int a[2] = { correct,num };
return a;
}
int* test_mouse_test()//测试用的函数,现在不用了
{
int correct = 0;
int x_pos = 20;
int y_pos = 10;
MOUSEMSG m;
if (MouseHit())
{
m = GetMouseMsg();
switch (m.uMsg)
{
//检测鼠标左键是否按下
case WM_LBUTTONDOWN:
if (m.x > 50 && m.x < 500 && m.y>50 && m.y < 500)
{
x_pos = (m.x - 50) / 50;
y_pos = (m.y - 50) / 50;
correct = 1;
}
break;
default:
break;
}
}
int a[3] = { correct,x_pos,y_pos };
return a;
}
int main()
{
int choice = iniscreem();//初始化屏幕,选择难度
int right_wrong = 1;
cleardevice();//清空屏幕
int Num = 0;//用来接收准备填入的数据
int correct = 0;//第一次鼠标是否点击的标志位
int correct2 = 2;//第二次鼠标是否点击的标志位
int n = 0;
int m = 0;//用来接收行列坐标
int k = (int)time(0);//获得时间,准备初始化随机种子
int** daanptr;//用来接收产生的数独数组
int* pos;//用来接收第一次鼠标点击得到的数组
int* pos2;//用来接收第二次鼠标点击得到的数组
daanptr = answer(k);//产生答案
daanptr = chansheng(daanptr, choice);//产生题面
//daanptr = chansheng(daanptr, 1); //测试时候用这一行
int** nunposptr = my_getzero_two(daanptr);//获取0元素的位置,也就是以后可由玩家填数的位置
show1(daanptr);//展示数独
show3();
while (mysum(daanptr) != 1)//游戏循环
//但此时用这个判断游戏是否结束会有问题,有可能几个数据都是错的但恰好数独和是405,游戏也会结束
{
pos = test_mouse(nunposptr);//检测鼠标是否点下
correct = *pos;//获取是否点下的标志位
if (*pos == 1)//如果点下,等待获取下一次点击位置
{
n = pos[1];
m = pos[2];
while (correct2 != 1 && correct2 != 0)//循环等待第二次是否点下
{
pos2 = test_mouse_second(daanptr, m, n);
//daanptr[m][n] = i;
correct2 = *pos2;//获取是否点下的标志位
Num = pos2[1];//获取准备填的数字
//i++;
//show2(daanptr);
}
if (correct2 == 1)//如果点在了选数区
{
daanptr[m][n] = Num;//将点击的数据填入数独矩阵
correct2 = 2;//修改标志位使循环退出
}
else//corect不为1说明点在了其他地方
{
correct2 = 2;//修改标志位使循环退出
}
}
show2(daanptr, nunposptr);//展示修改后的数独
show3();//展示失败次数
}
finish();//展示结束界面,游戏结束
system("pause"); //暂停
closegraph(); // 关闭绘图窗口
//以下代码都是测试上面函数是否正确时候使用的
//测试test_num函数
/*
int A1[9] = { 9,8,6,7,2,8,3,5,4 };
int A2[9] = { 3,5,8,0,9,6,1,2,7 };
int A3[9] = { 2,0,4,5,1,3,8,6,9 };
int A4[9] = { 7,6,3,2,5,1,9,4,0 };
int A5[9] = { 4,2,0,9,8,7,6,1,3 };
int A6[9] = { 1,8,9,6,0,4,2,7,5 };
int A7[9] = { 5,3,2,1,7,0,4,8,6,};
int A8[9] = { 8,4,7,3,6,2,5,0,1 };
int A9[9] = { 6,9,1,8,4,5,7,3,0 };
int* A[9] = { A1,A2,A3,A4,A5,A6,A7,A8,A9 };
int r = test_num(A,0,1);
cout << r << endl;
cout << A[0][1] << endl;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (*(A[i] + j) != 0)
{
cout << *(A[i] + j) << " ";
}
else
{
cout << ' ' << " ";
}
}
cout << endl;
}
*/
//测试test_mouse_test函数
/*
int correct = 0;
int* p1;
int x = 0;
int y = 0;
int A1[9] = { 1,2,3,4,5,6,7,8,0 };
int A2[9] = { 2,3,4,5,6,7,8,9,1 };
int A3[9] = { 3,4,5,6,7,0,9,1,2 };
int A4[9] = { 4,5,6,7,8,9,1,2,3 };
int A5[9] = { 5,6,0,8,9,1,2,3,4 };
int A6[9] = { 0,7,8,9,1,2,3,4,5 };
int A7[9] = { 7,8,9,1,2,3,4,5,6 };
int A8[9] = { 8,0,1,2,3,4,0,6,7 };
int A9[9] = { 9,1,2,3,4,5,6,7,0 };
int* A[9] = { A1,A2,A3,A4,A5,A6,A7,A8,A9 };
initgraph(740, 580); // 创建绘图窗口,大小为 740x580 像素
setbkcolor(RGB(222, 213, 176));
cleardevice();
setlinecolor(0);//设定线条颜色为黑
int a = 9; //方格个数
int w = 50; //方格宽度
for (int i = 0; i < a + 1; ++i)
{
line(w, w + w * i, w + w * a, w + w * i); //画横线
line(w + w * i, w, w + w * i, w + w * a); //画竖线
}
settextcolor(0);
while (true)
{
p1 = test_mouse_test(); //检测鼠标是否按下,并返回鼠标坐标
correct = *p1;
if (correct == 1)
{
wchar_t num[20];
wchar_t num2[20];
int n = p1[1];
int m = p1[2];
_itow_s(n, num, 10);
_itow_s(m, num2, 10);
outtextxy(200, 300, num);
outtextxy(300, 300, num2);
}
//Sleep(1000);
}
system("pause"); //暂停
closegraph(); // 关闭绘图窗口
*/
//测试my_getnonzero函数,但这个函数后来改成my_getzero_two函数了
/*
int k = (int)time(0);
int** daanptr;
daanptr = answer(k);
daanptr = chansheng(daanptr, 7);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
cout << *(daanptr[i] + j) << " ";
}
cout << endl;
}
int** posptr = my_getnonzero(daanptr);
for (int i = 1; i < posptr[0][0]+1; i++)
{
cout << posptr[0][i] << ' ' << posptr[1][i];
cout << endl;
}
cout << posptr[0][0] << endl;
system("pause");
*/
//测试运行主函数
/*
int k = (int)time(0);
int ** daanptr;
daanptr = answer(k);
daanptr = chansheng(daanptr, 1);
for(int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (*(daanptr[i] + j) != 0)
{
cout << *(daanptr[i] + j) << " ";
}
else
{
cout << ' ' << " ";
}
}
cout << endl;
}*/
//测试二级指针输出
/*
for (int i = 0; i < 9; i++)
{
cout << daanptr << endl;
daanptr++;
}
*/
//测试my_getzero函数
/*
int A[9] = { 1,2,0,4,0,6,8,0,9 };
int * p;
p = my_getzero(A);
int a = *p;
p++;
for (int i = 0; i < a; i++)
{
cout << *p << endl;
p++;
}*/
//测试my_union函数
/*
int A[] = { 6,1,2,3,7,8,9};
int B[] = { 4,5,2,3,6 };
int C[] = { 3,4,5,6 };
int* p1 = A;
int* p2 = B;
int* p3 = C;
int* t = my_union(p1, p2);
t = my_union(t, p3);
int a = *t;
for (int i = 0; i < a + 1; i++)
{
cout << t[i] << endl;
}*/
//测试my_difference函数
/*
int A[6] = { 5,1,2,3,7,9 };
int* p = A;
int* p1 = my_difference(p);
int a = *p1;
for (int i = 1; i < a + 1; i++)
{
cout << p1[i] << endl;
}
*/
//测试my_random函数
/*
for (int i = 0; i < 9; i++)
{
my_random(50*(i*i*i+100+i*i*5-20));
}
*/
//测试chansheng函数
/*static int A1[9] = { 0 };
static int A2[9] = { 0 };
static int A3[9] = { 0 };
static int A4[9] = { 0 };
static int A5[9] = { 0 };
static int A6[9] = { 0 };
static int A7[9] = { 0 };
static int A8[9] = { 0 };
static int A9[9] = { 0 };
static int* A[9] = { A1,A2,A3,A4,A5,A6,A7,A8,A9 };
int k = (int)time(0);
int** daanptr = A;
daanptr = chansheng(daanptr, 2);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
cout << *(daanptr[i] + j) << " ";
}
cout << endl;
}*/
return 0;
}
只要把代码复制到cpp文件中就应该可以跑了,运行效果如图
初始界面
产生数独界面
简单模式
困难模式
填数时正确和错的情况
结束界面展示
最后,在编译的时候把这里改成release然后编译,debug编译正确,运行会报错,我也不知道为什么