一、原型设计

1、链接与开发工具说明

  • pigTail采用的原型开发工具是:Axure,ps

2、原型展示

1、 初步原型由以下几个页面构成:

  • 登陆页面
  • 对局选择页面
  • 模式选择页面
  • 人机对战难度选择页面
  • 在线对战操作选择页面
  • 加载与等待页面
    结对_性能分析

2、登录页面

  • 有输入账号密码,密码为掩码构成,此外细节较为丰富,拥有“记住我”,“忘记密码”,音乐,设置,提示功能。输入正确账号密码后跳转到游戏模式选择界面。

结对_json_02

3、人机对战选择页面

结对_json_03

4、人机对战难度选择页面

结对_原型设计_04

  • 若选择在线对战,则进入在线对战模块,该页面基本细节均实现了,有创建对局,加入对局等功能(在线对战原型设计确实走心了)
    结对_python_05
  • 加入房间页面提供了目前空闲的uuid,用户可以点击加入房间,也可以选择查找uuid,若uuid存在,则显示出房间供用户选择加入与否。此外还有该原型界面加入了一些细节,如刷新信息,随机加入,回到主页等功能

    结对_json_06
  • 玩家在选择模式后,即将进入房间对局页面,期间会有3秒的动画等待过渡,期间可以选择退出等待,释放对局。(因为实际的接口并没有给予我们释放对局的功能,此处仅做展示)
    结对_python_07
  • 综合结果掩饰
    结对_json_08

3、后期原型优化。

  • 针对原型设计中的不足和美观缺陷做了一定的优化
  • 卡牌选取特效
  • 结对_性能分析_09
  • 隔空嘲讽特效(可惜接口不允许,只能本地隔空对线)
  • 结对_原型设计_10
  • 圆框登录界面看起来会更舒服一些
  • 结对_github_11
二、原型设计实现

0、后期原型优化:

  • 首先是主页面和选择页面:按钮更加圆滑了。
    结对_github_12
  • 卡牌做了显示特效
    结对_原型设计_13
  • 隔空对线功能(当然,接口没有给予我们对话功能????????,真是太可惜了????????????,静音啥的以及倒咖啡)
  • 结对_原型设计_14

1、代码实现思路

(1)网络接口的使用:

我们将测试组的同学们提供的接口文档细致阅读后,对于游戏的基本接口信息交互有了充分认知后,设计了一个类用于对每种接口的核心信息做了分类,以及接口信息返回做了分类,具体如下、对于异常状况做了相应的异常处理、否则可能会出现由于少量的网络波动和非理想状况(如:玩家登陆失败、网络波动导致程序终止、因此必须考虑所有可能的返回参数)

接口简称

接口参数需求

可能的返回状况

登录连接

​student_id​​、​​password​

登陆成功、登录失败(含网络超时)

登录连接

​student_id​​、​​password​

登陆成功、登录失败(含网络超时)

加入对局

​token​​、​​uuid​

加入成功、失败(对局不存在、无法加入(人满)、网络超时)

创建对局

​token​

创建成功、创建失败

获取上步信息

​token​​、​​uuid​

获取成功、网络超时

执行玩家操作

​token​​、​​uuid​

执行成功、失败

获取上步操作

​token​​、​​uuid​

获取成功、失败

  • 游戏运行过程中的调用:
    结对_原型设计_15
  • 为了确保对于所有状况的应对便于处理、我们对接口函数要求其返回整个返回信息字典、而非几个参数、举例来说、以获取上部操作为例、我们初步的做法是:
import requests
import json
def get_last(token, uuid):
url = 'http://172.17.173.97:9000/api/game/' + uuid + '/last'
header = {'Authorization': token, 'Content-Type': 'application/json'}
r = requests.get(url, headers=header,timeout=5)
user_dict = json.loads(r.text)
# print(user_dict)
return user_dict


  • 这样做的好处是显而易见的:get_last接口需要应对的返回结果很多、如果只使用 ​​user_dict['data']['last_code']​​ 某次偶发性的网络波动导致​​user_dict['data']​​根本不存在、没能正确处理而导致了程序的异常终止是非常糟糕的。而坏处也很明显将庞大的返回信息的处理交给了后续的程序、也加重了工作量。

