结对编程-四则运算练习题

一、作业要求
小学老师要每周给同学出300道四则运算练习题。
这个程序有很多种实现方式:
C/C++
C#/VB.net/Java
Excel
Unix Shell
Emacs/Powershell/Vbscript
Perl
Python
两个运算符,100 以内的数字,不写答案。
需要检查答案是否正确,并且保证答案在 0..1000 之间
二、结对编程成员:2352308(本博客)、2352106
三、运行环境:CodeBlocks
四、算法设计思路
(一)第一版
(1)核心设计思路:
题目生成:
完全随机生成两个运算符(+ - * /)和三个操作数(1-100)
对除法特殊处理:确保除数是被除数的因数(通过get_divisor())
通过is_valid_expression()验证题目有效性(结果范围、除法合法性等)
运算逻辑:
calculate()实现运算符优先级(先乘除后加减)
限制结果范围(0-1000),避免负数或过大数值
用户交互:
固定生成300题,每5题分组显示
最终输出总正确率和评价
(2)特点:
简单直接,无用户自定义选项
完全随机的运算符组合,可能生成单一运算符题目(如 a + b + c)
输入处理较基础(仅scanf)
(二)第二版
(1)改进点:
新增功能:
每5题显示分组正确率(group_correct计数器)
更清晰的题目分组标题(=== Group X-Y Summary ===)
算法优化:
计算和验证逻辑与第一个版本一致
增加中间统计功能,提升用户反馈即时性
(2)设计思路:
在基础版本上增强交互性
通过分组统计帮助用户了解阶段性学习效果
仍保持完全随机的运算符选择
(三)第三版
(1)核心改进:
运算符选择:
用户可自定义运算符集合(如仅选择+ *)
通过allowed_ops数组和op_count实现灵活控制
混合运算:
当用户选择多个运算符时,确保题目是混合运算(如 a + b * c)
当用户选择四个运算符时,系统将随机混合出题
通过random_op()从用户选择的运算符中随机挑选
增强交互:
支持随时退出(输入q)
退出时显示:完成题数、剩余题数、当前正确率
使用fgets替代scanf,输入处理更好
验证逻辑扩展:
is_valid_expression()新增运算符范围检查
确保题目仅包含用户选择的运算符
(2)设计思路:
以用户需求为中心,提供高度定制化
通过强制混合运算提升题目多样性
完善的退出机制和实时统计功能

五、程序代码
(一)第一版

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>

// 函数声明
int random_num();
char random_op();
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c);
void clear_input_buffer();

// 生成1-100的随机数
int random_num() {
    return rand() % 100 + 1;
}

// 随机选择运算符
char random_op() {
    char ops[] = {'+', '-', '*', '/'};
    return ops[rand() % 4];
}

// 生成能整除被除数的除数
int get_divisor(int dividend) {
    if (dividend == 0) return 1;
    int factors[20];
    int count = 0;
    for (int i = 1; i <= dividend && i <= 100; i++) {
        if (dividend % i == 0) {
            factors[count++] = i;
        }
    }
    return count > 0 ? factors[rand() % count] : 1;
}

// 计算表达式结果
int calculate(int a, char op1, int b, char op2, int c) {
    int result;
    
    if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
        if (op1 == '*') {
            result = a * b;
        } else {
            result = b != 0 ? a / b : -1;
        }
        result = op2 == '+' ? result + c : result - c;
    } 
    else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
        if (op2 == '*') {
            result = b * c;
        } else {
            result = c != 0 ? b / c : -1;
        }
        result = op1 == '+' ? a + result : a - result;
    } 
    else {
        if (op1 == '+') result = a + b;
        else if (op1 == '-') result = a - b;
        else if (op1 == '*') result = a * b;
        else result = b != 0 ? a / b : -1;
        
        if (op2 == '+') result += c;
        else if (op2 == '-') result -= c;
        else if (op2 == '*') result *= c;
        else result = c != 0 ? result / c : -1;
    }
    
    return result;
}

// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c) {
    int result = calculate(a, op1, b, op2, c);
    if (result < 0 || result > 1000) return false;
    
    if (op1 == '/' && (b == 0 || a % b != 0)) return false;
    if (op2 == '/' && c == 0) return false;
    
    if (op1 == '-' && a < b) return false;
    if (op2 == '-') {
        int temp = (op1 == '+') ? a + b :
                  (op1 == '-') ? a - b :
                  (op1 == '*') ? a * b : a / b;
        if (temp < c) return false;
    }
    
    if (op1 == '*' && a * b > 500) return false;
    if (op2 == '*' && b * c > 500) return false;
    
    return true;
}

// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c) {
    while (true) {
        *a = random_num();
        *op1 = random_op();
        *op2 = random_op();
        
        if (*op1 == '/') {
            *b = get_divisor(*a);
        } else {
            *b = random_num();
        }
        
        if (*op2 == '/') {
            int temp;
            if (*op1 == '+') temp = *a + *b;
            else if (*op1 == '-') temp = *a - *b;
            else if (*op1 == '*') temp = *a * *b;
            else temp = *a / *b;
            *c = get_divisor(temp);
        } else {
            *c = random_num();
        }
        
        if (is_valid_expression(*a, *op1, *b, *op2, *c)) {
            break;
        }
    }
}

void clear_input_buffer() {
    while (getchar() != '\n');
}

int main() {
    srand(time(NULL));
    
    int count = 0;
    const int total = 300;
    int correct_answers = 0;
    
    printf("Welcome to the Math Practice Generator!\n");
    printf("We will generate %d problems, 5 at a time.\n\n", total);
    
    while (count < total) {
        if (count % 5 == 0) {
            printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
        }
        
        int a, b, c;
        char op1, op2;
        
        generate_valid_expression(&a, &op1, &b, &op2, &c);
        
        int correct_answer = calculate(a, op1, b, op2, c);
        int user_answer;
        
        printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);
        
        while (scanf("%d", &user_answer) != 1) {
            printf("Invalid input, please enter a number: ");
            clear_input_buffer();
        }
        clear_input_buffer();
        
        if (user_answer == correct_answer) {
            printf("good job!\n");
            correct_answers++;
        } else {
            printf("it's wrong! The correct answer is: %d\n", correct_answer);
        }
        
        count++;
    }
    
    printf("\n=== Practice Completed ===\n");
    printf("Total problems: %d\n", total);
    printf("Correct answers: %d\n", correct_answers);
    printf("Accuracy: %.1f%%\n", (float)correct_answers / total * 100);
    
    if (correct_answers == total) {
        printf("Excellent! Perfect score!\n");
    } else if (correct_answers >= total * 0.8) {
        printf("Great job! Keep it up!\n");
    } else if (correct_answers >= total * 0.6) {
        printf("Not bad, keep practicing!\n");
    } else {
        printf("You need more practice!\n");
    }
    
    return 0;
}
(二)第二版
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>

// 函数声明
int random_num();
char random_op();
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c);
void clear_input_buffer();

// 生成1-100的随机数
int random_num() {
    return rand() % 100 + 1;
}

// 随机选择运算符
char random_op() {
    char ops[] = {'+', '-', '*', '/'};
    return ops[rand() % 4];
}

// 生成能整除被除数的除数
int get_divisor(int dividend) {
    if (dividend == 0) return 1;
    int factors[20];
    int count = 0;
    for (int i = 1; i <= dividend && i <= 100; i++) {
        if (dividend % i == 0) {
            factors[count++] = i;
        }
    }
    return count > 0 ? factors[rand() % count] : 1;
}

// 计算表达式结果(考虑运算符优先级)
int calculate(int a, char op1, int b, char op2, int c) {
    int result;

    // 处理运算符优先级
    if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
        // 先计算 op1
        if (op1 == '*') {
            result = a * b;
        } else {
            result = b != 0 ? a / b : -1;
        }
        // 再计算 op2
        result = op2 == '+' ? result + c : result - c;
    }
    else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
        // 先计算 op2
        if (op2 == '*') {
            result = b * c;
        } else {
            result = c != 0 ? b / c : -1;
        }
        // 再计算 op1
        result = op1 == '+' ? a + result : a - result;
    }
    else {
        // 无优先级冲突,从左到右计算
        if (op1 == '+') result = a + b;
        else if (op1 == '-') result = a - b;
        else if (op1 == '*') result = a * b;
        else result = b != 0 ? a / b : -1;

        if (op2 == '+') result += c;
        else if (op2 == '-') result -= c;
        else if (op2 == '*') result *= c;
        else result = c != 0 ? result / c : -1;
    }

    return result;
}

// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c) {
    // 检查计算结果范围
    int result = calculate(a, op1, b, op2, c);
    if (result < 0 || result > 1000) return false;

    // 检查除法合法性
    if (op1 == '/' && (b == 0 || a % b != 0)) return false;
    if (op2 == '/' && c == 0) return false;

    // 检查减法合法性
    if (op1 == '-' && a < b) return false;
    if (op2 == '-') {
        int temp = (op1 == '+') ? a + b :
                  (op1 == '-') ? a - b :
                  (op1 == '*') ? a * b : a / b;
        if (temp < c) return false;
    }

    // 限制乘法结果范围
    if (op1 == '*' && a * b > 500) return false;
    if (op2 == '*' && b * c > 500) return false;

    return true;
}

// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c) {
    while (true) {
        *a = random_num();
        *op1 = random_op();
        *op2 = random_op();

        // 处理第一个运算符是除法的情况
        if (*op1 == '/') {
            *b = get_divisor(*a);
        } else {
            *b = random_num();
        }

        // 处理第二个运算符是除法的情况
        if (*op2 == '/') {
            int temp;
            if (*op1 == '+') temp = *a + *b;
            else if (*op1 == '-') temp = *a - *b;
            else if (*op1 == '*') temp = *a * *b;
            else temp = *a / *b;
            *c = get_divisor(temp);
        } else {
            *c = random_num();
        }

        // 如果表达式有效,则退出循环
        if (is_valid_expression(*a, *op1, *b, *op2, *c)) {
            break;
        }
    }
}

// 清空输入缓冲区
void clear_input_buffer() {
    while (getchar() != '\n');
}

int main() {
    srand(time(NULL));  // 初始化随机数种子

    int count = 0;
    const int total = 300;
    int correct_answers = 0;
    int group_correct = 0;  // 每组的正确答题数

    printf("Welcome to the Math Practice Generator!\n");
    printf("We will generate %d problems, 5 at a time.\n\n", total);

    while (count < total) {
        // 每5题显示分组标题
        if (count % 5 == 0) {
            printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
        }

        int a, b, c;
        char op1, op2;

        // 生成有效表达式
        generate_valid_expression(&a, &op1, &b, &op2, &c);

        int correct_answer = calculate(a, op1, b, op2, c);
        int user_answer;

        // 显示题目并获取用户输入
        printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);

        // 处理非数字输入
        while (scanf("%d", &user_answer) != 1) {
            printf("Invalid input, please enter a number: ");
            clear_input_buffer();
        }
        clear_input_buffer();

        // 检查答案
        if (user_answer == correct_answer) {
            printf("good job!\n");
            correct_answers++;
            group_correct++;
        } else {
            printf("it's wrong! The correct answer is: %d\n", correct_answer);
        }

        count++;

        // 每5题显示一次分组统计
        if (count % 5 == 0) {
            printf("\n=== Group %d-%d Summary ===\n", count-4, count);
            printf("Correct answers in this group: %d/5\n", group_correct);
            printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
            group_correct = 0;  // 重置分组计数器
        }
    }

    // 最终统计
    printf("\n=== Practice Completed ===\n");
    printf("Total problems: %d\n", total);
    printf("Correct answers: %d\n", correct_answers);
    printf("Accuracy: %.1f%%\n", (float)correct_answers / total * 100);

    // 根据正确率给出评价
    if (correct_answers == total) {
        printf("Excellent! Perfect score!\n");
    } else if (correct_answers >= total * 0.8) {
        printf("Great job! Keep it up!\n");
    } else if (correct_answers >= total * 0.6) {
        printf("Not bad, keep practicing!\n");
    } else {
        printf("You need more practice!\n");
    }

    return 0;
}

(三)第三版
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>

// 函数声明
int random_num();
char random_op(char* allowed_ops, int op_count);
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c, char* allowed_ops, int op_count);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c, char* allowed_ops, int op_count);
void clear_input_buffer();
void print_summary(int total, int completed, int correct);

// 生成1-100的随机数
int random_num() {
    return rand() % 100 + 1;
}

// 从允许的运算符中随机选择
char random_op(char* allowed_ops, int op_count) {
    return allowed_ops[rand() % op_count];
}

// 生成能整除被除数的除数
int get_divisor(int dividend) {
    if (dividend == 0) return 1;
    int factors[20];
    int count = 0;
    for (int i = 1; i <= dividend && i <= 100; i++) {
        if (dividend % i == 0) {
            factors[count++] = i;
        }
    }
    return count > 0 ? factors[rand() % count] : 1;
}

