解猜数字问题

 解猜数字问题

/************************************************************************
文件名:    解猜数字问题
文件描述:  解猜数字问题
创建人:    陈泽丹,   2008年11月3日
版本号:    4.5
************************************************************************/
/*-----------------------------------------------------------------------
问题描述:
随机给出一个数位上的数字不重复的四位数,计算机每次给你提示这样的格
式的语句:xAyB (0<=x<=4, 0<=y<=4)
其中A表示数字正确位置也正确的,B表示数字正确位置不正确。
例如说: 1A2B  (表示1个数字正确位置也正确的,另有两个数字正确位置不正确)
现要求编程尽可能在8次机会内猜出这个四位数。
解题思路:
把它分两步进行,1,先求这个四位数。2,再求这个四位数各位的
位置。这两步又是互相独立的子问题,故可以同时进行解决的.
第一步:
如果猜测的四位数中的某一位就是答案的数字之一,那么只要它出现,提示就会相应
的加1,故可构造一个这样一个表格, 算法如下:其中首纵列为可选数字,首横列为各猜测的序号
(数字,序号) == 1 表示该数字在这一次出现了,
(数字,序号) == 0 表示该数字在这一次没有出现。
(例如答案是0,1,2,9,则有表如下
     第一次   第二次   第三次 ..... 第八次
0     0         1       0     .....  1
1:    0         0       0     .....  1
2:    1         1       1     .....  1
.
.
.
9     0         1       0     .....  0

猜测结果: 1     3       1     ...... 3
其中:
第一次:  0 + 0 + 1 + 0 = 1
第二次:  1 + 0 + 1 + 1 = 3
第三次:  0 + 0 + 1 + 0 = 3
...
第八次:  1 + 1 + 1 + 0 = 3
也就是说,如果目标数字是“答案数字的话”,那么其累加和会等于每一次的猜测结果。
更进一步优化的话,其实不必每次每格去验算,把每一整行看成是一个十进制数,把组合中
的四个猜测的数一性加在一起看是否为猜测结果那行的“十进制数”即可,如果不是则排除
该组合。
第二步:可以把位置猜测与已经猜过的位置核对一下, 相同位置的放法不用再猜,
相同位置数目多于当时的A提示数目的也不再猜。
------------------------------------------------------------------------*/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
程序使用说明:
第一次先对游戏输入欲猜的那四个数.再把游戏第一次的提示结果(A+B的和)告诉程
序.然后按程序执行操作。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/


#include <iostream>
#include <time.h>
using namespace std;
const int times = 10;         //总共可猜10次
const int Len = 4;          //选择的数字量
const int Max = 10;          //数字总数
const int NUMBER[Max] = {0,1,2,3,4,5,6,7,8,9};   //可选数字
const int Total = 210;         //组合情况的总数
const int PositionMax = 24;        //每组数字(4个)的排列情况总数
int m_iCount=0;           //对任意组合的数量进行统计
int m_iNumTotal[Total][Len];       //记录所有组合情况
int m_iNumber[Max];          //记录数字的编号(以出场情况为编号)

static struct GUESS
{
int A[times];          //记录每次游戏的A指示
int iGuess[times][Len];        //记录每次猜的数字
int iPguess;          //iGuess的一维指针
GUESS(){ init(); }
void init()
{
  for (int i=0; i<times; i++)
  {
   for (int j=0; j<Len; j++)
    iGuess [j]=-1;
   A=-1;
  }
  iPguess = 0;
}
void insert(const int Number[Len])
{
  for(int i=0; i<Len; i++)
   iGuess[iPguess] = Number;
  iPguess++;
}
}m_stGuess;
static struct MAYBE
{
int iMaybe[Total];         //记录可能是答案的组合的编号
int iPmaybe;
void init()
{
  for (int i=0; i<Total; i++)
   iMaybe=-1;
  iPmaybe=0;
}
void insert(int i)
{
  iMaybe[iPmaybe] = i;
  iPmaybe++;
}
}m_stMayBe;

