用c语言创建完全随机拉丁方阵 数据结构课程设计题目

用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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值