当前位置: 首页 > news >正文

软件工程结对项目-小学四则运算题目生成与判题程序

软件工程结对项目-小学四则运算题目生成与判题程序

软件工程结对项目

一、项目参与成员

计算机科学与技术3班 许晓喆 3223004302

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13477
这个作业目标 实现一个自动生成小学四则运算题目的命令行程序

PSP表格

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

二、设计实现

  1. 数据结构设计
    分数类(Fraction):处理真分数的表示、运算(加、减、乘、除)、约分和格式化输出。
    属性:integer(带分数的整数部分,默认 0)、numerator(分子)、denominator(分母,默认 1)。
    方法:add、subtract、multiply、divide(分数运算)、reduce(约分)、toString(格式化输出,如2’3/8)、compare(比较大小)。
    表达式类(Expression):处理表达式生成、计算和去重。
    属性:exprStr(表达式字符串)、result(计算结果,Fraction类型)。
    方法:generate(生成随机表达式)、calculate(计算结果)、isDuplicate(判断与其他表达式是否重复,考虑+和×的交换律)。
  2. 模块划分
    命令行解析模块:处理-n、-r、-e、-a等参数,控制程序流程。
    题目生成模块:调用Expression类生成满足约束的题目,确保不重复。
    文件操作模块:读写Exercises.txt、Answers.txt、Grade.txt。
    批改模块:对比题目文件和答案文件,统计对错。

三、代码实现(Python 示例)

  1. 分数类(Fraction.py)
点击查看代码
class Fraction:def __init__(self, numerator=0, denominator=1, integer=0):self.integer = integerself.numerator = numeratorself.denominator = denominatorself._normalize()self.reduce()def _normalize(self):if self.numerator >= self.denominator:self.integer += self.numerator // self.denominatorself.numerator = self.numerator % self.denominatorif self.integer != 0 and self.numerator == 0:self.denominator = 1def reduce(self):def gcd(a, b):while b:a, b = b, a % breturn ag = gcd(self.numerator, self.denominator)if g != 0:self.numerator //= gself.denominator //= gdef add(self, other):new_denominator = self.denominator * other.denominatornew_numerator = self.numerator * other.denominator + other.numerator * self.denominatornew_integer = self.integer + other.integerreturn Fraction(new_numerator, new_denominator, new_integer)def subtract(self, other):new_denominator = self.denominator * other.denominatornew_numerator = self.numerator * other.denominator - other.numerator * self.denominatornew_integer = self.integer - other.integerreturn Fraction(new_numerator, new_denominator, new_integer)def multiply(self, other):new_numerator = (self.integer * self.denominator + self.numerator) * (other.integer * other.denominator + other.numerator)new_denominator = self.denominator * other.denominatorreturn Fraction(new_numerator, new_denominator).reduce()def divide(self, other):if other.numerator == 0:raise ValueError("除数不能为0")new_numerator = (self.integer * self.denominator + self.numerator) * other.denominatornew_denominator = self.denominator * (other.integer * other.denominator + other.numerator)return Fraction(new_numerator, new_denominator).reduce()def toString(self):if self.integer != 0 and self.numerator != 0:return f"{self.integer}’{self.numerator}/{self.denominator}"elif self.integer != 0:return f"{self.integer}"elif self.numerator != 0:return f"{self.numerator}/{self.denominator}"else:return "0"@staticmethoddef fromString(s):if "'" in s:integer_part, frac_part = s.split("’")numerator, denominator = frac_part.split("/")return Fraction(int(numerator), int(denominator), int(integer_part))elif "/" in s:numerator, denominator = s.split("/")return Fraction(int(numerator), int(denominator), 0)else:return Fraction(0, 1, int(s))def __eq__(self, other):self._normalize()other._normalize()return (self.integer == other.integer andself.numerator == other.numerator andself.denominator == other.denominator)def compare(self, other):self_val = self.integer * self.denominator + self.numeratorother_val = other.integer * other.denominator + other.numeratorself_total = self_val * other.denominatorother_total = other_val * self.denominatorif self_total > other_total:return 1elif self_total == other_total:return 0else:return -1
  1. 表达式生成与计算(Expression.py)
点击查看代码
import random
from Fraction import Fractionclass Expression:def __init__(self, range_val):self.range_val = range_valself.expr_str = ""self.result = Fraction()self.operators = []def generate_number(self):is_fraction = random.choice([True, False])if is_fraction:denominator = random.randint(2, self.range_val)numerator = random.randint(1, denominator - 1)is_mixed = random.choice([True, False])if is_mixed:integer = random.randint(1, self.range_val - 1)return Fraction(numerator, denominator, integer)else:return Fraction(numerator, denominator, 0)else:return Fraction(0, 1, random.randint(0, self.range_val - 1))def generate_expression(self, depth=0, max_operators=3):if depth == 0 or random.random() < 0.5 or max_operators == 0:num = self.generate_number()self.expr_str = num.toString()self.result = numreturnop = random.choice(["+", "-", "×", "÷"])self.operators.append(op)left = Expression(self.range_val)left.generate_expression(depth + 1, max_operators - 1)right = Expression(self.range_val)right.generate_expression(depth + 1, max_operators - 1)if op == "-":while left.result.compare(right.result) < 0:right.generate_expression(depth + 1, max_operators - 1)if op == "÷":valid = Falsewhile not valid:right.generate_expression(depth + 1, max_operators - 1)left_val = left.result.integer * left.result.denominator + left.result.numeratorright_val = right.result.integer * right.result.denominator + right.result.numeratorif left_val < right_val and (left_val * right.result.denominator) % (right_val * left.result.denominator) == 0:valid = Trueself.expr_str = f"({left.expr_str} {op} {right.expr_str})"if op == "+":self.result = left.result.add(right.result)elif op == "-":self.result = left.result.subtract(right.result)elif op == "×":self.result = left.result.multiply(right.result)elif op == "÷":self.result = left.result.divide(right.result)if depth == 0:self.expr_str = self.expr_str.strip("()")def is_duplicate(self, other):if len(self.operators) != len(other.operators):return Falsedef normalize(expr, ops):parts = []idx = 0for op in ops:part = expr[:expr.index(op)]parts.append(part)expr = expr[expr.index(op) + 1:]parts.append(expr)i = 0while i < len(ops):if ops[i] in ["+", "×"]:j = i + 1while j < len(ops) and ops[j] in ["+", "×"]:j += 1sub_parts = parts[i:i+2]sub_parts.sort()parts[i:i+2] = sub_partsi = jelse:i += 1return parts, opsself_parts, self_ops = normalize(self.expr_str, self.operators)other_parts, other_ops = normalize(other.expr_str, other.operators)return self_parts == other_parts and self_ops == other_ops
  1. 主程序(main.py)
点击查看代码
import argparse
import os
from Expression import Expression
from Fraction import Fractiondef generate_exercises(num, range_val):exercises = []answers = []while len(exercises) < num:expr = Expression(range_val)expr.generate_expression()duplicate = Falsefor e in exercises:if expr.is_duplicate(e):duplicate = Truebreakif not duplicate:exercises.append(expr)answers.append(expr.result.toString())with open("Exercises.txt", "w", encoding="utf-8") as f:for i, e in enumerate(exercises, 1):f.write(f"{e.expr_str} =\n")with open("Answers.txt", "w", encoding="utf-8") as f:for a in answers:f.write(f"{a}\n")def parse_expression(expr_str):expr_str = expr_str.replace(" ", "")def tokenize(s):tokens = []i = 0while i < len(s):if s[i] in "()+-×÷":tokens.append(s[i])i += 1elif s[i].isdigit() or s[i] in "’/":j = iwhile j < len(s) and (s[j].isdigit() or s[j] in "’/"):j += 1tokens.append(s[i:j])i = jelse:i += 1return tokenstokens = tokenize(expr_str)def parse(tokens):def parse_primary():token = tokens.pop(0)if token == "(":expr = parse(tokens)if tokens.pop(0) != ")":raise SyntaxError("Mismatched parentheses")return exprelse:return Fraction.fromString(token)def parse_term():left = parse_primary()while tokens and tokens[0] in "×÷":op = tokens.pop(0)right = parse_primary()if op == "×":left = left.multiply(right)else:left = left.divide(right)return leftleft = parse_term()while tokens and tokens[0] in "+-":op = tokens.pop(0)right = parse_term()if op == "+":left = left.add(right)else:left = left.subtract(right)return leftreturn parse(tokens)def grade_exercises(exercise_file, answer_file):with open(exercise_file, "r", encoding="utf-8") as f:exercises = [line.strip().replace(" =", "") for line in f if line.strip()]with open(answer_file, "r", encoding="utf-8") as f:answers = [line.strip() for line in f if line.strip()]correct = []wrong = []for i in range(min(len(exercises), len(answers))):try:calculated = parse_expression(exercises[i])expected = Fraction.fromString(answers[i])if calculated == expected:correct.append(i + 1)else:wrong.append(i + 1)except:wrong.append(i + 1)with open("Grade.txt", "w", encoding="utf-8") as f:f.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")f.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")if __name__ == "__main__":parser = argparse.ArgumentParser(description="小学四则运算题目生成程序")parser.add_argument("-n", type=int, help="生成题目的个数")parser.add_argument("-r", type=int, help="数值范围(必须提供)")parser.add_argument("-e", type=str, help="题目文件路径")parser.add_argument("-a", type=str, help="答案文件路径")args = parser.parse_args()if args.e and args.a:grade_exercises(args.e, args.a)elif args.n and args.r:generate_exercises(args.n, args.r)else:parser.error("请提供正确的参数组合(-n和-r,或-e和-a)")

