结对编程作业

https://github.com/cyt199709/PigTail

队友分工:

姓名 分工内容
陈艺天032092119 后端
温致鹏032092121 前端

一、原型设计

(1)、作品链接

​ 链接:https://files.cnblogs.com/files/cyt199709/PigTail相关.rar

(2)、设计说明

本次结对作业的设计采用了三界面的形式,登陆界面(获取Token),主界面(选择模式),游戏界面(进行游戏)。

登陆学校VPN后在登陆界面输入账号密码后点击登陆就可以登录到主界面,可以选择三种模式,1,人机对战,2、人人对战,3、联网对战。其中联网对战点击后,又有创建对局,加入对局,以及查询对局可供选择,由于界面简单 ,故在设计程序的时候由代码实现,不进行ui的设计。仅仅只对登陆界面、主界面以及游戏界面进行ui设计。

设计过程分为两部分:

  • 由一名同学在亿图图示上进行简略的设计。
  • 另外一名同学在QtDesigner上面进行实现,并且对部分代码进行补充实现。

(3)、开发工具

本次结对作业所采用的原型设计工具为亿图图示QtDesigner,之后又采用样式表将界面美化。

(4)、设计结果

1)、亿图图示结果

  • 登陆界面
    image-20211015132405365
  • 主界面
    image-20211015132423467
  • 游戏界面
    image-20211015132439927

2)QtDesigner设计结果

  • 登陆界面
    image-20211015132643171
  • 主界面
    image-20211015132654089
  • 游戏界面
    image-20211015132727095

(5)、困难及解决方法

  • 由于起初对于工具的不熟练,对于QtDesigner中设计的窗口不能很好的进行美化,导致界面不太美观
  • 网上查找到使用层叠样式文件可以对样式进行修改,并进行了简单的学习后能够将样式与Ui进行结合
  • 学到了新的知识,了解到了样式表设计样式的简便

二、原型设计实现

(1)、代码实现思路

  • 网络接口采用C语言库curl,并在Postman工具的帮助下进行收发服务器的数据。

  • 类图
    image-20211015134622450

  • 算法的关键与关键实现部分流程图
    算法的关键在于对即将进入放置区的卡牌与放置区顶部的牌进行判定,相同则进行“吃”的操作。

    若是联网对战,对于摸牌的操作,向服务器put操作后获取摸取的牌,并显示在窗口中。游戏过程中(在没有轮到自己的回合时)向服务器get上一步操作,如果Json中的your_turn关键字变为true,就读取对手的操作,并显示在对应的窗口中,再进行自己的操作!

    image-20211015182147345

  • 重要的代码片段

    /*
    	输入:无
    	返回值:空
    	效果:在另一个线程中不断进行服务器数据的收取以此来判断是否轮到自己出牌,以及上一轮的出牌是啥
    */
    void GameWindow::getMsgInServer() // 从服务器中不断获取数据
    {
    	if (m_deckCard.size() == 0) { // 如果牌库空了就执行循环体的语句
    		judgeWinner();	// 判断胜者是谁,并显示出来
    		return;
    	}
        
    	// 如果玩家一在出牌的过程中,就不联网判断,或者在系统获取并执行玩家二的操作中,也不进行联网判断,防止浪费系统资源!
    	if (m_onPlayer1 || m_isOnPlayer2) 
    		return;
    
        // 互斥锁,防止相同的文件被同时访问导致一些bug
    	mutex.lock();
        // 下面都是获取上一步的操作
    	CURL* curl;
    	CURLcode res;
    	FILE* fp;
    	if ((fp = fopen("onlineReturn.txt", "w")) == NULL)
    		return;
    	curl = curl_easy_init();
    	if (curl) {
    		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
    		QByteArray get = "http://172.17.173.97:9000/api/game/" + gUuid.toUtf8() + "/last";
    		curl_easy_setopt(curl, CURLOPT_URL, get.data());
    		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    		curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "http");
    		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);	// 数据写入文件        
    		struct curl_slist* headers = NULL;
    		headers = curl_slist_append(headers, (QByteArray("Authorization: Bearer ") + gToken.toUtf8()).data());
    		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    		res = curl_easy_perform(curl);
    
    		fclose(fp);
    		if (res != 0)
    			return;
    	}
    	curl_easy_cleanup(curl);
    
        // 将保存到文件的Json数据存到字符串中
    	char* str = CCMainWindow::getFile("onlineReturn.txt");
    
    	mutex.unlock(); // 文件操作完后解开互斥锁
    
        // 存到Utf8字符数组中
    	QByteArray Json = QByteArray(str);
    
    	QJsonParseError err;
        // 将字符串转换为Json格式以方便解析
    	QJsonDocument document = QJsonDocument::fromJson(Json, &err);
        // 解析失败就退出
    	if (!(err.error == QJsonParseError::NoError))
    	{
    		QMessageBox::warning(nullptr, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("Json文件解析失败!"));
    		return;
    	}
    
    	QJsonObject obj = document.object();
    	int code = obj["code"].toInt(); // 获取访问code, 如果非200都是异常情况
    	QJsonValue jsonValue = obj.value(QLatin1Literal("data"));
    	obj = jsonValue.toObject();	
    	if (code != 200)
    		return;
    
    	bool turn = false;
    	turn = obj["your_turn"].toBool(); // 获取现在是否是自己的回合
        
        // 只有当游戏刚创建时才能进入修改玩家状态,一开始的m_isOnPlayer1与m_isOnPlayer2都为false
    	if (turn && m_isGameAtFirst) 
    	{
    		m_isGameAtFirst = false;
    		mutex.lock();
    		m_isOnPlayer2 = false;
    		m_onPlayer1 = true;
    		ui.userLabel->setText(QString::fromLocal8Bit("用户:") + gId + QString::fromLocal8Bit("的手牌") + "\n轮到你了");
    		mutex.unlock();
    	}	
    
        // 如果是你的回合就去获取对手的操作,并在游戏界面上面显示出来
    	if (turn)
    	{
            // 刚开始没有人出牌就直接跳出
    		if (obj["last_msg"].toString() == QString::fromLocal8Bit("对局刚开始"))
    			return;
    		
    		mutex.lock(); // 防止资源在不同线程中抢占的互斥锁
    		m_isOnPlayer2 = true; // 对手的操作过程中不会进入该函数
    		mutex.unlock();
    		int id;
    		QString last_code = obj["last_code"].toString();
    		id = analysisCode(last_code); // 由于本程序采用的是数字ID即1-52来排序,所以对code进行解析
    		
    		if (last_code[2] == "0") // 翻牌
    		{
                // 发送信号,执行翻牌操作
    			emit playerOper(true, id);
    			//onlineFlop(&m_player2Card, id);
    		}
    		else //出牌
    		{
                // 发送信号,执行出牌操作
    			emit playerOper(false, id);
    			//onPlayerOutCard(&m_player2Card, id);
    		}		
    	}
    }
    
    

