结对编程

1.结对编程作业要求:
小学老师要每周给同学出300道四则运算练习题。
这个程序有很多种实现方式:
C/C++
C#/VB.net/Java
Excel
Unix Shell
Emacs/Powershell/Vbscript
Perl
Python
两个运算符,100 以内的数字,不需要写答案。
需要检查答案是否正确,并且保证答案在 0..1000 之间
尽可能地多设置一些条件
请两位同学以结对编码(一个同学coding,另一个同学在旁边审核代码,之后再交换角色)的方式完成本次实验)

2.参与成员
本人:2352821
另一位:2352825

3.程序功能设计
首先我们实现了随机生成四则运算算式,三个数字与两个运算符,并且数字的范围均处于1-100之间。
并且在算式生成结束后,会进行结果检查,若本次生成答案超出了[0,1000]的范围,则重新生成当前算式。
由于乘除0对于结果的影响过大,可能导致计算难度大幅降低,故数字范围选择了1-100而非0-100
对于除法部分,考虑到可能产生小数,因此我们对于所有计算结果取两位小数计算

在以上基础功能之外,我们还设计了一些其它功能:
·单次题目产生量:
考虑到教师需要每周三百道题,而每天可能并不需要这么多,我们设置了一个变量size用于控制每次算式的生成量
代码中默认为10,更改此变量可以改变单次程序运行所产生的算式数量。
·答题功能:
在算式生成结束后,依次输入各个算式的答案,程序会将答案与生成算式时保存的答案进行比对。统计出错误数量和错误题号
在此基础上计算出正确率等信息,可以辅助教师批改,也可让学生全自动练习口算题。
在答题结束,并且展现完正确率等数据后,会列出所有算式的答案,老师可以根据答案批改作业,或者学生自行核对答案。

4.算法设计思路
本次作业我们采用了c++进行编写,核心思路是使用cpp内置的rand函数生成随机数,以此来产生算式。
定义了一个const int size常量,用于修改程序一次产生的算式量,所有数组和循环都调用了size。
在部分函数中使用传递引用的方式来传参,有效消减了程序大小和执行效率。

在核心的算式生成部分,首先我们使用了rand函数来生成三个数字,并且再生成两个1-4的整数,分别代指+、-、*、/
两个操作符数字分别记为t1和t2。
生成完后,首先调用judgeop函数,将1-4的整数t1t2转换为char类型的c1c2,为输出算式做准备。
然后调用createnum函数,使用随机数生成三个数字与两个操作符。
此后,调用check函数进行算式答案范围的检查,而check函数会调用calculate函数进行计算。

在calculate函数中,计算算式的算法如下:
·判断c1操作符是否为乘除,且c2为加减。若通过,则分类计算结果并返回。
·以上判断未通过,判断c2操作符是否为乘除,且c1为加减。若通过,计算结果并返回。
·以上判断均未通过,则代表算式中仅有加减/乘除,根据交换律,按顺序计算即可。

若check函数检查,算式答案超过了范围,则重新生成。check函数通过后,再次调用calculate函数,将算式的结果存入
一个大小为const size的数组内,以备之后的核验环节。
上方的过程全部结束之后,输出生成的若干个算式。

以上为算式生成部分,接下来是答题环节。根据上方生成的算式数量,用户输入对应的答案,存入一个数组内
全部输入完毕后,分别与预先存储的答案数组进行一一对比,并且统计出错题题号与错题量。
当比对发现某一题错误时,将预先定义的bool err[]数组的第n为改为false,用于标记。而当某一题正确时,correct技术+1。

在输出错误题号时,遍历err数组,若值为false,则输出数组下标+1,代表题号。使用correct/size来计算正确率
输出完毕后,遍历标准答案数组,输出所有参考答案,此后退出程序。

5.程序代码展示

点击查看代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

using namespace std;
char judgeop(char &cc1,char &cc2,int t);
float calculate(float a, float b, float c, char c1, char c2);
bool checkans(int aa,int bb,int cc,int t);
void createnum(int &aa,int &bb,int &cc,int &tt);

const int size = 10;

float calculate(float a, float b, float c, char c1, char c2) {//传入三个待计算数字与两个操作符 
    if ((c1 == '*' || c1 == '/') && (c2 == '+' || c2 == '-')) {
        float temp;
        switch (c1) {
            case '*':
                temp = a * b;
                break;
            case '/':
                if (b == 0) {
                    cerr << "Error: Division by zero!" << endl;
                    return 0;
                }
                temp = a / b;
                break;
            default:
                cerr << "Error: Invalid operator " << c1 << endl;
                return 0;
        }
        switch (c2) {
            case '+':
                return temp + c;
            case '-':
                return temp - c;
            default:
                cerr << "Error: Invalid operator " << c2 << endl;
                return 0;
        }
    } else if ((c2 == '*' || c2 == '/') && (c1 == '+' || c1 == '-')) {
        float temp;
        switch (c2) {
            case '*':
                temp = b * c;
                break;
            case '/':
                if (c == 0) {
                    cerr << "Error: Division by zero!" << endl;
                    return 0;
                }
                temp = b / c;
                break;
            default:
                cerr << "Error: Invalid operator " << c2 << endl;
                return 0;
        }
        switch (c1) {
            case '+':
                return a + temp;
            case '-':
                return a - temp;
            default:
                cerr << "Error: Invalid operator " << c1 << endl;
                return 0;
        }
    } else {
        float temp1;
        switch (c1) {
            case '+':
                temp1 = a + b;
                break;
            case '-':
                temp1 = a - b;
                break;
            case '*':
                temp1 = a * b;
                break;
            case '/':
                if (b == 0) {
                    cerr << "Error: Division by zero!" << endl;
                    return 0;
                }
                temp1 = a / b;
                break;
            default:
                cerr << "Error: Invalid operator " << c1 << endl;
                return 0;
        }
        float temp2;
        switch (c2) {
            case '+':
                temp2 = temp1 + c;
                break;
            case '-':
                temp2 = temp1 - c;
                break;
            case '*':
                temp2 = temp1 * c;
                break;
            case '/':
                if (c == 0) {
                    cerr << "Error: Division by zero!" << endl;
                    return 0;
                }
                temp2 = temp1 / c;
                break;
            default:
                cerr << "Error: Invalid operator " << c2 << endl;
                return 0;
        }
        return temp2;
    }
}

