Loading

结对项目

一、详情

课程 软件工程
队伍成员 3218005438蔡晓芬、3218005398罗秋彤
要求 作业需求
GitHub GitHub
目标 四则运算随机生成器

二、PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 80 60
Estimate 估计这个任务需要多少时间 30 20
Development 开发 800 1000
Analysis 需求分析 (包括学习新技术) 350 200
Design Spec 生成设计文档 40 30
Design Review 设计复审 20 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 20 25
Design 具体设计 60 40
Coding 具体编码 100 120
Code Review 代码复审 60 60
Test 测试(自我测试,修改代码,提交修改) 120 200
Reporting 报告 100 80
Test Repor 测试报告 30 30
Size Measurement 计算工作量 20 10
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 50 30
  合计 1880 1935

三、实现流程

四、关键问题

  1. 随机生成数的生成、多个运算符的生成
  2. 生成表达式的运算(调度场算法、后缀表达式)
  3. 分数的计算与化简,随机生成分数
  4. 题目与答案的导出文件
  5. 判断导入文件的答题情况

五、代码部分

1.随机生成数的生成、多个运算符的生成

// 随机数生成,通过传入参数Max与Min,生成该范围内的一个随机数
function GetRandomNum(Min,Max){
    var Range = Max - Min;
    var Rand = Math.random(); //随机生成0.0~1.0的一个数
    var x = Min + Math.round(Range * Rand); //确保最小值,取四舍五入的整数
    return x;
}
//定义一个运算符的数组,通过随机生成的数组下标,生成一个随机的运算符。
 var signArr = ['+','-','*','÷'];
// 随机生成运算符数组下标,最多三个运算符
var s0 = GetRandomNum(0,3);
var s1 = GetRandomNum(0,3);
var s2 = GetRandomNum(0,3);

// 随机生成运算符的个数
var count = GetRandomNum(1,3);

2.生成表达式的运算(调度场算法、后缀表达式)

Ⅰ. 调度场算法: 将中缀表达式转换为后缀表达式的一个算法。
如: 3 + 4 ——> 3 4 +

function schfa(exp){
    var inputStack = [];
    var outputStack = [];
    var outputQueue = [];
    for(var i=0,len = exp.length; i<len; i++){
        var op = exp[i];
        inputStack = exp.split(' ');  //将表达式的空格去掉,分裂成数组
    }
    while(inputStack.length > 0){
        var op = inputStack.shift();
        // 如果为运算符,当该运算符的优先级小于或等于则压入栈
        if(isOperator(op)){
            while(prioraty(op,outputStack[outputStack.length - 1]) && (outputStack.length > 0){
                outputQueue.push(outputStack.pop());
            }
            outputStack.push(op);
        }else{
            outputQueue.push(op);
        }
    }

    while(outputStack.length > 0){
        outputQueue.push(outputStack.pop());
    }
    return outputQueue;
}

Ⅱ. 后缀表达式

function rpn(rpnQueue){
    var outputStack = [];
    while(rpnQueue.length > 0){
        var op = rpnQueue.shift();
        if(!isOperator(op)){
            outputStack.push(op);
        }else{
            if(outputStack.length < 2){
                throw "unvalid stack length";
            }
            var num2 = outputStack.pop();
            var num1 = outputStack.pop();
            outputStack.push(getResult(num1,num2,op));
        }
    }

    if(outputStack.length != 1){
        throw "unvalid expression";
    }else{
        return outputStack[0];
    }
}

3. 分数的计算与化简,随机生成分数

Ⅰ. 分数的计算步骤:判断生成数是否为分数,是则通过split()将分数分割为字符串数组,再通过分数的计算方式算出结果

// 以运算符前的数字为分数,后一个数为整数为例
    if(num1.toString().indexOf('/') != -1 && num2.toString().indexOf('/' == -1)){
        var fraction = num1.split('/');
        num2 = Number(num2);
        switch(op){
            case '+': return (Number(fraction[0]) + Number(fraction[1])*num2 + '/' + Number(fraction[1]));
            case '-': return (Number(fraction[0]) - Number(fraction[1])*num2 + '/' + Number(fraction[1]));
            case '*': return (Number(fraction[0])*num2 + '/' + Number(fraction[1]));
            case '÷': return (Number(fraction[0]) + '/' + (Number(fraction[1])*num2));
            default: return 0;
        }
    }

Ⅱ. 分数的化简

function Fractions (a,b,mf) {
    if(a == 0 || b == 0) return 0;
// 当最大公约数为1时,分数不需要化简
    if(mf==1) {
        if(a>b && b!=1) {
            return parseInt(a/b) + "`" + a%b + '/' + b;
        } else if(a<b) {
            return a + '/' + b;
        } else {
            return 1;
        }
    } else {
// 最大公约数不为1,对x,y根据最大公因子进行化简
        var x = a/mf;
        var y = b/mf;
        if(y==1) {
            return x;
        } else {
            return Fractions(x,y, getMaxFactor(x, y));
        }
    }
}

Ⅲ.随机生成分数

// 随机是否生成分数,布尔值1即为分数
// 以一个运算符为例
   var isF = Math.round(Math.random());     //随机生成1或0
    switch(count){
        case 1:{
            for(i=0; i<2; i++){
                if(isF){
                    a[i] = GetRandomNum(1,MAX_NUM) + '/' + GetRandomNum(1,MAX_NUM);;
                }else{
                    a[i] = GetRandomNum(1,MAX_NUM);
                }  
            }
            return a[0] + signArr[s0] + a[1]; 
        }
    }

4. 题目与答案的导出文件

function download(filename, text) { 
    var pom = document.createElement('a'); 
    pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    pom.setAttribute('download', filename); 
    if (document.createEvent) { 
        var event = document.createEvent('MouseEvents'); 
        event.initEvent('click', true, true); 
        pom.dispatchEvent(event); 
    } else { 
        pom.click();
    } 
}

六、运行结果

1.初始页面

2.测试用例

3.答案、问题文本导出


七、小结

1.分工明确会更有效率,两个人讨论可以有更多的想法。
2. 不能单纯地通过表达式中的数字直接计算表达式结果,要学会利用栈。
3. ÷ 与 / :因为‘/’也可表示除法,一开始分数与除法运算符都用‘/’表示,虽然方便除法运算,后来发现对于判断分数以及分数的计算十分麻烦,故采用‘÷’。

参考文章

1. 随机数生成
2. 调度场算法

posted @ 2020-10-13 02:53  Avido  阅读(178)  评论(0编辑  收藏  举报