void Init()
{//初始化数据
for (int i=0; i<Max; i++)
        m_iNumber=0;
m_iCount=0;
m_stGuess.init();
m_stMayBe.init();
}
void set(const int Input[Max], int(* Output)[Len], int m=0, int n=0, int set_fist=1)
{//0到Max的集合里取Len个数的组合, m为所选择的数字放置的位置, n为选择的数字
static int iTemp[Len];
static int pOutput = 0;
if(set_fist == 1)
  pOutput = 0;
int i;
    if( m == Len)
    {
        for (i=0; i<Len; i++)
            Output[pOutput] = iTemp;
        m_iCount++;
        pOutput++;
    }
    else if( n < Max)
    {
        for( i=0; i<2; i++)
        {
            if ( i==0) { iTemp[m] = Input[n]; set(Input, Output, m+1,n+1,0); }
            else set(Input, Output, m,n+1,0);
        }
    }
}
void order(int Input[Max], int(* Output)[Len], int n = 0, int order_first = 1)
{//求m_iPosition数组里的元素所有排列情况
    int i, temp;
static int pOutput = 0;
if(order_first == 1)
  pOutput = 0;
    if (n == Len)
    {
        for (i=0; i<Len ;i++)
            Output[pOutput] = Input;
        pOutput++;
    }
    else
    {
        for (i=n; i<Len; i++)
        {
            temp=Input[n]; Input[n]=Input; Input=temp;
            order(Input, Output, n+1, 0);
            temp=Input[n]; Input[n]=Input; Input=temp;
        }
    }
}

void record_number(const int(* Next)[Len], const int line, int OutputNum[Max], GUESS& OutputGuess)
{//调整数字编号并记录下已猜过的数字序列,a[line]为下一步预定要猜测的数字序列
    int i, temp;
    for (i=0; i<Max; i++)
        OutputNum = OutputNum*10;
OutputGuess.insert(Next[line]);
    for (i=0; i<Len; i++)
    {
        temp = Next[line];
  OutputNum[temp]++;
    }
}
int think_1(const int sum, const int(* InputNumTotal)[Len], const int InputNum[Max], MAYBE& OutputMaybe)
{//获得符合条件1的所有组合情况, sum为直到当前为止所有猜测的记录
    int sumTemp;
    int numTemp;
OutputMaybe.init();
    for (int i=0; i<Total; i++)
    {
        sumTemp=0;
        for (int j=0; j<Len; j++)
        {
            numTemp = InputNumTotal[j];
            sumTemp += InputNum[numTemp];
        }
  if (sumTemp == sum)
  {
   OutputMaybe.insert(i);
  }
    }
if(OutputMaybe.iPmaybe <= 0) return 0;
return 1;
}
int eliminate(const int(* InputNum)[Len], const int n, const GUESS InputGuess, const int pg)
{//获得符合条件2的所有组合情况, n记录查找行, pg表示核对之前的猜测
    if (pg>=0)
    {
        int c=0;
        for (int i=0; i<Len; i++)
            if ( InputNum[n] == InputGuess.iGuess[pg]) c++;
        if (c == 4) return 0;
        if (c != InputGuess.A[pg]) return 0;//>
        return eliminate(InputNum, n, InputGuess, pg-1);
    }
    else return 1;
}
int think_2(const int(* InputNum)[Len], const GUESS InputGuess, const MAYBE MayBe,  int(* IO)[Len], int& iCHOOSE)
{//检验当前假设情况是否满足条件2
int iPosition[Len];
int i=0, choose=0;
    int k=0;
for (int pi=0; pi<MayBe.iPmaybe; pi++)
    {
        i = MayBe.iMaybe[pi];
        for (int po=0; po<Len; po++)
            iPosition[po] = InputNum[po];
        order(iPosition, IO);
        for (choose=0; choose<PositionMax; choose++)
            if ( eliminate(IO, choose, InputGuess, InputGuess.iPguess-1) ) {  k=1; break; }
        if ( k==1 ) break;
    }
    if (pi == MayBe.iPmaybe)
  return 0;
iCHOOSE = choose;
return 1;
}

