一.前提
(1)作业来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2213
(2)GitHub地址:https://github.com/GVictory/MakeOutQuestionsWithInterface
(3)调试环境:IntelliJ IDEA ,CHORME浏览器
二.作业要求
(1)基本要求
- 自动生成题目,单个题目最多不能超过4个运算符,操作数小于100。
- 用户可以输入答案
- 若用户输入答案正确,则提示正确;若答案错误,则提示错误,并要提示正确答案是多少。
(2)扩展要求
- 用户答题结束以后,程序可以显示用户答题所用的时间
- 用户可以选择出题的个数(最多不能超过5个题目),答题结束可以显示用户答错的题目个数和答对的题目个数
- 用户在第一次答题时,需要用户输入用户名,用户下次启动后,程序需要记住用户前一次输入的用户名
- 程序可以设置答题时间,时间设置为整数,单位为秒,最大不能超过120秒,若超过了答题时间未答题,则提示:时间已到,不能答题。
(3)结对成员
姓名:李志成 学号:201606110064 博客园地址:https://www.cnblogs.com/97lzc/
姓名:郭木凯 学号:201606110066 博客园地址:https://www.cnblogs.com/GMUK/
三.时间估算
结对项目软件过程耗时估计表与统计表
(时间单位:小时)
|
PSP2.1
|
个人软件实现阶段 |
预计时间 |
实际时间 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
Planning |
计划 |
1 |
2 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Estimate |
估计这个任务需要多少时间 |
10 |
15 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
Development |
开发 |
10 |
10 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Analysis |
需求分析 (包括学习新技术) |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Design Spec |
生成设计文档 |
1 |
1 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
· Design Review |
设计复审 |
0.5 |
0.5 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Coding Standard |
代码规范 |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Design |
具体设计 |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Coding |
具体编码 |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Code Review |
代码复审 |
0.5 |
0.5 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· Test |
测试(自我测试,修改代码,提交修改) |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
Reporting |
报告 |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· |
测试报告 |
1 |
1 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· |
计算工作量 |
2 |
2 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
· |
并提出过程改进计划 |
2 |
2 |
四:工作详情
(一)工作:
李志成: 题目和答案生成,前台题目和答案的渲染。
郭木凯: 前台设计,换肤,计时。
(二) 部分功能代码介绍:
首先是前端页面的实现,通过html,css,JavaScript,jQuery,vue.js编写
1 <!DOCTYPE html>
2 <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
3 <head>
4 <meta charset="UTF-8">
5 <title>志成出题</title>
6 <script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
7 <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
8 </head>
9 <body style="height: 100%;">
10 <div style="display: flex;justify-content: center;align-content: center">
11 <div id="boss" style="display:flex; 600px;height: 450px;border: 1px dashed gray; padding: 0px; color: rgb(0, 0, 255); line-height: 1.5 !important;">>
12 <div style=" 100px;border-right: 1px solid #bbbbbb;height: 100%;display:flex;align-content: center;justify-content: center">
13 <div style="font-size: 30px; 30px;margin-top: 20px">志成出题</div>
14 </div>
15 <div style=" 100%;height: 100%;display: flex;flex-direction: column">
16 <div style=" 100%;height: 90px;display: flex;align-items: flex-end;flex-direction: row;align-items:center;justify-content: space-between">
17 <div>
18 <div id="selectCount"
19 style="display: flex;flex-direction: column;align-items: center;margin-left: 20px">
20 <select id="select"
21 style="height:28px; 90px; line-height:28px; border:1px solid #9bc0dd; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; ">
22 <option value="1">1</option>
23 <option value="2">2</option>
24 <option value="3">3</option>
25 <option value="4">4</option>
26 <option value="5" selected>5</option>
27 </select>
28 <button id="countButton" onclick="getArithmetic()"
29 style="margin-top:10px;border:none;height: 30px;60px;color: white;border-radius: 15%;font-size: 9px">
30 确定
31 </button>
32 </div>
33 </div>
34 <div>
35 <div style="display: flex;align-items: flex-start; 150px;margin-bottom: 5px">
36 <span>所用时间:</span><span id="useTime">0</span><span>秒</span>
37 </div>
38 <div style="display: flex;align-items: flex-start; 150px;margin-top: 5px">
39 <span>答题时间:</span><span>120秒</span>
40 </div>
41 </div>
42
43 </div>
44 <div id="test"
45 style=" 100%;height: 270px;border-top: 1px solid #bbbbbb;border-bottom:1px solid #bbbbbb;display: flex;flex-direction: column;padding: 30px;box-sizing:border-box">
46 <div id="body">
47 <div style="margin-bottom: 10px;display: flex;" v-for="(ari,index) in arithmetic">
48 <div style=" 90px">{{ari.question}}</div>
49 <span> = </span>
50 <input v-bind:id="index" style="border:none;border-bottom: 1px solid #bbbbbb; 70px"/>
51 <i name="answers" style="margin-right: 25px;margin-left: 25px" v-bind:id="index+10">X</i>
52 <div name="answers">
53 <span>正确答案:</span>
54 <span>{{ari.answer}}</span>
55 </div>
56 </div>
57 </div>
58 </div>
59 <div id="result"
60 style=" 100%;height:85px;display: flex;flex-direction: row;justify-content: space-between;align-items: center;padding: 20px;box-sizing: border-box">
61 <div>
62 <div id="text">
63 <span>您答对了<span id="right">3</span>道题,答错了<span id="error">2</span>道题</span><br/>
64 <span>答题正确率为<span id="rate">60%</span></span>
65 </div>
66 </div>
67 <div style="display: flex;align-items: flex-end" id="commit">
68 <button onclick="commitAnswer()"
69 style="border:none;height: 45px;100px;color: white;border-radius: 12px;font-size: 17px;margin-right: 5px">
70 提交
71 </button>
72 <button id="skin" onclick="changeSkin()"
73 style="border:none;height: 30px;40px;color: white;border-radius: 15%;font-size: 9px">
74 换肤
75 </button>
76 </div>
77 </div>
78 </div>
79 </div>
80 </div>
81 </body>
82 <script>
83 var questions = new Array();
84 var vue;
85 var t;
86
87 function getArithmetic() {
88 var option = $("#select option:selected").text();
89 $.ajax({
90 type: 'GET',
91 url: "/hello?count=" + option,
92 success: function (data) {
93 var jsonData = JSON.stringify(data);
94 var obj = JSON.parse(jsonData);
95 array = obj;
96 for (var p in obj) {//遍历json对象的每个key/value对,p为key
97 var ob = {"question": p.toString(), "answer": obj[p]}
98 questions.push(ob);
99 }
100 vue = new Vue({
101 el: '#test',
102 data: {
103 arithmetic: questions
104 }
105 })
106 $("#body").show()
107 $("#selectCount").hide();
108 $("#commit").show();
109 $("#text").hide();
110 $("[name='answers']").hide();
111 var num = 0;
112 t = setInterval(function () {
113 num++;
114 $("#useTime").text(num)
115 if (num == 120) {
116 clearInterval(t);
117 alert("时间已到,答题结束")
118 commitAnswer();
119 }
120 }, 1000);
121
122 }
123 });
124 }
125
126 $(function () {
127 $("#body").hide();
128 $("#commit").hide();
129 $("#text").hide()
130 })
131
132 function changeSkin() {
133 $("#boss").css("background-color", "#2b2b2b");
134 $("#boss").addClass("changeSkin");
135 }
136
137 function commitAnswer() {
138 var rightCount = 0;
139 var errorCount = 0;
140 for (var i in questions) {
141 $("#" + i).attr("disabled", "disabled");
142 if (questions[i].answer == $("#" + i).val()) {
143 var num = parseInt(i) + 10;
144 $("#" + num.toString()).text("√");
145 rightCount++;
146 } else {
147 errorCount++;
148 }
149 }
150 clearInterval(t);
151 $("[name='answers']").show();
152 $("#commit").hide();
153 $("#text").show();
154 $("#right").text(rightCount);
155 $("#error").text(errorCount);
156 $("#rate").text((rightCount / (rightCount + errorCount) * 100) + "%")
157 }
158 </script>
159 <style>
160 .changeSkin {
161 color: #f5a528;
162 }
163 </style>
164 </html>
其次是后端控制器代码,如下:
1 public class testContraller {
2 @GetMapping("/getArithmetic")
3 public HashMap<String, Integer> getArithmetic(@RequestParam Integer count) throws JSONException {
4 return new Arithmetic().getArithmetic(count);
5 }
6 }
最后是解题函数(此处展示重要部分):
1 private static String getQuestion(Integer operatorNumber,Integer numberRange){
2 char[] operator = new char[]{'+', '-', '*', '/'};
3 Random random = new Random();
4 StringBuilder stringBuilder = new StringBuilder();
5 for (int operatorIndex = 0; operatorIndex < operatorNumber; operatorIndex++) {
6 stringBuilder.append(random.nextInt(numberRange+1));
7 stringBuilder.append(operator[random.nextInt(4)]);
8 }
9 stringBuilder.append(random.nextInt(numberRange+1));
10 return stringBuilder.toString();
11 }
12
13 private static Float getAnswer(String question){
14 Stack<Character> operatorStack=new Stack<Character>();
15 Stack<Float> numberStack=new Stack<Float>();
16 char operatorTemp;
17 StringBuilder numberTemp=new StringBuilder();
18 for (int questionIndex=0;questionIndex<question.length();questionIndex++){
19 char singleChar=question.charAt(questionIndex);
20 if (Character.isDigit(singleChar)){
21 numberTemp.append(singleChar);
22 }else {
23 if (!operatorStack.isEmpty()&&operatorStack.getTop()=='*'){
24 operatorStack.pop();
25 numberStack.push(numberStack.pop()*Float.valueOf(numberTemp.toString()));
26 }else if (!operatorStack.isEmpty()&&operatorStack.getTop()=='/'){
27 operatorStack.pop();
28 numberStack.push(numberStack.pop()/Float.valueOf(numberTemp.toString()));
29 }else if(!operatorStack.isEmpty()&&operatorStack.getTop()=='-'){
30 numberStack.push(-Float.valueOf(numberTemp.toString()));
31 }else {
32 numberStack.push(Float.valueOf(numberTemp.toString()));
33 }
34 operatorStack.push(singleChar);
35 numberTemp.delete(0,numberTemp.length());
36 }
37 }
38 if (!operatorStack.isEmpty()&&operatorStack.getTop()=='*'){
39 numberStack.push(numberStack.pop()*Float.valueOf(numberTemp.toString()));
40 operatorStack.pop();
41 }else if (!operatorStack.isEmpty()&&operatorStack.getTop()=='/'){
42 numberStack.push(numberStack.pop()/Float.valueOf(numberTemp.toString()));
43 operatorStack.pop();
44 }else if(!operatorStack.isEmpty()&&operatorStack.getTop()=='-'){
45 numberStack.push(-Float.valueOf(numberTemp.toString()));
46 }else {
47 numberStack.push(Float.valueOf(numberTemp.toString()));
48 }
49 while (!operatorStack.isEmpty()){
50 operatorStack.pop();
51 numberStack.push(numberStack.pop()+numberStack.pop());
52 }
53 return numberStack.pop();
54 }
五.软件演示
一进来网页时,网页的模样如下图,主要由五大部分组成,分别是选题数,时间计时,题目,换肤,答题情况,一开始进来时由于题目数未选择,所以时间计时是静止的,题目部分不存在。
PS:题数只能选择1-5。

当选好题数并单击按钮时,选题数部分消失,时间开始计时,题目出现,并且用户可以输入题目的答案并提交。

其次网页还具有换肤功能,当点击换肤时,会改变文字和背景色。

当点击提交时,答题情况部分出现,时间静止,考试结束。

当超过时间时,弹出提醒,并且输入框此时无法输入,进行与提交一样的操作。

六:结对照片

七:收获与感悟
由于此前已有计算类的实现,所以该作业的难度在于页面的交互以及逻辑的处理,与队友一路做下来,发现所花的时间甚多,特别是调试和测试上,一改再改,与计划的时间相差甚远,至此有感,技术决定效率,效率决定未来。
