• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
GreatestFox
博客园    首页    新随笔    联系   管理    订阅  订阅
结对编程——四则运算练习题

项目介绍

项目引言

      在学习编程的道路上,理论知识与实践项目相辅相成,而结对编程更是加速成长、深化理解的有效方式,对于两个可能编程风格和速度截然不同的人,想要共同完成一个项目就不得不需要沟通、设计和互相借鉴学习。近期,我与搭档(学号2352313)携手合作,共同完成了一个 C++ 编写的四则运算测验程序。通过两人思维的碰撞与技术的互补,我们不仅巩固了 C++ 编程的各类知识,还收获了团队协作的宝贵经验。该程序能够生成包含两个运算符的四则运算题目,引导用户进行答题,并在测验结束后给出得分与个性化评价,是一个兼具实用性与学习价值的小项目。接下来,我将详细分享我们在结对编程过程中的设计思路、代码实现与实践感悟 。

功能需求

      1.能够随机生成包含两个运算符的四则运算题目,运算符包括加、减、乘、除。

      2.确保生成的题目符合数学规则,例如除数不能为零,减法结果不能为负数,除法结果必须为整数。

      3.能够让用户输入答案,并判断答案是否正确。

      4.记录用户的正确答题数量,并计算得分。

      5.根据用户的得分给出相应的评价。

用户需求

      1.在学校教育体系中,四则运算是数学学科最基础且重要的内容。小学阶段,学生需要通过大量练习来熟练掌握整数的加减乘除运算,打好数学基础;初中阶段,运算的复杂性提升,包含小数、分数等类型,对运算的准确性和速度都有更高要求。此程序可以为学生提供个性化的练习方式,学生通过输入题目数量,能够自主安排学习强度,在课后进行针对性的训练,从而提高课堂知识的掌握程度,在考试中取得更好成绩。同时,程序即时反馈答案正误和最终得分评价的功能,能让学生快速了解自己的学习效果,及时发现知识薄弱点。

      2.教师在教学过程中,常常需要为学生布置适量的四则运算练习题。传统方式下,教师需要手动编写题目,耗时耗力。使用本程序,教师可以根据教学进度和学生的实际水平,输入合适的题目数量,快速生成大量符合要求的四则运算题目,用于课堂练习、课后作业或测验。而且,程序统一的评分和评价标准,也能为教师评估学生学习情况提供参考,减轻教师的教学负担,提高教学效率。

      3.家长在辅导孩子学习四则运算时,往往缺乏系统的练习资源。借助这个程序,家长可以根据孩子的学习状态和能力,灵活调整题目数量,为孩子制定专属的学习计划。在孩子完成练习后,家长能够通过程序给出的得分和评价,直观了解孩子的学习效果,有针对性地进行辅导和强化训练,助力孩子提升数学运算能力。

设计思路

整体架构

      程序采用面向对象的设计思想,将主要功能封装在 MathQuiz 类中。MathQuiz 类包含了随机数生成、题目生成、计算结果、运行测验等功能。main 函数负责与用户交互,获取用户输入的题目数量,并调用 MathQuiz 类的 runQuiz 方法开始测验。

数据结构

      使用 std::mt19937 作为随机数生成器,确保生成的随机数具有较好的随机性。

      使用 std::vector<char> 存储运算符,方便随机选择运算符。

      使用 std::stringstream 来拼接题目字符串。

算法设计

      随机数生成:使用 std::uniform_int_distribution 生成 1 到 100 之间的随机整数。

      题目生成:通过循环不断生成随机的运算符和操作数,直到生成的题目符合数学规则和结果范围要求。

      结果计算:根据运算符的优先级,先计算乘法和除法,再计算加法和减法。

代码实现

代码设计

以下是该项目的代码设计:

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <ctime>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <limits> 

class MathQuiz {
private:
    std::mt19937 rng;
    const std::vector<char> operators{ '+', '-', '*', '/' };

    int randomNum() {
        std::uniform_int_distribution<int> dist(1, 100);
        return dist(rng);
    }

    bool isDivisible(int a, int b) {
        return (b != 0) && (a % b == 0);
    }

