一、结对探索
1.1 队伍基本信息
结对编号:40;队伍名称:知天易,逆天男;
学号 | 姓名 | 作业博客链接 | 具体分工 |
---|---|---|---|
032002539 | 张凯昕 | ui设计,前后端代码编写 | |
032002542 | 朱智浩 | ui设计,绘制原型图 |
1.2 描述结对的过程
A: 你组队了吗
B: 还没
A: 那咱俩一组
1.3 非摆拍的两人在讨论设计或结对编程过程的照片(2分)
二、原型设计(16分)
2.1 原型工具的选择(2分)
(在此处说明选择了什么原型设计工具?为什么选择这一款原型软件?)
2.2 遇到的困难与解决办法(3分)
(原型设计过程中的困难描述、解决尝试、是否解决、有何收获)
2.3 原型作品链接(5分)
(静态原型作品得2分,交互性强的原型作品得5分)
2.4 原型界面图片展示(6分)
(尽可能图文并茂地在此处介绍你们队伍设计的各功能模块,创新点也在此处展示说明)
三、编程实现
3.1 网络接口的使用
使用了ajax与websocket,websocket主要用于匹配对决的实现,通过websocket来不断发送地图信息以及对手的落子,
ajax用于除游戏外一些不经常发送的请求,例如登陆注册等。
3.2 代码组织与内部实现设计(类图)
-
前端部分
-
后端部分
- backend部分
- matchingsystem部分
- backend部分
3.3 说明算法的关键与关键实现部分流程图(2分)
- 由于我不会机器学习,所以只能用普通的算法实现
- 算法的实现主要是贪心,每次下子时遍历一遍,找出分差最有利的落子位置
- 若有复数位置,先落于行空格最多位置,避免将所有位置堵死,使得原本可以消除对方的落子没
得落子 - 再判断点数与对方行空格最少的位置
- 使点数较小的位置落于对方行空格最大的地方,被对方消除时损失较小
- 使点数较大的位置落于对方行空格最小的地方,不容易被消除
3.4 贴出重要的/有价值的代码片段并解释(2分)
package com.example.matchingsystem.service.impl.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@Component
public class MatchingPool extends Thread{
private static List<Player> players = new ArrayList<>();
private ReentrantLock lock = new ReentrantLock();
private static RestTemplate restTemplate;
private final static String startGameUrl = "http://localhost:3000/pk/start/game/";
@Autowired
public void setRestTemplate(RestTemplate restTemplate){
MatchingPool.restTemplate = restTemplate;
}
public void addPlayer(Integer userId,Integer rating){
lock.lock();
try {
for (Player player:players){
if (player.getUserId().equals(userId)){
return;
}
}
players.add(new Player(userId,rating,0));
}finally {
lock.unlock();
}
}
public void removePlayer(Integer useId){
lock.lock();
try {
List<Player> newPlayers = new ArrayList<>();
for (Player player:players){
if (!player.getUserId().equals(useId)){
newPlayers.add(player);
}
}
players = newPlayers;
}finally {
lock.unlock();
}
}
private void increaseWaitingTime(){//所有玩家等待时间加一
for (Player player:players){
player.setWaitingTime(player.getWaitingTime() + 1);
}
}
private boolean checkMatched(Player a,Player b){
int ratingDelta = Math.abs(a.getRating() - b.getRating());
int waitingTime = Math.min(a.getWaitingTime(),b.getWaitingTime());
return ratingDelta <= waitingTime *10;
}
private void sendResult(Player a,Player b ){
MultiValueMap<String,String> data = new LinkedMultiValueMap<>();
data.add("a_id", a.getUserId().toString());
data.add("b_id",b.getUserId().toString());
restTemplate.postForObject(startGameUrl,data,String.class);
}
private void matchPlayers(){
System.out.println("match players: " + players.toString());
boolean[] used = new boolean[players.size()];
for (int i = 0; i < players.size(); i ++){
if (used[i]) continue;
for (int j = i + 1;j < players.size(); j++){
if (used[j]) continue;
Player a = players.get(i),b = players.get(j);
if (checkMatched(a , b)){
used[i] = used[j] = true;
sendResult(a , b);
break;
}
}
}
List<Player> newPlayer = new ArrayList<>();
for (int i = 0; i < players.size(); i ++){
if (!used[i]){
newPlayer.add(players.get(i));
}
}
players = newPlayer;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
lock.lock();
try {
increaseWaitingTime();
matchPlayers();
}finally {
lock.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
这部分代码是用于匹配池的实现
restTemplate
用于于另一模块backend交互
addPlayer
当前端发送请求时,程序先遍历匹配池,发现没有该用户,再把用户加入匹配池中,
防止用户自己匹配到自己。
removePlayer
当前端发送请求或者匹配到对象时,将玩家移除匹配池
increaseWaitingTime
,checkMatched
,matchPlayers
分别用于当玩家等待时间增加时,checkMatched中允许的分差也会逐渐增大,当增大一定程度,两个对象就会匹配,并更新匹配池
sendResult
是在当匹配成功时将匹配信息发送给backend
run
则是在每秒扫描一次匹配池,执行程序
由于该程序是异步程序,所以需要lock函数对函数进行上锁。
3.5 性能分析与改进(2分)
占用资源最多的函数是tomcat,我的优化的思路是将一些可以在前端实现的功能直接在前端实现
减少前后端的交互。
3.6 单元测试(2分)
利用apipost测试接口,用sout以及assert进行单元测试
3.7 贴出GitHub的代码签入记录,合理记录commit信息(2分)
四、总结反思
4.1 本次任务的PSP表格(2分)
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 5 | 5 |
· Estimate | · 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 5113 | 5796 |
· Analysis | · 需求分析 (包括学习新技术) | 2700 | 2800 |
· Design Spec | · 生成设计文档 | 15 | 15 |
· Design Review | · 设计复审 | 5 | 3 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 3 | 3 |
· Design | · 具体设计 | 30 | 15 |
· Coding | · 具体编码 | 2000 | 2500 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 300 | 400 |
Reporting | 报告 | 85 | 50 |
· Test Report | · 测试报告 | 15 | 15 |
· Size Measurement | · 计算工作量 | 10 | 5 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 30 |
· 合计 | 5203 | 5851 |
4.2 学习进度条(每周追加)
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 45 | 45 | 学习通过springboot+vue编写前后端 |
2 | 1580java+1681vue+309js | 3262 | 2 | 47 | 通过实践编写项目了解了许多看教学学不到的知识 |
3 | 61java+610vue+18js | 4259 | 1 | 48 | 小试了用CSS编写动画,但效果不尽如人意 |
4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?(2分)
(也就是谈一谈本次任务中**“理想与现实的差距”**,是哪些因素造成了这些差距?)
4.4 评价你的队友
-
值得学习的地方:临危不惧,步步为营
-
需要改进的地方:过于临危不惧
4.5 结对编程作业心得体会
-
作业难度
- 没做前:好难好难好难好难好难好难
- 做的时候:好难好难好难好难好难好难好难好难好难好难好难好难
- 做完后:就这?能不能再难点?
-
完成感受
- 心理:如释重负,身心愉悦
- 身体:不堪重负,面色憔悴
- 我终于不用天天背那笔记本去教室打代码了,太重了
-
代码模块
- 遇到问题,百度一下,百度不行,问问同学,同学不会,问问佛祖,然后Debug一整天,所幸最后还是顺利解决
-
学习启发
-
一开始的学习都是在模仿,知识其实并没有太多的吸收,真正吸收知识的时候,其实是模仿着模仿着,
模仿出bug的时候,为了debug,必须将代码的逻辑捋清楚,才可以改好bug
-
之后想学点动画,倒也不用特别深入,够用就行,看别人的作业的骰子会动,很是羡慕,我也想写。
-