第二次结对编程作业

一、博客链接

周华博客:https://www.cnblogs.com/fzuzh/p/11768398.html

吕瑞峰博客:https://www.cnblogs.com/ruifeng1/p/11768443.html

Fork的同名仓库的Github项目地址:https://github.com/ruifeng-1/031702533

二、具体分工

吕瑞峰:后端代码,AI设计
周华:前端代码,UI设计

三、PSP表格

过程 预估耗时(分钟) 实际耗时(分钟)
计划 15 15
估计任务时间 15 15
开发 1000 1200
需求分析 (包括学习新技术) 500 600
生成设计文档 30 60
设计复审 50 50
代码规范 (为目前的开发制定合适的规范) 20 30
具体设计 50 50
具体编码 80 100
代码复审 20 20
测试(自我测试,修改代码,提交修改) 100 150
报告 30 60
测试报告 10 20
计算工作量 10 10
事后总结, 并提出过程改进计划 30 30
合计 1960 2410

四、解题思路描述与设计实现说明

  • 解题方案

题目要求从十三张牌中选出最优牌组,一开始我感觉无从下手,于是从刚开始借鉴其他人的博客,然后与某位大佬进行深入的讨论,最后确定了解题方案(使用语言:c++):
1.定义一个pair<char,int>型作为牌组变量,将十三张牌存入牌组中,然后枚举十三张牌的所有情况,枚举的过程是先枚举5张牌作为后墩,再枚举3张作为前墩,最后5张作为中墩(不要问我为什么不枚举553而是535),因此枚举次数是c5,13*c3,8,而非13!。
2.对于任意情况,如何选出最优牌组?我们对每种牌型和牌面设置了权重,然后据此计算每种情况的权值(先算出每墩的权值再相加),选出权值最高的情况作为最优牌组。
3.对于牌组的单调性(即后墩>=中墩>=前墩),我们在计算每墩的权值后会进行判断,不符合单调性则直接丢弃。

  • 网络接口的使用

1.登录

Json::Value login(const string& username, const string& password) {
		Json::Value post;
		post["username"] = username;
		post["password"] = password;
		int re = http.ope("/auth/login", "status", "POST", "Content-Type: application/json\r\n", post.toStyledString());
		if (re) {
			cout << re;
			post["status"] = 1;
			return post;
		}
		Json::Value ret;
		Json::Reader reader;
		reader.parse(dt.getStatus(), ret);
		return ret;
	}

2.注册绑定

Json::Value regAndBind(const string& username, const string& password, const string& student_number, const string& student_password) {
		Json::Value post;
		post["username"] = username;
		post["password"] = password;
		post["student_number"] = student_number;
		post["student_password"] = student_password;
		int re = http.ope("/auth/register2", "status", "POST", "Content-Type: application/json\r\n", post.toStyledString());
		if (re) {
			cout << re;
			post["status"] = 1;
			return post;
		}
		Json::Value ret;
		Json::Reader reader;
		reader.parse(dt.getStatus(), ret);
		return ret;
	}

3.注销

Json::Value logout() {
		Json::Value ret;
		int re = http.ope("/auth/logout", "status", "POST", "X-Auth-Token: \"" + user.token + "\"\r\n", "");
		if (re) {
			cout << re;
			ret["status"] = 1;
			return ret;
		}
		Json::Reader reader;
		reader.parse(dt.getStatus(), ret);
		return ret;
	}

4.开始战局

Json::Value start() {
		Json::Value ret;
		int re = http.ope("/game/open", "status", "POST", "X-Auth-Token: " + user.token + "\r\n", "");
		if (re) {
			cout << re;
			ret["status"] = 1;
			return ret;
		}
		Json::Reader reader;
		reader.parse(dt.getStatus(), ret);
		return ret;
	}

5.出牌

Json::Value submit(const Json::Value& post) {
		Json::Value ret;
		int re = http.ope("/game/submit", "status", "POST", "X-Auth-Token: " + user.token + ",Content-Type: application/json\r\n", post.toStyledString());
		if (re) {
			cout << re;
			ret["status"] = 1;
			return ret;
		}
		Json::Reader reader;
		reader.parse(dt.getStatus(), ret);
		return ret;
	}
  • 代码组织与内部实现设计

  • 算法的关键与关键实现部分流程图

算法的关键在于两处:牌组的枚举,权值的计算。

五、关键代码解释

登录界面:

