首页 > 编程语言 > 详细

一个自动生成小学四则运算题目的命令行程序(C++)(王煜墉+徐伟浩)

时间:2020-04-14 22:01:56      阅读:137      评论:0      收藏:0      [点我收藏+]

github地址:https://github.com/includebug/ExerciseGenerate

结对伙伴:王煜墉(3118004972) + 徐伟浩(3118004980)

题目

实现一个自动生成小学四则运算题目的命令行程序(也可以用图像界面,具有相似功能)。

说明

自然数:0, 1, 2, …。

  • 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
  • 运算符:+, ?, ×, ÷。
  • 括号:(, )。
  • 等号:=。
  • 分隔符:空格(用于四则运算符和等号前后)。
  • 算术表达式:
    e = n | e1 + e2 | e1 ? e2 | e1 × e2 | e1 ÷ e2 | (e),

其中e, e1和e2为表达式,n为自然数或真分数。

  • 四则运算题目:e = ,其中e为算术表达式。

需求

  1. 使用 -n 参数控制生成题目的个数,例如

Myapp.exe -n 10

将生成10个题目。

使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围,例如

Myapp.exe -r 10

将生成10以内(不包括10)的四则运算题目。该参数可以设置为1或其他自然数。该参数必须给定,否则程序报错并给出帮助信息。

  1. 生成的题目中计算过程不能产生负数,也就是说算术表达式中如果存在形如e1? e2的子表达式,那么e1≥ e2。
  2. 生成的题目中如果存在形如e1÷ e2的子表达式,那么其结果应是真分数。
  3. 每道题目中出现的运算符个数不超过3个。
  4. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:

四则运算题目1
四则运算题目2
……

其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。

在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:

答案1
答案2

特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。

  1. 程序应能支持一万道题目的生成。
  2. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,输入参数如下:

Myapp.exe -e .txt -a .txt

统计结果输出到文件Grade.txt,格式如下:

Correct: 5 (1, 3, 5, 7, 9)

Wrong: 5 (2, 4, 6, 8, 10)

其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目都是按照顺序编号的符合规范的题目。

PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 20
· Estimate · 估计这个任务需要多少时间 1260 1400
Development 开发 900 1030
· Analysis · 需求分析 (包括学习新技术) 30 60
· Design Spec · 生成设计文档 30 20
· Design Review · 设计复审 (和同事审核设计文档) 20 20
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 30 30
· Coding · 具体编码 50 50
· Code Review · 代码复审 30 25
· Test · 测试(自我测试,修改代码,提交修改) 30 25
Reporting 报告 60 60
· Test Report · 测试报告 20 20
· Size Measurement · 计算工作量 20 20
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 20
合计 1280 1420

详细设计

总体设计

根据用户输入的不同参数,调用不同功能的模块。
技术分享图片
代码如下:

#include <iostream>
#include <fstream>
#include "Fraction.h"
#include "ExerciseGenerate.h"
#include "calculator.h"
using namespace std;

int main(int argc,char* argv[])
{
	wcout.imbue(locale("chs"));
	if (argc < 3)   //参数没有 4个 
	{
		cout << "输入错误参数少于3个,请到cmd下运行" << endl;
		system("pause");
		return 1;
	}
	if (strcmp(argv[1], "-n") == 0 && strcmp(argv[3], "-r") == 0)
	{
		wofstream ofs1, ofs2;
		ofs1.open("Exercise.txt", ios::app);
		ofs2.open("Result.txt", ios::app);
		ofs1.imbue(locale("chs"));
		ofs2.imbue(locale("chs"));
		int ExerciseNumber, MaxNum;
		ExerciseNumber = atoi(argv[2]);
		MaxNum = atoi(argv[4]);

		ExerciseGenerate *x = new ExerciseGenerate[ExerciseNumber];
		int j = 0;
		for (int i = 0; i < 20 && j < ExerciseNumber; i++)
		{
			x[j].ExerciseGenerateMaxNum(MaxNum);
			x[j].generateExpress();

			Expression temp = x[j].returnExpression();
			Fraction z = temp.returnResult();
			if (z.isPositive())
			{
				wstring y = temp.returnExpressionWstring();
				ofs1 << j + 1 << L"、 ";
				ofs1 << y << endl;
				y = z.FractionWstring();
				ofs2 << j + 1 << L"、 ";
				ofs2 << y << endl;
				j++;  //读取下一个表达式
				i = 0; //重新计数,超过20次不能存进去则跳出
			}
		}
		
		delete[]x;
		ofs1.close();
		ofs2.close();
	}
	else if (!strcmp(argv[1], "-e") && !strcmp(argv[3], "-a"))
	{
		string ExerciseFile = argv[2];
		string AnswerFile = argv[4];
		ReadANSI(ExerciseFile, AnswerFile);
	}
	system("pause");
	return 0;
}

