结对项目——自动生成小学四则运算

Posted vickyleung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结对项目——自动生成小学四则运算相关的知识,希望对你有一定的参考价值。

结对项目——自动生成小学四则运算

 

1.Github项目地址:

https://github.com/Vicky-Leung/demo

项目制作人:3218005081梁小燕  3218005083许梓莹

 

 

2.PSP表格:

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

 60

 159

· Estimate

· 估计这个任务需要多少时间

 60

 159

Development

开发

 1770

 2166

· Analysis

· 需求分析 (包括学习新技术)

 235

409

· Design Spec

· 生成设计文档

 25

 8

· Design Review

· 设计复审 (和同事审核设计文档)

 15

 25

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 25

 22

· Design

· 具体设计

 60

 30

· Coding

· 具体编码

 1260

1602

· Code Review

· 代码复审

 30

 10

· Test

· 测试(自我测试,修改代码,提交修改)

 120

 60

Reporting

报告

 120

 117

· Test Report

· 测试报告

 60

 33

· Size Measurement

· 计算工作量

 30

 10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 30

 72

合计

 

 1950

 2442

 

3.解题思路:

  • 语言选择:java script
  • 先随机生成运算数,运算符,并控制括号,从而生成题目
  • 对生成的题目转换成后缀表达式并计算结果(逆波兰算法)
  • 对结果和题目进行检查是否有重复题目
  • 对用户输入的答案进行批改
  • 提供题目和答案下载功能

 

4.设计实现过程:

  1.  function pro (){}  生成题目,并存储运算数,运算符,并进行括号匹配
  2. function polish(){}  对生成的中缀表达式转换成后缀表达式‘’
  3. function workpolish(){}  计算中缀表达式(在计算过程中,分数一律按假分数进行运算,并且只在整道题目运算结束后才对结果进行化简,转换成真分数)
  4. function confoim(){}  对结果进行检查,以及检查是否出现了重复的题目(检查重复的题目:先检查结果是否相等,再检查运算符个数是否相等,最后检查运算符和运算数是否都相同)
  5. function showAnswer(){}  显示答案
  6. function making(){}  批改
  7. function downloadQuestion(){}  下载题目
  8. function downloadAnswer(){}  下载答案

 

 

 关于后缀表达式(逆波兰表达式):

将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级(不包括括号运算符)大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
(cr:百度百科)

 

5.代码说明:

部分代码:

 

