1A2B猜数小游戏,电脑猜,C代码编写

文章介绍了猜数字游戏的玩法和规则,提出了一种简单的反向穷举算法来解决电脑猜数字的问题。通过列举所有可能的答案并根据用户反馈的A和B信息逐步排除错误选项,最多9步内能找到正确答案。还提供了C语言的代码实现作为例子。
摘要由CSDN通过智能技术生成


前言

猜数字(又称 Bulls and Cows )是一种古老的的密码破译类益智类小游戏,起源于20世纪中期,一般由两个人或多人玩,也可以由一个人和电脑玩。查了网上很多关于这个游戏的帖子,大多都是计算机出题,人来猜。有非常多种策略可以实现七步之内猜出答案,但大部分跟算法相关,需要数据功底,这里介绍一个简单的反向穷举法,快速且易实现。

游戏规则

0-9 10个数字设为4位密码数字不重复。现在猜这个密码,每次电脑猜完会提示,如果数字且位置都对则显示为A,数字对位置错显示B,例如:密码为0123, 猜0134, 则提示为2A1B。可以9次以内保证可以猜对的策略。这次是电脑猜,人给提示。

人猜电脑给提示参考:1AB2链接


游戏基本步骤

首先需要说明游戏下规则

  • 人写一个四位数的密码,每一位数都可以从0到9选一个,但四位数字不能有重复的。如4415这个密码就是不行的。0可以放到开头,如0123这样也是可以的。这是答案,电脑猜题人要猜的。
  • 猜题电脑打印一个自己猜测的密码,格式同上。写完后展示给人观看。
  • 人根据猜题电脑的数字回答几A几B,其中A的个数表示猜题电脑猜测的数字位置正确的数的个数,B表示数字正确而位置不对的数的个数。例如出题人写下的密码是1564,猜题人写下的是7514,这时人就要输入给电脑2A1B。
  • 电脑根据出题人提供的提示继续猜一个密码,出题人后续也要给出相应提示。
  • 直到电脑猜中出题人写下的数字,游戏结束。统计一下电脑猜了多少次。
     

算法思路

电脑最擅长的穷举法一个一个来猜,列出所有答案,通过提示一一排除不需要的错误答案,剩下最后一个即为正确答案,答案总共有5040种。即是:第一次,固定猜 0123;然后,人必定要给出一个正确的提示:XAXB(X代表数字)①。然后,电脑从0124开始搜索,每次加1,并分别和0123相比较,得到XAXB,找到与0123比较答案一样为XAXB的不重复所有新数字串,这里面的 数字串即有正确答案;选择这里面得第一个数字串为下一个猜的数字,如果对,则结束,如果不对,则人又会给出第二个提示XAXB-1,此时,我们从第二步中的新数字串猜的数的下一个开始继续搜索,对比获取满足XAXB-1的不重复数字串,把他存入又一个新的数字串里;以次类推····  
          可见,越往后猜,候选答案需要满足的约束条件越多,即越有可能是标准答案。如:当猜到第7步还没猜中时,第8步猜测的候选答案必须同时满足前7次的猜测记录,因此,越往后,排除掉的越多,加速越快。当搜索到数字串里没有数字时,则说明人的提示有误。  
          到这里,大家是否明白这种算法的原理呢?总结:就是,电脑从0124开始,假设它是正确答案,那么它和0123相比得到的XAXB,必然与正确答案和0123相比得到的XAXB相同;一直对比下去就会得到正确答案,即我们所猜测的候选答案与之前猜测的数字串相比,得到的XAXB序列,必然与历史记录完全相同,否则便可排除。  
          此算法的优点:实现简单,时间空间复杂度都不高,而且最多不超过9步可完成游侠,。

C代码实现

#include"stdio.h"

// 全局变量ab
int ab = 0;

/**
** @brief: 电脑猜数输出
** @param: number:表示猜的数字,a:记录提示A的值,b:记录提示B的值
**/
void Guess(int *num, int* a, int* b)
{
    printf("I guess the number: %d%d%d%d ?\n", num[0],num[1],num[2],num[3]);
    printf("the number of A B:");
    scanf("%d %d", a, b);
}