<div id="particles-js">
<div class="login">
<div class="login-top">
	登录
	</div>
<div class="login-center clearfix">
<div class="login-center-img"><img src="img/name.png"/></div>
<div class="login-center-input">
<input type="text" name="" value="" placeholder="请输入您的用户名" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的用户名'"/>
<div class="login-center-input-text">用户名</div>
	</div>
	</div>
<div class="login-center clearfix">
<div class="login-center-img"><img src="img/password.png"/></div>
<div class="login-center-input">
<input type="password" name=""value="" placeholder="请输入您的密码" onfocus="this.placeholder=''" onblur="this.placeholder='请输入您的密码'"/>
<div class="login-center-input-text">密码</div>
	</div>
	</div>
<div class="login-button">
	登录
	</div>
	</div>
<div class="sk-rotating-plane"></div>
	</div>

枚举:
Enume(枚举)类中的部分函数,主要用于枚举13张牌并分别放入三墩中

void Enume::clear(vector<pair<char, int> >& _a) {
	swap(poker, _a);
	max_weight = 0;
	vector<int> p;
	for (int i = 1; i <= 13; i++)
		p.push_back(i);
	dfs1(p, 5, 13);
}

void Enume::dfs1(vector<int>& p, int r, int n) {
	for (int s = (1 << r) - 1; s < 1 << n;) {
		choose.clear();
		vector<int> cur = p;
		for (int j = n - 1; j >= 0; j--) {
			if (((s >> j) & 1)) choose.push_back(poker[p[j]]), cur.erase(cur.begin() + j, cur.begin() + j + 1);
		}
		back.init(choose);//计算权值
		dfs2(cur, 5, 8);
		int x = s & -s;
		int y = s + x;
		s = ((s & ~y) / x >> 1) | y;
	}
}

void Enume::dfs2(vector<int> & p, int r, int n) {
	for (int s = (1 << r) - 1; s < 1 << n;) {
		choose.clear();
		vector<int> cur = p;
		for (int j = n - 1; j >= 0; j--) {
			if (((s >> j) & 1)) choose.push_back(poker[p[j]]), cur.erase(cur.begin() + j, cur.begin() + j + 1);
		}
		mid.init(choose);//计算权值
		int x = s & -s;
		int y = s + x;
		s = ((s & ~y) / x >> 1) | y;
		if (mid.weight > back.weight) continue;
		dfs3(cur, 3, 3);
	}
}

void Enume::dfs3(vector<int> & p, int r, int n) {
	choose.clear();
	for (int j = 0; j < n; j++) {
		choose.push_back(poker[p[j]]);
	}
	front.init(choose);//计算权值
	if (front.weight > mid.weight) return;
	best_choose();//放入最优牌组
}

六、性能分析与改进

  • 改进的思路

原来的算法是计算三墩的权值后,再比较三墩的牌型大小,如果不符合单调性则丢弃,后来觉得实在是有点膈应人,于是作了剪枝的优化处理:枚举到中墩时,如果中墩的牌型大于后墩的牌型,则直接丢弃,重新进行枚举。

  • 性能分析图和程序中消耗最大的函数


如图,消耗最大的函数分别是Enume类中的clear,dfs1,dfs2函数,即枚举所调用的函数。

七、单元测试


八、贴出Github的代码签入记录

九、遇到的代码模块异常或结对困难及解决方法

  • 问题描述

此次依然使用c++写后端代码,出现了许多问题,但最关键也最严重的是找不到相应的函数!!例如http请求和json的处理,c++相对java和python来说就非常麻烦。

  • 做过哪些尝试

在网上寻找第三方库,找了cjson,jsoncpp,libcurl一系列库等,在编译第三方库这一部分经历了一段很长的阵痛。

  • 是否解决

解决了,最后确定了jsoncpp和自带的wininet.h库来处理json和http请求。

  • 有何收获

熟悉了jsoncpp库的使用,比起cjson库使用起来更加方便。

十、评价你的队友

  • 值得学习的地方

设计的ui界面相当不错

  • 需要改进的地方

写代码的进度有点慢了,导致我们两个的进度有点对不上。

十一、学习进度条

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
1 0 0 10 10 学习用Axure RP 8设计原型模型
2 500 500 30 30 设计AI算法,掌握一些c++第三方库的使用
3 100 100 20 20 完善算法,学习了一点html的知识
posted @ 2019-10-30 22:27  ruifeng1  阅读(173)  评论(0编辑  收藏  举报