    int calculateResult(int num1, char op1, int num2, char op2, int num3) {
        int part1, part2, result;

        if ((op1 == '+' || op1 == '-') && (op2 == '*' || op2 == '/')) {
            part2 = (op2 == '*') ? num2 * num3 : num2 / num3;
            result = (op1 == '+') ? num1 + part2 : num1 - part2;
        }
        else {
            switch (op1) {
            case '+': part1 = num1 + num2; break;
            case '-': part1 = num1 - num2; break;
            case '*': part1 = num1 * num2; break;
            case '/': part1 = num1 / num2; break;
            }
            switch (op2) {
            case '+': result = part1 + num3; break;
            case '-': result = part1 - num3; break;
            case '*': result = part1 * num3; break;
            case '/': result = part1 / num3; break;
            }
        }
        return result;
    }

public:
    MathQuiz() {
        rng.seed(std::time(nullptr));
    }

    // 修改了返回类型,避免使用结构化绑定
    void generateProblem(std::string& problem, int& answer) {
        int num1, num2, num3;
        char op1, op2;
        bool valid;

        do {
            valid = true;
            std::uniform_int_distribution<int> opDist(0, 3);
            op1 = operators[opDist(rng)];
            op2 = operators[opDist(rng)];

            num1 = randomNum();
            num2 = randomNum();
            num3 = randomNum();

            if (op1 == '/' && !isDivisible(num1, num2)) {
                valid = false;
                continue;
            }

            if (op2 == '/') {
                if (op1 == '+' || op1 == '-') {
                    int temp = (op1 == '+') ? num1 + num2 : num1 - num2;
                    if (!isDivisible(temp, num3)) {
                        valid = false;
                        continue;
                    }
                }
                else {
                    if (!isDivisible(num2, num3)) {
                        valid = false;
                        continue;
                    }
                }
            }

            if (op1 == '-' && num1 < num2) {
                valid = false;
                continue;
            }

            if (op2 == '-') {
                if (op1 == '+' || op1 == '-') {
                    int temp = (op1 == '+') ? num1 + num2 : num1 - num2;
                    if (temp < num3) {
                        valid = false;
                        continue;
                    }
                }
                else {
                    if (num2 < num3) {
                        valid = false;
                        continue;
                    }
                }
            }

            answer = calculateResult(num1, op1, num2, op2, num3);
            if (answer < 0 || answer > 1000) {
                valid = false;
            }

        } while (!valid);

        std::stringstream ss;
        ss << num1 << " " << op1 << " " << num2 << " " << op2 << " " << num3;
        problem = ss.str();
    }

    void runQuiz(int numProblems) {
        int correctAnswers = 0;

        std::cout << "\n四则运算测验开始!共 " << numProblems << " 题。\n\n";

        for (int i = 0; i < numProblems; ++i) {
            std::string problem;
            int answer;
            generateProblem(problem, answer);  // 修改了调用方式

            int userAnswer;
            std::cout << "第 " << i + 1 << " 题: " << problem << " = ? ";

            while (!(std::cin >> userAnswer)) {
                std::cout << "请输入一个有效的整数: ";
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            }
            std::cin.ignore();  // 清除换行符

            if (userAnswer == answer) {
                std::cout << "✓ 正确!\n";
                correctAnswers++;
            }
            else {
                std::cout << "✗ 错误!正确答案是: " << answer << "\n";
            }
            std::cout << std::endl;
        }

        double score = static_cast<double>(correctAnswers) / numProblems * 100;
        std::cout << "测验结束!\n";
        std::cout << "你的得分: " << correctAnswers << "/" << numProblems
            << " (" << std::fixed << std::setprecision(1) << score << "%)\n";

        if (score == 100) {
            std::cout << "六百六十六你真的会做\n";
        }
        else if (score >= 80) {
            std::cout << "有点东西,但不多\n";
        }
        else if (score >= 60) {
            std::cout << "一般\n";
        }
        else {
            std::cout << "纯飞舞,菜就多练\n";
        }
    }
};

int main() {
    MathQuiz quiz;
    int numProblems;

    std::cout << "四则运算练习题与测验系统\n";
    std::cout << "请输入要回答的题目数量: ";
    std::cin >> numProblems;

    if (std::cin.fail() || numProblems <= 0) {
        std::cerr << "请输入一个有效的正整数" << std::endl;
        return 1;
    }

    quiz.runQuiz(numProblems);
    return 0;
}

代码解释

MathQuiz 类:

      rng:随机数生成器。

      operators:存储运算符的向量。

      randomNum 方法:生成 1 到 100 之间的随机整数。

      isDivisible 方法:判断两个数是否可以整除。

      calculateResult 方法:根据运算符的优先级计算表达式的结果。

      generateProblem 方法:生成符合规则的四则运算题目,并计算结果。

      runQuiz 方法:运行测验,显示题目,获取用户答案,判断答案是否正确,并计算得分和评价。

