一、给出结对同学的博客链接、本作业博客的链接、你所Fork的同名仓库的Github项目地址
二、具体分工
-
黄皓: UI 、部分接口
-
张泽宇: AI 、部分接口
三、PSP表格
PSP4.1 | Personal Software Process Stages |
预估耗时(min) | 实际耗时(min) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 10 | 20 |
Development | 开发 | 2000 | 2500 |
Analysis | 需求分析 (包括学习新技术) |
800 | 1000 |
Design Spec | 生成设计文档 | 60 | 30 |
Design Review | 设计复审 | 30 | 20 |
Coding Standard | 代码规范 (为开发制定合适的规范) |
30 | 20 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 240 | 180 |
Code Review | 代码复审 | 10 | 120 |
Test | 测试 (自我测试,修改,提交修改) |
180 | 180 |
Reporting | 报告 | 60 | 60 |
Test Report | 测试报告 | 20 | 20 |
Size Measurement | 计算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan |
事后总结 并提出过程改进计划 |
30 | 30 |
合计 | 3570 | 4280 |
四、解题思路描述与设计实现说明
1.网络接口的使用
UI部分:前端是使用html、css、javascript写的,接口是javascript中的XML类型。
注册API
localStorage.removeItem("token");
localStorage.removeItem("user_id");
localStorage.setItem("token",json.data.token);
localStorage.setItem("user_id",json.data.user_id);
window.location.href='登陆界面.html';
console.log(xhr.responseText);
}
}
xhr.open("POST", "http://api.revth.com/auth/register2",true);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(data);
历史记录API
xhr.open("GET", "http://api.revth.com/history?page="+x+"&limit=15&player_id="+localStorage.getItem("user_id"),true);
xhr.setRequestHeader("X-Auth-Token",localStorage.getItem("token"));
xhr.send();
2.代码组织与内部实现设计(类图)
没有类,全部功能由函数实现,所以没有类图。
-
排序使用到的函数getvalue(x)
-
给后墩评分的函数getlevel(cards)
-
给后墩评分的函数getsecondlevel(cards)
-
八选五函数getsecond(cards)
-
分出三墩函数getpostcards(cards)
3.算法的关键与关键实现部分流程图
流程图
算法关键
step1:字符串改成列表;
step2:使用评分的方法先找出后墩,但找的时候需要让中墩前墩尽量大;
step3:总分值最大的牌型,选定后墩,剩下八张中评分最高的作为中墩。
五、关键代码解释
贴出你认为重要的/有价值的代码片段,并解释
UI部分:
登陆界面:
mylogin=function(){
if(document.getElementById("username").value==""||document.getElementById("password").value=="")
{alert("账号和密码不能为空");return ;}
else{
var data = JSON.stringify({
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
})
var xhr = new XMLHttpRequest();
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
var json=JSON.parse(xhr.responseText);
alert("登陆成功");
localStorage.removeItem("token");
localStorage.removeItem("user_id");
localStorage.setItem("token",json.data.token);
localStorage.setItem("user_id",json.data.user_id);
window.location.href='首页.html';
console.log(xhr.responseText);
}
}
xhr.open("POST", "http://api.revth.com/auth/login",true);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(data);
}
}
排行榜界面:
var data=null;
var obj;
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
var json=xhr.responseText;
obj=JSON.parse(xhr.responseText);
function getJsonLength(obj){
var jsonLength=0;
for(var i in obj){
var j=jsonLength;
var s=j+1;
document.getElementById("mytbody").innerHTML+='<tr><td>'+s+'</td><td>'+obj[j].player_id+'</td><td>'+obj[j].name+'</td><td>'+obj[j].score+'</td></tr>';
jsonLength++;
}
}
getJsonLength(obj);
}
}
xhr.open("GET","http://api.revth.com/rank",true);
xhr.send();
注销界面:
function my() {
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function () {
if(xhr.readyState==4&&xhr.status==200){
alert(xhr.responseText);
window.location.href="登陆界面.html";
}
}
xhr.open("POST", "http://api.revth.com/auth/logout");
xhr.setRequestHeader("x-auth-token", localStorage.getItem("token"));
xhr.send();
}
AI部分:
def getpostcards(cards):
thirdlevel = [100, 0]
global second
global third
for i0 in range(0, 9):
for i1 in range(i0+1, 10):
for i2 in range(i1+1, 11):
for i3 in range(i2+1, 12):
for i4 in range(i3+1, 13):
currentcards = [cards[i0], cards[i1], cards[i2], cards[i3], cards[i4]]
newlevel = getlevel(currentcards)
if newlevel[0] < thirdlevel[0]:
third = currentcards
thirdlevel = newlevel
eightcards = [item for item in cards if item not in currentcards]
secondlevel = getsecondlevel(eightcards)
elif newlevel[0] == thirdlevel[0]:
eightcards = [item for item in cards if item not in currentcards]
newsecondlevel = getsecondlevel(eightcards)
if newsecondlevel[0] < secondlevel[0] or (newsecondlevel[0] == secondlevel[0] and newsecondlevel[1] > secondlevel[1]):
third = currentcards
thirdlevel = newlevel
secondlevel = newsecondlevel
elif newlevel[1] > thirdlevel[1]:
third = currentcards
thirdlevel = newlevel
secondlevel = newsecondlevel
eightcards = [item for item in cards if item not in third]
second = getsecond(eightcards)
first = list(set(cards) - set(second) - set(third))
first.sort(key=getvalue)
first = ' '.join(first)
second = ' '.join(second)
third = ' '.join(third)
thecards = [first, second, third]
return thecards
这是用来获取最终牌型的函数。其中调用了getlevel()、getsecondlevel()、getsecond()函数。先是一个五重循环来遍历所有C(13, 5),判断这个后墩行不行就是用他的牌型和剩下的八张牌组成的最好的中墩的牌型,而最好的中墩也包含了让前墩尽量大。
六、性能分析与改进
1.改进的思路:原先是判断后墩直接把最大的当作后端,前墩和中墩会变得很小,甚至是散排。后来改变了想法,判断后墩的时候加入中墩和前墩的判断。
2.性能分析图
消耗最大的函数:two_pair 判断并返回五张牌中两对的情况,是评分的一部分。
七、单元测试
部分单元测试代码
def test():
cards = [
['*J', '#Q', '#J', '*7', '*5', '#4', '*8', '#10', '*6', '&5', '#A', '$3', '*4'],
['$2', '*3', '$6', '$9', '*4', '$7', '$3', '*6', '*J', '&Q', '#10', '#3', '&4'],
['$10', '*6', '*4', '#J', '$K', '$3', '&9', '*5', '$7', '&A', '*J', '&Q', '&2'],
['$J', '*9', '$6', '$9', '$8', '&4', '$A', '#9', '&A', '&9', '$5', '*Q', '*10'],
['$A', '#A', '&6', '*10', '$6', '#7', '*3', '&2', '&9', '$8', '&8', '$5', '&5'],
['$10', '*8', '*A', '*4', '#8', '#J', '#7', '&2', '$2', '#2', '#5', '*6', '&Q'],
['*2', '#J', '$3', '#6', '#Q', '#9', '$K', '$J', '*3', '*A', '$10', '$A', '&7'],
['#7', '&5', '&3', '*A', '#2', '$8', '$9', '*5', '&7', '*8', '#4', '&2', '*3'],
['&K', '*Q', '$3', '#J', '&A', '$6', '#4', '$8', '&4', '#Q', '*8', '#9', '*3'],
['*Q', '$6', '&J', '#7', '#10', '*8', '#8', '&6', '*A', '#A', '&8', '&7', '$5'],
['$K', '*4', '&K', '&7', '#K', '#Q', '$Q', '*10', '#10', '$5', '&2', '*Q', '&10']
]
for i in cards:
i.sort(key=getvalue)
finalcards = getpostcards(i)
print(finalcards)
输出的结果
['$3 &5 *J', '#4 #10 #J #Q #A', '*4 *5 *6 *7 *8']
['$2 $7 $9', '$6 *6 #10 *J &Q', '*3 $3 #3 *4 &4']
['&2 &9 *J', '$3 *4 *5 *6 $7', '$10 #J &Q $K &A']
['*10 *Q &A', '$5 $6 $8 $J $A', '&4 *9 $9 #9 &9']
['*3 $5 $6', '#7 $8 *10 $A #A', '&2 &5 &6 &8 &9']
['*4 #5 *6', '#7 $10 #J &Q *A', '&2 $2 #2 *8 #8']
['*2 *3 #6', '&7 #9 #J #Q *A', '$3 $10 $J $K $A']
['*5 &5 $9', '#2 &2 &3 *3 *A', '#4 #7 &7 $8 *8']
['#9 #J *Q', '$8 *8 #Q &K &A', '$3 *3 #4 &4 $6']
['$5 #10 &J', '$6 &6 #7 &7 *Q', '*8 #8 &8 *A #A']
['&2 *4 $5', '&7 *10 #Q $Q *Q', '#10 &10 $K &K #K']
测试的函数:生成最终出牌的分出三墩函数getpostcards(cards)
构造测试数据的思路:常见的同花顺、炸弹、葫芦、同花、顺子、两对这几个主要牌型在后墩。
八、贴出Github的代码签入记录
九、遇到的代码模块异常或结对困难及解决方法
问题描述
1.API的调用有很多种方法,有点混乱;
2.UI中的开启战局部分需要把接收到的牌转成图片;
3.同一副牌运行出的牌型后墩一样,前墩和中墩都不一样;
做过哪些尝试
1.看了很多关于Ajax, XMLHttpRequest, Jquery的资料,也参学习了别的同学的部分代码;
2.查找特殊字符的判断,还有img scr相对地址的描述方法;
3.上网查找
是否解决
1.部分接口已经解决,还有部分接口还未实现;
2.未解决,只有一种花色的牌型能够输出图片;
3.已解决。
有何收获
1.API的调用不要多种方法掺着用,在不熟练的理解下这样做可能会出现很多错误
2.速成还是有很多缺陷的,很多细小的问题没办法解决。只有认认真真把每个知识点都看过了练习了可能才能解决问题;
3.从列表中删除元素,用集合的方法first = list(set(cards) - set(second) - set(third))来删除元素,删除后的列表中元素的顺序是随机的。用eightcards = [item for item in cards if item not in third]这种方式删除能保持原来的顺序
十、评价你的队友
值得学习的地方:
打代码很认真,不满足于现状,一直要改代码。
需要改进的地方:
不会劳逸结合,半夜了还在打代码,需要适当休息。
十一、学习进度条(2分)
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 24 | 24 | 学习了Axure Rp9 |
2 | 640 | 640 | 40 | 64 | 学习了html、css ,写出基本的页面布局,学习python |
3 | 300 | 940 | 42 | 106 | 学习了javascript 学会控制页面的行动 |
4 | 200 | 1140 | 24 | 130 | 学习了API的调用 |