bool checkans(int aa,int bb,int cc,int t){//检查答案是否处于0-1000,传入三个数与符号t 
	
	char c1,c2;
	judgeop(c1,c2,t);
	float a,b,c;
	a = aa;b = bb;c = cc;
	
	float ans = calculate(a,b,c,c1,c2);
	if (ans<=1000&&ans>=0)
	return true;
	else
	return false;
}

void createnum(int &aa,int &bb,int &cc,int &tt)//创建表达式并输出 
{
	int a,b,c,t1,t2,t;
	char c1,c2;
	a = rand() % 100+1;
	b = rand() % 100+1;
	c = rand() % 100+1;//1-100
	
	t1 = rand() % 4+1;//1-4,分别代表加减乘除 
	t2 = rand() % 4+1; 
	t = t1*10+t2;//合成为一个数
	
	aa=a;bb=b;cc=c;tt=t;		
	
}

char judgeop(char &cc1,char &cc2,int t){
		int t1 = t/10;
		int t2 = t%10;
		
		char c1,c2;
		char op[4] = {'+','-','*','/'}; 
		switch(t1){
		case 1:
			c1 = '+';
			break;
		case 2:
			c1 = '-';
			break;
		case 3:
			c1 = '*';
			break;
		case 4:
			c1 = '/';
			break;
		default:
			break;
	}
	switch(t2){
		case 1:
			c2 = '+';
			break;
		case 2:
			c2 = '-';
			break;
		case 3:
			c2 = '*';
			break;
		case 4:
			c2 = '/';
			break;
		default:
			break;
	}
	cc1 = c1;
	cc2 = c2;
}

void start(float (&an)[size],bool (&err)[size]){
	cout<<"正在生成题目,本次生成题目量为:"<<size;
	int i=0;
	int a,b,c,t;
	char c1,c2;
	while(i<=size){
		createnum(a,b,c,t);
		if(checkans(a,b,c,t)){
		judgeop(c1,c2,t);
		cout<<i<<":";
		cout<<a<<c1<<b<<c2<<c<<endl;
		an[i] = calculate(a,b,c,c1,c2);
		i++;
		}
	}
	cout<<"请开始答题,题目答案保留两位小数,不同题目答案使用空格分割"<<endl;
	
	float ans[size];
	int correct = 0;
	i=0;
	while(i<size){
		cin>>ans[i];
		if(ans[i] == an[i]){
			correct++;
		}
		else{
			err[i] = false;
		}
		i++;
	}
	
	cout<<"答题结束,正在核对结果"<<endl;
	float pct = (correct/size)*100; 
	cout<<"本次答题正确题目数为:"<<correct<<"题,正确率为"<< fixed << setprecision(2) << pct <<"%"<<endl;
	cout<<"错误题号为:";
	for(i=0;i<size;i++){
		if(err[i]==false)
		cout<<i+1<<" "<<endl; 
	}
	cout<<"以下为答案列表"<<endl;
	for(i=0;i<=size;i++){
		cout << "第" <<i<<"题答案为:";
		cout << fixed << setprecision(2) << answer[i] << endl;
	}
}

int main(int argc, char** argv) {
	srand((int)time(0));

	float answer[size];
	bool err[size] = {true};
	start(answer,err);
	
	return 0;
}

6.运行功能截图
算式生成部分(程序默认值10题)

修改算式生成量

答题功能与结果统计计算功能

7.结对编程体会
结对编程需要体会另一个人的编程思路,不同人的习惯不同编写、思考方式也略有不同。有时候写出一段代码,我自己可以很轻易的理解,但是需要让他人理解则需要费一番功夫。
但是在解释的过程中,我能够反思这段代码,发现一些潜在的问题,或者是产生一些新的理解。
因为coding风格的原因,在开始结对编程前最好规定一些两个人都认可的编写规范,例如格式,定义/传参方式等,这样可以减轻交流压力并且提高效率。
当一个人正思考代码实现时,另一个人可以从整体角度分析程序的结构,尽管存在一定程度的沟通成本,但是但收获的代码质量提升、知识快速积累和团队协作经验,
使得这成为了一种卓有价值的学习方式。

posted @ 2025-04-12 14:48  GeminiKun  阅读(36)  评论(0)    收藏  举报