一.结对探索
1.1队伍基本信息
结对编号:38 队伍名称:拉拉队
学号 | 姓名 | 作业博客链接 | 具体分工 |
---|---|---|---|
102101109 | 韩欣华 | https://blog.csdn.net/2301_77513568/article/details/133797922 | 代码设计、代码测试 |
102101110 | 魏燕清 | 2023软工K班结对编程任务_102101110的博客-CSDN博客 | 原型设计、前端编写、性能分析 |
1.2描述结对的过程
我们是同班同学,日常一起上课,交流起来很方便。
1.3非摆拍的两人在讨论设计或结对编程过程的照片
二.原型设计
2.1原型工具的选择
我们主要选择了Axure RP,iconpark
Axure RP是一款免费的可以进行原型设计的软件,并且最后可以导出成html文件,为编写前端程序减轻了一点负担;
iconpark是图标矢量库,可以提供大量免费的素材
2.2遇到的困难与解决方法
困难:
-
首先,一开始根本不知道什么是原型设计,应该用什么去做
-
网上推荐使用的软件很多,但是尝试了一下发现很多并不是很好用。比如我一开始使用墨客,制作了三张页面之后,他告诉我要收费了??!崩溃。然后我还使用了墨刀,是很容易上手,但是感觉功能有些欠缺。于是最后使用了Axure RP
-
素材:网上的资源很多但是符合心意的很难挑选,总感觉页面不够美观
解决方案:
先是在博客园中查找,了解了一下原型设计这是个什么东西,在这个软件开发中有什么用。然后,通过一个个软件的试错,最后确定了我们要使用的Axure。一开始我们找素材就是直接在浏览器中搜索,但是这种图片一般质量很低,后来通过询问GPT,它推荐了Pixabay网站和iconpark。
2.3原型作品链接
2.4原型界面图片展式
1.游戏首页
需要用户登录,注册;右上角是背景音乐控制键,可以控制背景音乐播放和停止
2.本地对战
设置游戏局数,筹码数
正式游戏页面
3.人机对战
4.在线对战
房间号:动态随机生成一个六位数
5.对战结果
6.关于
创新点
1.我们在右上角添加了背景音乐开关,点击时可以切换不同的图片控制背景音乐的 开关
2.在绘画艺术中,「孤注一掷」 可以理解为画家在作品创作时的勇敢和决心,并且投入了全部的心力。这种情感与独特的韵相结合,给作品带来了独特的魅力。
而水墨风则是一种以中国传统水墨画为基础的艺术风格。水墨画追求简洁、含蓄和意境,通过墨色的浓淡、线条的变化以及 留白的运用来表现事物的形态和情感。水墨画通常具有一种深邃、 灵动、凝重的氛围,给人以超然的美感。
在创作水墨画时,画家常常需要孤注一掷, 毫不吝啬地将自己的情感和灵感倾注到作品中。他们像是在画布上注入了生命的力量,通过稳定的手法和独特的笔触,展现出水墨画特有的凝重和灵动的韵味。这种勇敢追求艺术和以心传情的态度,让水墨画更加饱含了生命的力量和创作者的独特个性。
可以体会到「孤注一掷」 与「水墨风」之间的共通之处,即对艺术的投入和追求,以及将自己的情感融 入作品中的表现力。
所以在整体设计时,我们采用水墨画为主要背景。
三、编程实现(14分)
3.1 网络接口的使用(2分)
主要使用WebSockets进行实时通信,用于服务器端和客户端之间的数据交互;还有在线对战时多名玩家之间传递数据
例如websocket_connect
建立连接,websocket_receive
接收客户端消息,然后通过redis返回即可,最好一定用websocket_disconnect
断开与客户机的连接,客户机也可以用socketonclose
来断开连接。
还利用到了Fetch API,实现将游戏结果发送到服务器,或者从服务器获取其他数据,利用这些API进行AJAX请求。
3.2 代码组织与内部实现设计(类图)(2分)
以下是一些类的主要方法和代码的组织:
主要类:
-
牌类
-
sock(dice* a,int q,int* n1,int r,int fg):锁定位置以及计算倍率
-
count1(dice * a):计算骰子组合的分数
-
init(dice* a):初始化dice类中的锁定点数lock
-
cmp(dice &a,dice &b):交换排序
-
-
玩家类
-
twopeople();随即生成两个玩家的骰子组合
-
3.3 说明算法的关键与关键实现部分流程图(2分)
对于分数计算,首先先统计不同骰子元素出现的次数,让这些内容放在一个count数组里面,方便调用计算,其次先判断是否为四连和五连还有三连,这三块很容易,只需要一个while循环调用count数组看看count的内容是否存在count[i]是否等于3,4,5就好,这里无论i是几,也就是骰子点数为几都可以直接进行判断,然后如果是四连和五连的话,那么可以直接对sum也就是分数计算,退出函数了。但是如果是三连的话,还要判断一下是否为葫芦,这里仍旧是使用了一个循环,这里的小循环和大循环的内容一样来判断count[i]是否等于2,如果等于的话,sum+10,也就是三连本身sum+10的基础上再加10。
然后是判断是否为双对,双对和三连是一样的,只不过小循环的j,是从大循环判断好的i后面再进行判断。
之后是对小顺子和大顺子进行判断,这里首先先使用了递增数列删除重复项,这样再利用循环判断会很方便,删除重复项后只需要对数组内递增数列的个数dest进行判断就行,看看是否为连续的递增数列就能最后进行判断
流程图:
3.4 贴出重要的/有价值的代码片段并解释(2分)
判断骰子组合中的小顺子和大顺子思考了很久,因为就算先给骰子组合进行了排序,也还是难以判断,如果前后有重复项就很难用平时想的骰子点数加1一直到末尾看是否为顺子来进行判断,后面想到了算法中递增数列删除重复项的方法来解决这一问题,只要删除了重复项,那么就可以直接判断
//判断玩家的牌面,计算赢得的筹码数
int count1(dice * a)
{
int count[10] = { 0 };
int sum = 0;
int flag1 = 1;
int flag2 = 1;
for (int i = 0; i < 5; i++)
{
count[a[i].d]++;
}
sort(a, a+5, cmp);
for (int i = 1; i <= 6; i++)
{
if (count[i] == 5)
{
sum += 100;
break;
}//五连加100
else if (count[i] == 4)
{
sum += 40;
break;
}//四连
else if (count[i] == 3)
{
int p = 1;
sum += 10;
while (p <= 6)
{
if (count[p] == 2) sum += 10;
p++;
}
break;
}//三连和葫芦
else if (count[i] == 2)
{
int p = i + 1;
while (p <= 6)
{
if (count[p] == 2) sum += 10;
p++;
}
break;
}//双对
}
int b[10] = { 0 };
int t = 0;
int dest = 0;
int cur = 1;
a[dest].d = a[0].d;
//从cur==1 cur<numsSize
while (cur < 5)
{
if (a[cur].d != a[dest].d)
{
b[t] = a[dest].d;
a[++dest].d = a[cur++].d;
t++;
}
else
{
cur++;
}
}//递增数列删除重复项
b[dest] = a[dest].d;
if (dest == 4)
{
int m = dest;
while (m != 0)
{
if (b[m] != b[m - 1] + 1)
{
flag1 = 0;
break;
}
m--;
}
}//判断大顺子
else if (dest == 3)
{
int m = dest;
while (m != 0)
{
if (b[m] != b[m - 1] + 1)
{
flag2 = 0;
break;
}
m--;
}
}//判断小顺子
if (flag1 == 1 && dest == 4)
sum += 60;
if (flag2 == 1 && dest == 3)
sum += 30;
return sum;
}
这一片段是进行骰子锁定,这一片段的思路就是输入要锁定的位置后转成数组,看数组的元素等于哪一个位置的下标,然后让lock为1,进行锁定,不相等的就进行此位置生成随机数
typedef struct {
int d;//骰子点数
int lock;//锁定点数
}dice;
void sock(dice* a,int q,int* n1,int r,int fg)
{
cout << "你要锁定的位置: ";
char b1[10];
int num1 = 0;//t的长度
cin.getline(b1, 10);
int t[10] = { 0 };
int m1[10] = { 0 };//锁定区域
for (size_t i = 0; i < strlen(b1); i++) {
t[i] = t[i] * 10 + (b1[i] - '0');
num1++;
}
cout << "你要锁定的数字为: ";
if (num1 != 0)
for (int i = 0; i < num1; i++)
{
m1[i] = a[t[i]-1].d;
cout << m1[i] << " ";
}
cout << endl;
for (int i = 0; i < 5; i++)
{
int flag = 0;
for (int j = 0; j < num1; j++)
if (i == t[j]-1) {
flag = 1;
a[i].lock = 1;
break;
}
srand(time(0));
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(1, 6);
if (flag == 0&& a[i].lock == 0)
{
a[i].d = dis(gen);
n1[r] = a[i].d;
r++;
}
}//进行锁定
cout << "新的数组为: ";
for (int i = 0; i < 5; i++)
{
cout << a[i].d << " ";
}
cout << endl;
if (q < 5 && sum_round<4) {
cout << "你可以选择的区域为: ";
for (int i = q; i < r; i++, q++)
cout << n1[i] << " ";
cout << endl;
}
cout << "选择您的倍数:[1,2,3] ";
if (fg == 1)
{
cin >> mul1w1;
cin.get();
mulw1 = mul1w1 * mulw1;
}
else if (fg == 2)
{
cin >> mul1w2;
cin.get();
mulw2 = mul1w2 * mulw2;
}
sum_round++;
}
3.5 性能分析与改进(2分)
(描述你改进的思路,展示性能分析图和程序中消耗最大的函数)
由上图可以看出:消耗最大的是sock()函数,就是当玩家确认后要锁住骰子点数的函数。
改进:可以减少函数使用的参数个数,修改定义的dice类,将锁标志放在函数当中。
3.6 单元测试(2分)
(展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路)
//测试
void test()
{
cout << "设置局数: ";
cin >> numl;
cout << "设置筹码: ";
int dollor;//筹码
cin >> dollor;
int dollor1 = dollor;
int dollor2 = dollor;
cin.get();
for (int i = 0; i < numl; i++)
{
q1 = 0;
q2 = 0;
r1 = 0;
r2 = 0;
sum_round = 1;
init(a);
init(b);
twopeople();
mulw1 = 1;
mulw2 = 1;
while (sum_round < 5)
{
sock(a, q1, n1, r1, 1);
sock(b, q2, n2, r2, 2);
}
cout << "玩家1的分数: ";
cout << count1(a) << endl;
cout << "玩家2的分数: ";
cout << count1(b) << endl;
if (count1(a) > count1(b))
{
dollor1 = dollor1 + mulw1 * (count1(a) - count1(b));
cout << "玩家1从玩家2手里获得的筹码数:" << mulw1 * (count1(a) - count1(b)) << endl;
}
else if (count1(a) == count1(b))
{
cout << "平局" << endl;
}
else
{
dollor2 = dollor2 + mulw2 * (count1(b) - count1(a));
cout << "玩家2从玩家1手里获得的筹码数:" << mulw2 * (count1(b) - count1(a)) << endl;
}
}
cout << "玩家1的筹码为: " << dollor1 << endl;
cout << "玩家2的筹码为: " << dollor2 << endl;
if (dollor1 > dollor2) {
cout << "玩家1获胜" << endl;
}
else if (dollor1 == dollor2)
cout << "平局" << endl;
else
cout << "玩家2获胜" << endl;
}
思路:简单运行一下,查看编写的游戏逻辑是否有错。
3.7 贴出GitHub的代码签入记录,合理记录commit信息(2分)
四.反思与总结
4.1 本次任务的PSP表格(2分)
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 5040 | 5740 |
-Estimate | -估计这个任务需要多少时间 | 5040 | 5740 |
Development | 开发 | 4860 | 5500 |
-Analysis | -需求分析(包括学习新技术) | 660 | 480 |
-Design Spec | -生成设计文档 | 60 | 90 |
-Design Review | -设计复审 | 30 | 120 |
-Coding Standard | -代码规范 | 30 | 60 |
-Design | -具体设计 | 120 | 840 |
-Coding | -具体编码 | 3780 | 3680 |
-Code Review | -代码复审 | 60 | 60 |
-Test | -测试(自我测试,修改代码,提交修改) | 120 | 30 |
Reporting | 报告 | 180 | 240 |
-Test Repor | -测试报告 | 120 | 30 |
-Size Measurement | -计算工作量 | 30 | 50 |
-Postmortem & Process Improment Plan | -事后总结,并提出过程改进计划 | 30 | 60 |
-合计 | 5160 | 5740 |
4.2学习进度条(每周追加)
-
魏燕清
第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长 1 0 0 10 10 寻找素材,学习HTML和CSS,掌握Axure软件的使用方法,进行原型设计 2 1458 1458 30 40 编写前端页面代码 3 2079 3537 24 64 学习JS,编写页面中的交互效果
-
韩欣华
第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
---|---|---|---|---|---|
1 | 70 | 70 | 12 | 12 | 构思C++实现思路,实现基本布局 |
2 | 121 | 191 | 27 | 39 | 编写主要函数 |
3 | 89 | 280 | 25 | 64 | 制作 总体代码内容 |
4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?(2分)
(也就是谈一谈本次任务中“理想与现实的差距”,是哪些因素造成了这些差距?)
想象中的产品是想开发成微信小程序的一个多人联机,可以进行双人对战和人机对战以及增加各种趣味玩法的,但是事实上算法思考的问题很多,还有一些bug需要反复修复。后端要学习的东西很多,把基本算法写出来后还要学习后端的很多以及和前端进行交互,还要学习接口,而且只能进行网页版制作.产品最后的页面形态和预想的差不多,进行原型设计的时候非常顺利,但是自己编写前端代码的时候就会遇到各种问题,导致页面看起来没有原型设计的时候合理、流畅。开发成果没有达到预期,本来以后前端和后端可以分开编写,没有考虑到它们需要交互!!
4.4 评价你的队友(2分)
(分别评价队友值得学习的地方和需要改进的地方) (本部分需要包含队伍内所有成员的心得体会,若缺少一人,则队伍总分减少2分,减满4分为止)
-
魏燕清
评价队友:队友最让我佩服的一点就是在国庆节期间写这个程序写了很久,她负责前端部分,基本都是初学,我应该学习她在节假日放松期间仍然能够进行学习和自我进步 改进的地方:我们之间交流较少,所以后续的同步问题比较严重
-
韩欣华
评价队友:在这次之前我们都没有过做项目的经验,在这次结对编程期间,她也很负责地写完了这个骰子小游戏的逻辑部分,基本复现了群里的要求,已经有了很大进步!不过在前后端交互的时候有点欠缺,可以再多改进一点
4.5 结对编程作业心得体会(3分)
(可包含但不限于评价作业难度、完成后的感受、遇到的代码模块异常或结对困难及解决方法、对之后学习或软件开发的启发) (本部分需要包含队伍内所有成员的心得体会,若缺少一人,则队伍总分减少3分,减满6分为止)
-
魏燕清
-
作业还是有点难的,之前我只自学过HTML CSS JS之类的一些前端知识,但是还没有自己上手做过项目T~T。这次作业也让我捡起来了之前学过的东西,锻炼了自己的动手能力。然后在写一些页面交互效果的时候,一开始非常不熟悉JS的语法和怎么编写,但是一回生二回熟,多写几个页面就好咯~在这次作业过程中,和队友交流的不够多,导致很多地方实现的不够好T~T,以后要注意沟通的主要性!
-
-
韩欣华
- 心得体会:
这个作业我认为还是挺有挑战性的吧,其实代码的内容,我觉得并没有说特别难的地方,基本其实靠着数组就完全可以做出来,主要就是构思这些后端代码块和连接问题真的很需要逻辑,说实话我敲代码并没有说敲了特别久,主要就是构思占用了很大很大的时间,在作业发布期间,我没事干我就会构思这些内容,函数要写的部分,基本上就是每天都会花时间去想究竟要怎么才能实现这类功能,所以构思真的占用了我非常大的时间,然后就是一开始写的时候,就直接用构思好的东西写了很多很多,结果出现了bug都不知道哪里出错了,还是依靠我的队友来完成的,我还是很感谢我的队友,她不仅是前端设计,在一些构思方面也帮了我很大的忙,哭死。然后就这个第一块的代码bug找了很久之后我就学会了边写边测试,尽量让我之后不会再遇到bug不知道在哪里出现的情况,就是因为这一行为的改变,再写后续部分的代码bug方面的问题占用了很小一部分时间。这个作业的难度主要是在于我并不了解前后端交互问题,我不知道怎么让他们拼接在一起,因为这一部分真的就是没有实践过,我没有这个经验。不过说实话,在写后端的时候我还是真的学到了很多东西,我可能之前在算法中不会实践的内容这次完完整整的掌握了,而且也极大的提高了我思维能力,运用函数块是一个很方便的编写程序的方法。这样断断续续的完成,在单元测试出来那一瞬间我真的有一种从所未有的自豪感,没想到我也能写出来这一游戏!
就是这样的一个表情。这个作业进入了尾声了马上结束了,我觉得还是对我挺有用的,我学会了很多新的东西,巩固了曾经的东西,我也很感谢我的队友,她帮我解决了一些我构思很久想不出来的问题。
- 心得体会: