第二次结对编程作业
一、结对博客信息:
二、具体分工
前端:卢欢,设计与实现十三水界面和交互,实现网络api调用
后端:汪佳祥,负责出牌AI算法设计与实现
三,PSP表格
过程 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
计划 | 30 | 30 |
估计任务时间 | 30 | 30 |
开发 | 600 | 800 |
需求分析 (包括学习新技术) | 60 | 60 |
生成设计文档 | 30 | 30 |
设计复审 | 15 | 15 |
代码规范 (为目前的开发制定合适的规范) | 15 | 30 |
具体设计 | 30 | 15 |
具体编码 | 455 | 655 |
代码复审 | 15 | 15 |
测试(自我测试,修改代码,提交修改) | 30 | 30 |
报告 | 40 | 45 |
测试报告 | 15 | 15 |
计算工作量 | 10 | 15 |
事后总结, 并提出过程改进计划 | 15 | 15 |
合计 | 670 | 875 |
四、解题思路描述与设计实现说明
1.网络接口的使用
其实各个接口使用都是差不多的
贴出登录和开始游戏的C#代码
//开始一局游戏
UnityWebRequest webRequest = new UnityWebRequest(NetMgr.GetUrl("StartGame"), "POST");
webRequest.SetRequestHeader("X-Auth-Token", NetMgr.TokenDate);
webRequest.downloadHandler = new DownloadHandlerBuffer();
yield return webRequest.SendWebRequest();
//登录游戏
JsonData data = new JsonData
{
["username"] = username,
["password"] = password
};
string js1 = data.ToJson();
byte[] postBytes = Encoding.UTF8.GetBytes(js1);
UnityWebRequest webRequest = new UnityWebRequest(NetMgr.GetUrl("Rigister"), "POST")
{
uploadHandler = new UploadHandlerRaw(postBytes)
};
// UnityWebRequest.useHttpContinue = false;
webRequest.SetRequestHeader("Content-Type", "application/json;charset=utf-8");
webRequest.downloadHandler = new DownloadHandlerBuffer();
yield return webRequest.SendWebRequest();
五、关键代码解释
重要的/有价值的代码片段
AI出牌函数:
public static List<TypeCard> GetMaxCardType(List<int> cardList)
{
List<TypeCard> typeCardList = new List<TypeCard>();
//从大到小排序
SortCard(cardList);
//复制一份从小到大的牌
List<int> cardList2 = cardList.GetRange(0, cardList.Count);
SortCardMinToMax(cardList2);
List<int> FourNum = cardList.GroupBy(p => p % 100).Where(p => p.Count() >= 4).Select(p => p.Key).ToList();
List<int> ThreeNum = cardList.GroupBy(p => p % 100).Where(p => p.Count() >= 3).Select(p => p.Key).ToList();
List<int> TwoNum = cardList.GroupBy(p => p % 100).Where(p => p.Count() >= 2).Select(p => p.Key).ToList();
#region 同花顺
foreach (var item in cardList2)
{
//同花顺最小是从10开始
if (item % 100 >= 11)
break;
List<int> tempList = new List<int>();
tempList.Add(item);
foreach (var item2 in cardList2)
{
if (item2 - 1 == tempList.Last())
tempList.Add(item2);
if (tempList.Count >= 5)
{
TypeCard typeCard = new TypeCard() { cardList = tempList, cardType = DeckTypeEnum.TongHuaShun };
typeCardList.Add(typeCard);
break;
}
}
}
#endregion
#region 炸弹
foreach (var FourItem in FourNum)
{
List<int> tempList = new List<int>();
foreach (var item in cardList)
{
if (item % 100 == FourItem)
tempList.Add(item);
if (tempList.Count >= 4)
{
TypeCard typeCard = new TypeCard() { cardList = tempList, cardType = DeckTypeEnum.Bomb };
typeCardList.Add(typeCard);
break;
}
}
}
#endregion
#region 葫芦
foreach (var ThreeItem in ThreeNum)
{
List<int> tempList = new List<int>();
foreach (var item in cardList)
{
if (item % 100 == ThreeItem)
tempList.Add(item);
if (tempList.Count >= 3)
{
//找两对
foreach (var TwoItem in TwoNum)
{
if (ThreeItem != TwoItem)
{
foreach (var AllItem in cardList)
{
if (AllItem % 100 != ThreeItem && AllItem % 100 == TwoItem)
tempList.Add(AllItem);
if (tempList.Count >= 5)
{
TypeCard typeCard = new TypeCard() { cardList = tempList, cardType = DeckTypeEnum.Gourd };
typeCardList.Add(typeCard);
tempList = typeCard.cardList.GetRange(0, 3);
break;
}
}
}
}
break;
}
}
}
#endregion
#region 同花
List<int> FiveColor = cardList.GroupBy(p => p / 100).Where(p => p.Count() >= 5).Select(p => p.Key).ToList();
List<int> FourColor = cardList.GroupBy(p => p / 100).Where(p => p.Count() >= 4).Select(p => p.Key).ToList();
List<int> ThreeColor = cardList.GroupBy(p => p / 100).Where(p => p.Count() >= 3).Select(p => p.Key).ToList();
List<TypeCard> typeCards = new List<TypeCard>();
foreach (var Fiveitem in FiveColor)
{
List<int> tempList = new List<int>();
foreach (var item in cardList)
{
if (item / 100 == Fiveitem)
{
tempList.Add(item);
}
}
while (true)
{
if (tempList.Count >= 5)
{
TypeCard typeCard = new TypeCard() { cardList = tempList.GetRange(0, 5), cardType = DeckTypeEnum.TongHua };
typeCards.Add(typeCard);
//typeCardList.Add(typeCard);
tempList.RemoveAt(0);
}
else
{
break;
}
}
}
//收集同花集合后
//对同花进行排序
//
if (typeCards.Count > 1)
{
//排序的优先级从高到低
typeCards.Sort((x, y) => -((x.cardList[0] % 100).CompareTo(y.cardList[0] % 100) * (1 << 4)
+ (x.cardList[1] % 100).CompareTo(y.cardList[1] % 100) * (1 << 3)
+ (x.cardList[2] % 100).CompareTo(y.cardList[2] % 100) * (1 << 2)
+ (x.cardList[3] % 100).CompareTo(y.cardList[3] % 100) * (1 << 1)
+ (x.cardList[4] % 100).CompareTo(y.cardList[4] % 100)
));
//typeCards.Sort((x, y) => -((x.cardList[1]%100).CompareTo(y.cardList[1]%100)));
}
foreach (var typeCard in typeCards)
{
typeCardList.Add(typeCard);
}
#endregion
#region 顺子
foreach (var MaxItem in cardList)
{
if (MaxItem % 100 <= 5)
{
break;//从大到小,后面的也不需要循环了
}
List<int> tempList = new List<int>();
tempList.Add(MaxItem);
while (tempList.Count < 5)
{
bool flag = false;
foreach (var item in cardList)
{
if (item % 100 + 1 == tempList.Last() % 100)
{
tempList.Add(item);
flag = true;
break;
}
}
if (!flag)
{
break;
}
}
if (tempList.Count >= 5)
{
TypeCard typeCard = new TypeCard() { cardList = tempList, cardType = DeckTypeEnum.ShunZi };
typeCardList.Add(typeCard);
}
}
#endregion
#region 三张
foreach (var Threeitem in ThreeNum)
{
List<int> tempList = new List<int>();
foreach (var item in cardList)
{
if (item % 100 == Threeitem)
tempList.Add(item);
if (tempList.Count >= 3)
{
TypeCard typeCard = new TypeCard() { cardList = tempList, cardType = DeckTypeEnum.Three };
typeCardList.Add(typeCard);
break;
}
}
}
#endregion
#region 两对
for (int i = 0; i < TwoNum.Count; i++)
{
List<int> tempList = new List<int>();
foreach (var item in cardList)
{
if (item % 100 == TwoNum[i])
{
tempList.Add(item);
}
}
while (tempList.Count >= 2)
{
for (int j = i + 1; j < TwoNum.Count; j++)
{
List<int> tempList2 = new List<int>();
foreach (var item in cardList)
{
if (item % 100 == TwoNum[j])
{
tempList2.Add(item);
}
}
while ((tempList2.Count >= 2))
{
TypeCard typeCard = new TypeCard() { cardList = tempList.GetRange(0, 2), cardType = DeckTypeEnum.TwoDouble };
//直接加入连对的判断
if (tempList[0] % 100 - 1 == tempList2[0] % 100)
{
//连对
typeCard.cardType = DeckTypeEnum.ContinuousTwoDouble;
}
typeCard.cardList.AddRange(tempList2.GetRange(0, 2));
typeCardList.Add(typeCard);
tempList2.RemoveAt(0);
}
}
tempList.RemoveAt(0);
}
}
六、性能分析与改进
1.改进的思路
消耗最大的函数是网络请求和AI,我们重点关注AI的改进。
算法开始的时连对没考虑到,后面就加了这种情况
然后对于一些特殊情况,可以先提前判断,可以减少消耗。
2.展示性能分析图和程序中消耗最大的函数
IEnumerator PostResult(string jsondata)
{
byte[] postBytes = Encoding.UTF8.GetBytes(jsondata);
UnityWebRequest webRequest = new UnityWebRequest(NetMgr.GetUrl("submit"), "POST")
{
uploadHandler = new UploadHandlerRaw(postBytes)
};
webRequest.SetRequestHeader("X-Auth-Token", NetMgr.TokenDate);
webRequest.SetRequestHeader("Content-Type", "application/json;charset=utf-8");
webRequest.downloadHandler = new DownloadHandlerBuffer();
yield return webRequest.SendWebRequest();
if (webRequest.isDone)
{
string result = webRequest.downloadHandler.text;
if (result == "")
{
ShowMes("网络连接失败");
}
else
{
JsonData results = JsonMapper.ToObject(result);
string state = "";
try
{
state = results["status"].ToJson();
}
catch
{
ShowMes("连接失败");
}
if (state == "0")
{
Pokemgr.Instance.Clean();
ExitButton.onClick.Invoke();
BackButton.onClick.Invoke();
if (AIScore)
{
StartButton.onClick.Invoke();
}
else
{
ShowMes("出牌成功");
}
}
else
{
ShowMes(NetMgr.GetState(state));
}
}
}
else
{
if (Application.internetReachability == NetworkReachability.NotReachable)
{
ShowMes("网络连接失败");
}
}
}
七、单元测试
通过服务器获取牌堆,AI出牌后自动提交,同时留下记录
如果服务器返回错误,则说明我们测试失败
八、Github的代码签入记录
九、遇到的代码模块异常或结对困难及解决方法
汪佳祥(后端)
1.
遇到的问题:一开始AI出牌算法毫无思绪,后来。欢哥要求我使用C#写出算法,我被赶鸭子上架
做过哪些尝试:到微信小程序玩了几十把罗松渐渐熟悉起来
是否解决:是
收获:一天速成C#简单语法,第二天开始写算法,也遇到许多bug,例如中墩比尾墩来得大(都是我的锅),都被欢哥逐一解决(再次抱紧欢哥大腿)。这些问题在我欢哥面前简直都不是个事
卢欢(前端)
1.
问题描述:界面的设计没什么特别难的问题,主要是我自己写了很多界面动画,有时没有想要的效果
做过哪些尝试:一直在改,强迫症犯了,就一直想做得好看,虽然现在做的也挺丑。。。
是否解决:是
有何收获:提高审美
2.
问题描述:网络接口
做过哪些尝试:开始没用过,找个例子就理解了
是否解决:成功解决
有何收获:再次理解了网络异步通信,网络请求的代码写在协程里
十、评价你的队友
汪佳祥
- 值得学习的地方
- 评价队友:通过本次的软工实践,我紧抱欢哥大腿,感觉到了我的队友十分强悍,他设计的这个前端界面让我让我感觉我的后端算法有点配不上他,他也给我提供了许多的帮助,我还需要继续向他学习
- 需要改进的地方
- 应该尽可能地不要通宵,少熬夜。
卢欢
- 值得学习的地方
- 祥哥真是个大忙人,不过敲起代码来效率飞快,总的来说碰的壁比较少吧,因此我们这个项目花的时间不是很多就写完成了
- 需要改进的地方
- AI能够更强大就好了
十一、学习进度条
- 后端(汪佳祥)
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 10 | 10 | 上手墨刀,了解原型设计的过程 |
2 | 600 | 600 | 15 | 25 | 写算法 |
3 | 200 | 800 | 10 | 35 | 学习网络接口的使用 |
- 前端(卢欢)
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 0 | 0 | 8 | 8 | 上手墨刀,了解原型设计 |
2 | 0 | 0 | 20 | 28 | 学会设计界面 |
3 | 1170 | 1170 | 22 | 50 | 学会接口的使用 |