(2)代码组织与内部实现设计(类图)

  • 总体UML类图框架:
    结对_github_16
  • 实际上有一些组件可以实现python自动生成类图(当然这肯定不是让我们写完代码再画类图,这里也放出来展示下、以玩家类和game的交互为例子)
    结对_python_17

(3)算法的关键与关键实现部分流程图

  • AI算法的核心部分在于我们使用了一个矩阵来储存玩家的手牌状态
    结对_json_18

(4)重要的/有价值的代码片段

  • 在AI的开发过程中,注意到:当某一方玩家的牌数对比对手方少到一直翻牌也不会输时(即该玩家的牌数+1+放置区+(卡组区-1)*2<对手手牌-卡组区)、搜索结果并不能返回一直翻牌的决策、反而更容易输。人为加入特判后、测试了30局,21:9胜率远高于原本的版本:
def solusion(center_card,card_ai,card_people,ans):
#略去部分代码
lc_show = 'U' #中心排队的花色
la = len(card_ai) #AI的手牌
lp = len(card_people)#对手的手牌
lc = len(center_card)#放置区的手牌数
#具体特判
if la == 0 :
ans[0] = '0'
ans[1] = ''
return 0
elif la + 1 + (lo-1)*2 < lp - lo + 1 :
ans[0] = '0'
ans[1] = ''
return 0
else:
pass
#ans数组是反会的具体操作ans[0]='0'表示翻牌操作。


(5)性能分析与改进

  • 以本地的人人对战的性能分析为例子
  • Coverage(覆盖率):
    结对_python_19
  • Threading Graph(进程效率测试,整体运行状态平稳):
    结对_json_20
  • 性能分析:
    可以看到,大部分的调用还是集中在画面的渲染,毕竟一张图片的大小可以比肩上千万行代码。
    结对_原型设计_21

(6)具体的改进的思路

  • 具体来说还是有限优化画面渲染部分,详细阅读了pygame的文档后,引入了设置模块
# -*- coding: utf-8 -*-
# @Time : 2021/10/22 23:29
# @Author : Jimase
# @File : setting.py
from pygame import display
class Settings:
def __init__(self):
self.screen_width = 1800
self.screen_height = 900

display.set_caption("PiG TAiL--")
self.fps = 90 //多次测试,这是最适合我自己电脑的fps
self.hand_card_distance = 70


(7)性能分析图和程序中消耗最大的函数

  • cProfile是Python标准库中内置的性能分析模块,我们也选择了这个工具对本地和联网对战时候的游戏运行进程做了测试。
    结对_json_22
  • cProfile也能生成对应的可视化图,具体如下
    结对_原型设计_23

结对_性能分析_24结对_github_25结对_python_26

  • 进一步验证了,性能中占比最多的是画面渲染

从性能分析图来看,时间消耗最多的模块莫过于游戏的的渲染功能,这也是选用pygame的缺点,换取了编程的便利的同时也带来了更大的难以弥补的遗憾????????????????也诚挚地向我的队友道歉,擅长js的他向我做了妥协,导致他的工作陷入了窘迫的局面。

(8)部分单元测试代码,说明测试的函数,构造测试数据的思路

  • 为了编写单元测试,需要引入了Python自带的unittest模块,这里以网络接口部分的单元测试为例。测试接口的具体步骤:
  1. 获得接口的 URL。
  2. 向接口发送请求。
  3. 检查响应的 HTTP 状态码、返回的数据等是否符合预期。
