结对编程作业

开头

原型设计

1.设计说明

  • 功能设计:本次原型设计预期的基本功能有图块移动、计时计步数、更换图形查看目标图形等交互模块、排行榜以及个人成绩等。

  • 原型实现第一次进入图片资源加载可能会很慢

  • 原型设计图主要页面


  • 设计流程图:

  • 样式设计理念:考虑到原型的主要内容是华容道,是具有丰富历史内涵与文化底蕴的主题,所以本次原型设计的风格搭配采用的是以古风为主的简约设计。原型中的主要交互文字使用的是篆书,再联系到给的图片素材是以黑色为主要基调的图块,所以背景图打算用灰白搭配的山水网图,让原型整体戴上缕缕墨色。

2.原型工具

  • 本次项目使用的原型设计工具是Axure Rp。
  • AxureRP 是一个快速原型制作软件,由美国Axure Software Solutions, Inc.公司开发。Axure RP 能让操作它的人快速准确的创建基于Web的网站流程图、原型页面、交互体验设计、标注详细开发说明,并导出Html原型或规格的Word开发文档。
  • 本次原型设计使用版本是8企业版。使用的交互素材是Axure素材库里的移动端开发素材库。

3.结对的过程

  • 结对过程描述:出作业时刚好坐在一起,一拍即合。虽然两个都是后端开发,但考虑到对方都是有着开发经验的“老咸鱼”,所以结对的也挺顺利的。
  • 结对照片:

4.遇到的困难及解决方法

困难描述 解决尝试 是否解决
1.图块移动问题。起初的图块移动过于敏感,常常随便一移就导致图块乱窜,严重的可能导致多相同图块的bug 改变了图块变化的思路,有原先的拖动移动变化变成点击白块周围的图块进而交换
2.小程序登录认证问题。登录时长丢失后端给的token,导致提交记录失败。 先是后端解决了证书的问题(无证书无法正常请求接口),后来小程序端也对登录模块进行了修改
3.样式显示缺失问题。初涉前端,很多样式会莫名其妙不显示。 查阅了很多css、js以及小程序相关博客
4.上线问题。因为本次原型实现采用的是小程序,小程序的上线存在着诸多问题。 查官方文档,查博客,问客服
5.审美问题。老直男了,界面设计一直感觉不是很满意,-_-|| 看其他优秀设计 ×

AI与原型设计实现

代码实现思路

网络接口的使用

  • 网络接口用的都是python的requests库

代码组织

  • 算法框架(算法详细在后面)

tim503b268bf8b2d840.png

  • 微信小程序后台

后台使用的是django框架。整个类的使用都是依据django而来的,唯二值得提的是

1.首先是token的构造,由于没找到类似的库,我是参考JWT构造的token,

def generate_token(no, key="key", expire=1000000):
    ts_str = str(time.time() + expire)
    ts_byte = ts_str.encode("utf-8")
    sha1_result = hmac.new((key + str(no)).encode("utf-8"), ts_byte, 'sha1').hexdigest()
    token = str(no) + ':' + ts_str + ':' + sha1_result
    b64_token = base64.b64encode(token.encode("utf-8"))
    return b64_token.decode("utf-8")


def certify_token(token, key="key"):
    if token is None:
        raise TokenError("没有token")
    try:
        token_str = base64.b64decode(token)
        token_list = token_str.decode('utf-8').split(':')
    except Exception:
        raise TokenError("token解析错误")
    if len(token_list) != 3:
        raise TokenError("token格式错误")
    ts_str = token_list[1]
    if float(ts_str) < time.time():
        # token expired
        raise TokenError("token过期")
    known_sha1 = token_list[2]
    sha1 = hmac.new((key + token_list[0]).encode("utf-8"), ts_str.encode('utf-8'), 'sha1')
    sha_ans = sha1.hexdigest()
    if sha_ans != known_sha1:
        # token certification failed
        raise TokenError("token错误")
        # token certification success
    return str(token_list[0])

然后在view中对需要请求进行token验证与创建

  1. 异常处理

一个正常的后台必须要对错误的请求返回正确的错误码。错误时,django似乎本身会返回html页面。而我在了解中间件(middleware)后,使用中间件构造了异常处理模块。

class ExceptionMiddleware(MiddlewareMixin):

    def __init__(self, get_response=None):
        super(ExceptionMiddleware, self).__init__(get_response)

    @staticmethod
    def process_exception(request, exception):

        if isinstance(exception, TokenError):
            return JsonResponse({"result": 401, "msg": exception.value})

        if isinstance(exception, NoResultError):
            return JsonResponse({"result": 404, "msg": exception.value})

        print("========================================================================")
        print('traceback.format_exc():\n%s' % traceback.format_exc())

        return JsonResponse({"result": 500, "msg": "error"})

数字华容道算法/算法的关键

基本思想是bfs,由于强制交换的存在,我们需要考虑两轮bfs,分别为

  • 在强制交换前进行bfs
  • 在强制交换前无解启用强制交换后进行bfs

然而还有存在两个问题:

  1. 在强制交换时华容道有哪几种情况?

首先由于bfs的特性(每一次都是此时最远的一步),强制交换时有的情况一定在之前的bfs中出现过。

