1.小组成员名单:2352332、2352326
2.需求分析与功能亮点:
小学教师每周需生成 300道 四则运算练习题,程序实现以下核心功能:

题目生成:

生成 A op1 B op2 C 形式的表达式,其中 A, B, C 为 1~100 的随机整数,op1 和 op2 从 [+ - * /] 中随机选择。

结果合法性控制:

答案必须为 0~1000 的整数,超出范围自动重新生成。

避免负数(如 A < B 时不生成 A - B)。

避免小数(除法必须整除,如 A % B == 0)。

题目唯一性:使用哈希集合 set 存储题目字符串,确保无重复。

交互式界面:

实时验证答案正确性,反馈 yes/wrong 并显示正确答案。

动态统计正确率(正确数/总题数),进度条显示当前题号。

控制台界面美化(光标定位、颜色高亮)。

3.代码展示:

点击查看代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
#include <Windows.h>
#include <stdexcept>
#include <set>

using namespace std;

// 光标
static void SetPos(int x, int y)
{
    COORD pos = { x,y };
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hout, pos);
}

// 字体颜色(2:绿色,11:青蓝色,12:红色,13:紫色,14:淡黄色,15:白色)
static int color(int c)
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
    return 0;
}

class question {
private:
    int A = 0;
    int B = 0;
    int C = 0;
    int Answer = 1001;
    int op1 = 0;
    int op2 = 0;
    char operation[4] = { '+','-','*','/' };

    // 计算表达式结果,考虑运算优先级
    int calculate() {
        int temp1;
        if (op1 == 2 || op1 == 3) {
            switch (op1) {
            case 2:
                temp1 = A * B;
                break;
            case 3:
                if (B == 0) return 1001;
                temp1 = A / B;
                break;
            }
            switch (op2) {
            case 0:
                return temp1 + C;
            case 1:
                return temp1 - C;
            case 2:
                return temp1 * C;
            case 3:
                if (C == 0) return 1001;
                return temp1 / C;
            }
        }
        else {
            switch (op2) {
            case 2:
                return A + op1 == 0 ? B * C : B * (-C);
            case 3:
                if (C == 0) return 1001;
                return A + op1 == 0 ? B / C : B / (-C);
            default:
                temp1 = op1 == 0 ? A + B : A - B;
                return op2 == 0 ? temp1 + C : temp1 - C;
            }
        }
        return 1001;
    }

    // 将题目转换为字符串,方便存储和比较
    string toString() const {
        string str = to_string(A) + operation[op1] + to_string(B) + operation[op2] + to_string(C);
        return str;
    }

public:
    // Getter 方法
    int getA() const { return A; }
    int getB() const { return B; }
    int getC() const { return C; }
    int getOp1() const { return op1; }
    int getOp2() const { return op2; }
    const char* getOperation() const { return operation; }

    question(const set<string>& existingQuestions) {
        static bool seedSet = false;
        if (!seedSet) {
            srand(static_cast<unsigned int>(time(nullptr)));
            seedSet = true;
        }
        string questionStr;
        do {
            while (Answer > 1000 || Answer < 0) {
                A = rand() % 100 + 1;
                B = rand() % 100 + 1;
                C = rand() % 100 + 1;
                op1 = rand() % 4;
                op2 = rand() % 4;

                // 避免出现负数结果
                if ((op1 == 1 && A < B) || ((op1 == 0 || op1 == 1) && op2 == 1 && (A + B < C))) continue;

                // 避免出现小数结果
                if ((op1 == 3 && A % B != 0) || (op2 == 3 && ((op1 == 0 || op1 == 1) && (A + B) % C != 0) ||
                    (op1 == 2 && A * B % C != 0))) continue;

                Answer = calculate();
            }
            questionStr = toString();
        } while (existingQuestions.find(questionStr) != existingQuestions.end());

        SetPos(45, 7);
        color(6);
        cout << A << operation[op1] << B << operation[op2] << C << "=";
    }