void Head()
{//第一次输入取决于运气, 可由用户来决定
    int temp[1][Len], limit=0;
    while( limit < Len)
    {
        cout<<"请输入你第一次猜时的第"<<limit+1<<"个数字:";
        cin>>temp[0][limit];
  for(int i=0; i<limit; i++)
   if( temp[0] == temp[0][limit])
   {
    cout<<"猜测数字有重复,请重输!"<<endl;
    break;
   }
  if(i >= limit)
  {
   if( temp[0][limit] >=0 && temp[0][limit]<Max)
    limit++;
   else
    cout<<"输入数字不在范围内,请重输!"<<endl;
  }
    }
    record_number(temp, 0, m_iNumber, m_stGuess);
}
void HeadAoto()
{//第一次输入取决于运气, 可由用户来决定
    int temp[1][Len], limit=0;
int i = 0;
    while( limit < Len)
    {
  do
  {
   temp[0][limit] = rand()%10;
   for(i=0; i<limit; i++)
    if(temp[0] == temp[0][limit]) break;
  }while(i<limit);
  limit++;
    }
    record_number(temp, 0, m_iNumber, m_stGuess);
cout<<"请输入猜测数字: "<<endl;
for(i=0; i<Len; i++)
  cout<<temp[0]<<" ";
cout<<endl;
}
int InputAB(const int i, int& sum)
{
cout<<"请输入游戏的第"<<i<<"次时A的提示情况:";
cin>>m_stGuess.A[m_stGuess.iPguess-1];
    if( m_stGuess.A[m_stGuess.iPguess-1] == 4)
    {
        return 1;
    }
int result = 0;
cout<<"请输入游戏的第"<<i<<"次时B的提示情况:";
    cin>>result;
    result = result + m_stGuess.A[m_stGuess.iPguess-1];
    sum = sum*10 + result;
return 0;
}
int please_input(const int sum)
{//提示下一步输入信息,sum为直到当前为止所有猜测的记录
int choose=0;
static int NextCase[PositionMax][Len];    
//记录每组数字的所有排列情况
    if(!think_1(sum, m_iNumTotal, m_iNumber, m_stMayBe)) return 0;
if(!think_2(m_iNumTotal, m_stGuess, m_stMayBe, NextCase, choose)) return 0;
    record_number(NextCase, choose, m_iNumber, m_stGuess);
    cout<<"请向游戏输入:";
    for (int kk=0; kk<Len; kk++)
        cout<<NextCase[choose][kk]<<" ";
    cout<<endl;
    return 1;
}
int Control()
{//控制游戏进程
Init();
set(NUMBER, m_iNumTotal);
cout<<"组合情况数目: "<<m_iCount<<endl;
//Head();
HeadAoto();
int sum = 0;
InputAB(1, sum);
    for( int t=2; t <= times; t++)
    {
  if( !please_input(sum))
  {
   cout<<"该题目无解"<<endl;
   break;
  }
        if(InputAB(t, sum)) break;
    }
return 0;
}
void main()
{
srand((unsigned)time(NULL));
    char a;
    do
    {
  Control();
        cout<<"若输入#退出本程序:";
        cin>>a;
        cout<<endl<<endl;
    }while (a != '#');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mind是一款专为青少年设计的编程软件,它提供了一个猜数字游戏模块,让青少年在学习编程的过程中可以进行互动和娱乐。 猜数字是一种经典的逻辑思维游戏,通过编程语言来实现其规则和逻辑非常有益于青少年的思维发展。通过Mind软件,青少年可以学会使用编程语言来创建一个猜数字游戏程序。 玩家可以根据规则设定一个数字范围,然后电脑会随机生成一个目标数字。玩家需要通过编写程序来猜测目标数字,并根据电脑给出的提示逐步缩小猜测范围,直到猜中目标数字为止。 在这个过程中,青少年可以学到很多关于逻辑思维和编程的知识。他们需要学会使用循环、条件语句等编程概念来实现游戏的逻辑,并通过试错的方法不断改进和优化自己的程序。 通过使用Mind软件进行猜数字,青少年可以培养他们的逻辑思维能力和问题的能力。他们会学会分析问题、推理和寻找最优的方法,以及如何将这些思维过程转化为代码实现。 同时,猜数字游戏也具有很强的娱乐性,能够吸引青少年的注意力和兴趣。他们可以根据自己的兴趣和创意来设计独特的猜数字游戏,通过编程将其实现,并与朋友们一起分享和竞争,增加了编程学习的趣味性和互动性。 总之,Mind软件的猜数字模块是一个很好的编程学习工具,既教会了青少年如何运用编程语言问题,又提供了互动和娱乐的体验。通过这种方式,青少年能够在学习中获得乐趣,并培养出与编程相关的重要技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值