计算器的设计

计算器是整个程序中难度最大的一部分,是后面判断表达式的值与用户所填写的值是否相同的关键。实现计算器的算法有很多,如栈,递归,或者是利用后序遍历二叉树的方法。这里我们采用最为暴力的一种解法,这就利用if else进行判断求值。流程图如下:
技术分享图片
代码如下:

#include "calculator.h"
#include "Fraction.h"

int simplify(int a, int b)  //求最大公约数
{
	int c = 0;
	while (c = a % b)   //c==0时 循环结束
	{
		a = b;
		b = c;
	}
	return b;
}

bool isNo(wchar_t c) //is Number
{
	return c >= L‘0‘ && c <= L‘9‘ || c == L‘\‘‘ || c == L‘/‘;
}
bool isSyb(wstring c)//is Symbol
{
	return (c[0] == L‘+‘ || c[0] == L‘-‘ || c[0] == L‘ב || c[0] == L‘÷‘) && c.size() == 1; //ver1.2
}
bool isSyb(wchar_t c)//is Symbol
{
	return c == L‘+‘ || c == L‘-‘ || c == L‘ב || c == L‘÷‘;
}

bool isIlg(wchar_t c) //is illegal
{
	return !isNo(c) && !isSyb(c) && !(c == L‘(‘ || c == L‘)‘ || c == L‘ ‘);
}

wstring GetSubtext(wstring S, size_t bgn, size_t end) //follow "left-inclusive interval"
{
	wstring subtext(end - bgn, L‘ ‘);
	for (size_t i = bgn; i != end; i++)
		subtext[i - bgn] = S[i];
	return subtext;
}

