1、链接
队友博客链接戳这里
本次作业博客链接戳这里
github项目地址
UI演示视频
2、具体分工
- 王景弘:负责实现AI部分,设计出牌算法,编写单元测试,提供算法思路、关键、改进和性能分析等博客内容。
- 陈靖雯:负责实现UI部分,用接口连接算法形成最终文件,提供UI部分博客内容,用markdown格式编写博客内容。
3、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时 (小时) |
实际耗时 (小时) |
---|---|---|---|
Planning | 计划 | 1 | 1.5 |
· Estimate | · 估计这个任务需要多少时间 | 45 | 50 |
Development | 开发 | 5 | 5 |
· Analysis | · 需求分析 (包括学习新技术) | 8 | 7.5 |
· Design | · 生成设计文档 | 0.5 | 0.5 |
· Design Review | · 设计复审 | 0.2 | 0.3 |
· Coding Standard | · 代码规范 (为目前的开发制定或选择合适的规范) | 1 | 1 |
· Design | · 具体设计 | 4 | 5 |
· Coding | · 具体编码 | 15 | 20 |
· Code Review | · 代码复审 | 1 | 2 |
· Test | · 测试(自我测试,修改代码,提交修改) | 2 | 3 |
Reporting | 报告 | 1 | 0.8 |
· Test Report | · 测试报告 | 1 | 0.5 |
· Size Measurement | · 计算工作量 | 0.1 | 0.1 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出改进计划 | 0.5 | 0.5 |
· 合计 | 45.3 | 50.2 |
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、单元测试
public static void main(String[] args) {
List<Card> allCards = new ArrayList<>();
Random random = new Random();
CardController cardController = new CardController();
for (int i = 1;i <= 4; i++){
for (int j = 1; j <= 13; j++){
allCards.add(new Card(j,i));
}
}
for (int i = 0; i < 10; i++){
List<Card> tempCards = new ArrayList<>();
List<Card> cards = new ArrayList<>();
tempCards.addAll(allCards);
for (int j = 0; j < 13; j++){
Card card = tempCards.get(random.nextInt(52 - j));
cards.add(card);
tempCards.remove(card);
}
String cardStr = "";
for (int j = 0; j < 13; j++){
Card card = cards.get(j);
cardStr += card.toString();
if (j < 12)
cardStr += " ";
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("id",0);
jsonObject.put("card",cardStr);
} catch (JSONException e) {
e.printStackTrace();
}
System.out.println(cardController.card2(jsonObject.toString()));;
}
}
每次随机构造13张牌,并且转化为符合json格式的字符串,再调用接口,得出结果
8、Github的代码签入记录
9、遇到的代码模块异常或结对困难及解决办法
(1)问题描述
UI部分:
- 不熟悉如何将json数据显示在页面中。
- 接口调用不知道如何实现。
- http请求一直失败,显示未授权。
AI部分:
- 因为刚开始接触java,关键的算法也是一筹莫展。
- 在调用接口的时候也遇到了不会调接口,每个请求的写法不会,无数次请求失败。
(2)做过哪些尝试
UI部分:
- 在百度等渠道疯狂搜索解决方法,查找之前练习的代码。
- 询问同学。
AI部分:
- 接口和java算法的问题都是老老实实看资料学习
(3)是否解决
UI部分:
已解决。(以下每一点与问题一一对应)
- 正确使用javascript,理清标签父子关系,使用json.parse()将json格式转化成js对象。
- 接口文档有code generation,根据需要修改。
- token值没有保存,设置的请求头有错,使用了document.cookie解决。
AI部分:
- 已解决。
(4)有何收获
因为刚刚接触java很多知识都不甚了解
这次比较复杂的程序设计也算是逼迫我在ddl之前尝试了一次敏捷开发
虽然很多代码都是对着查到的资料现学现用,但也算是收获了不少java语法、算法相关的知识
10、评价你的队友
(1)值得学习的地方
- 界面设计得很漂亮,对UI设计有经验。
(2)需要改进的地方
- 没啥需要改进的地方已经做得很好了
11、学习进度条
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 476 | 476 | 15 | 15 | 熟悉了java的基本语法 |
2 | 421 | 897 | 10 | 25 | 通过练习,掌握了数组的多种用法 |
3 | 1300 | 2197 | 25 | 50 | 完善了剩余的算法,学习了接口的使用 |
制作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