♥软工结对作业♥
结对成员:萨伊拜 3221005241
阿比旦 3221005195
一、作业题目及要求:
作业题目 | 实现一个自动生成小学四则运算题目的命令行程序 |
---|---|
作业需求 | 博客园-flowet |
二、 程序实现:
项目代码
总体流程图
- 命令行参数解析和选项处理:
1.1 设计思路:
-
这个模块的目标是解析命令行参数并根据参数执行相应的功能。使用getopt库来解析参数。
1.2 关键步骤:
-
导入getopt和sys模块。
-
定义默认的参数值,如n_default(题目数量,默认为10)、r_default(数值范围,默认为10)、input_np(题目文件路径,默认为空)、input_rp(答案文件路径,默认为空)、back(是否需要回退,默认为1,表示不需要回退)。
-
使用getopt.getopt函数解析命令行参数,接受用户提供的参数和选项。
-
根据选项的不同,更新相应的参数变量,例如n_default和r_default。
-
如果用户提供了-e和-a选项,表示需要执行批改操作,并记录题目文件和答案文件的路径。
-
返回解析后的参数值供后续模块使用。
代码如下
n_default = 10 # 默认题目数量
r_default = 10 # 默认数值范围
try:
input_np= '' # 题目文件
input_rp = '' # 答案文件
opts, args = getopt.getopt(argv, "hgn:r:e:a:", ["ifile=", "ofile="])
except getopt.GetoptError:
print('输入错误: \n 请按以下格式输入:-n num -r num / -e -a \n(可输入参数-h输出帮助信息)')
sys.exit(2)
2.1 设计思路:
-
这个模块的目标是生成满足题目要求的四则运算题目和对应的答案。
2.2 关键步骤:
-
定义makeproblem(n_num,r_num)函数,接受用户指定的题目数量n_num和数值范围r_num。
-
创建两个空列表exercises_txt和answers_txt,用于存储生成的题目和答案。
-
使用循环生成指定数量的题目,每次生成一个题目和对应的答案。
-
在生成题目时,确保题目满足要求,包括数值范围、运算符个数、运算过程不产生负数等。
-
计算生成题目的答案。
-
将生成的题目和答案分别添加到exercises和answers列表中。
-
并将题目和答案存到TXT文件中
-
返回生成的题目和答案列表供后续模块使用。
查看代码
def makeproblem(n_num, r_num):
Exercises_txt = open('Exercises' + '.txt', "w", encoding='utf-8')
Answers_txt = open('Answers' + '.txt', "w", encoding='utf-8')
getmain = Rmain(r_num, n_num)
for i in range(len(getmain[0])):
Exercises_txt.write(str(i + 1) + ". " + getmain[0][i] + '\n')
Answers_txt.write(str(i + 1) + ". " + getmain[1][i] + '\n')
print('正在生成算式...')
Exercises_txt.close()
Answers_txt.close()
print("已生成" + str(n_num) + "个题目,其中题目中的数值(自然数、真分数和真分数分母)的范围在[0," + str(r_num) + "]")
return getmain
- 批改题目和答案:
3.2 设计思路:
-
这个模块的目标是批改题目和答案,并输出批改结果。
3.2 关键步骤:
-
定义check_exercises_and_answers函数,接受题目列表exercises和答案列表answers。
-
初始化正确题目数量correct_count为0,正确题目的编号列表correct_indices为空,错误题目数量wrong_count为0,错误题目的编号列表wrong_indices为空。
-
使用循环遍历题目列表和答案列表,逐个比对题目的用户答案和正确答案。
-
如果用户答案与正确答案一致,将correct_count增加1,并将题目的编号添加到correct_indices列表中。
-
如果用户答案与正确答案不一致,将wrong_count增加1,并将题目的编号添加到wrong_indices列表中。
-
返回正确题目数量、正确题目的编号列表、错误题目数量和错误题目的编号列表供后续模块使用。
查看代码
def jianchadaan(file1, file2):
try:
question_path = open(file1, 'r', encoding='utf-8')
question_text = question_path.read()
except IOError:
print("读取失败".format(file1))
else:
try:
answer_path = open(file2, 'r', encoding='utf-8')
answer_text = answer_path.read()
except IOError:
print("读取失败".format(file2))
else:
q_spilt = re.split('\n', question_text)
a_spilt = re.split('\n', answer_text)
q_spilt = [i for i in q_spilt if i != '']
a_spilt = [i for i in a_spilt if i != '']
q_spilt = renameaq(q_spilt)
a_spilt = renameaq(a_spilt)
if (len(q_spilt) == len(a_spilt)):
print("正在检查问题答案对错.....\n" + "\n问题来源:" + file1 +
"\n答案来源:" + file2 + "\n即将批改" + str(len(q_spilt)) + "道题目\n\n")
# print('检查题目: 已检查' + str(len(q_spilt)) + '道题目')
aq_dict = dict(zip(q_spilt, a_spilt))
checkanswers = checkAnswers(aq_dict)
wrong_list = wrongAnswers(aq_dict)
correct_str = "Correct: " + str(len(checkanswers)) + '(' + ",".join(
str(i) for i in checkanswers) + ')'
wrong_str = " Wrong: " + str(len(wrong_list)) + '(' + ",".join(str(i) for i in wrong_list) + ')'
print(correct_str + wrong_str + "\n正确率:" + str(
round((len(q_spilt) - len(wrong_list)) / len(q_spilt),
2)))
getdown = pigaijieguo(aq_dict)
Grade_txt = open('Grade' + '.txt', "w", encoding='utf-8')
Grade_txt.write(getdown)
Grade_txt.close()
else:
print("题目总数和答案总数不相等:\n题目个数" + str(len(q_spilt)) + "\n答案个数:" + str(
len(a_spilt)) + "\n请检查上传的问题答案文件n\n")
4.2 关键步骤:
- 根据需要编写函数来处理真分数的表示、进行四则运算的计算、获取当前时间等功能。
- 这些函数可以在不同的地方被调用,以提高代码的可维护性和可读性。
查看代码
def get_current_time():
current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
return current_time
def renameaq(aq):
last_aq = []
for change in aq:
print(change)
last_aq.append("".join(str(i) for i in pro_suanshi(change)))
return last_aq
5.2 关键步骤:
- 在程序中使用try和except语句来捕获和处理可能的异常。
- 根据不同的异常类型采取相应的处理措施,例如打印错误信息、终止程序等。
- 在关键的文件读写操作前后加入异常处理机制,以防止文件不存在或无法读写的情况。
查看代码
try: input_np= '' # 题目文件 input_rp = '' # 答案文件 opts, args = getopt.getopt(argv, "hgn:r:e:a:", ["ifile=", "ofile="]) except getopt.GetoptError: print('输入错误: \n 请按以下格式输入:-n num -r num / -e -a \n(可输入参数-h输出帮助信息)') sys.exit(2) for opt, arg in opts: if opt == '-h': print( " 程序指令说明\n-n <数字>(大于0) ,指定生成题目的数量,默认为10" "\n-r <数字>(大于0) ,指定题目中数值范围,默认[0,10]" "\n-e
.txt -a .txt 对给定的题目文件和答案文件,判定答案中的对错并进行数量统计 ") sys.exit(2) elif opt in ("-n", "--num"): n_default = arg elif opt in ("-r", "--range"): r_default= arg elif opt in ("-e", "--question"): input_np= arg elif opt in ("-a", "--answer"): input_rp = arg if (input_np == '' and input_rp == ''): makeproblem(n_default, r_default) else: jianchadaan(input_np ,input_rp)
6. 帮助信息:
6.1 设计思路:
-
在命令行参数解析模块中提供帮助信息,解释每个选项的用途和格式。
6.2 关键步骤:
-
在解析命令行参数时,如果用户提供了-h选项,则打印帮助信息,并提供程序的使用说明。
-
帮助信息应包括每个选项的说明,以便用户了解如何正确使用程序。
查看代码
if opt == '-h':
print(
" 程序指令说明\n-n <数字>(大于0) ,指定生成题目的数量,默认为10"
"\n-r <数字>(大于0) ,指定题目中数值范围,默认[0,10]"
"\n-e .txt -a .txt 对给定的题目文件和答案文件,判定答案中的对错并进行数量统计 ")
sys.exit(2)
7.2 关键步骤:
- 在if name == 'main':中调用parse_command_line_arguments函数解析命令行参数,获取各个选项的值。
- 根据back的值,判断用户是要生成题目还是批改题目,并执行相应的操作。
- 如果生成题目,调用generate_exercises_and_answers函数生成题目和答案,并保存到文件。
- 如果批改题目,调用check_exercises_and_answers函数批改题目和答案,并输出批改结果到文件。
查看代码
if __name__ == '__main__':
main(sys.argv[1:])
# jianchadaan('1.txt','2.txt')
import cProfile
import re
#
cProfile.run('re.compile("foo|bar")')
三、 程序结果:
-
使用 -n 参数控制生成题目的个数
-
使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围
-
在生成题目的同时计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件
4.生成一万道题目
5.程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计
四、 PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 180 | 150 |
Estimate | 估计这个任务需要多少时间 | 180 | 150 |
Development | 开发 | 50 | 60 |
Analysis | 需求分析 (包括学习新技术) | 30 | 30 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 (和同事审核设计文档) | 20 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
Design | 具体设计 | 30 | 50 |
Coding | 具体编码 | 30 | 40 |
Code Review | 代码复审 | 20 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 10 | 10 |
Reporting | 报告 | 30 | 30 |
Test Report | 测试报告 | 10 | 20 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 660 | 640 |
五、 总结与体会
通过这次结对编程项目,我深刻体会到了合作与协作的力量,这些体会对个人和团队都有着重要的意义:
1)团队协作的重要性:在项目中,与队友紧密协作的重要性变得非常明显。良好的协作可以提高项目的效率,减少误解和偏差,确保项目朝着正确的方向前进。不断的交流、分享思路和问题解决对于团队的成功至关重要。
2)分工与互补:合理的角色分工是项目成功的关键。根据队友的技能和兴趣,可以将任务分配得更合理。这样可以充分发挥每个人的专长,提高项目的质量和效率。同时,不同背景和经验的人在项目中可以相互补充,带来更多创新和多样性。
3)问题解决和学习:在项目中,我们遇到了各种各样的挑战和问题。与队友一起解决这些问题是一次宝贵的学习机会。通过合作,我们能够共同寻找解决方案,学习新的知识和技能,不断提高自己的能力。
4)沟通与理解:良好的沟通是协作的基础。在项目中,我学会了更加积极地倾听队友的意见,表达自己的想法,并确保信息的传递是清晰和明确的。这有助于避免误解和提高工作效率。
5)团队凝聚力:共同努力完成一个项目可以增强团队的凝聚力。互相支持、鼓励和分享成功是建立友谊和信任的途径。我们为共同取得的成就感到自豪,这种成就感可以持续激励我们继续前进。
6)成果展示与分享:完成项目后,我们有机会展示和分享自己的成果。这不仅是对我们努力工作的认可,也是向他人展示我们的能力和经验。同时,分享经验也有助于其他人学习和成长。
总的来说,结对编程项目为我提供了一个宝贵的机会,不仅在技术层面有所收获,还锻炼了团队协作、沟通和问题解决的能力。通过与队友共同努力,我不仅学到了更多知识,还建立了深厚的友谊,这将对我的职业生涯产生长远的影响。