技术图片
 1 function pro(){
 2     var operatorNum = randomNum(1,3);       //题目会使用多少个符号?
 3     arr[i][0] = operatorNum;
 4     var num = 1, op = 1;
 5     while (num <= operatorNum+1 && op <= operatorNum){
 6         if (arr[i][op-1] != "/")
 7             s[i][num] = randomNum(0,range);      //生成运算数
 8         else
 9             s[i][num] = randomNum(1,range);      //生成运算数
10         arr[i][op] = randomOperator();      //生成运算符
11         num++;
12         op++;
13     }
14     var brack;   //控制括号
15     switch (operatorNum) {//控制括号
16         case 1:
17             problem[i] = s[i][1] + arr[i][1] + s[i][2];
18             break;
19         case 2:
20             brack = randomNum(1,2);
21             if (brack == 1)
22                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] +s[i][3];
23             else
24                 problem[i] = s[i][1] + arr[i][1] + "(" + s[i][2] + arr[i][2] +s[i][3] + ")";
25             break;
26         case 3:
27             brack = randomNum(1,5)
28             if (brack == 1)
29                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] +s[i][3] + arr[i][3] + s[i][4];
30             else if (brack == 2)
31                 problem[i] = "(" + s[i][1] + arr[i][1] + s[i][2] + ")" + arr[i][2] +s[i][3] + arr[i][3] + s[i][4];
32             else if (brack == 3)
33                 problem[i] = s[i][1] + arr[i][1] + "(" + s[i][2] + arr[i][2] +s[i][3] + ")" + arr[i][3] + s[i][4];
34             else if (brack == 4)
35                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] + "(" +s[i][3] + arr[i][3] + s[i][4] + ")";
36             else
37                 problem[i] = s[i][1] + arr[i][1] +"("  + s[i][2] + arr[i][2] +s[i][3] + arr[i][3] + s[i][4] + ")";
38             break;
39     }//end switch
40 }//end pro
41 
42 
43 function randomNum(min,max) {
44     return Math.floor(Math.random() * (max - min + 1) + min);
45 }
46 
47 
48 function randomOperator() {
49     var operator;
50     operator = randomNum(1,4);
51     if (operator == 1)
52         return "+";
53     else if (operator == 2)
54         return "-";
55     else if (operator ==3)
56         return "*";
57     else
58         return "/";
59 }
生成一道题目
技术图片
 1 function polish() {      //中缀转后缀
 2     var str_p = problem[i].toString(); //中缀表达式转字符串
 3     var middleArr = str_p.split(‘‘);   //中缀表达式转数组
 4     var opStack = [];   //运算符栈
 5     var outputQueue = [];   //输出队列,后缀表达式
 6     var pi = 0;
 7     while (pi < middleArr.length) {
 8         var ch = middleArr[pi].toString();
 9         var out;
10         switch (ch) {
11             case "+":
12             case "-":
13                 if (opStack.length > 0) {   //栈不空
14                     out = opStack.pop();    //取出栈顶元素
15                     if (out != "(") {    //栈顶不是左括号
16                         outputQueue.push(out);  //栈顶元素添加到后缀表达式
17                     }
18                     else {    //栈顶元素是左括号
19                         opStack.push(out);   //把刚刚的栈顶元素放回去
20                     }
21                 }
22                 opStack.push(ch);     //当前运算符进栈
23                 pi++;
24                 break;
25 
26             case "*":
27             case "/":
28                 if (opStack.length > 0) {   //栈不空
29                     out = opStack.pop();    //取出栈顶元素
30                     if (out == "*" || out == "/") {    //栈顶是乘号或除号
31                         outputQueue.push(out);  //栈顶元素添加到后缀表达式
32                     }
33                     else {    //栈顶不是乘号也不是除号
34                         opStack.push(out);   //把刚刚的栈顶元素放回去
35                     }
36                 }
37                 opStack.push(ch);     //当前运算符进栈
38                 pi++;
39                 break;
40 
41             case "(":
42                 opStack.push(ch);
43                 pi++;
44                 break;
45             case ")":
46                 out = opStack.pop();    //取出栈顶元素
47                 while (out != null && out != "(") {    //直到遇到左括号
48                     outputQueue.push(out);  //栈顶元素添加到后缀表达式
49                     out = opStack.pop();
50                 }
51                 pi++;
52                 break;
53 
54             default:    //遇到数字
55                 while ( pi < middleArr.length && (ch >= ‘0‘ && ch <= ‘9‘ ) ) {
56                     outputQueue.push(ch);  //直接添加到输出队列
57                     pi++;
58                     if (pi < middleArr.length)
59                         ch = middleArr[pi];
60                 }
61                 outputQueue.push(‘ ‘);  //添加空格作为数值之间的分隔符
62         }//end switch
63 
64     }//end while
65 
66     while (opStack.length != 0){    //已遍历完中缀表达式,若运算符栈不为空
67         out = opStack.pop();    //取出栈顶元素
68         outputQueue.push(out);  //添加到后缀表达式
69     }
70 
71     return outputQueue;
72 
73 }//end polish
后缀表达式
技术图片
  1 function workPolish() {    //计算后缀表达式
  2     var value = "";     //用于还原运算数
  3     var value2= "";
  4     var numStack = [];  //运算数栈
  5     // var vue = "";
  6     while (Queue.length > 0) {
  7         var cur = Queue.shift();    //取队头
  8         if (cur >= ‘0‘ && cur <= ‘9‘ ) {    //遇到数字
  9             value = "";
 10             while(cur != ‘ ‘) { //不是空格
 11                 value2 = cur;
 12                 value = value + value2;
 13                 cur = Queue.shift();    //继续取队头
 14             }
 15             numStack.push(value.toString());     //压入运算数栈
 16         }
 17         else if(cur != ‘ ‘){     //出现了运算符,则取出两个运算数
 18             var y = numStack.pop();
 19             var x = numStack.pop();
 20             var vue = worktwo(x, y, cur);
 21             numStack.push(vue);
 22         }
 23     }//end while
 24     return numStack;        //这个结果是还没化简的
 25 }
 26 
 27 
 28 function worktwo (fir, sec, cur) {
 29     if(fir.toString().indexOf(‘/‘) == -1 && sec.toString().indexOf(‘/‘) == -1) {    //两数都不是分数
 30         fir = Number(fir);
 31         sec = Number(sec);
 32         switch(cur) {
 33             case ‘+‘: return (fir + sec);
 34             case ‘-‘: return (fir - sec);
 35             case ‘*‘: return (fir * sec);
 36             case ‘/‘: return fir + ‘/‘ + sec;
 37         }
 38     }
 39     else if(fir.toString().indexOf(‘/‘) != -1 && sec.toString().indexOf(‘/‘) == -1){    //第一个数为分数
 40         var fractional = fir.split(‘/‘);   //字符串分割成数组  fractional【0】分子/fractional【1】分母
 41         switch(cur) {
 42             case ‘+‘: return ( Number(fractional[1]) * Number(sec) + Number(fractional[0]) ) + ‘/‘ + Number(fractional[1]);
 43             case ‘-‘: return ( Number(fractional[0]) - Number(fractional[1]) * Number(sec) ) + ‘/‘ + Number(fractional[1]);
 44             case ‘*‘: return ( Number(fractional[0]) * Number(sec) ) + ‘/‘ + Number(fractional[1]);
 45             case ‘/‘: return Number(fractional[0]) + ‘/‘ + ( Number(fractional[1]) * Number(sec) );
 46         }
 47 
 48     }
 49     else if(fir.toString().indexOf(‘/‘) == -1 && sec.toString().indexOf(‘/‘) != -1){    //第二个数为分数
 50         var fractional = sec.split(‘/‘);
 51         switch(cur) {
 52             case ‘+‘: return Number(fractional[1]) * Number(fir) + Number(fractional[0]) + ‘/‘ + Number(fractional[1]);
 53             case ‘-‘: return ( Number(fractional[1]) * Number(fir) - Number(fractional[0]) ) + ‘/‘ + Number(fractional[1]);
 54             case ‘*‘: return ( Number(fractional[0]) * Number(fir) ) + ‘/‘ + Number(fractional[1]);
 55             case ‘/‘: return ( Number(fractional[1]) * Number(fir) ) + ‘/‘ + Number(fractional[0]);
 56         }
 57     }
 58     else if(fir.toString().indexOf(‘/‘) != -1 && sec.toString().indexOf(‘/‘) != -1){    //两个数都是分数
 59         var fractional1 = fir.split(‘/‘);
 60         var fractional2 = sec.split(‘/‘);
 61         switch(cur) {
 62             case ‘+‘: return ( Number(fractional2[1]) * Number(fractional1[0]) + Number(fractional2[0]) * Number(fractional1[1]) ) + ‘/‘ + (Number(fractional1[1]) * Number(fractional2[1]) );
 63             case ‘-‘: return ( Number(fractional1[0]) * Number(fractional2[1]) - Number(fractional2[0]) * Number(fractional1[1]) ) + ‘/‘ + (Number( fractional1[1]) * Number(fractional2[1]) );
 64             case ‘*‘: return ( Number(fractional1[0]) * Number(fractional2[0]) ) + ‘/‘ + ( Number(fractional1[1]) * Number(fractional2[1]) );
 65             case ‘/‘: return ( Number(fractional1[0]) * Number(fractional2[1]) ) + ‘/‘ + ( Number(fractional1[1]) * Number(fractional2[0]) );
 66         }
 67     }
 68 }
 69 
 70 
 71 function factor(fx, fy) {       // 找最大公因数
 72     var t = 0;
 73     while(fy) {
 74         t = fx%fy;    //取余
 75         fx = fy;
 76         fy = t;
 77     }
 78     return fx;
 79 }
 80 
 81 
 82 function fenShu (a, b, ft) {     // 分数化简 (a为分子,b为分母,mf为最大公因数)
 83     if(ft == 1) {         // 最大公因数是1
 84         if(a > b) {    // 分子大,则转化为真分式
 85             return parseInt(a/b) + ‘’‘ + a%b + ‘/‘ + b;
 86         }
 87         else if(a < b) {      // 分子小
 88             return a + ‘/‘ + b;
 89         }
 90         //若最大公因数为1,且a==b,那么a=b=1,而b==1这种情况已经在huajian(num)里面解决了,所以这里不写
 91     }
 92     else {      //最大公因数不是1,eg:a=12, b=18, ft=6
 93         var fa = a/ft;
 94         var fb = b/ft;
 95         if( fb==1) {
 96             return fa;
 97         }
 98         else {      //此时最大公因数是1,回到前面部分,所以这里用递归
 99             return fenShu(fa, fb, factor(fa, fb));
100         }
101     }
102 }
103 
104 
105 function huajian(num) {
106     num = num.toString();
107     if (num.indexOf(‘/‘) == -1) {       //不是分数
108         if (num >= 0)  return num;
109         else return "#";        //"#"用于标记无效题目
110     }
111     else {          //若是分数,化简
112         var arr = num.split(‘/‘);
113         arr[0] = Number(arr[0]);        //分子
114         arr[1] = Number(arr[1]);        //分母
115         if (arr[0] < 0 || arr[1] <= 0)
116             return "#";
117         if (arr[1] == 1)
118             return arr[0];
119         else
120             return fenShu(arr[0], arr[1], factor(arr[0], arr[1]));
121     }
122 }
计算
技术图片
 1 function conform() {
 2     var ci = 1;
 3     Queue = polish();   //Queue是一个全局队列,将会用于计算后缀表达式
 4     sum = workPolish();    //sum此时暂存未化简的结果
 5     sum = huajian(sum);    //sum此时是化简后的分数
 6     if (sum == "#") {
 7         return 0;
 8     }
 9     if (sum != "#" ){
10         arr[i][4] = sum;
11         for(ci = 1; ci < i; ci++){
12             if (arr[ci][4].toString()==arr[i][4].toString()) {     //与ci题结果相同
13                 if (arr[ci][0]==arr[i][0]) {      //运算符个数也相同
14                     var str_a = "";     //存入ci题所有运算符
15                     var str_b = "";     //存入ci题所有运算数
16                     switch (arr[i][0]) {
17                         case 1:   //一个运算符
18                             str_b = s[ci][1].toString() + s[ci][2].toString();
19                             if( arr[ci][1]==arr[i][1] && str_b.indexOf(s[i][1].toString())!=-1 )   //运算符和运算数也相同
20                                 return 0;
21                             break;
22                         case 2:
23                             str_a = arr[ci][1] + arr[ci][2];
24                             str_b = s[ci][1].toString() + s[ci][2].toString() + s[ci][3].toString();
25                             if( str_a.indexOf(arr[i][1])!=-1 && str_a.indexOf(arr[i][2])!=-1
26                                 && str_b.indexOf(s[i][1].toString())!=-1 && str_b.indexOf(s[i][2].toString())!=-1 && str_b.indexOf(s[i][3].toString())!=-1 )
27                                 return 0;
28                             break;
29                         case 3:
30                             str_a = arr[ci][1] + arr[ci][2] + arr[ci][3];
31                             str_b = s[ci][1].toString() + s[ci][2].toString() + s[ci][3].toString() + s[ci][4].toString();
32                             if( str_a.indexOf(arr[i][1])!=-1 && str_a.indexOf(arr[i][2])!=-1 && str_a.indexOf(arr[i][3])!=-1
33                                 && str_b.indexOf(s[i][1].toString())!=-1 && str_b.indexOf(s[i][2].toString())!=-1 && str_b.indexOf(s[i][3].toString())!=-1 && str_b.indexOf(s[i][4].toString())!=-1 )
34                                 return 0;
35                             break;
36                     }//end switch
37                 }
38             }
39         }
40         return 1;
41     }//end if
42 }
检验
技术图片
 1 function downloadQuestion(){
 2     if(sign ==0 ){alert("请先出题");return false;}
 3     var question = quesitonshtmlArr.toString();
 4     var name = "question.txt";
 5     question = question.split("<input class=‘userA‘ type=‘text‘/></li>");
 6     question = question.join("
");
 7     question = question.split("<li>");
 8     question = question.join("");
 9 
10     download(name,question)
11 }
12 
13 
14 function donloadAnswer(){
15     if(sign ==0 ){alert("请先出题");return false;}
16     var answer =answerHtmlArr.toString();
17     var name = "answer.txt";
18     answer = answer.split("</li>");
19     answer = answer.join("
");
20     answer = answer.split("<li>");
21     answer = answer.join("");
22     download(name,answer)
23 }
24 
25 
26 function download(filename, text) {
27     var pom = document.createElement(‘a‘);
28     pom.setAttribute(‘href‘, ‘data:text/plain;charset=utf-8,‘ + encodeURIComponent(text));
29     pom.setAttribute(‘download‘, filename);
30     if (document.createEvent) {
31         var event = document.createEvent(‘MouseEvents‘);
32         event.initEvent(‘click‘, true, true);
33         pom.dispatchEvent(event);
34     } else {
35         pom.click();
36     }
37 }
下载

 

全部代码:

 

技术图片
 1 <!DOCTYPE html>
 2 <!DOCTYPE html>
 3 <html>
 4 <head>
 5     <title>四则运算生成器</title>
 6     <meta charset="utf-8">
 7     <link rel="stylesheet" type="text/css" href="index.css">
 8     <script src="index.js"></script>
 9 </head>
10 <body>
11     <div class="site-header">
12         <p>软件工程结对项目</p>
13     </div>
14     <div class="box"></div>
15     <div class="premises">
16         <div class="premises-content1">
17         <p>题目数量:<input type="txt" name="subject" id="subject" placeholder="如:10"></p>
18         <p>题目范围:<input type="txt" name="range" id="range" placeholder="如:20"></p>
19         <button class="premises-submit" onclick="start()">确定</button>
20         </div>
21     </div>
22     <div class="content">
23         <p>生成题目内容如下:</p>
24         <div class="question">
25             <ul id="question-text">
26 
27             </ul>
28 
29         </div>
30         <div class="answer">
31             <ul id="answer-text">
32                 <li>点击下方功能键查看答案</li>
33             </ul>
34         </div>
35 
36     </div>
37     <div class="content2">
38         
39         <a class="change"><button class="bleft" onclick="marking()">自动批改</button></a>
40         <a class="change"><button class="bleft2" onclick="downloadQuestion()">下载题目</button></a>
41         <a class="change"><button class="bright2" onclick="donloadAnswer()">下载答案</button></a>
42         <a class="change"><button class="bright" onclick="showAnswer()">查看完整答案</button></a>
43     </div>
44     <div id="Right">
45         <p>点击批改可查看正确题数<p>
46     </div>
47     <div id="Fault">
48         <p>点击批改可查看错误题数</p>
49     </div>
50 
51 </body>
52 </html>
html
技术图片
  1 window.sign=0;
  2 
  3 
  4 function start() {
  5     quesitonsHtmlArr = new Array();//所有题目字段,可用于下载
  6     answerHtmlArr = new Array();//字符串,页面备用
  7     answerSign=0;
  8 
  9 
 10     subject = document.getElementById("subject").value;     //题目数
 11     range = document.getElementById("range").value;     //数字范围
 12     
 13     if(subject == 0 || subject < 0 || subject >10000 ) {alert("请输入正确题目数量,不大于10000道");return; }
 14     if(range == 0 || range < 0) {alert("请输入正确题目范围");return; }
 15     sign=1;
 16 
 17     s = new Array();   //存数字
 18         for (s_i = 0; s_i <= subject; s_i++) {
 19             s [s_i] = new Array();
 20             for (s_j = 0; s_j <= 4; s_j++) {  //s_j==1-4时,存运算数
 21                 s[s_i][s_j] = 1;
 22 
 23             }
 24         }
 25     arr = new Array();  //存字符串
 26         for (arr_i = 0; arr_i <= subject; arr_i++) {
 27             arr [arr_i] = new Array();
 28             for (arr_j = 0; arr_j <= 4; arr_j++) { //arr_j==0时存运算符个数,arr_j==1-3时存入运算符,arr_j==4时存入结果
 29                 arr[arr_i][arr_j] = ‘‘;
 30             }
 31         }
 32     problem = new Array();    //存储整道题目,用于打印和计算结果
 33 
 34     i = 1;  //第几号题目
 35     while(i <= subject){
 36         pro();
 37         if (conform()){
 38             console.log(‘第‘+i+‘题: ‘);
 39             console.log(problem[i]+" = " + arr[i][4].toString());
 40             quesitonsHtmlArr += (‘<li>‘ + ‘第‘ + i + ‘题: ‘ + problem[i].toString() + ‘ = ‘ + "<input class=‘userA‘ type=‘text‘/>"  + ‘</li>‘ );
 41             i++;
 42         }
 43     }
 44     document.getElementById("question-text").innerHTML = quesitonsHtmlArr;
 45 }
 46 
 47 
 48 function conform() {
 49     var ci = 1;
 50     Queue = polish();   //Queue是一个全局队列,将会用于计算后缀表达式
 51     sum = workPolish();    //sum此时暂存未化简的结果
 52     sum = huajian(sum);    //sum此时是化简后的分数
 53     if (sum == "#") {
 54         return 0;
 55     }
 56     if (sum != "#" ){
 57         arr[i][4] = sum;
 58         for(ci = 1; ci < i; ci++){
 59             if (arr[ci][4].toString()==arr[i][4].toString()) {     //与ci题结果相同
 60                 if (arr[ci][0]==arr[i][0]) {      //运算符个数也相同
 61                     var str_a = "";     //存入ci题所有运算符
 62                     var str_b = "";     //存入ci题所有运算数
 63                     switch (arr[i][0]) {
 64                         case 1:   //一个运算符
 65                             str_b = s[ci][1].toString() + s[ci][2].toString();
 66                             if( arr[ci][1]==arr[i][1] && str_b.indexOf(s[i][1].toString())!=-1 )   //运算符和运算数也相同
 67                                 return 0;
 68                             break;
 69                         case 2:
 70                             str_a = arr[ci][1] + arr[ci][2];
 71                             str_b = s[ci][1].toString() + s[ci][2].toString() + s[ci][3].toString();
 72                             if( str_a.indexOf(arr[i][1])!=-1 && str_a.indexOf(arr[i][2])!=-1
 73                                 && str_b.indexOf(s[i][1].toString())!=-1 && str_b.indexOf(s[i][2].toString())!=-1 && str_b.indexOf(s[i][3].toString())!=-1 )
 74                                 return 0;
 75                             break;
 76                         case 3:
 77                             str_a = arr[ci][1] + arr[ci][2] + arr[ci][3];
 78                             str_b = s[ci][1].toString() + s[ci][2].toString() + s[ci][3].toString() + s[ci][4].toString();
 79                             if( str_a.indexOf(arr[i][1])!=-1 && str_a.indexOf(arr[i][2])!=-1 && str_a.indexOf(arr[i][3])!=-1
 80                                 && str_b.indexOf(s[i][1].toString())!=-1 && str_b.indexOf(s[i][2].toString())!=-1 && str_b.indexOf(s[i][3].toString())!=-1 && str_b.indexOf(s[i][4].toString())!=-1 )
 81                                 return 0;
 82                             break;
 83                     }//end switch
 84                 }
 85             }
 86         }
 87         return 1;
 88     }//end if
 89 }
 90 
 91 
 92 
 93 function polish() {      //中缀转后缀
 94     var str_p = problem[i].toString(); //中缀表达式转字符串
 95     var middleArr = str_p.split(‘‘);   //中缀表达式转数组
 96     var opStack = [];   //运算符栈
 97     var outputQueue = [];   //输出队列,后缀表达式
 98     var pi = 0;
 99     while (pi < middleArr.length) {
100         var ch = middleArr[pi].toString();
101         var out;
102         switch (ch) {
103             case "+":
104             case "-":
105                 if (opStack.length > 0) {   //栈不空
106                     out = opStack.pop();    //取出栈顶元素
107                     if (out != "(") {    //栈顶不是左括号
108                         outputQueue.push(out);  //栈顶元素添加到后缀表达式
109                     }
110                     else {    //栈顶元素是左括号
111                         opStack.push(out);   //把刚刚的栈顶元素放回去
112                     }
113                 }
114                 opStack.push(ch);     //当前运算符进栈
115                 pi++;
116                 break;
117 
118             case "*":
119             case "/":
120                 if (opStack.length > 0) {   //栈不空
121                     out = opStack.pop();    //取出栈顶元素
122                     if (out == "*" || out == "/") {    //栈顶是乘号或除号
123                         outputQueue.push(out);  //栈顶元素添加到后缀表达式
124                     }
125                     else {    //栈顶不是乘号也不是除号
126                         opStack.push(out);   //把刚刚的栈顶元素放回去
127                     }
128                 }
129                 opStack.push(ch);     //当前运算符进栈
130                 pi++;
131                 break;
132 
133             case "(":
134                 opStack.push(ch);
135                 pi++;
136                 break;
137             case ")":
138                 out = opStack.pop();    //取出栈顶元素
139                 while (out != null && out != "(") {    //直到遇到左括号
140                     outputQueue.push(out);  //栈顶元素添加到后缀表达式
141                     out = opStack.pop();
142                 }
143                 pi++;
144                 break;
145 
146             default:    //遇到数字
147                 while ( pi < middleArr.length && (ch >= ‘0‘ && ch <= ‘9‘ ) ) {
148                     outputQueue.push(ch);  //直接添加到输出队列
149                     pi++;
150                     if (pi < middleArr.length)
151                         ch = middleArr[pi];
152                 }
153                 outputQueue.push(‘ ‘);  //添加空格作为数值之间的分隔符
154         }//end switch
155 
156     }//end while
157 
158     while (opStack.length != 0){    //已遍历完中缀表达式,若运算符栈不为空
159         out = opStack.pop();    //取出栈顶元素
160         outputQueue.push(out);  //添加到后缀表达式
161     }
162 
163     return outputQueue;
164 
165 }//end polish
166 
167 
168 function workPolish() {    //计算后缀表达式
169     var value = "";     //用于还原运算数
170     var value2= "";
171     var numStack = [];  //运算数栈
172     // var vue = "";
173     while (Queue.length > 0) {
174         var cur = Queue.shift();    //取队头
175         if (cur >= ‘0‘ && cur <= ‘9‘ ) {    //遇到数字
176             value = "";
177             while(cur != ‘ ‘) { //不是空格
178                 value2 = cur;
179                 value = value + value2;
180                 cur = Queue.shift();    //继续取队头
181             }
182             numStack.push(value.toString());     //压入运算数栈
183         }
184         else if(cur != ‘ ‘){     //出现了运算符,则取出两个运算数
185             var y = numStack.pop();
186             var x = numStack.pop();
187             var vue = worktwo(x, y, cur);
188             numStack.push(vue);
189         }
190     }//end while
191     return numStack;        //这个结果是还没化简的
192 }
193 
194 
195 function worktwo (fir, sec, cur) {
196     if(fir.toString().indexOf(‘/‘) == -1 && sec.toString().indexOf(‘/‘) == -1) {    //两数都不是分数
197         fir = Number(fir);
198         sec = Number(sec);
199         switch(cur) {
200             case ‘+‘: return (fir + sec);
201             case ‘-‘: return (fir - sec);
202             case ‘*‘: return (fir * sec);
203             case ‘/‘: return fir + ‘/‘ + sec;
204         }
205     }
206     else if(fir.toString().indexOf(‘/‘) != -1 && sec.toString().indexOf(‘/‘) == -1){    //第一个数为分数
207         var fractional = fir.split(‘/‘);   //字符串分割成数组  fractional【0】分子/fractional【1】分母
208         switch(cur) {
209             case ‘+‘: return ( Number(fractional[1]) * Number(sec) + Number(fractional[0]) ) + ‘/‘ + Number(fractional[1]);
210             case ‘-‘: return ( Number(fractional[0]) - Number(fractional[1]) * Number(sec) ) + ‘/‘ + Number(fractional[1]);
211             case ‘*‘: return ( Number(fractional[0]) * Number(sec) ) + ‘/‘ + Number(fractional[1]);
212             case ‘/‘: return Number(fractional[0]) + ‘/‘ + ( Number(fractional[1]) * Number(sec) );
213         }
214 
215     }
216     else if(fir.toString().indexOf(‘/‘) == -1 && sec.toString().indexOf(‘/‘) != -1){    //第二个数为分数
217         var fractional = sec.split(‘/‘);
218         switch(cur) {
219             case ‘+‘: return Number(fractional[1]) * Number(fir) + Number(fractional[0]) + ‘/‘ + Number(fractional[1]);
220             case ‘-‘: return ( Number(fractional[1]) * Number(fir) - Number(fractional[0]) ) + ‘/‘ + Number(fractional[1]);
221             case ‘*‘: return ( Number(fractional[0]) * Number(fir) ) + ‘/‘ + Number(fractional[1]);
222             case ‘/‘: return ( Number(fractional[1]) * Number(fir) ) + ‘/‘ + Number(fractional[0]);
223         }
224     }
225     else if(fir.toString().indexOf(‘/‘) != -1 && sec.toString().indexOf(‘/‘) != -1){    //两个数都是分数
226         var fractional1 = fir.split(‘/‘);
227         var fractional2 = sec.split(‘/‘);
228         switch(cur) {
229             case ‘+‘: return ( Number(fractional2[1]) * Number(fractional1[0]) + Number(fractional2[0]) * Number(fractional1[1]) ) + ‘/‘ + (Number(fractional1[1]) * Number(fractional2[1]) );
230             case ‘-‘: return ( Number(fractional1[0]) * Number(fractional2[1]) - Number(fractional2[0]) * Number(fractional1[1]) ) + ‘/‘ + (Number( fractional1[1]) * Number(fractional2[1]) );
231             case ‘*‘: return ( Number(fractional1[0]) * Number(fractional2[0]) ) + ‘/‘ + ( Number(fractional1[1]) * Number(fractional2[1]) );
232             case ‘/‘: return ( Number(fractional1[0]) * Number(fractional2[1]) ) + ‘/‘ + ( Number(fractional1[1]) * Number(fractional2[0]) );
233         }
234     }
235 }
236 
237 
238 function factor(fx, fy) {       // 找最大公因数
239     var t = 0;
240     while(fy) {
241         t = fx%fy;    //取余
242         fx = fy;
243         fy = t;
244     }
245     return fx;
246 }
247 
248 
249 function fenShu (a, b, ft) {     // 分数化简 (a为分子,b为分母,mf为最大公因数)
250     if(ft == 1) {         // 最大公因数是1
251         if(a > b) {    // 分子大,则转化为真分式
252             return parseInt(a/b) + ‘’‘ + a%b + ‘/‘ + b;
253         }
254         else if(a < b) {      // 分子小
255             return a + ‘/‘ + b;
256         }
257         //若最大公因数为1,且a==b,那么a=b=1,而b==1这种情况已经在huajian(num)里面解决了,所以这里不写
258     }
259     else {      //最大公因数不是1,eg:a=12, b=18, ft=6
260         var fa = a/ft;
261         var fb = b/ft;
262         if( fb==1) {
263             return fa;
264         }
265         else {      //此时最大公因数是1,回到前面部分,所以这里用递归
266             return fenShu(fa, fb, factor(fa, fb));
267         }
268     }
269 }
270 
271 
272 function huajian(num) {
273     num = num.toString();
274     if (num.indexOf(‘/‘) == -1) {       //不是分数
275         if (num >= 0)  return num;
276         else return "#";        //"#"用于标记无效题目
277     }
278     else {          //若是分数,化简
279         var arr = num.split(‘/‘);
280         arr[0] = Number(arr[0]);        //分子
281         arr[1] = Number(arr[1]);        //分母
282         if (arr[0] < 0 || arr[1] <= 0)
283             return "#";
284         if (arr[1] == 1)
285             return arr[0];
286         else
287             return fenShu(arr[0], arr[1], factor(arr[0], arr[1]));
288     }
289 }
290 
291 
292 function pro(){
293     var operatorNum = randomNum(1,3);       //题目会使用多少个符号?
294     arr[i][0] = operatorNum;
295     var num = 1, op = 1;
296     while (num <= operatorNum+1 && op <= operatorNum){
297         if (arr[i][op-1] != "/")
298             s[i][num] = randomNum(0,range);      //生成运算数
299         else
300             s[i][num] = randomNum(1,range);      //生成运算数
301         arr[i][op] = randomOperator();      //生成运算符
302         num++;
303         op++;
304     }
305     var brack;   //控制括号
306     switch (operatorNum) {//控制括号
307         case 1:
308             problem[i] = s[i][1] + arr[i][1] + s[i][2];
309             break;
310         case 2:
311             brack = randomNum(1,2);
312             if (brack == 1)
313                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] +s[i][3];
314             else
315                 problem[i] = s[i][1] + arr[i][1] + "(" + s[i][2] + arr[i][2] +s[i][3] + ")";
316             break;
317         case 3:
318             brack = randomNum(1,5)
319             if (brack == 1)
320                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] +s[i][3] + arr[i][3] + s[i][4];
321             else if (brack == 2)
322                 problem[i] = "(" + s[i][1] + arr[i][1] + s[i][2] + ")" + arr[i][2] +s[i][3] + arr[i][3] + s[i][4];
323             else if (brack == 3)
324                 problem[i] = s[i][1] + arr[i][1] + "(" + s[i][2] + arr[i][2] +s[i][3] + ")" + arr[i][3] + s[i][4];
325             else if (brack == 4)
326                 problem[i] = s[i][1] + arr[i][1] + s[i][2] + arr[i][2] + "(" +s[i][3] + arr[i][3] + s[i][4] + ")";
327             else
328                 problem[i] = s[i][1] + arr[i][1] +"("  + s[i][2] + arr[i][2] +s[i][3] + arr[i][3] + s[i][4] + ")";
329             break;
330     }//end switch
331 }//end pro
332 
333 
334 function randomNum(min,max) {
335     return Math.floor(Math.random() * (max - min + 1) + min);
336 }
337 
338 
339 function randomOperator() {
340     var operator;
341     operator = randomNum(1,4);
342     if (operator == 1)
343         return "+";
344     else if (operator == 2)
345         return "-";
346     else if (operator ==3)
347         return "*";
348     else
349         return "/";
350 }
351 
352 
353 function showAnswer(){
354     if(sign == 0 ){alert("请先出题");return false;}
355     if(answerSign==1){alert("已输出答案,查看上方答案栏");return false;}
356    
357     var j;
358     for(j = 1;j <= subject;j++)
359     {
360         answerHtmlArr += ‘<li>‘+ ‘第‘ + j +‘题:‘+ arr[j][4] +‘</li>‘;
361     }
362     document.getElementById(‘answer-text‘).innerHTML=answerHtmlArr;
363     
364     answerSign=1;
365 
366 
367 }
368 
369 
370 function marking(){
371     if(sign ==0 ){alert("请先出题");return false;}
372     var j,tureTotal,flaseTotal;
373     var userAnswer=document.getElementsByClassName("userA")
374     userAn = [];
375     trueAnswer = new Array();
376     trueAnswer="<p>正确题号:";
377      flaseAnswer = new Array();
378     flaseAnswer="<p>错误题号:";
379     tureTotal=0;
380     flaseTotal=0;
381 
382 
383     for(j = 1;j <= subject;j++)
384     {
385        if(userAnswer[j-1].value == arr[j][4])
386            { trueAnswer+= j + ‘,‘;tureTotal++;}
387        else
388          { flaseAnswer += j+‘,‘;flaseTotal++;}
389         userAn[j] = userAnswer[j-1].value;
390 
391     }
392     console.log(userAn);
393     console.log(tureTotal);
394     console.log(flaseTotal);
395     trueAnswer+="</p><h>共"+tureTotal+"题</h>";
396     flaseAnswer+="</p><h>共"+flaseTotal+"题</h>";
397     console.log(trueAnswer);
398     console.log(flaseAnswer);
399     
400     document.getElementById("Right").innerHTML = trueAnswer;
401     document.getElementById("Fault").innerHTML = flaseAnswer;
402         
403 }
404 
405 
406 function downloadQuestion(){
407     if(sign ==0 ){alert("请先出题");return false;}
408     var question = quesitonsHtmlArr.toString();
409     var name = "question.txt";
410     question = question.split("<input class=‘userA‘ type=‘text‘/></li>");
411     question = question.join("
");
412     question = question.split("<li>");
413     question = question.join("");
414 
415     download(name,question)
416 }
417 
418 
419 function donloadAnswer(){
420     if(sign ==0 ){alert("请先出题");return false;}
421     var answer =answerHtmlArr.toString();
422     var name = "answer.txt";
423     answer = answer.split("</li>");
424     answer = answer.join("
");
425     answer = answer.split("<li>");
426     answer = answer.join("");
427     download(name,answer)
428 }
429 
430 
431 function download(filename, text) {
432     var pom = document.createElement(‘a‘);
433     pom.setAttribute(‘href‘, ‘data:text/plain;charset=utf-8,‘ + encodeURIComponent(text));
434     pom.setAttribute(‘download‘, filename);
435     if (document.createEvent) {
436         var event = document.createEvent(‘MouseEvents‘);
437         event.initEvent(‘click‘, true, true);
438         pom.dispatchEvent(event);
439     } else {
440         pom.click();
441     }
442 }
js
技术图片
  1 *{
  2     margin: 0;
  3     padding: 0;
  4     
  5 }
  6 body{
  7     min-width:1000px;
  8     background-image: linear-gradient(to bottom right ,#eaafc8,#654ea3);
  9 }
 10 .site-header{
 11     width:100%;
 12     text-align: center;
 13     background-color:#ffffff;
 14     padding:1rem;
 15     color: #654ea3;
 16     font-weight:bold;
 17     position:fixed;
 18     font-family: "STCaiyun";
 19     font-size:1.5rem;
 20 }
 21 .box{
 22     height:3.56rem;
 23 
 24 }
 25 .premises{
 26     font-family: "楷体";
 27     background-color:#654ea3;
 28     /*background-image: linear-gradient(to bottom right, #9cbdb3 , #37b8e9);*/
 29 
 30 }
 31 
 32 .premises-content1{
 33     padding-top:1rem;
 34     text-align:center;
 35     width:20rem;
 36     margin:0 auto;
 37     line-height:3rem;
 38     color:#ffffff;
 39 }
 40 .premises-content1 button{
 41     height:2rem;
 42     width:5rem;
 43     border-radius:5px;
 44     border:none;
 45     background-color:#ffffff; 
 46     color:#654ea3;
 47     text-align:center;
 48     text-decoration:none;
 49     cursor:pointer;
 50     font-weight:bold;
 51     outline:none;
 52 }
 53 .premises-content1 button:hover{
 54     background-color:black;
 55     color:#ffffff;
 56 
 57 }
 58 
 59 
 60 
 61 .premises-content1 input{
 62     border:1px solid #ccc;
 63     padding:7px 0px;
 64     padding-left:0.3rem;
 65     border-radius:3px;
 66 }
 67 .content{
 68     width:60%;
 69     height:38rem;
 70     margin:0 auto;
 71     line-height:2rem;
 72     padding-top:2rem;
 73 }
 74 .question{
 75     float:left;
 76     background-color:#ececec;
 77     height:35rem;
 78     width: 50%;
 79     box-shadow:-2px 3px 5px 0px gray;
 80     
 81     padding-left: 2rem;
 82     overflow:auto;
 83 }
 84 .question input{
 85     border:none;
 86     border-bottom:1px solid black;
 87     background:transparent;
 88     outline:medium;
 89     padding-left:1rem;
 90     text-align:center;
 91     font-size:1.2rem;
 92     width:7rem;
 93 
 94 
 95 }
 96 .answer{
 97     float:right;
 98     background-color:#ececec;
 99     height:35rem;
100     width:38%;
101     box-shadow:2px 3px 5px 0px gray;
102     padding-left:2rem;
103     overflow:auto;
104 }
105 .content ul{
106     list-style:none;
107 }
108 .content2{
109     width:30rem;
110     margin:0 auto;
111     height:3rem;
112     transform:translateX(25%);
113     
114 }
115 .content2 button{
116     height:2rem;
117     width:auto;
118     border-radius:5px;
119     border:none;
120     background-color:#ffffff; 
121     color:#654ea3;
122     text-align:center;
123     text-decoration:none;
124     cursor:pointer;
125     font-weight:bold;
126     padding:0.5rem;
127     display:block;
128     outline:none;
129 
130 }
131 .content2 button:hover{
132     background-color:black;
133     color:#ffffff;
134 }
135 .bleft{
136 
137     float:left;
138 }
139 .bleft2{
140     float:left;
141     margin-left:1rem;
142 }
143 .bright2{
144     float:right;
145     margin-left:1rem;
146 }
147 
148 .bright{
149 
150     float:right;
151 }
152 #Right{
153     width:80%;
154     height:5rem;
155     margin:0 auto;
156     border:1px solid gray;
157     padding-left: 2rem;
158     padding-top:1rem;
159     overflow:auto;
160     background-color:#ffffff;
161     opacity:0.4;
162 }
163 #Fault{
164     width:80%;
165     height:5rem;
166     margin:0 auto;
167     border:1px solid gray;
168     padding-left: 2rem;
169     padding-top:1rem;
170     background-color:#ffffff;
171     opacity:0.4;
172     margin-bottom:5rem;
173     overflow:auto;
174 
175 }
css

 

 

 

 

 

6.测试运行:

界面

技术图片

 

 

 

 

生成题目

技术图片

技术图片

 

 

 

 

 

 

批改及显示答案

技术图片

 

 

 

 

下载

 

 

 技术图片

 

 

 

7.项目小结:
1.在这次项目中,我们不仅更加熟悉了html,css javascript语言的运用,还学习了逆波兰算法,同时也增加了与人合作开发的经验。

2.在完成这个项目的时候遇到了很多不懂的内容,我们提出彼此的想法,互相交流学习进度。而且结对项目让我们互相督促彼此,让两个人更有学习的动力。

 

以上是关于结对项目——自动生成小学四则运算的主要内容,如果未能解决你的问题,请参考以下文章

201571030303/201571030315《 小学四则运算练习软件》结对项目报告;

201571030122/201571030129 《小学生四则运算》 结对项目

201571030129/201571030122 《小学生四则运算》 结对项目

结对项目----实现一个自动生成小学四则运算题目的命令行程序

小学生四则运算结对项目

结对项目----实现一个自动生成小学四则运算题目的命令行程序