// 计算表达式结果(考虑运算符优先级)
int calculate(int a, char op1, int b, char op2, int c) {
    int result;

    // 处理运算符优先级
    if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
        // 先计算 op1
        if (op1 == '*') {
            result = a * b;
        } else {
            result = b != 0 ? a / b : -1;
        }
        // 再计算 op2
        result = op2 == '+' ? result + c : result - c;
    }
    else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
        // 先计算 op2
        if (op2 == '*') {
            result = b * c;
        } else {
            result = c != 0 ? b / c : -1;
        }
        // 再计算 op1
        result = op1 == '+' ? a + result : a - result;
    }
    else {
        // 无优先级冲突,从左到右计算
        if (op1 == '+') result = a + b;
        else if (op1 == '-') result = a - b;
        else if (op1 == '*') result = a * b;
        else result = b != 0 ? a / b : -1;

        if (op2 == '+') result += c;
        else if (op2 == '-') result -= c;
        else if (op2 == '*') result *= c;
        else result = c != 0 ? result / c : -1;
    }

    return result;
}

// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c, char* allowed_ops, int op_count) {
    // 检查运算符是否在允许范围内
    bool op1_valid = false, op2_valid = false;
    for (int i = 0; i < op_count; i++) {
        if (op1 == allowed_ops[i]) op1_valid = true;
        if (op2 == allowed_ops[i]) op2_valid = true;
    }
    if (!op1_valid || !op2_valid) return false;

    // 检查计算结果范围
    int result = calculate(a, op1, b, op2, c);
    if (result < 0 || result > 1000) return false;

    // 检查除法合法性
    if (op1 == '/' && (b == 0 || a % b != 0)) return false;
    if (op2 == '/' && c == 0) return false;

    // 检查减法合法性
    if (op1 == '-' && a < b) return false;
    if (op2 == '-') {
        int temp = (op1 == '+') ? a + b :
                  (op1 == '-') ? a - b :
                  (op1 == '*') ? a * b : a / b;
        if (temp < c) return false;
    }

    // 限制乘法结果范围
    if (op1 == '*' && a * b > 500) return false;
    if (op2 == '*' && b * c > 500) return false;

    return true;
}

// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c, char* allowed_ops, int op_count) {
    while (true) {
        *a = random_num();
        *op1 = random_op(allowed_ops, op_count);
        *op2 = random_op(allowed_ops, op_count);

        if (*op1 == '/') {
            *b = get_divisor(*a);
        } else {
            *b = random_num();
        }

        if (*op2 == '/') {
            int temp;
            if (*op1 == '+') temp = *a + *b;
            else if (*op1 == '-') temp = *a - *b;
            else if (*op1 == '*') temp = *a * *b;
            else temp = *a / *b;
            *c = get_divisor(temp);
        } else {
            *c = random_num();
        }

        if (is_valid_expression(*a, *op1, *b, *op2, *c, allowed_ops, op_count)) {
            break;
        }
    }
}

// 清空输入缓冲区
void clear_input_buffer() {
    while (getchar() != '\n');
}

// 打印退出时的统计信息
void print_summary(int total, int completed, int correct) {
    printf("\n=== Practice Summary ===\n");
    printf("Total problems: %d\n", total);
    printf("Completed: %d\n", completed);
    printf("Remaining: %d\n", total - completed);
    if (completed > 0) {
        printf("Correct answers: %d\n", correct);
        printf("Accuracy: %.1f%%\n", (float)correct / completed * 100);

        if (correct == completed) {
            printf("Excellent! Perfect score!\n");
        } else if (correct >= completed * 0.8) {
            printf("Great job! Keep it up!\n");
        } else if (correct >= completed * 0.6) {
            printf("Not bad, keep practicing!\n");
        } else {
            printf("You need more practice!\n");
        }
    } else {
        printf("No problems completed.\n");
    }
}

