结对对对项目
这个作业属于哪个课程 | 软件工程课程 |
---|---|
这个作业要求在哪里 | 个人项目 - 作业 - 计科22级34班 - 班级博客 - 博客园 (cnblogs.com) |
这个作业的目标 | 按照要求写一个四则运算生成器 |
成员一 | 3122004883许億驰 |
任务列表
-
- 创建一个命令行程序,能够生成小学四则运算题目。
-
- 使用
-n
参数控制生成题目的个数。 - 使用
-r
参数控制题目中数值的范围。 - 该参数必须给定,否则程序报错并给出帮助信息。
- 使用
-
- 生成的题目中计算过程不能产生负数。
- 如果存在形如
e1 - e2
的子表达式,那么e1 ≥ e2
。
-
- 生成的题目中如果存在形如
e1 ÷ e2
的子表达式,那么其结果应是真分数。
- 生成的题目中如果存在形如
-
- 每道题目中出现的运算符个数不超过3个。
-
- 程序一次运行生成的题目不能重复。
- 任何两道题目不能通过有限次交换
+
和×
左右的算术表达式变换为同一道题目。
-
- 生成的题目存入执行程序的当前目录下的
Exercises.txt
文件。 - 真分数在输入输出时采用特定格式(如
3/5
和2’3/8
)。
- 生成的题目存入执行程序的当前目录下的
-
- 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的
Answers.txt
文件。 - 真分数的运算结果应符合规范。
- 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的
-
- 程序应能支持一万道题目的生成。
-
- 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。
- 输入参数为
-e <exercisefile>.txt -a <answerfile>.txt
。 - 统计结果输出到文件
Grade.txt
,格式如下:Correct: 5 (1, 3, 5, 7, 9) Wrong: 5 (2, 4, 6, 8, 10)
作业正文
作业仓库地址
效能分析
性能分析中,代码执行时间最长的是
function generateQuestions() {const numQuestions = parseInt(document.getElementById('numQuestions').value, 10);questions = [];answers = [];const questionsDiv = document.getElementById('questions');questionsDiv.innerHTML = '';for (let i = 0; i < numQuestions; i++) {let question, answer;// 随机选择是否包含括号const hasBrackets = Math.random() > 0.5;if (hasBrackets) {question = generateExpressionWithBrackets();} else {question = generateSimpleExpression();}questions.push(question);// 计算答案answer = calculateAnswer(question);answers.push(answer);const questionElement = document.createElement('p');questionElement.innerText = `${i + 1}. ${question} =`;questionsDiv.appendChild(questionElement);}}
设计思路
设计思路是通过一个前端网页来生成、下载、上传和校验小学四则运算题目。以下是对你设计思路的详细解释:
设计思路
用户界面:
创建一个包含输入框和按钮的网页界面,用户可以通过输入框设置生成题目的数量和数值范围。
提供文件上传功能,用户可以上传包含答案和题目的文本文件。
提供按钮用于生成题目、下载题目和答案、以及计算正确率。
生成题目:
用户输入生成题目的数量和数值范围。
程序根据用户输入生成指定数量的四则运算题目,并显示在页面上。
生成的题目可能包含括号和带分数。
下载题目和答案:
用户可以点击按钮下载生成的题目和答案,分别保存为 questions.txt 和 answers.txt 文件。
上传答案和题目文件:
用户可以上传包含答案和题目的文本文件。
程序解析上传的文件,提取题目和答案,并显示在页面上。
计算正确率:
用户上传答案文件后,程序可以计算上传答案的正确率。
程序将正确率和正确/错误的题目编号输出到 grade.txt 文件中。
具体实现步骤
生成题目:
使用 generateQuestions 函数生成题目,根据用户输入的数量和数值范围生成题目。
使用 generateSimpleExpression 和 generateExpressionWithBrackets 函数生成简单的和带括号的表达式。
使用 generateNumber 函数生成自然数或带分数。
计算答案:
使用 calculateAnswer 函数计算表达式的答案。
使用 convertToMathExpression 函数将带分数转换为浮点数以便计算。
下载题目和答案:
使用 downloadQuestions 和 downloadAnswers 函数将生成的题目和答案下载为文本文件。
上传答案和题目文件:
使用 parseAnswersFile 和 parseQuestionsFile 函数解析上传的答案和题目文件。
提取文件内容并显示在页面上。
计算正确率:
使用 calculateAccuracy 函数计算上传答案的正确率。
将正确率和正确/错误的题目编号输出到 grade.txt 文件中。
代码结构
HTML部分:
包含输入框和按钮,用于设置生成题目的数量和数值范围,以及上传和下载文件。
包含一个显示题目的容器。
JavaScript部分:
包含生成题目、计算答案、下载文件、上传文件和计算正确率的函数。
使用 document.getElementById 获取页面元素,使用 FileReader 读取上传的文件。
代码说明
let questions = [];let answers = [];let userAnswers = [];function generateQuestions() {const numQuestions = parseInt(document.getElementById('numQuestions').value, 10);questions = [];answers = [];const questionsDiv = document.getElementById('questions');questionsDiv.innerHTML = '';for (let i = 0; i < numQuestions; i++) {let question, answer;// 随机选择是否包含括号const hasBrackets = Math.random() > 0.5;if (hasBrackets) {question = generateExpressionWithBrackets();} else {question = generateSimpleExpression();}questions.push(question);// 计算答案answer = calculateAnswer(question);answers.push(answer);const questionElement = document.createElement('p');questionElement.innerText = `${i + 1}. ${question} =`;questionsDiv.appendChild(questionElement);}}function generateSimpleExpression() {const num1 = generateNumber();const num2 = generateNumber();const operator = ['+', '-', '*', '/'][Math.floor(Math.random() * 4)];return `${num1} ${operator} ${num2}`;}function generateExpressionWithBrackets() {const num1 = generateNumber();const num2 = generateNumber();const num3 = generateNumber();const operator1 = ['+', '-', '*', '/'][Math.floor(Math.random() * 4)];const operator2 = ['+', '-', '*', '/'][Math.floor(Math.random() * 4)];return `(${num1} ${operator1} ${num2}) ${operator2} ${num3}`;}function generateNumber() {const numSetUp = parseInt(document.getElementById('numSetUp').value, 10);const isFraction = Math.random() > 0.5;if (isFraction) {const numerator = Math.floor(Math.random() * 10) + 1;const denominator = Math.floor(Math.random() * 10) + 1;return convertToMixedNumber(`${numerator}/${denominator}`);} else {return Math.floor(Math.random() * numSetUp).toString();}}function convertToMixedNumber(fraction) {const [numerator, denominator] = fraction.split('/').map(Number);const integerPart = Math.floor(numerator / denominator);const remainder = numerator % denominator;if (integerPart === 0) {return fraction;}else if (remainder ===0){return integerPart;} else {return `${integerPart}'${remainder}/${denominator}`;}}function calculateAnswer(expression) {// 使用 eval 计算表达式,注意 eval 的安全性问题try {return eval(convertToMathExpression(expression));} catch (e) {return 'Error';}}function convertToMathExpression(expression) {// 将带分数转换为浮点数return expression.replace(/(\d+)'(\d+)\/(\d+)/g, (match, p1, p2, p3) => parseFloat(p1) + parseFloat(p2) / parseFloat(p3));}function downloadQuestions() {if (questions.length === 0) {alert('请先生成题目!');return;}const questionsText = questions.map((q, i) => `${i + 1}. ${q}`).join('\n');const allText = `题目:\n${questionsText}\n`;const blob = new Blob([allText], { type: 'text/plain' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'questions.txt';document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);}function downloadAnswers() {if (answers.length === 0) {alert('请先生成题目!');return;}const answersText = answers.map((a, i) => `${i + 1}. ${a}`).join('\n');const allText = `答案:\n${answersText}\n`;const blob = new Blob([allText], { type: 'text/plain' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'answers.txt';document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);}function parseAnswersFile(file) {userAnswers = [];const reader = new FileReader();reader.onload = function(event) {const content = event.target.result;const lines = content.split('\n').map(line => line.trim()).filter(line => line);const answersText = lines.join('\n');userAnswers = answersText.replace(/^答案:\n/, '').split('\n').map(line => line.trim().split('. ')[1]).filter(line => line);};reader.readAsText(file);}function parseQuestionsFile(file) {questions = [];const reader = new FileReader();reader.onload = function(event) {const content = event.target.result;const lines = content.split('\n').map(line => line.trim()).filter(line => line);const answersText = lines.join('\n');questions = answersText.replace(/^题目:\n/, '').split('\n').map(line => line.trim().split('. ')[1]).filter(line => line);const questionsDiv = document.getElementById('questions');questionsDiv.innerHTML = '';// 显示题目questions.forEach((question) => {const questionElement = document.createElement('p');questionElement.innerText = `${question}=`;questionsDiv.appendChild(questionElement);});// 计算答案questions.forEach((question) => {const answer = calculateAnswer(question);answers.push(answer);});};reader.readAsText(file);}function calculateAccuracy(userAnswers) {let rightGrade = [];let wrongGrade = [];if (userAnswers.length === 0) {alert('请先上传答案文件!');return;}if (answers.length === 0) {alert('请先生成题目!');return;}let correctCount = 0;for (let i = 0; i < answers.length; i++) {if (parseFloat(userAnswers[i]) === answers[i]) {rightGrade.push(i + 1);correctCount++;}else {wrongGrade.push(i + 1);}}const accuracy = (correctCount / answers.length) * 100;alert(`正确率: ${accuracy.toFixed(2)}%`);grade = `正确题目:${rightGrade.join(', ')}\n错误题目:${wrongGrade.join(', ')}\n正确率: ${accuracy.toFixed(2)}%\n`;const blob = new Blob([grade], { type: 'text/plain' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'grade.txt';document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);}
测试运行
运行效果
PSP表格如下
2.在PSP表格[附录2]记录下你估计在程序开发各个步骤上耗费的时间
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 70 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 35 |
Development | 开发 | 240 | 260 |
· Analysis | · 需求分析(包括学习新技术) | 45 | 50 |
· Design Spec | · 生成设计文档 | 40 | 45 |
· Design Review | · 设计复审 | 30 | 35 |
· Coding Standard | · 代码规范(为目前的开发制定合适的规范) | 20 | 25 |
· Design | · 具体设计 | 50 | 55 |
· Coding | · 具体编码 | 100 | 110 |
· Code Review | · 代码复审 | 25 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 40 |
Reporting | 报告 | 60 | 65 |
· Test Report | · 测试报告 | 20 | 25 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结,并提出过程改进计划 | 20 | 30 |
合计 | 360 | 400 |
项目小结
-
在本次结对编程项目中,我们共同开发了一个小学四则运算生成器。该程序能够生成指定数量和数值范围的四则运算题目,支持带分数和括号的表达式,并能够下载题目和答案文件,上传答案文件进行校验,计算正确率。
-
结对编程能够提高代码质量,减少错误。两个人可以互相监督,及时发现和解决问题。
-
结对编程能够提高开发效率,两个人可以分工合作,共同完成任务。