第二次结对编程作业
第二次结对编程作业
1.博客及仓库地址
2.具体分工
黄益颂:java写AI
汪倍民:网页前端html,与服务器的交互
3.PSP表格
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
Planning | 计划 | 60 |
Estimate | 估计这个任务需要多少时间 | 10 |
Development | 开发 | 600 |
Analysis | 需求分析 (包括学习新技术) | 120 |
Design Spec | 生成设计文档 | 20 |
Design Review | 设计复审 | 30 |
Coding Standard | 代码规范(为开发制定合适的规范) | 15 |
Design | 具体设计 | 100 |
Coding | 具体编码 | 150 |
Code Review | 代码复审 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 150 |
Reporting | 报告 | 40 |
Test Repor | 测试报告 | 10 |
Size Measurement | 计算工作量 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 20 |
Total | 总计 | 1375 |
4.解题思路描述和设计实现说明
1.网络接口的使用
- 注册和与教务处绑定
type: "POST",
dataType: "json",
url: "http://api.revth.com/auth/register2",
data: JSON.stringify(reg_data), //提交的数据
contentType: "application/json;charset-UTF-8",
success: function (result) { //todo
console.log(result); //打印服务端返回的数据(调试用)
if (result.status == 0) {
// alert("注册成功");
$('<div>').appendTo('body').addClass('alert alert-success').html('注册成功').show().delay(1500).fadeOut();
window.location.href = './index.html'
};
},
error: function () {
alert("注册失败")
}
- 登录
type: "POST",
dataType: "json",
url: "http://api.revth.com/auth/login",
data: JSON.stringify(login_data), //提交的数据
contentType: "application/json;charset-UTF-8",
success: function (result) {
if (result.status == 0) {
alert("登录成功");
window.location.href = './menu.html'
};
},
- 开始对局
type: "POST",
url: "http://api.revth.com/game/open",//请求url
contentType: "application/json;charset=UTF-8",
cacheontrol: "no-cache, no-store, max-age=0, must-revalidate",
success: (data) => {
document.getElementsByTagName("title")[0].innerText = '游戏中...等待出牌';
localStorage.setItem('id', data.data.id);
localStorage.setItem('card', data.data.card);
window.location.href = "./game.html";
- 排行榜与历史记录
type: "GET",
url: "http://api.revth.com/rank",
contentType: "application/json;charset-UTF-8"
url: "http://api.revth.com/history/" + Math.floor(20000 * Math.random()),
contentType: "application/json;charset-UTF-8",
2.类图
3.算法的关键与关键实现部分流程图
在思考算法实现前,我和队友一起进行了几局游戏,并从游戏过程中体会到了几个关键的信息:
- 想要出牌合法且在某一墩获胜,后墩必须尽可能大
- 确定其中两墩的牌型后,第三墩的牌一般不够优秀
- 如果后墩和中墩都不不够优秀的情况下,前墩必须往大调,否则容易被打枪
对于第一点,由于“相公”规则的存在,要求后墩一定要大于等于中墩,这使得后墩牌型的大小决定了中墩牌型的可能性。并且由于该游戏最大可凑出的牌是何种牌型运气要素占相当大的一部分,因此后墩不如孤注一掷,将最大的牌型打出,不仅可以凭借运气得分,还可以大大提高前中墩的牌型大小(事实上在和搭档的游戏过程中尝试过两种打法,拆散中墩的牌凑成更大的后墩牌更容易获得胜利)。
第二点很明显,第三墩的牌相当于集合中的差集,其牌型完全取决于其他两墩的取法。
对于第三点,根据几天的游戏,一个“田忌赛马”风格的算法逐渐被提出:
第一步:对于发下来的牌,特判掉特殊牌型的可能性后,我们首先贪心凑出最大可能的后墩牌型,以保障前中墩的牌型尽量大,且可以赢下一水。
第二步:对于剩下的牌,如果我们能在中墩凑出葫芦以上的牌型(中墩葫芦以上的牌型得分效率高,且后墩一定大于等于葫芦),那么我们称之为好马,直接凑出最大的中墩并放弃前墩。如果不行则称之孬马,凑出最大可能的前墩牌并放弃中墩,由于前墩只有3张,对子以上的牌型便大概率可以打赢对手。
按此算法,后墩与前墩的获胜概率较大,当局期望为2水。
![img](file:///C:\Users\DELL\Documents\Tencent Files\976806477\Image\C2C\G5JWVPDRSG$5{}B0Y[%U
8.png)##5.关键代码解释
“田忌赛马”式算法:
1、首先先找出最大可能的后墩,保证前中墩的可能性,并凭借运气先拿一水
2、考虑中墩是否可以凑出葫芦以上的牌型
2.1、如果可以凑出(好马),直接中墩凑出大牌,前墩求差
2.2、如果不可以凑出(孬马),放弃考虑中墩,保证不相公的情况下凑出最大的前墩牌,尽可能在前墩获胜
``
if((score=isTongHuaShun(cardListOfRearPier,10))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(1111100000);
}
backCardArray(cardListOfRearPier);
}
else if((score=isZhaDan(cardListOfRearPier,9))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(1111122222);
// System.out.println(maxScore);
}
backCardArray(cardListOfRearPier);
}
else if((score=isHuLu(cardListOfRearPier,8))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(111113333);
// List<String> list=getStrList(theBestCardListofRearPier);
// System.out.println(list.toString());
}
backCardArray(cardListOfRearPier);
}
else if((score=isTongHua(cardListOfRearPier,7))>0){
renewCardArray(cardListOfRearPier);
scoreFromMidPier=getMidPier();
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(1111144444);
}
backCardArray(cardListOfRearPier);
}
else if((score=isZhaShun(cardListOfRearPier,6))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
System.out.println(111115555);
//
// List<String> list=getStrList(theBestCardListofRearPier);
// System.out.println(list.toString());
}
backCardArray(cardListOfRearPier);
}
else if((score=isSanTiao(cardListOfRearPier,5))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(1111166666);
}
backCardArray(cardListOfRearPier);
}
else if((score=isLiangDui(cardListOfRearPier,4))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(111117777);
}
backCardArray(cardListOfRearPier);
}
else if((score=isYiDui(cardListOfRearPier,3))>0){
renewCardArray(cardListOfRearPier);
if((score>(scoreFromMidPier=getMidPier()))&&(maxScore<=score+scoreFromMidPier)){
maxScore=score+scoreFromMidPier;
renewBestCardListOfMidPier();
renewBestCardListOfRearPier();
// System.out.println(111118888);
}
backCardArray(cardListOfRearPier);
}
从13张牌中选出5张做为后墩,计算后墩的牌型和分数,计算剩下的牌出能组合出的中墩的最大分数(若中墩未能组合出葫芦及以上的牌型则返回0),把中墩和后墩的分数相加,分数最大时的则为最优的方案。该方案结束时中墩可能为空,因为中墩不存在葫芦及以上的牌型。
6.性能分析与改进
按照一开始的思路我们采用一种贪心的算法去实现,但是实际表现并不理想,分析之后发现是算法太过保守,只能保证尽量不输掉,而不能追求分数最大化,然而十三水显然是个很看脸的赌博游戏,如果你不在抽到好牌的时候最大化收益,那么运气差的时候就会输掉好多局赢来的分数。所以只能“前瞻顾后”,在选后墩时就要考虑中墩,看看后墩是否会把中墩的好牌给拆掉,选前墩时也要保证要使前墩比中墩小的情况下使前墩尽量大。
7.单元测试
8.贴出github的代码迁入记录
9.遇到的代码异常或结对困难及解决方法
汪倍民:
问题描述 | 做过哪些尝试 | 是否解决 | 有何收获 |
---|---|---|---|
ajax发post和get | 好多种 | 是 | 我太菜了 |
|github的使用:徽章?开源协议?持续集成?分支? |找了一堆网站看了看,一个人开分支意义不大 |否 |菜就完事了,开源还是没整明白
黄益颂:
-
问题描述
- 多种网络请求在代码中如何整合
- 算法如何实现
- 规范化Java工程项目
-
做过哪些尝试
- 运用Java优秀的类特性将所有的网络请求整合于一个类中,所有和网络工程相关的类全部继承自这个类
- 设计算法流程图,拆分不同牌型的判断方法
- 将所有的类和文件根据功能整合在不同的文件夹中,变量和类的名称遵照通用的Java设计规范
-
是否解决
基本解决
-
有何收获
了解了Java语言的设计规范,让自己大有所获吧
10.评价你的队友
汪倍民
值得学习的地方:阿颂一直在打代码,太强了
需要改进的地方:速度不够快
黄益颂
值得学习的地方:倍民的UI设计得很快,相比起来我的速度就显得很慢了,而且倍民的UI设计的很好!
需要改进的地方:无
学习进度条
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 10 | 10 | 学习了墨刀的使用方法,了解原型设计 |
2 | 480 | 480 | 10 | 10 | 学习了java网络接口,学习了web |
3 | 1000 | 2500 | 20 | 25 | 实现了算法框架和UI界面 |