vector<wstring> split(const std::wstring &s, wchar_t delim)  //切割wstring,以delim符号为分界
{
	if (!s.find(delim))
	{
		cout << "没有这个字符,该数不是分数" << endl;
	}
	vector<wstring> elems;
	wstringstream ss;
	ss.str(s);
	std::wstring item;
	while (getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}

bool spiltNum(int a[3], wstring x)  //把分数的wstring传进去,返回三个整数,存在数组a里
{
	vector<wstring> k, k1;
	k = split(x, L‘\‘‘);
	if (k.at(0) == x)    //判断是否切割成功
		return false;
	k1 = split(k.at(1), L‘/‘);
	if (k1.at(0) == k.at(1))
		return false;
	a[0] = stoi(k.at(0));
	a[1] = stoi(k1.at(0));
	a[2] = stoi(k1.at(1));
	return true;
}

wstring calculatorFractionAndInt(wstring x, wstring y, char z)
{
	int b = stoi(y);
	int a[3];
	spiltNum(a, x);
	int c[3];
	wstring TempResult;
	if (z == ‘+‘)
	{
		c[0] = a[0] + b;
		c[1] = a[1];
		c[2] = a[2];
	}
	else if (z == ‘-‘)
	{
		c[0] = a[0] - b;
		c[1] = a[1];
		c[2] = a[2];
	}
	else if (z == ‘*‘)
	{
		c[0] = a[0] * b;
		c[1] = a[1] * b;
		c[2] = a[2];
	}
	else
	{
		c[0] = 0;
		c[1] = a[0] * a[2] + a[1];
		c[2] = a[2] * b;
	}
	if (c[2] != 0 && c[1] != 0)
	{
		int d = simplify(c[1], c[2]);
		c[1] /= d;
		c[2] /= d;
	}
	if (c[1] > c[2] && c[2] != 0)
	{
		c[0] += c[1] / c[2];
		c[1] = c[1] % c[2];
	}
		
	TempResult = to_wstring(c[0]) + L‘\‘‘ + to_wstring(c[1]) + L‘/‘ + to_wstring(c[2]);
	return TempResult;
}

wstring calculatorIntAndFraction(wstring x, wstring y, char z)
{
	int a = stoi(x);
	int b[3];
	spiltNum(b, y);
	int c[3];
	wstring TempResult;
	if (z == ‘+‘)
	{
		c[0] = a + b[0];
		c[1] = b[1];
		c[2] = b[2];
	}
	else if (z == ‘-‘)
	{
		c[0] = a - b[0] - 1;
		c[1] = b[2] - b[1];
		c[2] = b[2];
	}
	else if (z == ‘*‘)
	{
		c[0] = b[0] * a;
		c[1] = b[1] * a;
		c[2] = b[2];
	}
	else
	{
		c[0] = 0;
		c[1] = b[0] * b[2] + b[1];
		c[2] = b[2] * a;
	}
	if (c[2] != 0 && c[1] != 0)
	{
		int d = simplify(c[1], c[2]);
		c[1] /= d;
		c[2] /= d;
	}
	if (c[1] > c[2] && c[2] != 0)
	{
		c[0] += c[1] / c[2];
		c[1] = c[1] % c[2];
	}
	TempResult = to_wstring(c[0]) + L‘\‘‘ + to_wstring(c[1]) + L‘/‘ + to_wstring(c[2]);
	return TempResult;
}

wstring calculatorFraction(wstring x, wstring y, char z)
{
	int a[3], b[3];
	spiltNum(a, x);
	spiltNum(b, y);
	int c[3];
	wstring TempResult;
	if (z == ‘+‘)
	{
		c[0] = a[0] + b[0];
		c[1] = a[1] * b[2] + a[2] * b[1];
		c[2] = a[2] * b[2];
	}
	else if (z == ‘-‘)
	{
		c[0] = a[0] - b[0];
		c[1] = a[1] * b[2] - a[2] * b[1];
		c[2] = a[2] * b[2];
		if (c[1] < 0)
		{
			c[0]--;
			c[1] = c[2] - c[1];
		}
	}
	else if (z == ‘*‘)
	{
		c[0] = 0;
		c[1] = (a[0] * a[2] + a[1])*(b[0] * b[2] + b[1]);
		c[2] = a[2] * b[2];
	}
	else
	{
		c[0] = 0;
		c[1] = (a[0] * a[2] + a[1])*b[2];
		c[2] = a[2] * (b[0] * b[2] + b[1]);
	}
	if (c[2] != 0 && c[1] != 0)
	{
		int d = simplify(c[1], c[2]);
		c[1] /= d;
		c[2] /= d;
	}
	if (c[1] > c[2] && c[2] != 0)
	{
		c[0] += c[1] / c[2];
		c[1] = c[1] % c[2];
	}
	TempResult = to_wstring(c[0]) + L‘\‘‘ + to_wstring(c[1]) + L‘/‘ + to_wstring(c[2]);
	return TempResult;
}

wstring calculatorInt(wstring x, wstring y, char z)
{
	int a[3];
	wstring CtmpResult;
	int tempResult;
	if (z == ‘+‘)
	{
		tempResult = stoi(x) + stoi(y);
	}
	if (z == ‘-‘)
	{
		tempResult = stoi(x) - stoi(y);
	}
	if (z == ‘*‘)
	{
		tempResult = stoi(x) * stoi(y);
	}
	if (z == ‘/‘)
	{
		if (stoi(y) == 0)
		{
			CtmpResult = L"0\‘0/0";
			return CtmpResult;
		}
		else if (stoi(x) % stoi(y) == 0)
			tempResult = stoi(x) / stoi(y);
		else
		{
			int num1 = stoi(x), num2 = stoi(y);
			a[0] = num1 / num2;
			a[1] = num1 % num2;
			a[2] = num2;
			CtmpResult = to_wstring(a[0]) + L‘\‘‘ + to_wstring(a[1]) + L‘/‘ + to_wstring(a[2]);
			return CtmpResult;
		}
	}
	CtmpResult = to_wstring(tempResult); // int to wstring
	return CtmpResult;
}

wstring BasicCalculation(wstring x, wstring y, char z)
{
	wstring CtmpResult;
	if (string::npos != x.find(L"\‘") && string::npos != y.find(L"\‘"))  //两个分数计算
		CtmpResult = calculatorFraction(x, y, z);
	else if (string::npos == x.find(L"\‘") && string::npos != y.find(L"\‘"))  //左边整数,右边分数
		CtmpResult = calculatorIntAndFraction(x, y, z);
	else if (string::npos != x.find(L"\‘") && string::npos == y.find(L"\‘"))  //左边分数,右边整数
		CtmpResult = calculatorFractionAndInt(x, y, z);
	else                                                                           //两个整数
		CtmpResult = calculatorInt(x, y, z); // int to wstring
	return CtmpResult;
}

wstring calc(wstring S, size_t len)
{
	deque<wstring> words;
	bool inNo = false; //door for isNo
	//bool inSyb = false; //door for isSyb
	size_t NoPos = 0;
	//size_t SybPos = 0;
	size_t ParPos = 0, ParDep = 0;
	size_t begin = 0, end = len;
	for (size_t temp = 0; temp < len; temp++)
	{
		if (S[temp] == L‘、‘)
			begin = temp + 1;
		if (S[temp] == L‘=‘)
			end = temp;
	}
	for (size_t i = begin; i <= end; i++) //build standard formula
	{

		if (isIlg(S[i]) && i != end) //formula illegal checking
			return L"The formula is illegal1!";

		if (isNo(S[i]) && !inNo) //Number postion begin
		{
			inNo = true;
			NoPos = i;
		}
		if (!isNo(S[i]) && inNo) //Number postion end
		{
			inNo = false;
			words.push_back(GetSubtext(S, NoPos, i));
		}

		if (isSyb(S[i])/* && !inSyb*/)
		{
			words.push_back(GetSubtext(S, i, i + 1));
		}

		if (S[i] == L‘)‘)
			return L"RightParentheses is not match!";

		if (S[i] == L‘(‘)
		{
			//inPar = true;
			ParDep++;
			ParPos = i + 1; //left-inclusive interval
			size_t j;
			for (j = i + 1; ParDep && j <= end; j++)
			{
				if (S[j] == L‘(‘) ParDep++;
				if (S[j] == L‘)‘) ParDep--;
			}
			if (j <= end)
			{
				wstring recResult(calc(GetSubtext(S, ParPos, j - 1), GetSubtext(S, ParPos, j - 1).size()));
				if (recResult == L"The formula is illegal!")
					return L"The formula is illegal2!";

				else if (recResult == L"Parentheses is not match!")
					return L"LeftParentheses is not match!";

				else
					words.push_back(recResult);
			}
			else
			{
				//parentheses is not match
				return L"LeftParentheses is not match!";
			}
			i = j - 1; //jump over subtext
		}

	} //end for

	int tempResult = 0;
	wstring CtmpResult;

	//check formula
	if (words.size() == 0) return L"0"; // 0 element
	if (words.size() == 1) //1 element
		if (!isSyb(words.front()))
		{
			//strcpy_s(CtmpResult, words.front().c_str());
			CtmpResult = words.front();
			return CtmpResult;
		}
		else
		{
			wstring s(L"The formula is illegal3!");
			return s;
		}
	if (words.front() == L"×" || words.front() == L"÷")  //front is symble
		return L"The formula is illegal4!";
	if (words.front() == L"+" || words.front() == L"-")
	{
		if (!isSyb(*(words.begin() + 1)))
		{
			words.front() += *(words.begin() + 1);
			words.erase(words.begin() + 1); //erase second one
		}
		else
			return L"The formula is illegal5!";
	}
	if (isSyb(words.back()))
	{
		wcout.imbue(locale("chs"));
		wcout << words.back() << endl;
		return L"The formula is illegal6!";
	}

	for (deque<wstring>::iterator i = words.begin() + 1; i < words.end(); i++)
	{
		if ((*i == L"×" || *i == L"÷") && (isSyb(*(i - 1))) && (*(i - 1)).size())
			return L"The formula is illegal7!";
		if ((*i == L"+" || *i == L"-") && (isSyb(*(i - 1))) && (*(i - 1)).size())
			if (!isSyb(*(i + 1)))
			{
				*(i + 1) = *i + *(i + 1);
				i = words.erase(i);
			}
			else
				return L"The formula is illegal8!";
	}

	//start calculate
	for (deque<wstring>::iterator i = words.begin(); i != words.end(); i++)
	{
		//calculate * and /
		if (*i == L"×")
		{
			CtmpResult = BasicCalculation(*(i - 1), *(i + 1), ‘*‘);
			i = words.erase(i - 1);
			i = words.erase(i);
			*i = CtmpResult;
		}
		if (*i == L"÷")
		{
			CtmpResult = BasicCalculation(*(i - 1), *(i + 1), ‘/‘);
			i = words.erase(i - 1);   //erase函数返回下一个的对象,相当于数组的i++
			i = words.erase(i);
			*i = CtmpResult;
		}
	}
	for (deque<wstring>::iterator i = words.begin(); i != words.end(); i++)
	{
		//calculate + and -
		if (*i == L"+")
		{
			CtmpResult = BasicCalculation(*(i - 1), *(i + 1), ‘+‘);
			i = words.erase(i - 1);
			i = words.erase(i);
			*i = CtmpResult;
		}
		if (*i == L"-")
		{
			CtmpResult = BasicCalculation(*(i - 1), *(i + 1), ‘-‘);
			i = words.erase(i - 1);
			i = words.erase(i);
			*i = CtmpResult;
		}
	}

	CtmpResult = words.front();
	return CtmpResult;
}

void ReadANSI(string expressionFilename, string resultFilename)  //ANSI编码的txt读取
{
	wstring b;
	wstring c;
	wifstream infile;
	wifstream infile1;
	infile.imbue(locale("chs"));
	infile1.imbue(locale("chs"));
	wcout.imbue(locale("chs"));
	//ANSI型保存的txt才能用
	infile.open(expressionFilename);
	infile1.open(resultFilename);
	if (!infile.is_open())
	{
		exit(EXIT_FAILURE);
	}
	int i = 0;
	while (!infile.eof())
	{
		i++;
		getline(infile, b);
		getline(infile1, c);
		if (b.size() == 0 && c.size() == 0)
			return;
		wstring result1 = calc(b, b.size());
		if (string::npos == result1.find(L"\‘"))
			result1 = result1 + L"\‘0/1";
		Fraction temp(result1);
		wcout << temp.FractionWstring() << endl;
		if (string::npos == c.find(temp.FractionWstring()))
			cout << "error:" << i << endl;
		else
			cout << "right:" << i << endl;
		wcout << b << endl;
	}
	infile.close();
}

void ReadUTF8(string expressionFilename, string resultFilename)  //不带BOM的utf8的读取
{
	wstring_convert<codecvt_utf8<wchar_t> > conv;
	ifstream ifs(expressionFilename);
	ifstream ifs1(resultFilename);
	if (!ifs.is_open())
	{
		exit(EXIT_FAILURE);
	}
	int i = 0;
	while (!ifs.eof())
	{
		i++;
		string line1;
		getline(ifs, line1);
		wstring wb1 = conv.from_bytes(line1);
		string line2;
		getline(ifs, line2);
		wstring wb2 = conv.from_bytes(line2);
		wcout << calc(wb1, wb1.size()) << endl;
		if (string::npos == wb2.find(calc(wb1, wb1.size())))
			cout << "error:" << i << endl;
		else
			cout << "right:" << i << endl;
		wcout << wb1 << endl;
	}
	ifs.close();
}

随机生成表达式模块

利用c语言的rand函数生成随机数量的n个操作数以及n-1个操作符生成不同的表达式。代码如下:

#include "ExerciseGenerate.h"

bool ExerciseGenerate::ExerciseGenerateMaxNum(int i)
{
	numSize = i;
	return true;
}

wstring ExerciseGenerate::generateExpress()
{
	srand(clock());
	int i = rand() % 3 + 2;

	for (int k = 0; k < i; k++)          //3*3的二维数组存数据,一行为一个数据
	{
		int isFraction = rand() % 2;     //是否为整数,若为整数a[k][1]=0,即分子置为0
		if (isFraction == 0)
		{
			for (int j = 0; j < 3; j++)
			{
				if (j == 2)  //保证分母不为0
					a[k][j] = (rand() % (10 - 1)) + 1;
				else
					a[k][j] = rand() % 10;
			}
				
		}
		else
		{
			for (int j = 0; j < 3 ; j++)
			{
				if (j == 2)
					a[k][j] = (rand() % (10 - 1)) + 1;
				else
					a[k][j] = rand() % 10;
			}
			a[k][1] = 0;
		}
	}

	wchar_t oprtr[3];

	for (int p = 0; p < i-1; p++)
	{
		int u = rand() % 4;
		if (u == 0)
			oprtr[p] = L‘+‘;
		else if(u==1)
			oprtr[p] = L‘-‘;
		else if (u == 2)
			oprtr[p] = L‘ב;
		else 
			oprtr[p] = L‘÷‘;
	}

	int bracketsNum[2];
	if (i == 2)
	{
		bracketsNum[0] = 0;
		bracketsNum[1] = 0;
	}
	else if (i == 3)
	{
		bracketsNum[0] = rand() % 2;
		if (bracketsNum[0] == 0)
			bracketsNum[1] = 0;
		else
			bracketsNum[1] = rand() % 2;
	}
	else
	{
		bracketsNum[0] = rand() % 3;
		if (bracketsNum[0] == 0)
			bracketsNum[1] = 0;
		else if(bracketsNum[0] == 1)
			bracketsNum[1] = rand() % 5;
		else
			bracketsNum[1] = rand() % 4;
	}

	cout << bracketsNum[0] << bracketsNum[1] << endl;

	for (int x = 0; x < i; x++)
	{
		for (int y = 0; y < 3; y++)
		{
			cout << a[x][y];
		}
		cout << endl;
	}	

	Fraction fraction[4];

	for (int z = 0; z < i; z++)
	{
		wstring ex = to_wstring(a[z][0]) + L"\‘" + to_wstring(a[z][1]) + L"/" + to_wstring(a[z][2]);
		Fraction k(ex);
		fraction[z] = k;
		fraction[z].print();
	}

	Expression t(fraction, oprtr, i, bracketsNum);
	cout << "i的值" << i << endl;
	t.toWstring();
	t.CalculateFraction();
	t.print();
	NewExpression = t;

	return t.returnExpressionWstring();
}

Expression ExerciseGenerate::returnExpression()
{
	return NewExpression;
}

数据测试

  1. Exercise.exe -n 10 -r 10测试结果
    技术分享图片
    能够正确生成10条表达式,以及每条表达式的每个项系数都小于10.
  2. Exercise.exe -e Exercise.txt -a Result.txt测试结果
    技术分享图片
    能够正确判断表达式结果是否正确
  3. 增加测试的数据量,将数据量提升至1万
    Exercise.exe -n 10000 -r 60
    技术分享图片
    能够生成10000条表达式
    将其中两条表达式的答案改为错的,测试程序能否判断出两条错误答案。
    技术分享图片

项目总结

结对感受

  1. 第一次利用vs(徐伟浩)和vscode(王煜墉)的插件live share进行远程结对编程,一人写代码,一人复审。
  2. 第一次进行结对编程,效率很低,很不习惯,编程效率有待提高。经常出现两人结对编程,突然一人就掉线了。
  3. 容易出现两人思维发生冲突。
  4. 有效避免低级错误的发生。
  5. 利用远程工具进行结对编程,不能有效的进行沟通(用live share进行结对编程,用微信语音进行交流)。

个人感受

王煜墉

第一次听说这种一人写代码一人复审的编程方式,听老师介绍的时候感觉很有趣。第一次利用live share进行结对编程,一开始真的很不习惯,甚至出现各种翻车,各种掉线
技术分享图片

技术分享图片

事情进展得并没有那么顺利,总有不少的磕磕碰碰,但好在最后也完成了项目。伟浩的代码能力很强,实现了很多复杂的功能,错误也很少。

徐伟浩

  1. 这次结对编程主要是由我编写代码,在设计阶段由于理解错误,开始是打算用运算符重载来写计算的,后来看到是四个操作数,原本写的函数逻辑不能改回来,然后就重写了这部分代码。
  2. 在处理数据是用宽字符去区分分数的/和除号,宽字符网上教程也不多,折腾了好久才写好。
  3. 思路是大家一起想的,但是想象和实现是有区别的,在写的时候遇到了挺多曲折的,有宽字符串wstring读写的问题,还有txt编码的问题,很神奇的是本来txt编码是utf8的,代码读写后变成了ANSI,当时还想了根据txt的编码方式去处理txt,后来发现搞了好久的辨别txt编码方式只能区分ANSI和utf8带BOM的和其他编码方式,弃用这一段。
  4. 总的来说,主要是这次想法太多,没有一种合理实用的处理方法,到处磕磕碰碰。结对编程可以让对方想到不同于自己的想法,对不同的问题有不同的见解,但是我觉得没有达到1+1>2的效率,在使用VS的live share老是掉线,沟通是通过微信或者微信电话,感觉还好,希望下次能做到更好吧。

一个自动生成小学四则运算题目的命令行程序(C++)(王煜墉+徐伟浩)

原文:https://www.cnblogs.com/handsomeyong/p/12700938.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!