然后在交换前偶数次都可以通过左右横跳(ad)来达到强制交换时存在。

而由于华容道的特点——他每一步都需要移动而且是上下左右选一。所以如果奇数步白块是在(1,3,5,7,9)中的一个。而偶数步白块是一定是在(2,4,6,8)中的一个。所以交换前奇数步是不可能在交换前出现。

所以我们只需要把所有交换前偶数次步数的华容道状态存起来。在强制交换时把这些珍藏的状态那来交换作为第二次bfs的初始状态。

  1. 如何确定强制交换后有解

这个判定方法是判断逆序对的数量(不把空白块计入)是否为偶数个。

在排序好的华容道上,逆序对是0;

而空白块的移动有四种情况,wasd,在ad——左右变化的时候,华容道的逆序对不会变

当进行w或s时

原来第一列 原来第二列 原来第三列 移动 移后第一列 移后第二列 移后第三列
a b c ----------------------------> a c
d f ----------------------------> d b f
g h i ----------------------------> g h i

原来的逆序对数为 m + (b,c)+ (b,d)

移后的逆序对数为 m + (c,d)+ (c,b)

其中m为前后无变化的逆序对信息

以此变化量为 delta(逆序对) = (b,c)+ (b,d) - (c,d)- (c,b)

因为(b,c)与(c,b)只有一个会同时是逆序对,(b,d)与(d,b)也只有一个会同时是逆序对,所以delta(逆序对)为 -2,0,2。因此我们只需要确定是偶数个逆序对有解。

性能分析与改进

我一开始是用python写算法,然而python展现的效率。。。

所以我对python算法进行了改进:

最早是__Hash__函数,因为已出现的状态存在于字典,而华容道的特点使我们可以构造一种__Hash__算法即

    def __hash__(self):
        t = 0
        for i in range(3):
            for j in range(3):
                t = t*10 + self.square[i][j]
        return t

但优化后时间仍在30s左右

pythonProject.png

接着取消复制类(deepcopy),改为创建新的对象

pythonProject.png
pythonProject1_1.png

结果只能达到10s左右,因此,我更改语言,使用c++(果然写算法用C++才是最舒服),最后能达0.8s的水平。

接着优化在于我用来存储曾经出现的华容道状态的数组,(因为我开辟了一个1000000000的bool数组)在强制交换后马上需要将其清零。这里占了极大的时间。我先将数组改下十倍(华容道九宫格九个数字只要出现8个就能推出最后一个所以用更小的数组),然后又开辟一个新的数组用于记录华容道交换后的状态。这样一来时间能在单独算法的时间能0.4秒以下。

关于图像处理,我一开始使用的是PIL的ImageChops.difference,我尝试过将给的base64进行Hash,本想到时候可进行查表直接返回对应的华容道状态。然而我直接拼接的华容道图片终是与接口返回的有差别。用PIL的ImageChops.difference是可判别,但是在文件大小等方面却不一样,导致hash不出相同的值。结果优化一直失败。

单元测试

链接

上面是我写的脚本,作用是用于自动对测试组提供的问题接口来请求,求解,返回,并将结果存取下来。

用他来判别算法是否正确

Github的代码签入记录

算法

QQ20201019084211.png

小程序

QQ20201016194637.png

困难及解决方法

  • 算法在最开始我遗漏了,交换前有哪些状态这个问题,不过最后还是改回来了

  • django的orm是一个感觉奇怪的玩意。他一定义外键就会变成拉入一个类进来。导致在返回排行榜的时候,会自己返回一个用户。而解决方法,我是靠修改序列化的方法,将返回一个用户改为返回他的头像与名字

  • 另外一个问题是微信小程序需要的https证书与域名,这个https证书依靠阿里云的免费ssl,域名5元一年,真正的问题在于网站备案,由于办事效率的不确定,我最后借用了别人的域名

评价你的队友

  • 值得学习的地方

    他提供了非常优秀前端界面,对我们的作业提供了许多优秀的建议

  • 需要改进的地方

    还需要加强审美

结对作业的PSP和学习进度条

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
1 278 278 12 12 学习了python的PIL,能够对比头像,并实现了算法一部分
2 385-142 421 13 25 将算法改为c++,算法完全实现 ,学习了django的orm集
3 272 693 10 35 后台功能加强,实现token,一对一实现,算法修正,测试脚本实现
4 182 876 8 43 实现Ai大比拼脚本,进行算法优化
PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 7 6
· Estimate · 估计这个任务需要多少时间 7 6
Development 开发 2000 2239
· Analysis · 需求分析 (包括学习新技术) 450 672
· Design Spec · 生成设计文档 40 68
· Design Review · 设计复审 40 62
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 0 0
· Design · 具体设计 20 12
· Coding · 具体编码 1000 815
· Code Review · 代码复审 20 58
· Test · 测试(自我测试,修改代码,提交修改) 430 552
Reporting 报告 190 317
· Test Repor · 测试报告 90 235
· Size Measurement · 计算工作量 40 48
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60 34
合计 2197 2562
posted @ 2020-10-19 09:40  sdasdxgdxc  阅读(165)  评论(0编辑  收藏  举报