第二次结对编程作业
一、结对博客信息:
二、具体分工
前端:卢欢,设计与实现十三水界面和交互,实现网络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 StartAGame() { UnityWebRequest webRequest = new UnityWebRequest(NetMgr.GetUrl("StartGame"), "POST"); webRequest.SetRequestHeader("X-Auth-Token", NetMgr.TokenDate); webRequest.downloadHandler = new DownloadHandlerBuffer(); yield return webRequest.SendWebRequest(); if (webRequest.isDone) { string result = webRequest.downloadHandler.text; // Debug.Log(result); if (result == "") { ShowMes("网络连接失败"); } else { JsonData results = JsonMapper.ToObject(result); string state = ""; try { state = results["status"].ToJson(); } catch { ShowMes("连接失败"); } if (state == "0") { Debug.Log("成功获取牌"); NetMgr.GameID = (int)results["data"]["id"]; JsonData list = results["data"]["card"]; NetMgr.CardList = list.ToString(); Debug.Log(NetMgr.GameID + "牌:" + NetMgr.CardList); CardIsDone(); } else { ShowMes(NetMgr.GetState(state)); } } } else { if (Application.internetReachability == NetworkReachability.NotReachable) { ShowMes("网络连接失败"); } } } 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("网络连接失败"); } } }
七、单元测试
先进行本地测试