# filename="./tests/test_api.py
import unittest
from datetime import datetime
from django.core.cache import cache
from ..utils import Highlighter, UpdatedAtKeyBit
class PostViewSetTestCase(APITestCase):
def test_list_post_create_game(self):
def test_list_post_join_game(self):
def test_list_post_getlast_game(self,token):
'''
:param token:
:param uuid:
:return:
'''
#这里以获取上步操作为例:本以为这个接口不会有太大的问题,因为很偶然的错误没能加入了一场已经人满的对局
#在测试过程中才发现,没有考虑到人没齐的时候,返回的报文不存在last_code字段,看了错误堆栈才明白问题所在。
url = 'http://172.17.173.97:9000/api/game/' + uuid + '/last'
header = {'Authorization': token, 'Content-Type': 'application/json'}
r = requests.get(url, headers=header)
user_dict = json.loads(r.text)
response = self.client.get(url, {"token": token, "uuid":uuid})
self.assertEqual(response.status_code, status.HTTP_200_OK)
#可能返回的有状态码"200"、"403"、"404"
serializer = PostListSerializer(instance=[self.post2, self.post1], many=True)
self.assertEqual(response.data["results"], serializer.data)
result = field.to_representation(document)
self.assertEqual(user_dict_result, expected)
return user_dict_result
def test_list_put_Do_card(self):
def test_list_get_result(self):
def test_list_get_list(self):


2、Github的代码签入记录

  • 这里向大家推荐一个蛮有意思的项目gitmoji,这看起来是一个很无厘头的项目,将表情包用于Github commmit 信息的签入。
  • 然而事实上,像在GitHub上优秀的许多项目一样、Github社区不但对于commit 提交信息有严格规范,对于commit。信息中的表情包也有一样严格的要求????????????????????????????太糟心了,明明deadline已经要到了,却又看到了这么萌的功能,实在是忍不住想去弄一下,花了好大的心思才让自己的gitBush可以直接看到可爱的表情包。
    结对_python_27
  • 我们使用了社区比较常见的Angular:
  • 部分签入记录如下:(包括bug修复在内一共五个分支,删除了两个)

branch:main
结对_python_28
branch:dev
结对_json_29

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

  • 这里写在最前面、向我的队友致歉、由于自己命名的的过程中使用了和方法一样的名字json。给他造成了很大的困扰。
  • 代码模块异常主要是前文提到的接口部分,没有考虑登录接受的所有可能的status。后来经过测试加以完善也就解决了。

4、队友评价

  • 队友对队长的评价
    队长是队里的主力,我主要是给他端茶倒水,擦汗扇风,找找bug,写写边角料的代码和文字工作。队长虽然能力强,但是作风武断,恃强凌弱,不顾及我的感受把我原本用js写的web端猪尾巴程序给否定掉了(毕竟正经人谁用pygame写这种程序啊)。但是毕竟他是巨佬,抱条大腿不容易,最后作业也绝大部分都做出来了,我也学到很多东西,只能心怀感恩了。
  • 值得学习的地方
    能力极强,效率极高,身体素质极强,熬夜肝代码太顶了。
  • 需要改进的地方
    乖乖的,这种游戏下次我们用js写吗,虽然python我也承认也强,但是ui组件太难写了。
    合作期间发生几次小分歧,不过都无伤大雅,更加增进了合作的默契性,领会到脾气平静平静再平静,至少应该做到说的比做的多。

-队长对队友的评价

  • 值得学习的地方:

对新事物的接受能力强,不像我,还是总想着接着用python做。
对我保持了极大的宽容,照顾了我的小情绪。现在看来我的决策几乎全都是错的、从用python做开始、一错再错。

  • 待改进的地方:

宽容度是一把双刃剑
deadline期间都蛮紧张的,不过这也正常。几乎所有认识的柯老师的学生我感觉这段时间情绪大家都不是很好。

5、此次结对作业的PSP和学习进度条(周更)

第N周

新增代码(行)

