四则运算2
一、设计思路:
1、题目避免重复:
(1)利用系统时间来产生随机数,重复率会降低。
(2)建立链表,逐个判断。可读取写入文件。
2、可定制(数量/打印方式):
(1)格式有默认值;
(2)可以选择重新设置分几列和每行的间隔。打印方式用%取余来实现分列输出。
3、可以控制参数:
(1)这些参数都有默认值;
(2)出题之前可以选择重新设置某一个或多个参数;
(3)是否有乘除法/括号/负数/余数/支持分数/支持小数:用户输入1/0表示是/否;
数值范围、真分数、假分数、精确到几位小数、每行的间隔:由用户输入决定;
(4)参数值得记录借鉴老师的方法,用数组来存储;用if-else来确定最终的格式。
是否有乘除法:判断数组中的参数是1还是0,若为0,则判断表示符号的随机数是不是乘除,是的话跳过;
数值范围:由rand()%(b-a+1)+a实现范围为a~b的随机数;
加减有无负数:判断数组中的参数是1还是0,若为0,则判断前一个数是否小于后一个数,是的话跳过;
每行的间隔:根据数组中的数,循环cout<<endl;
是否有余数:判断数组中的参数是1还是0,若为0,用%来判断
二、源代码
(1)
// 四则运算2.cpp : Defines the entry point for the console application.
// 袁佩佩 信1201-1班 20122785 2015/3/15
#include "stdafx.h"
#include "iostream.h"
#include "stdlib.h"
#include "time.h"
#include "Caculation.h"
#include "iomanip.h"
//******重新生成算术题******
void ReBuild(Caculation &Q)
{
if(para[4]==1)
Q.sign=rand()%4;
else
Q.sign=rand()%2;
Q.num1=rand()%(para[6]-para[5]+1)+para[5];
Q.num2=rand()%(para[6]-para[5]+1)+para[5];
}
//*****输出函数******
void Display(LinkC C,Caculation &Q)
{
int temp,count=0; //count记录重新生成题目的次数
for(int i=1;i<=para[1];i++)
{
cout<<"("<<i<<")";
if(para[4]==1)
Q.sign=rand()%4; //有乘除法
else
Q.sign=rand()%2; //没有乘除法
Q.num1=rand()%(para[6]-para[5]+1)+para[5]; //随机的(下限~上限)以内的整数
Q.num2=rand()%(para[6]-para[5]+1)+para[5];
RB: ReBuild(Q); //检查是否有出过的题目
if(count>((para[6]-para[5]+1)*(para[6]-para[5]+1)*100))
{
cout<<endl<<"该难度的题目已出完,请更改出题设置!"<<endl;
break;
}
switch(Q.sign)
{
case 0:
if(ExistQues(C,Q))
{
count++;
goto RB;
}
cout<<Q.num1<<"+"<<Q.num2<<"="<<setw(5);
break;
case 1:
if((para[7]==0)&&(Q.num1<Q.num2))
{ //若为负数,则交换
temp=Q.num1;
Q.num1=Q.num2;
Q.num2=temp;
}
if(ExistQues(C,Q))
{
count++;
goto RB;
}
cout<<Q.num1<<"-"<<Q.num2<<"="<<setw(5);break;
case 2:
if(ExistQues(C,Q))
{
count++;
goto RB;
}
cout<<Q.num1<<"*"<<Q.num2<<"="<<setw(5);break;
case 3:
while(Q.num2==0)
Q.num2=rand()%(para[6]-para[5]+1)+para[5];
if(!para[8])
{
while((Q.num1%Q.num2)!=0||Q.num2==0)
{ //重新生成
Q.num1=rand()%(para[6]-para[5]+1)+para[5];
Q.num2=rand()%(para[6]-para[5]+1)+para[5];
}
}
if(ExistQues(C,Q))
{
count++;
goto RB;
}
cout<<Q.num1<<"/"<<Q.num2<<"="<<setw(5);break;
}
InsertQues(C,Q);
if(i%para[2]==0) //一行打印完规定列数,换行
for(int j=0;j<=para[3];j++)
cout<<endl;
}
cout<<endl<<endl;
}
//*****判断难度*****
void YesOrNo(int para)
{
if(para)
cout<<"是";
else
cout<<"否";
}
//*****查看设置*****
void ShowSetting()
{
system("cls");
cout<<"\t/*************四则运算出题系统*************/"<<endl;
cout<<"\t题目数量:"<<para[1]<<"个\t\t打印列数:"<<para[2]<<"列"<<endl;
cout<<"\t每行间隔:"<<para[3]<<"行\t\t是否有乘除法:";YesOrNo(para[4]);cout<<endl;
cout<<"\t数值范围下限:"<<para[5]<<"\t\t数值范围上限:"<<para[6]<<endl;
cout<<"\t是否有负数:";YesOrNo(para[7]);cout<<"\t\t是否有余数:";YesOrNo(para[8]);cout<<endl;
cout<<"\t/******************************************/"<<endl;
}
//*****设置打印方式*****
void SetPrint()
{
system("cls");
char move1;
cout<<"\t/*************设置打印方式*************/"<<endl;
cout<<"\t 0.设置打印列数("<<para[2]<<"列)"<<endl;
cout<<"\t 1.设置每行间隔("<<para[3]<<"行)"<<endl;
cout<<"\t 2.返回主菜单"<<endl;
cout<<"\t/**************************************/"<<endl;
cout<<"请选择后续操作(0~2):";
cin>>move1;
while(move1<‘0‘||move1>‘2‘)
{
cout<<"错误!请正确输入操作序号(0~2):";
cin>>move1;
}
switch(move1)
{
case ‘0‘:
reset2: cout<<"新的打印列数(建议7列以内):";
cin>>para[2];
if(para[2]<0)
{
cout<<"出错!请重新输入!"<<endl;
goto reset2;
}
break;
case ‘1‘:
reset3: cout<<"新的间隔行数:";
cin>>para[3];
if(para[3]<0)
{
cout<<"出错!请重新输入!"<<endl;
goto reset3;
}
break;
case ‘2‘:break;
}
}
//*****判断输入正确*****
void Reset(int i)
{
do
{
cout<<"请重新设置(是1/否0):";
cin>>para[i]; //此处输入字符出错,但没解决
}while(para[i]!=0&¶[i]!=1);
}
//*****设置题目难度*****
void SetLevel()
{
system("cls");
char move2;
cout<<"\t/*************设置题目难度*************/"<<endl;
cout<<"\t 0.是否有乘除法(";YesOrNo(para[4]);cout<<")"<<endl;
cout<<"\t 1.数值范围("<<para[5]<<"~"<<para[6]<<")"<<endl;
cout<<"\t 2.是否有负数(";YesOrNo(para[7]);cout<<")"<<endl;
cout<<"\t 3.是否有余数(";YesOrNo(para[8]);cout<<")"<<endl;
cout<<"\t 4.返回主菜单"<<endl;
cout<<"\t/**************************************/"<<endl;
cout<<"请选择后续操作(0~4):";
cin>>move2;
while(move2<‘0‘||move2>‘4‘)
{
cout<<"错误!请正确输入操作序号(0~4):";
cin>>move2;
}
switch(move2)
{
case ‘0‘:Reset(4);break;
case ‘1‘: //此处若输入字符,则出错
reset1: cout<<"新的数值下限:"; //但没找到解决方法
cin>>para[5];
cout<<"新的数值上限:";
cin>>para[6];
if(para[5]>=para[6])
{
cout<<"出错!请重新输入数值范围!"<<endl;
goto reset1;
}
break;
case ‘2‘:Reset(7);break;
case ‘3‘:Reset(8);break;
case ‘4‘:break;
}
}
//****主页面*****
void MainMenu(LinkC &C,Caculation &Q)
{
char move,save;
cout<<"\t/*************四则运算出题系统*************/"<<endl;
cout<<"\t 0.开始出题"<<endl;
cout<<"\t 1.设置出题数量"<<endl;
cout<<"\t 2.设置打印方式"<<endl;
cout<<"\t 3.设置题目难度"<<endl;
cout<<"\t 4.查看当前设置"<<endl;
cout<<"\t 5.退出系统"<<endl;
cout<<"\t/******************************************/"<<endl;
cout<<"请选择后续操作(0~5):";
cin>>move;
while(move<‘0‘||move>‘5‘)
{
cout<<"错误!请正确输入操作序号(0~5):";
cin>>move;
}
switch(move)
{
case ‘0‘:Display(C,Q);break;
case ‘1‘:
reset4: cout<<"请设置出题数量(建议100道以内):";
cin>>para[1];
if(para[1]<=0)
{
cout<<"出错!请重新输入!"<<endl;
goto reset4;
}
break;
case ‘2‘:SetPrint();break;
case ‘3‘:SetLevel();break;
case ‘4‘:ShowSetting();break;
case ‘5‘:
cout<<"是否保存出题记录(是1/否0):";
cin>>save;
while(save!=‘1‘&&save!=‘0‘)
{
cout<<"出错!请正确输入(是1/否0):";
cin>>save;
}
if(save==‘1‘)
WriteQues(C);
cout<<"感谢您的使用,再见!"<<endl;
para[0]=0;break;
}
}
int main(int argc, char* argv[])
{
srand((unsigned)time(NULL)); //srand()函数产生一个以当前时间开始的随机种子
LinkC Cacu;
Caculation ques;
InitList(Cacu);
ReadQues(Cacu);
while(para[0])
{
system("cls");
MainMenu(Cacu,ques);
system("pause");
}
return 0;
}
(2)
#include "iostream.h"
#include "fstream.h"
//0退出、1出题数量、2打印列数、3每行间隔、4乘除、5数值范围下限、6数值范围上限、7负数、8余数、9出过的题目数
int para[10]={1,30,3,0,0,0,5,0,0,0}; //默认参数
//*****四则算术题的数据结构*****
typedef struct
{
int num1;
int num2;
int sign;
}Caculation;
typedef struct CNode //结点
{
Caculation ques;
struct CNode * next;
}CNode,*LinkC;
//******题目初始化******
void InitList(LinkC &C)
{
C=new CNode;
C->next=NULL;
}
//******添加题目信息******
void InsertQues(LinkC &C,Caculation Q)
{ //尾插入
LinkC tail,temp;
tail=C;
while(tail&&tail->next!=NULL)
tail=tail->next;
temp=new CNode;
temp->ques=Q;
temp->next=NULL;
tail->next=temp;
tail=temp;
para[9]++;
}
//******判断题目存在******
int ExistQues(LinkC C,Caculation Q)
{
LinkC temp;
temp=C->next;
while(temp)
{
if((temp->ques.num1==Q.num1)&&(temp->ques.num2==Q.num2)&&(temp->ques.sign==Q.sign))
return 1; //当两个数字和算符与链表中的一样,则存在
else
temp=temp->next;
}
return 0;
}
//******读取出过的问题******
void ReadQues(LinkC &C)
{
LinkC temp;
ifstream infile("question.txt");
for(int i=0;i<10;i++) //读取参数表
infile>>para[i];
for(i=0;i<para[9];i++) //读取出过的题目
{
temp=new CNode;
infile>>temp->ques.num1;
infile>>temp->ques.num2;
infile>>temp->ques.sign;
temp->next=NULL;
}
}
//******写入文件******
void WriteQues(LinkC C)
{
LinkC temp;
ofstream outfile("question.txt");
if(!outfile)
{
cout<<"文件存储失败!"<<endl;
exit(0);
}
for(int i=0;i<10;i++)
outfile<<para[i]<<" ";
for(temp=C->next;temp;temp=temp->next)
{
outfile<<temp->ques.num1<<" ";
outfile<<temp->ques.num2<<" ";
outfile<<temp->ques.sign<<" ";
}
}
三、运行结果
第一次使用时,程序默认10以内四则运算10道题,有负数余数,分三列打印,每行间隔一行。见下图。
对参数进行一些修改。见下图。
对打印方式进行修改。见下图。
对题目的一些设置
退出系统,可选择保存出过的题目和参数设置。
后来经过我的代码优化,当某种类型的题目全部都出过以后,会提示。
首先当前设置如下。
连续出题多次发现
四、遇到的困难
设计思想里已经写了,编写程序的时候,我是渐进式的自顶向下的开发的。但是我不太清楚编写代码时,该不该用自顶向下。因为我比较注重细节,先写框架 再写核心往往会导致编出来的程序虎头蛇尾。而且这次我是最后才加上的数据结构,以至于之前写的变量名、参数等等都要变更,有些麻烦。以后我会训练自己自底 向上写代码的能力。我有个坏毛病就是,边写边思考,有时候这个问题还差一点就解决了,结果就又扯到另一个问题上了。我在与其他同学交流的过程中,也了解到“下手”之前,必须要先把整个程序在心里构建的差不多了,再敲代码。多和编程能力强或编程习惯好的同学交流,多向他们学习,也是受益匪浅啊。
最后就是,数据结构部分我是借鉴之前数据结构小学期自己做的员工管理系统来编写的,回忆起了链表以及相关操作的知识。