(2)、Github记录

image-20211015195442547

(3)、困难及解决方法

  • 刚开始写完人机与本地对战后,由于没有事先对网络接口进行分析,导致花了大量时间在连接服务器上。
  • 最后使用postman工具成功从服务器上获得内容
  • 加深了每个人对HTTP协议的认识,并且对请求方法的一种区分

(4)、队友评价

温致鹏:由于本组只有两个成员,大家都尽力而为。

陈艺天:队友的代码功力很厉害,很多时候我开发界面,然后一些不能使用ui写的界面也询问了一些,总之帮助很大。虽然界面不是很多,但是样式表,ui,以及后期的文档编辑,大部分都是我在做,程序功能上的代码大多都是队友完成。

缺点:平时做事情不是很积极,快到结束了才努力,导致后期精力消耗比较大。

(5)、进度条

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
1 0 0 25 25 复习掌握了C/C++的知识
2 0 0 30 55 在基础上了解了Qt的基本用法
3 1000 1000 50 105 开始尝试编写游戏,并掌握基本的接口使用方法
4 1500 2500 60 165 程序编写完成,但任有一些不足

三、心得

温致鹏:本次结对作业是我第一次团队合作,并且也是第一次使用Qt,通过不断的学习与摸索最终还是完成了这次作业的大部分要求。

对于本次作业中最令我们团队困扰的部分应该就是接口数据的请求与获取,之后就是将获取的数据与团队成果的一个交互,并且将效果显示在游戏窗口中。

陈艺天:对于我们这个团队来说,由于人手不足,我们不得不花更多的时间来进行学习与设计,但是这个过程是很充实的,因为人少的原因,团队的配合显得更加的默契。

本次作业的难度还是适中的,主要锻炼我们的团队合作能力,代码格式,版本管理,界面设计以及算法设计等能力。本次作业令我们团队最大的收获不仅仅只是完成了任务规定的作业,而是从中获取了很多对自己以后的人生更加有益的经验,无论是在团队开发还是个人开发。之后的学习呢我们也将精益求精,在尽可能的情况下,完成任务要求的前提下尽可能的拓展功力,获得经验。

posted @ 2021-10-23 20:13  老憨皮  阅读(84)  评论(0编辑  收藏  举报