累计代码(行)

周学习耗时(小时)

累计学习耗时(小时)

重要成长与任务进展

1

506

506

15

15

学习了JS的初步知识、尝试修改自己的博客样式、测试了接口的通用性、学会了gitmoji、gitcommit规范

2

1006

1512

12

27

使用JS完成了基本的登陆界面、寻找了相关素材、对柯老师的感恩之情深入心府

3

200

1712

19

46

JS解决跨域问题纯前端方法太困难了、很痛苦地换了方案、开始学习python的pygame

4

1700

3412

10

66

pygame写完了最基本的人人对战,人机对战,基本的登陆逻辑、对柯老师课堂上的淳淳教导更加深有体会、后悔没有早点遇到这样的好老师

5

1000

4412

20

86

完成了通过手动输入uuid进行在线人人对战的代码、进行了部分网络测试

三、心得

队长(su)心得

1、戒骄戒躁

很多事情应该有大局观、过渡的焦虑和紧张并不能促进项目的进展。情绪波动过大,也感谢队友的极大包容和谅解。

2、规划不够明确

初期规划的时候选择了随大流的web端实现。我却因为因为一个小小的跨域问题未能解决焦虑不已,非常草率的换了python解决(python的requrest模块可以替我解决跨域问题),后来由于草率地换了python实现本项目,UI界面实现加入对局极度困难,而测试组的同学又从后,端替我们解决了跨题????????????进退两难之余没能稳定自己的情绪。我不是一个很好的牵头者。

3、缺乏和队友足够的沟通。

导致在项目开始阶段做了非常错误的决定,使用python的pygame来实现项目,到后面基本上只剩我自己完成在线对战(很遗憾没能实现一个很完美的加入对局功能,需要手动在命令行输入uuid和查询uuid),算是给自己的本部优秀的项目上留下了个瑕疵。也就是我的队友能供容纳我的小脾气,甚至做了两手准备,依然实现了web端的人人对战,确保我无后顾之忧

5、感谢妈妈

那段时间因为紧逼的DDL,母亲关心我的电话老是不接、负面情绪往她身上撒。母亲学历有限,也许只是抖音刷到一个《考研多重要》的视频,很多时候只是想和我聊一下考研规划,谈一下人生大事。我若不是逃避、就是一肚子苦水。????????????

队友(weng)心得

1、感谢互联网

这份作业学习到了很多知识,大多数知识来源途径来自于网络,查询了很多优秀的文档以及翻看了github上游戏编者的代码,受益非强,从刚才是的配置环境都会出错的菜鸟慢慢成长了,至少有所进步。

2、对这份作业的评价

这份作业难度适中,可能在ai算法那部分比较难吧,由于本人厌恶算法,队长临危受命承担算法部分,感恩戴德。这次作业也是我第一次接触到数据接口处理,python中的request模块雀食功能强大,模块齐全,不得不说,python,及时行乐。另外也接触了很多ui框架,原生js,pygame和pyqt,不必重新造轮子。

3、提高认知

好像自己也没有那么菜(虽然好像确实挺菜的)但是一些功能,多花点时间,找找资料,熬夜写一写代码,逼一逼自己似乎也能写出不错的功能。另外这份作业也改变了我的作息,以前都没熬过那么晚的夜,增强了我熬夜写代码的能力。提前为日后的996做铺垫。

4、吹捧队长(su)

代码写完了,肯定要夸队长啊(我实在太了解他了,他这个人就喜欢别人夸他),不夸队长下次不和我一起写代码。一个人写?这辈子都不可能一个写的,数学很差,代码能力又不强,就是靠抱队长大腿才能写得出代码这个样子的。和队长一些写代码感觉比自己一个人写好多啦,一个人写很无聊,和队长一起写灵感迸发,码力无限。另外队长人又聪明,说话又好听,我超喜欢和他一起写代码的。

队长队友互评

感谢不杀之恩。