    bool check(int t)
    {
        if (t == Answer)
        {
            SetPos(60, 7);
            cout << "yes" << endl;
            color(2);
            return true;
        }
        else {
            SetPos(60, 7);
            color(12);
            cout << "wrong" << endl;
            SetPos(45, 9);
            color(14);
            cout << "  The Answer is " << Answer << endl;
            return false;
        }
    }
};

void window() {
    color(7);
    SetPos(44, 3);
    cout << "----------------------";
    SetPos(44, 13);
    cout << "----------------------";
    for (int i = 4; i < 13; i++) {
        SetPos(43, i);
        cout << "|";
        SetPos(67, i);
        cout << "|";
    }
    
}
int main()
{
    const int NUM_QUESTIONS = 300;
    set<string> existingQuestions;
    int correctCount = 0;
    for (int i = 0; i < NUM_QUESTIONS; ++i) {
        double accuracy = static_cast<double>(correctCount) / (i + 1) * 100;
        window();
        color(11);
        SetPos(45, 4);
        cout << "  300道四则运算训练";
        color(11);
        SetPos(45, 5);
        cout << " (" << i << "/" << NUM_QUESTIONS << ") 正确率: " << accuracy << "%" << endl;


        float t;
        question q(existingQuestions);
        const char* op = q.getOperation();
        string questionStr = to_string(q.getA()) + op[q.getOp1()] + to_string(q.getB()) + op[q.getOp2()] + to_string(q.getC());
        existingQuestions.insert(questionStr);
        cin >> t;

        if (q.check(t)) {
            correctCount++;
        }
        SetPos(45, 10);
        color(11);
        cout << "按任意键继续下一题..." << endl;
        SetPos(45, 11);
        cin.ignore();  // 忽略之前输入的换行符
        cin.get();     // 等待用户输入一个字符

        system("cls");
        
    }
    return 0;
}

4.实机操作展示:

5.项目总结与体会:
在本次四则运算生成器的开发中,我们两人以均等分工、紧密协作的方式完成了从需求分析到功能实现的全流程。整个过程不仅是技术的实践,更是团队协作能力的锻炼。

分工与合作
我们约定每人承担50%的核心任务,并定期交换角色。初期由我负责搭建题目生成的核心算法,而搭档专注设计用户交互界面与统计模块。当基础框架完成后,我们互换角色:我转向优化去重逻辑与边界条件测试,搭档则深入调试运算优先级处理与错误反馈机制。这种交替模式既保证了代码的全面性,又避免了个体思维的局限性。例如,在解决“运算优先级导致结果错误”的问题时,我提出了分步计算的策略,搭档则通过设计多组测试用例(如A+BC和AB+C)验证了算法的健壮性,最终共同完善了calculate()函数的分支逻辑。

挑战与突破
项目初期,我们曾因“重复题目检测效率低下”陷入瓶颈——直接遍历历史题目列表导致性能骤降。经过头脑风暴,搭档提出利用set容器的哈希特性实现O(1)复杂度查重,而我则标准化了题目字符串的拼接格式(如固定为A+BC形式),彻底解决了因格式差异导致的漏检问题。另一个难点是“除零错误的随机性”:我们共同设计了一套预过滤机制,在生成参数时即跳过B=0或C=0的除法组合,而非依赖计算后的异常捕获,从根源上提升了生成效率。

收获与反思
结对编程的“双人四眼”模式显著提升了代码质量。例如,我在编写运算符优先级逻辑时,因疏忽未处理A-B*C类表达式,搭档在审核中立刻发现并补充了负号场景的兼容逻辑;而搭档在界面设计中使用硬编码坐标时,我建议提取常量定义,使布局调整更加灵活。这种实时监督与互补极大减少了后期调试成本。
我们也深刻体会到沟通的重要性。起初因需求理解偏差,两人分别实现了不同的去重方案,导致代码冲突。此后我们养成了每日同步进展的习惯,并在关键算法上通过手绘流程图达成共识。项目结束时,不仅完成了功能需求,更磨合出一套高效的协作模式——技术问题的争论不再是对立,而是推动解决方案优化的契机。