用c语言创建完全随机拉丁方阵
一、问题描述
给定一个N×N(2≤N≤9)阶的方阵,若方阵中每行和每列中数字1~N各出现一次且仅出现一次,则该方阵称作拉丁方阵,如图6-36所示。初始时,从一个拉丁方阵中随机地挖掉若干数字,要求玩家将挖掉的数字补充出来。若玩家将全部缺失的数字都补充出来则胜利。
图6-36一个4阶拉丁方阵
二、需求分析
拉丁方阵的阶数允许玩家自己设定。
已实现
被挖掉的数字应随机分布,尽量使得每行每列均有被挖掉的数字。
已实现
具有提示功能,可提示玩家当前在特定的方格中应填入哪个候选数字。
未实现
玩家选择开始新一局游戏后,立即向玩家显示待填充的拉丁方阵,并开始计时。游戏进行过程中不允许暂停。直至玩家选择结束本局游戏时,计时结束。
已实现
游戏结束时,若玩家填充出所有数字且这些数字全部正确,则显示“恭喜你,获胜了!”的字样,并询问玩家是否记录结果。如果玩家要求记录结果,则进一步要求玩家输入用户名。记录内容包括用户名和所用时间。游戏结束时,若玩家未填充出所有数字或所填数字中有不正确的,则显示“很遗憾,您输了!”的字样,同时,向玩家显示正确的结果。
已实现
一局游戏结束后,允许玩家选择进行新一局游戏或退出游戏。
已实现
提供对游戏规则和玩法的说明。
已实现
三、程序设计
1.建立拉丁方阵
通过随机算法随机出一个1~n的数。逐行逐列的填充。每随机出一个数分别和对应行对应列的其他数进行比较。如果重复则重新随机。
如果重复次数达到上限1000次,则说明之前的排列错误无法实现。则从头开始,再次建立拉丁方阵。
代码如下:
//创造对应结束的拉丁函数。
for(j=0;j<n;j++)
{
for(i=0;i<n;i++,count++)
{
if(1000==count)//如果重复1000次,人不能算出结果,则该方阵不能成立。初始化重新进行。
{
count=0;
i=0;
j=0;
break;
}
a=rand()%n+1;
for(hpd=0;hpd<=i;hpd++)//判断是否和同一行的其他数字相等。
{
if(a==lading[hpd][j])
yanzheng=1;
}
for(lpd=0;lpd<=j;lpd++)//判断是否和同一列的其他数字相等。
{
if(a==lading[i][lpd])
yanzheng=1;
}
if(yanzheng==1)
i--;
else
{
lading[i][j]=a;
}
yanzheng=0;
}
}
2.设置空缺的位置
用和创造拉丁方阵相似的方法。创造一串由一到n组成的不连续的数组成的数组。每行挖去对应序号的数字。这样就能确保每行每列都有空缺的数字。同时由于空缺位置过多,可能造成答案不唯一。无法判定正误。所以每行每列仅挖去一个。以保证程序的正确性。
就像这样分别挖去第一行第三个、第二行第四个、第三行第一个和第四行第二个。
代码如下:
for(i=0;i<=n;i++)
{
a=rand()%n+1;
for(hpd=0;hpd<=i;hpd++)
{
if(a==kongque[hpd])//如果和同一行的其他数字相同,则再次随机,直到不相同为止。
yanzheng=1;
}
if(yanzheng==1)
i--;
else
{
kongque[i]=a;
}
yanzheng=0;
if(kongque[n-1]!=0)
break;
}
3.设置正确答案。
根据空缺的顺序。让方阵中对应的数字组成一个正确答案的数组。
代码如下:
for(j=0;j<n;j++)
{
for(i=0;i<n;i++)
{
if((kongque[j])-1==i)
zhengque[j]=lading[j][i];
}
printf("%d",zhengque[j]);
}
printf("\n");
4.答案正误判断
让用户的答案组成一个数组和正确答案数组进行对比,如果相同,则为正确,若不同,则为错误。同时打印出正确答案和正确的方阵。游戏结束时,若玩家填充出所有数字且这些数字全部正确,则显示“恭喜你,获胜了!”的字样,并询问玩家是否记录结果。如果玩家要求记录结果,则进一步要求玩家输入用户名。记录内容包括用户名和所用时间。游戏结束时,若玩家未填充出所有数字或所填数字中有不正确的,则显示“很遗憾,您输了!”的字样,同时,向玩家显示正确的结果。一局游戏结束后,允许玩家选择进行新一局游戏或退出游戏。
代码如下:
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
printf("请从第一行开始逐行写下你的答案。请一位一位的输入。\n");//玩家开始输入答案。
for(i=0;i<n;i++)
{
scanf("%d",&answer[i]);
}
printf("你的答案是:");
for(i=0;i<n;i++)
{
printf("%d",answer[i]);
}
printf("\n正确答案是:");
for(hpd=0;hpd<n;hpd++)//判断是否和同一行的其他数字相等。
{
printf("%d",zhengque[hpd]);
}
printf("\n");
printf("完整拉丁方阵如下:\n");
for(j=0;j<n;j++)//打印出完整的方阵,供玩家参考。
{
for(i=0;i<n;i++)
{
printf("%d ",lading[j][i]);
}
printf("\n");
}
for(i=0;i<n;i++)
{
if(zhengque[i]!=answer[i])
yanzheng=1;
}
//if(1==yanzheng)
if(1==yanzheng)
printf("很遗憾,您输了!");
else
{
printf("恭喜你,获胜了!是否记录结果.若记录请输入1,若不记录请输入2,");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
scanf("%d",&a);
if(1==a)
{
printf("请输入用户名:");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
j=0;
while((ch = getchar())&&ch!='\n')
name[j++] = ch;
for(i=0;i<20;i++)
{
printf("%c",name[i]);
}
printf("恭喜您完成%d阶拉丁方阵用时:",n);
printf(" %u 秒。\n",clock()/CLOCKS_PER_SEC);
}
}
printf("您是否想继续开始新的游戏,如果是请输入y,如果不是请输入n。\n");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
ch=getchar();
if(ch=='y')
printf("您将开始下一轮游戏。");
if(ch=='n')
printf("祝您玩儿的愉快,再见!");
四、测试分析
1.测试能否输出个各阶拉丁方阵
4阶: 6阶:
8阶:
9阶:
所有阶的拉丁方阵都能正常随机作出。并且每行每列都有空缺的位置。
2.答案正误判断
错误输入:
显示你的答案,正确答案以及完整的方阵。提示输入是否再次进行游戏的信息。
正确输入:显示你的答案,正确答案以及完整的方阵。提示输入是否进行游戏的信息,同时提示输入用户名。如果输入用户名,显示用户名和完成时间。如果选择不记录,则不会记录。
3.重复进行游戏:无论是否完成游戏输入y则会重新进入游戏。n会退出程序。
重新进入游戏:
退出游戏:直接退出游戏并送出祝福语。
五、设计小结
在这次实验中我实现了大部分功。图形界面的学习不够深入。特定位置的提示功能无法实现。其余功能都已成功实现。这次的实验难点在于如何随机的创造。拉丁方阵,并实现题目的制作。实验过程中发现当阶数较低时,可以较为轻松的实现,但一旦阶数高于六阶。就会存在由于前面的错误排序,导致拉丁方阵无法实行。必须重新排列。例如,count字段是我设置的每一个数字的随机次数。当五阶及以下时。Count字段最大值为100就可以实现方阵的创造。但为六阶以上时,count字段最大值必须为1000才能实现。
同时,由于使用的二维数组进行保存拉丁方阵。使着得把它做成一个单独的类非常麻烦。我就简化的将它保存在了主函数中,实际上这是可以改进的。
六、附录
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int a=0;//这个字段是用于中间字段进行测试所用。
int i=0,j=0,n=9;//这三个用于循环时确定边界。
int hpd=0,lpd=0;//行判断和列判断字段,判断随机数是否与之前的重复。
int yanzheng=0;//验证是否重复字段为零时则不重复,为1则重复。
int count=0;//对每次计算进行计数如果重复次数过多,则说明该方阵不成立,需要重来。
int lading[9][9]={0};//建立数组
int kongque[9]={0};//用于存放空缺出来的顺序。
int zhengque[9]={0};//用于存放正确答案。
int answer[9]={0};//用于存放答题者给的答案。
char name[20]={0};//用于储存用户姓名。
char ch;//无特殊意义,用来实现需要字符的特定功能。
do{
printf("给定一个N×N(2≤N≤9)阶的方阵!阵中每行和每列中数字1~N各出现一次且仅出现一次。每行每列均有被挖掉的数字。您需要将被挖掉的数字逐行填充上去。\n");
srand((unsigned)time(NULL));
printf("请输入你需要的N\n");
scanf("%d",&n);
//判断是否和同一行的其他数字相等。
for(i=0;i<=n;i++)
{
a=rand()%n+1;
for(hpd=0;hpd<=i;hpd++)
{
if(a==kongque[hpd])//如果和同一行的其他数字相同,则再次随机,直到不相同为止。
yanzheng=1;
}
if(yanzheng==1)
i--;
else
{
kongque[i]=a;
}
yanzheng=0;
if(kongque[n-1]!=0)
break;
}
//创造对应结束的拉丁函数。
for(j=0;j<n;j++)
{
for(i=0;i<n;i++,count++)
{
if(1000==count)//如果重复1000次,人不能算出结果,则该方阵不能成立。初始化重新进行。
{
count=0;
i=0;
j=0;
break;
}
a=rand()%n+1;
for(hpd=0;hpd<=i;hpd++)//判断是否和同一行的其他数字相等。
{
if(a==lading[hpd][j])
yanzheng=1;
}
for(lpd=0;lpd<=j;lpd++)//判断是否和同一列的其他数字相等。
{
if(a==lading[i][lpd])
yanzheng=1;
}
if(yanzheng==1)
i--;
else
{
lading[i][j]=a;
}
yanzheng=0;
}
}
printf("空缺顺序是:");
for(hpd=0;hpd<n;hpd++)//判断是否和同一行的其他数字相等。
{
printf("%d",kongque[hpd]);
}
printf("\n");
yanzheng=0;//打印出空缺出来的方阵。
for(j=0;j<n;j++)
{
for(i=0;i<n;i++)
{
if(kongque[j]-1==i)
printf(" ");
else
printf("%d ",lading[j][i]);
}
printf("\n");
}
yanzheng=0;
for(j=0;j<n;j++)
{
for(i=0;i<n;i++)
{
if((kongque[j])-1==i)
zhengque[j]=lading[j][i];
}
}
printf("\n");
i=0;
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
printf("请从第一行开始逐行写下你的答案。请一位一位的输入。\n");//玩家开始输入答案。
for(i=0;i<n;i++)
{
scanf("%d",&answer[i]);
}
printf("你的答案是:");
for(i=0;i<n;i++)
{
printf("%d",answer[i]);
}
printf("\n正确答案是:");
for(hpd=0;hpd<n;hpd++)//判断是否和同一行的其他数字相等。
{
printf("%d",zhengque[hpd]);
}
printf("\n");
printf("完整拉丁方阵如下:\n");
for(j=0;j<n;j++)//打印出完整的方阵,供玩家参考。
{
for(i=0;i<n;i++)
{
printf("%d ",lading[j][i]);
}
printf("\n");
}
for(i=0;i<n;i++)
{
if(zhengque[i]!=answer[i])
yanzheng=1;
}
//if(1==yanzheng)
if(1==yanzheng)
printf("很遗憾,您输了!");
else
{
printf("恭喜你,获胜了!是否记录结果.若记录请输入1,若不记录请输入2,");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
scanf("%d",&a);
if(1==a)
{
printf("请输入用户名:");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
j=0;
while((ch = getchar())&&ch!='\n')
name[j++] = ch;
for(i=0;i<20;i++)
{
printf("%c",name[i]);
}
printf("恭喜您完成%d阶拉丁方阵用时:",n);
printf(" %u 秒。\n",clock()/CLOCKS_PER_SEC);
}
}
printf("您是否想继续开始新的游戏,如果是请输入y,如果不是请输入n。\n");
while((ch= getchar())!='\n'&& ch!=EOF);//用于清空缓冲区。
ch=getchar();
if(ch=='y')
printf("您将开始下一轮游戏。");
if(ch=='n')
printf("祝您玩儿的愉快,再见!");
}while(ch=='y');
return 0;
}