Github project address: https://github.com/bravedreamer/test/tree/master/Arithmetic
Online preview: https://bravedreamer.github.io/test/Arithmetic/index.html
Project Partner: Wu Shangqian 3118004977 Wu Maoping 3118004976
1. Title Description
Implements a command line program that automatically generates four arithmetic titles for elementary schools (also using an image interface with similar functions).
Natural numbers: 0, 1, 2,....
True score: 1/2, 1/3, 2/3, 1/4, 1'1/2,....
Operators: +,, *,.
Brackets: (,).
Equal sign: =.
Separator: Space (used before and after the four operators and the equal sign).
Arithmetic expression:
e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
Where e, e1 and e2 are expressions and n are natural numbers or true fractions.
Four operation titles: e = where e is an arithmetic expression.
Requirements:
-
Using the -n parameter to control the number of generated titles, such as Myapp.exe-n 10, will generate 10 titles.
-
Use the -r parameter to control the range of values (natural numbers, true fractions, and true fractional denominators) in the title, such as Myapp.exe -r 10
Four arithmetic titles within 10 (excluding 10) will be generated.This parameter can be set to 1 or another natural number.This parameter must be given or the program will error and give help. -
The calculation process in the generated Title cannot produce negative numbers, that is, if there are subexpressions in the arithmetic expression such as e1_e2, E1 is greater than or equal to e2.
-
If a subexpression such as e1_e2 exists in the generated title, the result should be a true fraction.
-
There are no more than three operators in each topic.
-
The Title generated by a single run of the program cannot be repeated, that is, no two titles can be transformed into the same title by a finite number of exchanges of arithmetic expressions of +and *For example, 23 + 45 = and 45 + 23 = are duplicate titles, and 6 *8 = and 8 *6 = are also duplicate titles.The two titles 3+ (2+1) and 1+2+3 are duplicated, because + is left-joined, 1+2+3 is equivalent to (1+2)+3, which is 3+ (1+2), or 3+ (2+1).However, 1+2+3 and 3+2+1 are not duplicate questions, because 1+2+3 is equivalent to (1+2)+3 and 3+2+1 is equivalent to (3+2)+1. They cannot be changed into the same topic through a finite exchange.
The generated title is saved to the Exercises.txt file in the current directory of the executor in the following format:
Four operations Title 1
Four operations Title 2
......
True fractions are input and output in the following format: three fifths of the true fraction is 3/5, and two and three eighths of the true fraction is 2'3/8. -
At the same time the questions are generated, the answers to all questions are calculated and stored in the Answers.txt file in the current directory of the executor in the following format:
Answer 1
Answer 2
In particular, the operation of true fractions is shown in the following example: 1/6 + 1/8 = 7/24. -
The program should be able to support 10,000 questions.
-
The program supports determining the right and wrong answers for a given title file and answer file and making quantitative statistics with the following input parameters:
Myapp.exe -e .txt -a .txt
The statistical results are output to the file Grade.txt in the following format:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
The number 5 after':'denotes the number of correct/wrong titles, and the number of correct/wrong titles is enclosed in parentheses.For simplicity, assume that the titles entered are all sequentially numbered, canonical titles
2.PSP:
PSP2.1 | Personal Software Process Stages | Estimated time-consuming (minutes) | Actual time consumed (minutes) |
---|---|---|---|
Planning | plan | 30 | 15 |
· Estimate | Estimate how long this task will take | 960 | 1365 |
Development | Development | 840 | 1320 |
· Analysis | Needs analysis (including learning new technologies) | 30 | 15 |
· Design Spec | Generate design documents | 20 | 20 |
· Design Review | Design review (and review design documents with colleagues) | 10 | 5 |
· Coding Standard | Code specifications (develop appropriate specifications for current development) | 10 | 10 |
· Design | Specific design | 10 | 10 |
· Coding | Specific encoding | 720 | 1230 |
· Code Review | Code Review | 10 | 10 |
· Test | Test (self-test, modify code, submit changes) | 30 | 20 |
Reporting | Presentation | 40 | 30 |
· Test Report | . Test Report | 20 | 10 |
· Size Measurement | Calculate Workload | 10 | 10 |
· Postmortem & Process Improvement Plan | Post-mortem Summary and Process Improvement Plan | 10 | 10 |
Total | 910 | 1365 |
3. Performance Analysis
As the number of generated titles increases, the consumption of this part of the function increases with the number of titles.
createQuestion(){//Generate multiple titles //Initialize data list ... let questionData=[] for(let i=0;i<this.form.questionNum;){ let content=this.createQuestionInfo() let answer=content.answer let question=content.question if(answer>=0){ this.form.questionList[i]=question this.form.answerList[i]=answer let tag={} tag.question=question+answer tag.index=i+1 questionData[i]=tag i++ } } this.tableData=questionData },
4. Ideas for implementation
5. Key Code Analysis
The functions of each function are basically implemented in one vue, which is more clear.
new Vue({ ... beforeCreate() { // read file FileReader.prototype.reading = function ({encode} = pms) { let bytes = new Uint8Array(this.result); //Unsigned integer array let text = new TextDecoder(encode || 'UTF-8').decode(bytes); return text; }; /* Override readAsBinaryString function */ FileReader.prototype.readAsBinaryString = function (f) { if (!this.onload) //If this does not override the onload function, create a common handling this.onload = e => { //In this.onload function, complete the public processing let rs = this.reading(); console.log(rs); }; this.readAsArrayBuffer(f); //The internal callback to this.onload method }; }, methods:{ ... tableRowClassName({row, rowIndex}) {//Change table style ... }, createOperationArr(arr1,arr2){//Merge the generated array of operations and the array of operators let operationArr=[] let question="" for(let i=0;i<arr2.length;i++){ question+=(arr1[i]+arr2[i]) operationArr.push(arr1[i]) operationArr.push(arr2[i]) if(i==(arr2.length-1)) { question+=arr1[(i+1)] operationArr.push(arr1[(i+1)]) } } return {operationArr,question} }, createQuestionInfo(){//Create operators and operands for a topic let operation=[" + ", " − ", " × ", " ÷ ", " / "," = "]//Save Related Operators let operationTime=Math.floor(Math.random() * (3 - 1+1)+1)//Number of operations //Random Generation Operator let operationSymbol=[]//Save generated operators for(let k=0;k<operationTime;){ let i=Math.floor(Math.random() * (4 - 0+1)) if(i==4){ if(operationSymbol.length>0&&operationSymbol[operationSymbol.length-1]==operation[i]){ }else{ operationSymbol[operationSymbol.length]=operation[i] } }else{ operationSymbol[operationSymbol.length]=operation[i] k++ } } // Math.floor (Math.random()*(n-m+1)+m takes random numbers between m-n [m,n] //Random Generation Operator let operationTagNumber=[]//Save generated operands for(let k=0;k<=operationSymbol.length;){ let last=k-1 if(k>0&&(operationSymbol[last]==operation[4]||operationSymbol[last]==operation[3])){ let t=Math.floor(Math.random() * (Number(this.form.max) - Number(this.form.min))) +Number(this.form.min) if(operationSymbol[last]==operation[4]&&t!=0&&operationTagNumber[last]<=t){ operationTagNumber[k]=t k++ } if(t!=0&&operationSymbol[last]==operation[3]){ operationTagNumber[k]=t k++ } }else{ operationTagNumber[k]=Math.floor(Math.random() * (Number(this.form.max) - Number(this.form.min))) +Number(this.form.min) k++ } } let content=this.createOperationArr(operationTagNumber,operationSymbol) let operationArr=content.operationArr let question=content.question question+=operation[5] operationArr=this.getRPN(operationArr) let answer=this.getResult(operationArr) return{question,answer} }, createQuestion(){//Generate multiple titles //Initialize data list ... let questionData=[] for(let i=0;i<this.form.questionNum;){ ... for(let j=0;j<this.form.questionList.length;j++){ if(this.form.questionList[j]==question){//Check for duplicates in generated titles isRepeat=true break; }else{ isRepeat=false } } if(answer>=0&&!isRepeat){ this.form.questionList[i]=question this.form.answerList[i]=answer let tag={} tag.question=question+answer tag.index=i+1 questionData[i]=tag i++ } } this.tableData=questionData }, getRPN(arr){//Infix expression to suffix expression let symbolPriority = {//Determining Operational Priority " # ": 0, " + ": 1, " − ": 1, " × ": 2, " ÷ ": 2, " / ": 3 } let operand=[]//Stack holding operands let operator=[]//Stack to save operators arr.unshift(" # ")//facilitate operation priority comparison for(let i=0;i<arr.length;i++){ if(typeof(arr[i])=="number"){ operand.push(arr[i]) }else{ switch (true){ case (arr[i]==' ( '||operator.slice(-1)[0]==' ( '): operator.push(arr[i]); break; case (arr[i] == ' ) '): do{ operand.push(operator.pop()); }while(operator.slice(-1)[0] != " ( ") operator.pop() break; default: if(operator.length == 0){ operator.push(arr[i]); }else if(symbolPriority[operator.slice(-1)[0]]>=symbolPriority[arr[i]]){ do{ operand.push(operator.pop()); }while (symbolPriority[arr[i]]<=symbolPriority[operator[operator.length-1]]) operator.push(arr[i]); }else { operator.push(arr[i]); } break; } } } operator.forEach(function(){ operand.push(operator.pop()); }); operator.pop();//Eject "#" return operand; }, getResult(arr){//Obtain calculation results let result=[]//Used to save results let count for(let i=0;i<arr.length;i++){ if(typeof(arr[i])=='string'){ .... }else{ result.push(arr[i]) } } return result[0] }, downloadQuestion(){//Download txt files for titles and answers let questionContent=""//Topic Content let answerContent=""//Answer Content if(this.form.questionList.length!=0){ let name1="Exercises" let name2="Answers" for(let i=0;i<this.form.questionList.length;i++){ questionContent+=(i+1)+","+this.form.questionList[i]+"\n" answerContent+=(i+1)+","+this.form.answerList[i]+"\n" } this.download(name1,questionContent) this.download(name2,answerContent) }else{ this.$alert('The list of titles is empty. Please regenerate the titles', '', { confirmButtonText: 'Determine', }); } }, download(filename, text){//Download TXT file let element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); }, beforeUpload(file){//Upload Files this.fileList = [file] console.log('File selected beforeUpload') // Read data this.read(file); return false }, read(f) {//Parse Uploaded Files let rd = new FileReader(); rd.onload = e => { //Within this.readAsArrayBuffer function, this.onload function is called back.Processing results here let cont = rd.reading({encode: 'UTF-8'}); this.fileData.push(cont) let formerData = this.textData; this.textData = formerData + "\n" + cont; }; rd.readAsBinaryString(f); }, compareAnswer(){//Check the correctness of the answers to the uploaded questions and count the relevant results let questionContent=[]//Save uploaded titles let answerContent=[]//Save uploaded answers let corretAnswer=[]//Save the correct answer let corretList=[]//Save the serial number of the correct answer to the question let wrongList=[]//Save the serial number of the incorrect answer to the title let corret="" let wrong="" //Initialize data list this.form.questionList=[] this.form.answerList=[] if(this.fileData.length!=0){ for(let i=0;i<this.fileData.length;i++){ if(this.fileData[i].includes("=")){ questionContent=this.fileData[i].split("\n") for(let k=0;k<questionContent.length;k++){ for(let n=0;n<questionContent[i].length;n++){ if(questionContent[k][n]==",") questionContent[k]=questionContent[k].substr(n+1) } if(questionContent[k]==""){ questionContent.pop() }else{ corretAnswer[k]=this.getCorrectAnswer(questionContent[k])//Get the right answer } } }else{ answerContent=this.fileData[i].split("\n") for(let j=0;j<answerContent.length;j++){ for(let m=0;m<answerContent[j].length;m++){ if(answerContent[j][m]==",") answerContent[j]=answerContent[j].substr(m+1) } if(answerContent[j]!=""){ answerContent[j]=Number(answerContent[j]) }else{ answerContent.pop() } } } } let questionData=[] for(let n=0;n<answerContent.length;n++){ if(answerContent[n]==corretAnswer[n]){ corretList.push(n+1) corret+=(n+1)+"," }else{ wrongList.push(n+1) wrong+=(n+1)+"," } let tag={} tag.question=questionContent[n]+answerContent[n] tag.index=n+1 questionData[n]=tag } this.tableData=questionData this.corretList=corretList this.wrongList=wrongList corret=corret.substr(0, corret.length-1) wrong=wrong.substr(0, wrong.length-1) corret="Correct:"+corretList.length+"("+corret+")" wrong="Wrong:"+wrongList.length+"("+wrong+")" this.corret=corret this.wrong=wrong }else{ this.$alert('Title not uploaded yet, please re-upload the title', '', { confirmButtonText: 'Determine', }); } }, getCorrectAnswer(str){//Get the right answer let questionArr=str.split(" ") questionArr.pop()//Pop up the last space cut for(let i=0;i<questionArr.length;i++){ if(questionArr[i]=='='){ questionArr.splice(i,1) }else{ if(questionArr[i]=="/"||isNaN(Number(questionArr[i]))){ questionArr[i]=" "+questionArr[i]+" " }else{ questionArr[i]=Number(questionArr[i]) } } } questionArr=this.getRPN(questionArr) let corretAnswer=this.getResult(questionArr) return corretAnswer } }, })
6. Test Run
-
The interface as a whole is as follows:
-
Control parameters can generate 10,000 titles or adjust the access to generated values
-
Download and upload files, no errors
-
homework correcting
7. Summary
- Team project collaboration is important. It's not messy to plan before you start
- Choosing the right tools for co-development, such as github
3. Two people working together can interact with each other to come up with new ideas