main 函数:

      创建 MathQuiz 对象。

      获取用户输入的题目数量。

      调用 runQuiz 方法开始测验。

测试与调试

1.当使用者点下开始运行后,出现用户界面,输入需要生成的题目数量

2.在输入题目数量后,将分别输出题目,请使用者回答

3.在每道题做完之后,都会判断正确与否,并输出相应的答案

4.在做完题目后,会输出总正确率,以及一句评价

5.其他评价如下:

问题与解决:

1.题目生成的逻辑复杂度问题
      在生成包含两个运算符的四则运算题目时,需要同时满足多种规则,如除法的整除性、减法结果非负性,还要处理运算符优先级。最初代码逻辑混乱,导致生成的题目经常出现不符合要求的情况,且难以排查错误。
解决方法:

      将题目生成的逻辑拆分为多个独立的函数,如randomNum()用于生成随机数,isDivisible()检查整除性,calculateResult()计算表达式结果。通过函数模块化,降低了代码耦合度,提高了可读性和可维护性。

      采用do-while循环结构,在循环中不断生成新的题目并进行规则检查,直到生成符合所有要求的题目。同时,在每次循环中添加详细的continue条件判断,及时排除不符合规则的中间结果,减少无效计算。

2. 用户输入异常处理不全面

      当用户输入非整数内容时,程序会陷入错误状态,无法继续正常运行。此外,用户可能输入负数或过大的题目数量,也会导致程序异常。
解决方法:
      在获取用户输入题目数量时,使用std::cin.fail()判断输入是否合法。如果输入失败,通过std::cin.clear()清除错误状态,std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')清空输入缓冲区,然后提示用户重新输入有效的正整数。

      在用户答题环节,同样使用循环检查输入合法性。当用户输入非整数时,提示用户输入有效整数,并重复等待输入,直到获取到合法输入。

3. 代码风格与协作冲突

      由于是结对编程,我和搭档在代码缩进风格、变量命名习惯等方面存在差异,导致合并代码时出现较多冲突,影响开发效率。
解决方法:

      双方共同查阅 C++ 代码规范,最终确定采用 Google C++ Style 作为统一标准。明确了代码缩进、命名规则、注释格式等具体要求。

总结与展望

      在本次结对开发四则运算测验程序的过程中,我们不仅将 C++ 编程知识付诸实践,更在团队协作中收获颇丰。面对题目生成逻辑复杂、用户输入异常处理、代码风格统一及程序扩展性等诸多挑战,我们通过模块化编程、制定统一规范、优化架构设计等方式逐一攻克。
      在技术层面,我们深入理解了 C++ 中随机数生成、输入输出流处理、类与对象的设计和使用。通过将功能拆分为独立函数和模块,提升了代码的可读性和可维护性;利用版本控制工具 Git 解决了代码合并冲突,保障了开发流程的顺畅。在协作层面,结对编程模式让我们能够相互学习、查漏补缺,不同的思维方式碰撞出更优的解决方案,极大提高了开发效率和代码质量。
      最终完成的程序不仅实现了随机生成四则运算题目、用户答题、自动评分及评价等核心功能,还具备一定的容错性和可扩展性,能够满足学生、成人练习心算、教师布置作业等多样化需求。这次实践让我们深刻体会到,一个成功的项目不仅需要扎实的技术功底,更离不开良好的团队协作和问题解决能力。
      尽管当前版本的四则运算测验程序已经具备了基础功能,但仍有许多优化和扩展的空间:
      功能拓展:未来计划增加更多运算类型,如幂运算、开方运算、三角函数运算等,以满足更高阶的数学练习需求;支持分数、小数的运算,进一步提升题目多样性。同时,考虑添加计时功能,让用户在规定时间内完成测验,增强练习的挑战性和趣味性。
      用户体验优化:引入图形化界面,使用 Qt 或 SDL 等库替代当前的命令行交互,让程序更直观易用;设计个性化的用户界面主题,提供错题回顾、学习进度统计等功能,帮助用户更好地掌握学习情况。
      教育功能深化:针对学生用户,结合教学大纲设计分阶段的练习题库;为教师用户提供更多的题目筛选和导出功能,方便生成定制化试卷;增加智能提示和解题思路引导,帮助用户理解和掌握运算方法。
      性能与稳定性提升:优化随机数生成和题目计算的算法,提高程序运行效率;进行全面的压力测试,确保程序在处理大量题目和高并发使用场景下的稳定性。
posted on 2025-04-16 11:00  小狐狸爱吃萝卜  阅读(35)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3