1、链接
队友博客链接戳这里
本次作业博客链接戳这里
github项目地址
2、具体分工
- 王景弘:负责实现AI部分,设计出牌算法,编写单元测试,提供算法思路、关键、改进和性能分析等博客内容。
- 陈靖雯:负责实现UI部分,用接口连接算法形成最终文件,提供UI部分博客内容,用markdown格式编写博客内容。
3、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时 (分钟) |
实际耗时 (分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 4020 | 5195 |
· Analysis | · 需求分析 (包括学习新技术) | 600 | 1200 |
· Design | · 生成设计文档 | 40 | 30 |
· Design Review | · 设计复审 | 15 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定或选择合适的规范) | 5 | 5 |
· Design | · 具体设计 | 40 | 40 |
· Coding | · 具体编码 | 3000 | 3580 |
· Code Review | · 代码复审 | 120 | 100 |
· Test | · 测试(自我测试,修改代码,提交修改) | 200 | 230 |
Reporting | 报告 | 80 | 90 |
· Test Report | · 测试报告 | 30 | 40 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出改进计划 | 30 | 30 |
· 合计 | 4130 | 5315 |
4、解题思路描述与设计实现说明
(1)网络接口的使用
按照所给的接口文档,调用所给接口。本次作业采用html、css、javascript实现UI部分,需要新建一个XMLHttpRequest对象,向所给地址发送GET或POST请求,需要在控制台观察是否响应以便修改错误。成功响应的请求会返回需要的内容。发送的数据用JSON.stringify()转换成json字符串发送,返回的json字符串用JSON.parse()转换为JS对象,再逐一匹配标签id显示到页面中或进行其他操作。由于用到Token认证,需要用cookie保存token值并加入到请求头中。
(2)代码组织与内部实现设计(类图)
(3)说明算法的关键与关键实现部分流程图
算法关键:
- 实现的时候需要用到很多重复的switch和if/else语句。
- 发到的牌按大小排完序之后,存入数组中,按照相同的牌的数量来分类。
- 给每种牌型赋予权重值。
- 利用switch语句不断的找到手牌中所有的牌型。
- 之后将最大的拿出来留给后墩,然后剩下的牌再去寻找最大的牌型留给中墩,前墩的牌型就放在最后用剩下来的三张牌补进去,直到三道都有牌型。
- 再把牌放到Choice.java中创建的三个数组中(即前中后墩)
关键实现部分流程图
5、关键代码解释
AI部分:
最开始发到牌后,将牌从小到大排序,存储到数组中。
public void change(List<Card> handCard) { Collections.sort(handCard,new Comparator<Card>() //从小到大排序 { public int compare(Card c1, Card c2) { int i = c1.rank - c2.rank; if(i == 0) return c1.type - c2.type; return i; } }); arrange(handCard); //将牌整理到arr中
将排好序的牌按照相同的牌的数量来对数组进行分类
for(int i=0;i<handCard.size();i++) { if((i+1)<handCard.size()&&handCard.get(i).rank==handCard.get(i+1).rank) if((i+2)<handCard.size()&&handCard.get(i).rank==handCard.get(i+2).rank) if((i+3)<handCard.size()&&handCard.get(i).rank==handCard.get(i+3).rank) //四张相同的牌 { arr.ranknum4.addAll(handCard.subList(i,i+4)); i+=3; } else //三张相同的牌 { arr.ranknum3.addAll(handCard.subList(i,i+3)); i+=2; } else //两张相同的牌 { arr.ranknum2.addAll(handCard.subList(i,i+2)); i+=1; } else //没有相同的牌 { arr.ranknum1.add(handCard.get(i)); } }
通过判断读取出的对子数目和剩下的牌的数目来判断是否有牌型
此处为判断是否有四套三条和五对三条
if(arr.ranknum3.size()==12||(arr.ranknum3.size()==9&&arr.ranknum4.size()==4)) //四套三条 { choice=tochoice(handCard); choice.headType="sitaosantiao"; return; } if(arr.ranknum2.size()==10&&arr.ranknum3.size()==3) //五对三条 { choice=tochoice(handCard); choice.headType="wuduisantiao"; return; }
通过arr.ranknum4.size和arr.ranknum3.size的大小来判断牌型,并且改变Choice.java中的前中后墩数组(choice.headType/midType/endType)来进行出牌时的文字说明
if(arr.ranknum4.size()==4) //尾道为铁支 { choice.end.addAll(arr.ranknum4); card.removeAll(choice.end); arrange(card); if(arr.ranknum3.size()==6) //中道是葫芦 { if(!arr.ranknum2.isEmpty()) { choice.mid.addAll(arr.ranknum3.subList(3, 6)); choice.mid.addAll(arr.ranknum2); choice.midType="hulu"; choice.head.addAll(arr.ranknum3.subList(0, 3)); choice.headType="santiao"; card.removeAll(choice.head); card.removeAll(choice.mid); choice.end.addAll(card); choice.endType="tiezhi"; return; } else { choice.mid.addAll(arr.ranknum3.subList(1, 6)); card.removeAll(choice.mid); choice.end.add(card.get(0)); choice.head.addAll(card.subList(1, 4)); choice.endType="tiezhi"; choice.midType="hulu"; choice.headType="wulong"; return; } }
UI部分:
登录的请求成功后会返回一个token,要用cookie保存,之后的请求要用split函数从cookie中提取出token放在其他需要token的请求的请求头中。
xhr.addEventListener("readystatechange", function () { if (this.readyState === this.DONE) { console.log(this.responseText); var JsonObj = JSON.parse(this.responseText); if(JsonObj.status==0) { document.cookie = JsonObj.data.token; valid(); } } });
var token = document.cookie.split(";")[0]; xhr.setRequestHeader("x-auth-token",token);
进行下一次查询时需要删除之前表格中存在的数据,用到deleteRow函数将存在的行删除,若按从下标小到大的顺序删除,在删除过程中行的下标会不断改变,所以要从大到小删除。
var tb = document.getElementById('table'); var rowNum=tb.rows.length; for (var j=rowNum-1;j>=0;j--) //下标会变化,要从后往前删 { tb.deleteRow(j); }
6、性能分析与改进
(1)描述改进思路
一开始只是单纯的想全用if/else语句来进行所有牌型的罗列但发现工程量实在是太大了,还是得逐步分析才能得到解法。后面想到先对花色和点数综合排序之后填入数组进行第一次分类(分点数大小的类),然后用判断数组大小的方式来进行第二次分类(分牌型的类,如对子三条之类的),再根据第二次分类出的结果来判断有没有特殊牌型(如全大全小、至尊青龙、五对三条之类的),最后给每种判断出的牌型赋予权重,用以判断什么牌型该放在什么位置。在进行完判断牌型的步骤之后再进行一下文字说明。
(2)展示性能分析图和程序中消耗最大的函数
7、单元测试
8、Github的代码签入记录
9、遇到的代码模块异常或结对困难及解决办法
(1)问题描述
UI部分:
- 不熟悉如何将json数据显示在页面中。
- 接口调用不知道如何实现。
- http请求一直失败,显示未授权。
AI部分:
(2)做过哪些尝试
UI部分:
- 在百度等渠道疯狂搜索解决方法,查找之前练习的代码。
- 询问同学。
AI部分:
(3)是否解决
UI部分:
已解决。(以下每一点与问题一一对应)
- 正确使用javascript,理清标签父子关系,使用json.parse()将json格式转化成js对象。
- 接口文档有code generation,根据需要修改。
- token值没有保存,设置的请求头有错,使用了document.cookie解决。
AI部分:
(4)有何收获
10、评价你的队友
(1)值得学习的地方
(2)需要改进的地方
11、学习进度条
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 18 | 18 | 学习原型工具,完成第一次原型设计 |
制作UI时查找到的实用资料
HTML页面跳转的5种方法
用js实现动态添加表格数据
JSON.parse()
js中设置元素class的三种方法小结
js中删除table里所有行
详细介绍NW.js基本使用
HTML网页打包成EXE可执行文件
将Token添加到请求头Header中
JSON.parse() 与 JSON.stringify() 简单使用
Session与Token认证机制 前后端分离下如何登录
js使用sessionStorage、cookie保存token