四、测试用例

1.功能测试:基本生成

  • 命令:python main.py -n 5 -r 5
  • 预期:生成 5 道 5 以内的题目,无负数、除法结果为真分数,运算符≤3 个,无重复。
    2.边界测试:r=1
  • 命令:python main.py -n 3 -r 1
  • 预期:仅能生成自然数 0 的运算(如0 + 0 =、0 × 0 =)。
    3.去重测试
  • 生成题目后,检查Exercises.txt中无2+3=和3+2=同时出现的情况。
    4.批改功能测试
  • 手动修改Answers.txt中的答案,运行python main.py -e Exercises.txt -a Answers.txt,检查Grade.txt统计是否正确。
    5.大规模测试
  • 命令:python main.py -n 10000 -r 20
  • 预期:成功生成 1 万道题,无内存溢出,文件写入正常。
http://www.hskmm.com/?act=detail&tid=35958

相关文章:

  • 2025年上海装修公司电话推荐:极家与俞润本土双选参考
  • 2025上海装修公司电话推荐:极家与俞润实测对比。
  • 教科书上令人触动的话
  • 生日
  • 2025 年防淹门源头厂家最新推荐排行榜权威发布,含地铁 / 防洪 / 地下通道专用款,15 项专利 + 央视报道品牌领衔
  • 2025年防静电/劳保/国网/餐厅/工厂/电工/防酸碱/电力/车间/航空/员工广告衫,文化衫/t恤/polo衫/冲锋衣厂家推荐排行榜
  • 一文带你掌握Visual Studio中集成的git功能
  • 【往届已检索!稳定检索】2025年第二届人工智能、数字媒体技术与交互设计国际学术会议(ICADI 2025)
  • 苹果最折腾的功能!iPhone快捷指令分享
  • 单提交智能评审上线!用云效精准定位复杂 MR 代码问题
  • GitLab小坑:remote: GitLab: You are not allowed to create protected branches on this project.
  • ubuntu安装nvidia驱动 - Leonardo
  • 2025 年少儿英语品牌口碑排行榜最新发布:欧美外教 + 原版教材甄选,含最新推荐及靠谱选择指南
  • 2025年滑石粉厂家推荐排行榜,纳米级滑石粉,工业级滑石粉,黑色滑石粉,高白滑石粉,化妆品级滑石粉,食品级滑石粉,表面改性滑石粉,大片径比滑石粉,低收缩率滑石粉,高填充母粒滑石粉
  • 自动化智能体与测试用例生成
  • 设置某些网站不走代理
  • 2025 年试验箱厂家最新推荐排行榜:涵盖高低温 / 恒温恒湿 / 冷热冲击等设备,精选实力厂商助力企业选购
  • 2025年除尘设备厂家权威推荐榜:除尘器,脉冲除尘器,中央脉冲除尘器,工业除尘器源头企业综合测评与选购指南
  • 2025 年国内充电桩厂家最新推荐排行榜:技术、安全与服务全方位对比的优质供应商优选榜单
  • 2025年最新游戏机和游艺机的屏幕驱动方案(含音乐播放和功放芯片)
  • 2025 年最新推荐!国内加工厂家排行榜:含车铣复合 / 精密零件 / CNC 车床等领域优质企业
  • spring是怎么解决循环依赖的?
  • 2025年精密球轴承厂家权威推荐榜:半导体设备/加工中心/机床主轴/直联主轴/电主轴/定制/国产高端/不锈钢/陶瓷/耐腐蚀/超高真空/真空泵/晶圆搬运机械手臂/进口替代/国产半导体/低温泵轴承精选
  • 【安徽财经大学主办】第七届管理科学信息化与经济创新发展国际学术会议 (MSIEID 2025)
  • 2025 盐城美术培训机构最新推荐榜单:涵盖全龄段课程 + 4A 信用单位,优质机构助你精准选课
  • ACCL和NCCL对比
  • 凌晨 2 点的朋友圈,她靠微擎实现了 “带娃赚钱两不误”
  • git pull中有 merge功能解释
  • 先收藏系列 工业相机的八问八答!
  • 2025年信息流代运营服务商权威推荐榜:专业投放策略与高转化效果深度解析,助力品牌精准营销