Foreword: This project is a part of pair programming task. We implement an command-line based arithmometer by JavaScript in Node.js environment. ......
Project Elaboration
In this project, We are required to actualize a command line program for automatically generating four arithmetic problems for primary schools.
Now the project is still in progress, we have so far finished exercise judgement, and soon we will update more information.
Team members: Wu Tang Huang, Zhang Guo Jun
GitHub: https://github.com/m8705/Arithmometer
Detail Description
Program usage
Generate problem file:
node e.js -n 10 -r 10
Validate exercise:
node e.js -e exercisefile.txt -a answerfile.txt
Parameter and regulation
- Use -n parameter to control the number of generated questions ( 1 ~ 10000 ).
- Use -r parameter to control the range of numeric value (natural number, true fraction and true fraction denominator) in the title ( 1 ~ 100 ).
- The calculation process in the generated problem does not produce a negative number, that is, if there is a sub-expression in the arithmetic expression, such as e1 - e2, then e1 < e2
- If there is a subexpression e1 ÷ e2 in the generated exercise, the result should be true score.
- There are no more than 3 operators in each problem.
- The problem generated by the program running at one time can not be repeated, that is, any two problems can not be transformed into the same problem by the finite number of exchange + and * arithmetic expressions.The generated problem is stored in the Exercises.txt file under the current directory of the execution program.
- At the same time, the answers to all the questions are computed and stored in the Answers.txt file in the current directory of the execution program.
- The program should support the generation of ten thousand problems.
- Program support for a given question file and answer file, determine the right and wrong answers and statistics, statistics output to the file Grade.txt
Code Preview
Convert fraction
1 function convert(str){//将任何数转成真分数(小数不换) 2 3 //整数 2 = 2'1/1 4 //真分数 3/8 5 //假分数 5/3 6 //带分数 1'1/2 7 8 //console.log(str) 9 10 if( str.indexOf("/") >= 0 ){//真分数或带分数 11 12 if( str.indexOf("'") >= 0 ){//带分数 13 14 first = str.split("'")[0]; 15 second = str.split("'")[1]; 16 17 up = second.split("/")[0]; 18 down = second.split("/")[1]; 19 20 if( ( up === down ) || ( down === "1" ) ){//带分数情况下,不可能存在分子分母相同或分母为1的情况 21 return "ERROR"; 22 } 23 24 str = ( (+first) * (+down) + (+up) ) + "/" + down; 25 26 } 27 else{//真分数 28 ; 29 } 30 31 } 32 else{//整数 33 34 str = str + "/1"; 35 36 } 37 38 return str 39 //console.log(str); 40 }
Fraction calculation
1 function calculate(num1,num2,operator){//根据数字和符号进行分数运算 2 3 var n1 = []; 4 var n2 = []; 5 6 var result; 7 8 n1 = convert(num1).split( "/" ); // [ 0分子,1分母 ] 9 n2 = convert(num2).split( "/" ); // [ 0分子,1分母 ] 10 11 switch(operator){ 12 case "+": 13 result = (n1[0]*n2[1]+n2[0]*n1[1]) + "/" + (n1[1]*n2[1]); 14 break; 15 case "-": 16 result = (n1[0]*n2[1]-n2[0]*n1[1]) + "/" + (n1[1]*n2[1]); 17 break; 18 case "*": 19 result = (n1[0]*n2[0]) + "/" + (n1[1]*n2[1]); 20 break; 21 case "/": 22 result = (n1[0]*n2[1]) + "/" + (n1[1]*n2[0]); 23 break; 24 } 25 26 //console.log(result); 27 return result; 28 29 }
Produce symbol
1 function produceSymbol(){//产生符号 2 3 var symbol = Math.random(); 4 var symbolNum; 5 6 if( symbol <= 1/3 ){//生成一个符号 7 symbolNum = 1; 8 } 9 else if( symbol <= 2/3 ){//生成两个符号 10 symbolNum = 2; 11 } 12 else{//生成三个符号 13 symbolNum = 3; 14 } 15 16 var symbolChoice = []; 17 var tmp; 18 for(var a = 0; a < symbolNum; a++){//用概率决定符号 19 20 tmp = Math.random(); 21 if( tmp <= 1/4 ){ 22 symbolChoice.push("+"); 23 } 24 else if( tmp <= 2/4 ){ 25 symbolChoice.push("-"); 26 } 27 else if( tmp <= 3/4 ){ 28 symbolChoice.push("*"); 29 } 30 else{ 31 symbolChoice.push("/"); 32 } 33 34 } 35 36 return symbolChoice; 37 38 }
Produce number
1 function produceNumber(symbolNum, range){//产生数字 2 3 var symbolChoice = produceSymbol(); 4 5 var numType; 6 var numChoice = []; 7 var up, down; 8 9 for( var b = 0; b < symbolNum + 1; b++ ){//用概率决定数字 10 11 numType = Math.random(); 12 13 if( numType <= 7 / 10 ){//生成整数 14 15 numChoice.push( Math.floor(Math.random()*range) + "" ); 16 17 } 18 else{//生成分数或1(避免生成分子或分母为0) 19 20 up = Math.ceil( Math.random() * range );//向上取整 21 down = Math.ceil( Math.random() * range );//向上取整 22 23 if( up === down ){//分子分母相同 24 numChoice.push("1"); 25 continue; 26 } 27 28 var tmp = Math.random();//是否产生带分数 29 if( tmp <= 1/4 ){//产生带分数 30 31 while(up <= down || (up%down === 0) ){//重新产生带分数 32 33 up = Math.ceil( Math.random() * range );//向上取整 34 down = Math.ceil( Math.random() * range );//向上取整 35 36 } 37 38 numChoice.push( 39 (up - up%down)/down + 40 "'" + 41 (up%down / gcd(up%down,down)) + 42 "/" + 43 down / gcd(up%down,down) 44 ); 45 46 } 47 else{//产生分数 48 49 numChoice.push( up + "/" + down ); 50 51 } 52 53 54 55 } 56 57 } 58 return numChoice; 59 }
Produce array
1 function produceRightArray(n, range){//产生n组符合规定的数字和符号 2 3 var rightArray = []; 4 var flag; 5 6 for(var a = 0; a < n; a++){//循环n次 7 8 flag = ""; 9 10 symbolChoice = produceSymbol(); 11 numChoice = produceNumber(symbolChoice.length,range); 12 13 for(var b = 0; b < symbolChoice.length; b++ ){//遍历检查每个符号 14 15 if( symbolChoice[b] === "*" || symbolChoice[b] === "/" ){ 16 17 if(numChoice[b] === "0" || numChoice[b+1] === "0"){ 18 19 flag = "err"; 20 a--; 21 break; 22 23 } 24 25 } 26 27 } 28 29 //console.log(a + flag); 30 31 if(flag !== "err"){ 32 rightArray.push([ 33 symbolChoice,numChoice 34 ]); 35 } 36 37 38 } 39 40 //console.log(rightArray); 41 return rightArray; 42 43 }
Core computation
1 function produceExercise(n,range){//产生n个习题(题目+答案) 2 3 var expression = []; 4 var tmp = "";//保存用于产生结果的算式 5 var tmp1 = "";//保存用于产生题目的算式 6 7 var rightArray = produceRightArray(n,range); 8 9 for(var a = 0; a < n; a++ ){//遍历每个产生的结果数组,分别验算结果是否非负 10 11 tmp = ""; 12 tmp1 = "" 13 tmp += "(" + convert(rightArray[a][1][0]) + ")" ; 14 tmp1 += rightArray[a][1][0]; 15 16 for(var b = 0; b < rightArray[a][0].length; b++ ){//符号+数字 17 tmp += rightArray[a][0][b] + "(" + convert(rightArray[a][1][b+1]) + ")"; 18 tmp1 += " " + rightArray[a][0][b] + " " + rightArray[a][1][b+1]; 19 } 20 21 while( eval(tmp) < 0 ){//不允许产生算式最终值小于0的情况 22 23 rightArray[a] = produceRightArray(1,range)[0]; 24 25 26 tmp = ""; 27 tmp1 = ""; 28 tmp += convert(rightArray[a][1][0]); 29 tmp1 += rightArray[a][1][0]; 30 31 for(var c = 0; c < rightArray[a][0].length; c++ ){//符号+数字 32 tmp += rightArray[a][0][c] + "(" + convert(rightArray[a][1][c+1]) + ")"; 33 tmp1 += " " + rightArray[a][0][c] + " " + rightArray[a][1][c+1]; 34 } 35 36 37 } 38 //console.log(tmp); 39 expression.push(tmp1); 40 } 41 42 //console.log(expression) 43 44 //console.log(rightArray); 45 46 //遍历符号列表,根据优先级(先乘除,后加减)对数进行运算,并更新运算结果(逐一替换)至数组 47 48 var tmpArray = rightArray; 49 var operator; 50 51 var symIndex; 52 var numIndex1, numIndex2; 53 54 var answer = []; 55 56 for(var d = 0; d < n; d++){ 57 58 for(var e = 0; e < tmpArray[d][0].length; e++){//先进行乘除运算 59 60 operator = tmpArray[d][0][e]; 61 62 switch(operator){ 63 64 case "*": 65 //console.log(tmpArray[d][1][e],tmpArray[d][1][e+1]); 66 67 68 replaceNumber(tmpArray[d][1],tmpArray[d][1][e],calculate( convert(tmpArray[d][1][e]),convert(tmpArray[d][1][e+1]),operator ) ); 69 removeOperator(tmpArray[d][0],"*"); 70 e--; 71 break; 72 73 case "/": 74 //console.log(tmpArray[d][1][e],tmpArray[d][1][e+1]); 75 76 77 replaceNumber(tmpArray[d][1],tmpArray[d][1][e],calculate( convert(tmpArray[d][1][e]),convert(tmpArray[d][1][e+1]),operator ) ); 78 removeOperator(tmpArray[d][0],"/"); 79 e--; 80 break; 81 82 } 83 84 85 86 } 87 88 //console.log(tmpArray) 89 90 for(var f = 0; f < tmpArray[d][0].length; f++){//后进行加减运算 91 92 operator = tmpArray[d][0][f]; 93 94 switch(operator){ 95 96 case "+": 97 //console.log(tmpArray[d][1][f],tmpArray[d][1][f+1]); 98 99 100 replaceNumber(tmpArray[d][1],tmpArray[d][1][f],calculate( convert(tmpArray[d][1][f]),convert(tmpArray[d][1][f+1]),operator ) ); 101 removeOperator(tmpArray[d][0],"+"); 102 f--; 103 break; 104 105 case "-": 106 //console.log(tmpArray[d][1][f],tmpArray[d][1][f+1]); 107 108 109 replaceNumber(tmpArray[d][1],tmpArray[d][1][f],calculate( convert(tmpArray[d][1][f]),convert(tmpArray[d][1][f+1]),operator ) ); 110 removeOperator(tmpArray[d][0],"-"); 111 f--; 112 break; 113 114 } 115 116 } 117 118 answer.push( simplify(tmpArray[d][1][0]) ); 119 } 120 121 //console.log(answer); 122 123 return [expression,answer]; 124 125 }
PSP 2.1
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 120 | 60 |
· Estimate | · 估计这个任务需要多少时间 | 15 | 15 |
Development | 开发 | 360 | 300 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 60 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 15 | 15 |
· Design | · 具体设计 | 60 | 60 |
· Coding | · 具体编码 | 120 | 100 |
· Code Review | · 代码复审 | 120 | 160 |
· Test | · 测试(自我测试,修改代码,提交修改) | 40 | 40 |
· Reporting | · 报告 | 90 | 90 |
· Test Report | · 测试报告 | 60 | 60 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1180 | 1080 |
Screenshot
Produce
Judge
Project Summary
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()