zoukankan      html  css  js  c++  java
  • 结对编程作业

    github链接

    姓名 分工 博客链接
    黄朝威 游戏界面,游戏逻辑 https://www.cnblogs.com/pekkasuper/p/15450956.html
    蔡树峰 原型设计、卡牌设计 https://www.cnblogs.com/fzu-rookie/p/15449524.html

    一、原型设计

    pigtail原型设计

    设计说明

    根据网上普遍的PVP游戏逻辑,利用原型设计工具墨刀,进行原型设计。之前也是没怎么接触过原型设计,甚至闻所未闻,当然在DeadLine的索命镰刀面前硬着头皮上准是没错的,于是打开了速成秘籍(速成大法好),也就是倍速看网课,看完后立马着手设计,设计素材来源于SpaceEnginee和Stellaris的部分游戏截图,具体设计如下:

    • 登录界面:输入账号密码,登录成功之后跳转至模式选择界面,背景来源于SpaceEnginee截屏时的美景,原本打算登录界面采用动态背景即截取地球饶日公转的视频进行加工,但是由于后期游戏界面设计能力不足就鸽了,登录界面添加了监听鼠标点击和键盘回车键事件,即在用户学号以及密码能够匹配的情况下按下回车即可登录,节省鼠标移动到登录框的时间了,改良了用户体验!

    • 模式选择界面:进行联网对战、本地对战和AI对战三种对战模式模式的选择,点击对应按钮可跳转到对应模式。

    • 联网对战:联网对战又可进行三种选择——创建对局、加入对局、查询公开对局。创建或加入对局后可选择是否托管;查询公开对局可根据uuid查找在进行中的对局。
      联网对战界面中央部分电子脑勾选框提供了托管的功能实现,左上方提供复制对局uuid的文本框,当载入对局时可供用户邀请玩家加入对局,以下为非托管时界面表现形式:

    • 托管时页面显示,勾选中央电子脑框后启动托管,可以看到左下方人类被型号XT489的机械取代,血肉痛苦机械飞升。

    • 查询公开对局,由于后期设计界面时技术能力有限无法提供完整的公开uuid列表,于是采用了将获取到的公开uuid进行随机抽签显示一个给用户,由于是随机因此采用Stellaris中的虫洞图片,在传送结束前你无法提前预知虫洞的另一边的事物,就好像随机获取的uuid有可能是不可行的比如说是正在进行比赛的uuid

    • 本地对战:进行本地PVP对战,我认为本地对战时两个人需要一较高下,就没有提供托管的功能,加上托管的功能有点违背本地对战的设计理念,总不能是两个挂机在玩别的游戏吧

    • AI对战:进行本地人机对战,当鼠标移动到右上方托管图片时触发鼠标悬停事件,托管将在文本框中予以回复。

    遇到的困难及解决方法

    • 困难描述
      1.思路易得,素材难寻。随着国家相关法律愈加的完善,用户版权意识的提高,白嫖素材的难度越来越高,百般搜寻,始终难以找到想要的素材,网上搜索到的素材大多与预期设想不太符合,有些比较符合的又有水印且较难去除,着实棘手。
      2.第一次使用原型设计工具,不能熟练使用,磕磕绊绊,许多功能和自己预想的设计不同,只能不断琢磨,一遍又一遍删除原型,重新塑造原型,直到整出了双方都相对满意的设计界面。
    • 解决过程
      1.金钱的力量是无穷的。百般搜索素材无果之后,最终选择氪金,上某宝买了一些素材,省时省力,此外还从其他游戏获得了部分素材,例如从Stellaris和SpaceEnginee这两款太空游戏获得相应的素材,所选的图片几乎都挺符合界面设计理念,例如托管对应的图片能在游戏中找到对应的机器人图片素材,人物对应的图片也能在游戏中找到对应的素材,当然这两款游戏也不是免费的也倒是呼应了金钱的力量确实是无穷的。
      2.使用墨刀时,上b站看了一些入门的墨刀使用介绍视频(老白嫖怪了),遇到不懂的问题就进行百度搜索,
    • 有何收获
      学会了如何使用原型设计工具,熟悉了产品设计的流程,科学的进行产品设计;同时素材搜集渠道扩增。包括Pexels,Pexels是一提供海量共享图片素材的网站,每周都会定量更新,照片都是有专人在众多图片中精心挑选而来的。Gratisography,Gratisography是一个免费高分辨率摄影图片库,所有的图片都可以用于个人或者商业用途,每周更新图片你只需要点击即可下载。Unsplash,Unsplash是一个数量很大的免费高质量照片的网站,每天更新一张高质量的图片素材,全是生活中的景象作品,清新的生活气息图片可以应用于各种需要的环境,非常值得收藏,等等许多的素材网站。

    二、原型设计实现

    2.1代码实现思路

    网络接口的使用:

    ​ 联网对战中最为重要的是获取上步操作的接口实现,在创建对局或者加入对局后,通过计时器timer不断获取上步操作,并根据返回的系列信息进行判断对局战况,例如创建对局后需要不断通过计时器请求获取上步操作的接口,通过状态码判断对局是否开始即是否有人加入房间中,对局开始后也需要不断请求获取上步操作的接口以及时更新对方的操作并提示用户可以进行操作,在接口实现中采用先获取上步操作再进行实时更新。由于采用Python和C#交互的方式这边仅仅贴出部分接口请求实现的Python代码:

    # 将token从文件中读取出来后续使用
    # 这是由于并非采用Python实现游戏逻辑而由于游戏中大量使用token,故将登录后的token记录其中。
    def tokenRead() -> str:
        f = open("token.txt", "r")
        user_token = f.read()
        f.close()
        return user_token
    
    
    # 用户登录
    def logIn(student_id: str, password: str) -> json:
        url = "http://172.17.173.97:8080/api/user/login"
        data = {"student_id": student_id, "password": password}
        results = requests.post(url=url, data=data)
        if results.json()["status"] != 200:
            return json.dumps(results.json())
        # 由于命令行参数长度限制需要将token记录到文件中以便后续使用
        f = open("token.txt", "w")
        f.write(results.json()["data"]["token"])
        f.close()
        return json.dumps(results.json())
    

    代码组织与内部实现设计:

    由于各部分页面采用的实现思路略有不同,但以联网对战为模板故这里仅仅介绍联网对战代码组织:

    基本页面处理函数

    ​ PS:部分函数命名是系统自动生成的代码,命名规范遵从winform的规范例如Inter_Mode_Load为

    ​ 自动生成的函数(简单来说就是会自动生成个外壳内容需要自己动手),非系统生成函数命名采用 驼峰式命名。

    • Inter_Mode_Load:页面加载处理函数

    • InterMode_FormClosing:页面关闭处理函数

    • timer_Tick:计时器事件,驱动计时器加载对应事件

    • initialOperation:基本属性初始化操作

    • resetPokerDecorPublished:重置放置区扑克牌花色数

    • refreshContest:根据打出或翻开的扑克牌刷新界面函数

    • refreshPokerNum:刷新不同区域的扑克牌对应数目

    • refreshPokerImg:重新加载玩家手中卡牌情况

      对局详情类函数:

    • cardPile_Click:牌堆点击出发事件处理函数

    • spadeLeft_Click:点击用户黑桃牌触发事件处理函数

    • heartLeft_Click:点击用户红桃牌触发事件处理函数

    • clubLeft_Click:点击用户梅花牌触发事件处理函数

    • diamondLeft_Click:点击用户方块牌触发事件处理函数

    • machineFuture_CheckedChanged:勾选托管框处理事件

    • transformPoker:解析请求获得的字符串进而获得扑克牌

    • logicCheck:判断是否达成需要吃牌的条件函数

    • eatingPoker:吃牌处理函数

      AI类函数:

    • makeStrategy:指定反映策略函数

    • pokerMachine_Click:模拟点击触发事件处理函数

    • machineOperation:托管操作处理函数

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

    页面实现流程:

    贴出你认为重要的/有价值的代码片段,并解释

    黄朝威:

    第一部分应该是timer_Tick函数用于不断监听处理,不断获取上一步操作来进行更新对局情况:

    /// <summary>
            /// 计时器事件,turnCue,Cue为信号暗示线索的意思,即为提示回合
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void timer_Tick(object sender, System.EventArgs e)
            {
                string rec;
                JObject jo;
                //rec用于获取调用接口返回的内容并转换成JObject对象
                rec = FetchInfo.executeOperation("getPreviousOperation " + this.uuid);
                jo = (JObject)JsonConvert.DeserializeObject(rec);
                if (jo["code"].ToString() == "403")
                {
                    //对局尚未开始
                    matchBegin = false;
                    return;
                }
                else 
                {
                    if (jo["code"].ToString() == "200")//对局开始
                    {
                        matchBegin = true;
                        //用于判断是否我方回合
                        if (jo["data"]["your_turn"].ToString() == "False")
                        {
                            //通过freshFlag和last_msg进行比较判断是否需要刷新界面
                            if (jo["data"]["last_msg"].ToString() != this.freshFlag)
                            {
                                //对方回合说明上回为我方回合无需进行刷新,因为我方执行
                                //对应操作后会刷新
                                this.freshFlag = jo["data"]["last_msg"].ToString();
                                this.turnCue.Text = "对方抉择中!";
                                this.turnCue.Refresh();
                            }
                            yourTurn = false;//当前为对方回合
                        }
                        else
                        {
                            if (jo["data"]["last_code"].ToString() == "")//回合刚开始且为我方回合
                            {
                                yourTurn = true;
                                this.turnCue.Text = "你的回合!";
                                this.turnCue.Refresh();
                                if (machineCrisis) machineOperation(sender, e);//如果为托管(智械)则进行操作
                                return;
                            }
                            //目前是我方回合,说明对方操作结束需要刷新界面,需要判断是否已经刷新
                            string[] results = jo["data"]["last_code"].ToString().Split(' ');
                            //last_code格式为0 0 C8,玩家 出牌方式 扑克类型
                            char how = Convert.ToChar(results[1]);//获取出牌方式
                            if (jo["data"]["last_msg"].ToString() != this.freshFlag)
                            {
                                //当碰到"烧条"玩家,多次监听返回值相同仅需刷新一次
                                this.freshFlag = jo["data"]["last_msg"].ToString();
                                if (how == '1')
                                {
                                    if (results[2][0] == 'S')Norch.getSpadePile().Pop();
                                    else if (results[2][0] == 'H')Norch.getHeartPile().Pop();
                                    else if (results[2][0] == 'C')Norch.getClubPile().Pop();
                                    else Norch.getDiamondPile().Pop();
                                }
                                //刷新界面操作
                                refreshContest(results[2], how - '0');
                                //刷新不同区域的扑克牌数目
                                refreshPokerNum();
                                //刷新不同区域的扑克牌图片
                                refreshPokerImg();
                                this.turnCue.Text = "你的回合!";
                                this.turnCue.Refresh();
                            }
                            yourTurn = true;
                            //如果为托管(智械),刷新后自动操作
                            if (machineCrisis) machineOperation(sender, e);
                            return;
                        }
                    }
                    else if (jo["code"].ToString() == "400")//对局已经结束
                    {
                        this.timer.Enabled = false;
                        this.timer.Stop();//停止监听                   
                        rec = FetchInfo.executeOperation("fetchContestInfo " + this.uuid);
                        jo = (JObject)JsonConvert.DeserializeObject(rec);
                        if(!this.matchEnd)
                        {
                            string ending = "";
                            if (jo["data"]["winner"].ToString() == "0" && this.host)
                                ending = "恭喜你,你获胜了。";
                            else if(jo["data"]["winner"].ToString() == "0" && !this.host)
                            {
                                ending = "胜败乃兵家常事很正常的啦。";
                            }
                            else if(jo["data"]["winner"].ToString() == "1" && !this.host)
                            {
                                ending = "恭喜你,你获胜了。";
                            }
                            else
                            {
                                ending = "胜败乃兵家常事很正常的啦。";
                            }
                            MessageBox.Show(ending);
                            matchEnd = true;
                        }
                        this.Dispose();
                        this.Close();//关闭当前窗体
                        this.internetMenu.Show();//显示上一个窗体
                    }
                }
            }
    

    第二部分应该是有关托管时指定策略并及时做出反应的代码,代码中有相应的解释不在赘述:

    /// <summary>
            /// 其中描述了智械的策略(为何将托管美名其曰
            /// 智械,这次我采用的所有素材来源于对Stellaris
            /// 和SpaceEnginee游戏的加工,智械来源于Stellaris
            /// 虽然达不到对应的智力。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void machineOperation(object sender, EventArgs e)
            {
                /* 策略零:智械没有手牌时则一直翻牌
                     * 策略一:智械手牌数+两倍的牌库数+放置区数<玩家手牌数时 一直翻
                     * 策略二:智械有手牌时计算卡牌中各种花色概率,优先打出花色概率最高且与牌顶不同,
                     *        当只有与牌顶相同的卡牌时,则考虑
                     *        玩家手牌数+两倍牌库数<智械手牌数+放置区数?是则翻牌,否则打出花色相同牌
                     * 策略三:摆了,viva la Machine!
                     */
                if (Steve.getPokerNum() == 0)
                {
                    cardPile_Click(sender, e);
                    return;
                }
                else if (Steve.getPokerNum() + 2 * pokerPileNum + pokerPublished.Count()
                    < Norch.getPokerNum())
                {
                    cardPile_Click(sender, e);
                    return;
                }
                else
                {
                    //用于获取花色比例排序
                    string order = makeStrategy();
                    //按照比例顺序优先打出与放置区顶部不同花色的牌
                    for (int i = 0; i < order.Length; i++)
                    {
                        //放置区没有牌的情况
                        if (this.pokerPublished.Count == 0)
                        {
                            //判断是否有无对应的卡牌
                            if (pokerMachine_Click(order[i].ToString(), sender, e)) return;
                        }
                        //放置区有牌的情况
                        else
                        {
                            if (order[i].ToString() != this.pokerPublished.Peek().getPokerType())
                            {
                                if (pokerMachine_Click(order[i].ToString(), sender, e)) return;
                            }
                        }
                    }
                    //说明手上只有和牌顶相同的牌这时候就要进行判断玩家手牌数+两倍牌库数<智械手牌数+放置区数
                    //如若打出则必输,需要翻牌对赌
                    if (this.Norch.getPokerNum() + 2 * this.pokerPileNum
                        < this.Steve.getPokerNum() + this.pokerPublished.Count())
                    {
                        cardPile_Click(sender, e);
                        return;
                    }
                    //否则点击与放置区顶部相同的牌进行吃牌,还有余地
                    else
                    {
                        if (this.Steve.getSpadePile().Count != 0)
                        {
                            spadeLeft_Click(sender, e);
                            return;
                        }
                        else if (this.Steve.getHeartPile().Count != 0)
                        {
                            heartLeft_Click(sender, e);
                            return;
                        }
                        else if (this.Steve.getClubPile().Count != 0)
                        {
                            clubLeft_Click(sender, e);
                            return;
                        }
                        else
                        {
                            diamondLeft_Click(sender, e);
                            return;
                        }
                    }
                }
            }
    

    性能分析与改进

    ​ 肯定是不断监听获取上步操作的的timer_Tick函数,尽管用户没有操作计时器也在不断执行相应的函数即不断发送请求,其它的基本没有什么消耗。

    描述你改进的思路

    ​ 举个例子,再和别人磋炉石时如果碰到对方一直在“烧条”(即在沉思),那么就在这段时间内不能够进行页面刷新,必须及时止损不能够重复刷新,于是添加了额外的freshFlag用于存储上一步操作的信息如果请求返回的上一步操作信息和当前的freshFlag一致说明不应该进行更新,否则进行更新并将新的值赋值给freshFlag,能在一定程度上减少刷新次数。

    ​ 再者就是监听的设置时间,不能过短造成资源消耗加大,不能过长,因为过长导致实时更新效果较差,于是经过不断测试总算找到了勉强合格的时间1000ms。

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

    ​ 消耗最大函数就在上面重要/有价值的代码回答中,即timer_Tick函数。

    此图为VS诊断会话性能,采用对CPU占用率测试,且测试过程中两个频率较高的托管进行对战的结果。

    展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路

    这里仅仅列出制定策略的单元测试代码,即对牌的概率进行计算的函数的测试代码:

    List<Probablity> tmp = new List<Probablity>();
    tmp.Add(new Probablity(0.5, "S"));
    tmp.Add(new Probablity(0.7, "H"));
    tmp.Add(new Probablity(0.1, "C"));
    tmp.Add(new Probablity(0.5, "D"));
    tmp.Sort(Probablity.Compare);
    for(int i=0;i<tmp.Count;i++)
    	Console.WriteLine(tmp[i].getPokerType());
    

    用于测试概率重载过后的概率计算函数是否合格,通过控制台检验输出数据

    2.2贴出Github的代码签入记录,合理记录commit信息

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

    PS:由于在本次结对中黄朝威编写了几乎100%的代码,因此只给出黄朝威对于这部分内容的回答。

    困难描述:一、在本次作业中作为编程手前期碰到困难的事情是无法解决联网的问题这部分在心得中也会有所提及,早期模块化了许多代码(这个也成了后期最大的困难),当时对于联网部分欠缺接口的实现,于是网上找了许多份C#相关报文发送实现的代码,进行对比优化后得到了一份代码,初期使用代码测试登录接口时能够返回登录成功的相关报文,这时候给了作为编程手的我看见了能够及时完成作业的希望然后就给我一巴掌扇回了起点,创建对局和加入对局无法通过C#的HttpRequest实现,我当时的心电图应该是这样的:

    二、第二个困难在于模块化代码部分存在相互调用的情况,部分模块化的代码存在相互调用的情况,在架构初期未能考虑好各个代码之间的相互调用情况,应该尽量避免代码之间的大量相互调用。

    解决过程:对于第一个困难我的解决方法是通过CMD架起桥梁,实现C#和Python之间的交互,这个过程说起来简单但实际非常困难,因为我一开始并不知道可以这么操作,我一开始发现C#无法实现本次除登录外的其它接口(基本联网对战是宣布死刑了),然后转手使用Python解决了接口的问题,然后暴露在我面前的是整个项目移植到Python上还是在C#中嵌入Python脚本,我毅然决然选择了后者却没想到是梦魇的开始,上网搜索了大量资料可以通过IronPython实现C#中通过ScriptEnginee来驱动脚本运行,我大意了啊这IronPython和Python相差甚远的同时缺乏足够的可供参考资料,于是就想着有没有什么办法能够让Python脚本打包成可执行程序,然后直接通过C#提供的方法来调用可执行程序,然后一通折腾下来发现打包失败了,于是就想着能不能直接实现两个文件的交互谁来充当这个桥梁于是CMD充当了本次网络对战接口实现的重要工具,通过C#调用CMD将命令参数传入到对应脚本中,通过输出的值来加以裁剪无用信息来实现网络接口;对于第二个困难我的解决方法是重新设计部分代码,于是没日没夜的重新设计代码,奇怪的代码量莫名其妙上升了。

    有何收获:

    我的评价是面向搜索引擎编程真的重要,在本次结对作业中解决代码模块异常的困难都是通过不断查找大量资料来解决,以及今后的作业中尽量减少使用小众人群语言,例如提到的IronPython我连个语法介绍都不能查到,这写的时候难不成要凭空想象,总结就是避免掉坑。

    2.4 评价你的队友

    蔡树峰:

    • 队友值得学习的地方
      威少YYDS!究极强大的学习能力与无比执着的精神。在从未接触C#基础的情况下,毅然决定从0开始学C#,搞定pigtail,在这个过程遇到种种问题,我的队友威少从未产生畏难心理,而是从不同角度、通过各种方式去解决问题,而不是消极摆烂,令我佩服,更值得我学习。
    • 队友需要改进的地方
      威少作为一个深夜战神,一个肝弟(偷偷改队友的嘿嘿,肝帝称不上,一个一边挂机打游戏一边写代码的是个肝弟),灵感总是在夜晚来临。想劝威少注意身体,做一个时间管理大师,少熬夜,将时间安排的更合理一些。

    黄朝威:

    • 队友值得学习的地方:

      峰哥在本次作业代码编写上为我提供了间接的帮助,我本人在本次结对作业中出现了过度投入忽视其他学科的学习的情况,于是就找峰哥为我解答问题果然上课认真听课是非常非常有必要的,要学会暂时放下

    • 队友需要改进的地方:

      笑死,队友修改改进的地方就是他吐槽我需要改进的地方,太养生了,睡太早了,把生物钟往后稍微调整一下应该问题不大

    2.5提供此次结对作业的PSP和学习进度条(每周追加):

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 20 60
    · Estimate · 估计这个任务需要多少时间 20 30
    Development 开发 2400 8760
    · Analysis · 需求分析 (包括学习新技术) 240 60
    · Design Spec · 生成设计文档 10 30
    · Design Review · 设计复审 5 25
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 50
    · Design · 具体设计 120 255
    · Coding · 具体编码 1500 1600
    · Code Review · 代码复审 660 1000
    · Test · 测试(自我测试,修改代码,提交修改) 1200 60
    Reporting 报告 100 120
    · Test Repor · 测试报告 60 80
    · Size Measurement · 计算工作量 10 10
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 30
    · 合计 6335 12170
    第一周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
    1 0 0 21 21 速通C#基础语法以及高级语法,以及Unity入门使用和winform控件使用,界面设计。
    2 1000+ 1000+ 21 42 熟悉使用winform控件,winform控件属性以及事件的设置触发,多窗体交互,通过编写基本代码和对系统生成的代码进行修改来提升对winform的了解度。
    3 3000+ 4000+ 42 84 通过使用CMD实现C#和Python的交互,解决了C#在本次结对作业中Post请求创建对局、加入对局等失败的问题,为联网对战奠定了坚实的基础,以及大规模改动界面设计、美化界面布局,逻辑完善。
    4 1000+ 5000+ 42 126 重构了部分窗体的设计代码,完善各个不同窗体间的逻辑,以及针对timer计时器的熟悉运用,和极大加强了VS的winform开发工具使用熟悉度,在该阶段通过不断调试、不断使用VS中的各种工具。
    5 300+ 5380 20 146 修改大量Bug,Debug让人成仙了属于是。

    三、心得

    蔡树峰:
    对于这样的一个pigtail小游戏,在游戏规则相对简单清晰的情况下,考验的可能就是大家的功能完善程度和自己的UI界面友好程度了。最重要的是一开始给自己的产品设计设立较高的目标和要求,这样即使在过程中遇到一些困难,削减需求后再去实现,最终做出的产品还是有一定特点和风格的。在敲代码的过程中,有点遗憾的是完成度还不够,设计出的游戏界面相对比较简单,没有塑造出高级的感觉。此外,对于AI的设计,本来是有很多想法的,思考过在牌少的情况下先主动吃牌,通过一系列抽牌吃牌操作,控制好手上四种花色与剩余卡牌的比例,掌握游戏的节奏,朝着对自己有利的操作方向前进。这部分算法最后还是主要靠队友来完成了,十分惭愧。千军易得,一将难求。感谢队友威少挑起项目大梁,从零开始学C#,奋战三周,项目起飞。对威少致以献上崇高的敬意(^^ゞ

    黄朝威:

    ​ 还真是从零开始,一开始我也打算用前端三件套来完成本次作业,但是最要命的事情是我只拿过这三件套整过博客的一些基础的文字设计,对于能不能用于完成本次作业,心里还真是没底,可能就会出现直接摆了的情况,因此我还是首先采用上网搜索有无可以直接用来的改改样式和逻辑就行了,后来我看到了一套网课,确实可以从零基础开始学习C#和Unity制作联网斗地主,于是去速通了C#语法,给我的感觉是C#就好比C++和Java的结合体,熟悉到一小时就可以速成基础语法,当然高级特性花了点时间,但这无伤大雅,然后挑起整个项目的重担,一开始其实是偷懒打算就随便做了个界面就行了,和原型设计有点差距我可以解释为请以实物为准,但是那个时候我想了想已经投入了那么多的时间在设计界面和完善界面逻辑了,那就干脆把界面完善到我预期,于是就开始了没课的时候都坐在电脑旁重新设计界面,不断地调试不断地解决error,中途想过放弃但还是坚持了下去。

    ​ 对于作业的难度我只想吐槽一个点就是联网对战的接口可能存在一定的问题,本次代码构成中有一部分代码为Python代码本来只需要基于.Net框架下的C#通过底层的流式传输就可以实现网络接口,但是着实给我上了一课,发送的报文信息在调试过程中是正确的返回的结果总是鉴权失败,使用Postman发送同样的报文时却能正确获取信息,这让我有点怀疑我Post请求代码是否存在问题,于是开始不断比对网上查找的相关资料无一例外我的代码是正确的,于是我使用了Python来执行操作就可以了,然后我就想着那我就通过CMD实现这二者的交互,这其中的苦不是这段文字所能体现的,我想了想如果真的是C#底层的问题的话那么采用C#开发相应应用的公司应该早就反馈给微软,所以我还是觉得是接口的问题。

    作业感想的话倒是没什么,可能也是集中在网络对战的问题上,头一次接触调用API来开发还是觉得挺新颖的,由于技术能力的限制未能在本次作业中添加动画,打出牌或是翻牌仅仅采用硬核刷新的方式,对于这部分没能采用动画实现深感遗憾,我还是觉得这次所实现的游戏在一定程度上是个运气游戏,例如我在和同学测试两个托管对战时将牌堆累积到了37张牌然后我翻开了一张反转局面的牌使得顺风的局面变逆风了,可能是托管的算法太垃圾了,训练模型至少这次不会。

  • 相关阅读:
    Flume spooldir 报错 MalformedInputException: Input length = 1
    Python股票量化投资-2.量化投资介绍
    Python股票量化投资-1.开发环境部署
    centos 8 安装 activemq5.15 开机自启动
    Hystrix 说明
    Centos 8 安装 tomcat8.5 开机自启动
    Centos 8 安装 JDK 1.8
    centos 8.0 安装 nginx-1.18.0 开机自启动
    Error LNK2019: unresolved external symbol "char * __stdcall _com_util::ConvertBSTRToString(wchar_t *)"
    如何复制DataRow(dataTabel中的行)
  • 原文地址:https://www.cnblogs.com/fzu-rookie/p/15449524.html
Copyright © 2011-2022 走看看