int main() {
    srand(time(NULL));

    const int total = 300;
    int count = 0;
    int correct_answers = 0;
    int group_correct = 0;
    char allowed_ops[4];
    int op_count = 0;

    printf("Welcome to the Math Practice Generator!\n");
    printf("Press 'q' at any time to quit and see your summary.\n");

    // 运算符选择菜单
    printf("\nSelect operators to include:\n");
    printf("1. + (Addition)\n");
    printf("2. - (Subtraction)\n");
    printf("3. * (Multiplication)\n");
    printf("4. / (Division)\n");
    printf("Enter numbers separated by spaces (e.g. '1 2 3' for +-*): ");

    char input[20];
    fgets(input, sizeof(input), stdin);
    char* token = strtok(input, " ");
    while (token != NULL) {
        int choice = atoi(token);
        if (choice >= 1 && choice <= 4) {
            allowed_ops[op_count++] = "+-*/"[choice-1];
        }
        token = strtok(NULL, " ");
    }

    if (op_count == 0) {
        allowed_ops[0] = '+';
        allowed_ops[1] = '-';
        allowed_ops[2] = '*';
        allowed_ops[3] = '/';
        op_count = 4;
        printf("No valid selection. Using all operators by default.\n");
    }

    printf("\nSelected operators: ");
    for (int i = 0; i < op_count; i++) {
        printf("%c ", allowed_ops[i]);
    }
    printf("\n");

    printf("\nWe will generate %d problems, 5 at a time.\n", total);
    printf("Enter 'q' to quit early.\n\n");

    while (count < total) {
        if (count % 5 == 0 && count > 0) {
            printf("\n=== Group %d-%d Summary ===\n", count-4, count);
            printf("Correct answers in this group: %d/5\n", group_correct);
            printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
            group_correct = 0;
        }

        if (count % 5 == 0) {
            printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
        }

        int a, b, c;
        char op1, op2;

        generate_valid_expression(&a, &op1, &b, &op2, &c, allowed_ops, op_count);

        int correct_answer = calculate(a, op1, b, op2, c);
        int user_answer;
        char user_input[20];

        printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);
        fgets(user_input, sizeof(user_input), stdin);

        // 检查是否要退出
        if (tolower(user_input[0]) == 'q') {
            print_summary(total, count, correct_answers);
            return 0;
        }

        user_answer = atoi(user_input);

        if (user_answer == correct_answer) {
            printf("good job!\n");
            correct_answers++;
            group_correct++;
        } else {
            printf("it's wrong! The correct answer is: %d\n", correct_answer);
        }

        count++;
    }

    // 最终统计
    if (count % 5 == 0 && count > 0) {
        printf("\n=== Group %d-%d Summary ===\n", count-4, count);
        printf("Correct answers in this group: %d/5\n", group_correct);
        printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
    }

    print_summary(total, count, correct_answers);
    return 0;
}

六、运算结果

(一)第一版

计算正确显示:good job!
计算错误显示:it's wrong!The ccorrect answer is: +正确答案

完成三百题显示正确率:

(二)第二版

考虑到5题为一组,所以添加了每5题统计一次正确率,300道题全部完成后统计一次总的正确率:

(三)第三版

添加了自定义运算符集合,可自由选择题目出现的运算符:

添加了随时可结束,输入q时结束练习,并统计所完成的题目,未完成的题目,正确率等:

选择两个运算符:

选择两个以上运算符时,系统将随机组合出题:

当输入非1(+),2(-),3(*),4(/)时,系统将忽略该数字,顺延识别下一个数字:

七、版本对比分析

八、体会

2352308:最初的基础版本像一张白纸,虽然功能完整但缺乏边界。通过逐步添加限制条件(如分组统计、运算符过滤、输入校验),让代码产生了价值。例如第三个版本中混合运算的设计,表面上限制了随机性,实则通过约束条件(如while (*op1 == *op2))倒生成更符合训练目标的题目。在本次的结对编程中我体会到这不仅仅是一次分工的合作,更是双方的思维碰撞使得程序代码不断地优化。这种方式不仅帮助我们及时发现并修正潜在问题,更显著提升了代码质量。当然,过程中也遇到了一些挑战,比如代码理解上的差异导致需要花费额外时间沟通协调。但正是这些挑战促使我们不断优化沟通方式,确保双方思路保持一致。这次经历让我收获颇丰。通过密切合作,我们不仅互相学习到对方的编程优点,更发现了自身编码习惯中的不足之处。
2352106:这次结对编程实验让我更加体会到团队合作的重要性。我们的任务是实现三百道加减乘除运算,在分工合作中,我和搭档充分发挥各自的优势。在实验中,我们不断讨论,遇到问题时及时调整策略,确保程序高效准确。例如,如何高效处理大量数据。通过及时沟通,我们一起探讨了解决方案,并在调试过程中互相帮助,解决了多个问题。通过这次合作,我不仅提升了编程技巧,还意识到良好的沟通和分工能极大提高效率。结对编程让我学到了如何更好地协作,也让我更注重代码质量和可维护性。这次经历对我的编程学习非常有帮助。总体来说,这次实验让我认识到,团队合作和高效的沟通是顺利完成任务的关键,结对编程是一种提升编程能力和解决问题的有效方式。

posted @ 2025-04-16 18:46  园友3607115  阅读(41)  评论(0)    收藏  举报