/**
** @brief: 比较两个4位数的位置和数值情况
** @param: num1,num1:两个数组的指针,数组存了4个数字.ab:比较后AB的值
**/
int compare(int* num1, int* num2)
{
    ab = 0;
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            if(num1[i]==num2[j] && i==j)
            {
                ab += 10;
            }else if(num1[i]==num2[j] && i!=j)
            {
                ab += 1;
            }
        }
    }
    return ab;
}

/**
** @brief: 遍历与guessNumber比较得到AB相同的数,表示可能是正确数的新数组
** @param: arryCnt:被遍历的数组大小,guessNumber:猜数,
**        Allarray:数组,AB:AB信息
**/
void enumrate(int *arryCnt,int* guessNumber,int Allarray[][4],int* AB)
{
    int j, forCnt=0;
    int tem_AB, tem_ab=0;


    tem_AB = AB[0]*10 + AB[1];

    printf("-- arryCnt:%d \n",*arryCnt);
    printf("-- array[0]:%d%d%d%d \n",Allarray[0][0],Allarray[0][1],Allarray[0][2],Allarray[0][3]);
    printf("-- tem_AB:%d \n",tem_AB);

    j = *arryCnt;
    for(int i=1; i<j; i++){
        tem_ab = compare(guessNumber, Allarray[i]);

        if(tem_ab == tem_AB){

            Allarray[forCnt][0]=Allarray[i][0];
            Allarray[forCnt][1]=Allarray[i][1];
            Allarray[forCnt][2]=Allarray[i][2];
            Allarray[forCnt][3]=Allarray[i][3];

            // printf("%d --",i);
            printf("%d Allarray: %d%d%d%d \n", i,Allarray[forCnt][0],Allarray[forCnt][1],Allarray[forCnt][2],Allarray[forCnt][3]);
            forCnt++;
        }
    }

    printf("--forCnt:%d  \n",forCnt);
    (*arryCnt) = forCnt;
    if(*arryCnt == 0){
        printf("Great! great! great! fuck... \n");
    }

}



int main()
{
    int Allarray[5040][4];
    int guessNumber[4]={0,1,2,3};
    int AB[2]={0};
    int arryCnt = 0; // 数组的大小记录

    // 遍历所有的值,存起来
    for(int i=0;i<10;i++){
        for(int j=0;j<10;j++){
            if(i==j) continue;
            for(int k=0;k<10;k++){
                if(k==i || k==j) continue;
                for(int l=0;l<10;l++){
                    if(l==i||l==j||l==k){
                        continue;
                    }else{
                        Allarray[arryCnt][0]=i;
                        Allarray[arryCnt][1]=j;
                        Allarray[arryCnt][2]=k;
                        Allarray[arryCnt][3]=l;
                        // printf("array:%d%d%d%d \n",Allarray[arryCnt-1][0],Allarray[arryCnt-1][1],Allarray[arryCnt-1][2],Allarray[arryCnt-1][3]);
                        arryCnt +=1;
                    }
                }
            }
        }
    }

    printf("end of the array:%d%d%d%d \n",Allarray[arryCnt-1][0],Allarray[arryCnt-1][1],Allarray[arryCnt-1][2],Allarray[arryCnt-1][3]);
    printf("arryCnt:%d \n",arryCnt);

    // 处理数组和判断
    arryCnt = 5040;
    for(int i=0;i<10; i++){
        printf("\n");
        printf("RAND %d \n", i+1);

        Guess(Allarray[0],&AB[0],&AB[1]);
        enumrate(&arryCnt, guessNumber, Allarray, AB);
        guessNumber[0] = Allarray[0][0];
        guessNumber[1] = Allarray[0][1];
        guessNumber[2] = Allarray[0][2];
        guessNumber[3] = Allarray[0][3];

        if(AB[0]==4){
            printf("the number is %d%d%d%d \n",Allarray[0][0],Allarray[0][1],Allarray[0][2],Allarray[0][3]);
            break;
        }

    }

    printf("Game over!");

    return 0;
}



总结

这里还有其他的算法:https://www.zhihu.com/question/279643347
这些算法最多再7布就能找到答案,不过算法比较抽象,数学需要比较好,逻辑强,有空可以写一写。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值