结对编程作业

一、一些小要求

  • 如下

我的博客链接

我队友的博客链接

我们的github项目地址如下:雨文丶丶队伍的GitHub

具体分工:

原型设计 AI设计与实现 AI大比拼 Github相关 游戏主体 接口实现
队友

二、原型设计

2.1我们使用的原型设计工具:

Axure Rp 9

2.2设计说明:首先需要完成基础原型设计的要求:

(1)开始界面:

  • 在窗体中设计一个独特的开始按钮,并且使用经典的数字华容道的图片作为背景。

(2)游戏界面:

  • 在窗体左侧为基本信息以及一些附加功能,比如当前步数,目前为止最好成绩,还有内嵌的AI提示功能。

  • 窗体右侧就是游戏的主界面,会有一块被空白块剔除,需要识别出原先的字母,并且使用wasd控制白色方块完成复原。

  • 点击左下角的提示按钮就是AI内嵌的功能,按下时将会弹出接下来能够复原的步骤序列,指导你完成游戏

之后需要完成一些提高游戏体验的功能:

(3)额外功能:

  • 在完成一局游戏之后弹出是否继续的按钮,这样就可以选择继续冲击更少的步数或者退出游戏

  • 以防按错×按键退出游戏,在点击之后追加提问是否退出游戏

2.3结对照片:提供非摆拍的两人在讨论、细化和使用专用原型模型工具时的结对照片:

2.4 遇到的困难以及解决方法:

  • 困难描述:对产品经理这一类的原型设计一点都不了解,一度以为只是画出类似流程图之类的东西。

  • 解决尝试:后来在知道原型设计的实质以及其重要性之后,安装了Axure以及汉化,在B站上自学两天掌握了基础的原型设计能力,并且设计出了项目的原型图,成功解决了问题

  • 有何收获:对原型设计有了初步的认识,扭转了之前直接上手代码的习惯,在认真设计出原型之后再通过代码实现会让工作效率更高。

三、AI与原型设计实现

3.1、代码实现思路:

  • 网络接口的使用
def gethtml(url):
    r = requests.get(url)
    r.encoding = r.apparent_encoding
    html = r.text
    return html
def getProblemlist():
    #获取赛题列表
    url = "http://47.102.118.1:8089/api/challenge/list"
    text = json.loads(gethtml(url))
    for t in text:
        print(t)
def createProblem():
    #创建赛题
    url = "http://47.102.118.1:8089/api/challenge/create"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3941.4 Safari/537.36',
        'Content-Type': 'application/json'
    }
    data_json = json.dumps({
        "teamid": 35,
    "data": {
        "letter": "a",
        "exclude": 5,
        "challenge": [
            [0, 8, 4],
            [1, 9, 7],
            [2, 6, 3]
        ],
        "step": 19,
        "swap": [1,2]
    },
        "token":"56f315e5-051d-493c-ab96-dc7bb87ea443"
    })
    r = requests.post(url, headers=headers, data=data_json)
    print(r.text)
def getproblem():
    #挑战赛题
    url = "http://47.102.118.1:8089/api/challenge/start/cbc7a355-f385-4a4c-801c-da845f785336"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3941.4 Safari/537.36',
        'Content-Type': 'application/json'
    }
    data_json = json.dumps({
        "teamid": 35,
        "token": "56f315e5-051d-493c-ab96-dc7bb87ea443"
    })
    r = requests.post(url, headers=headers, data=data_json)
    text = json.loads(r.text)
    img_base64 = text["data"]["img"]
    step = text["data"]["step"]
    swap = text["data"]["swap"]
    uuid = text["uuid"]
    chance = text["chanceleft"]
    print("chance = "+str(chance))
    img = base64.b64decode(img_base64)
def postresult(uuid,totalpath,swap):
    #提交赛题答案
    url = "http://47.102.118.1:8089/api/challenge/submit"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3941.4 Safari/537.36',
        'Content-Type': 'application/json'
    }
    data_json = json.dumps({
    "uuid": uuid,
    "teamid": 35,
    "token": "56f315e5-051d-493c-ab96-dc7bb87ea443",
    "answer": {
        "operations": totalpath,
        "swap": swap
    }
    })
    r = requests.post(url, headers=headers, data=data_json)
    print(r.text)
  • 代码组织与内部实现设计

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

  • 贴出你认为重要的/有价值的代码片段,并解释
    使用堆来存储结点,每次将启发函数最小的结点取出,获取其子结点,加入堆中,直到最终从堆中取出的点为目的结点

def AStar(start, end, distance_fn, generate_child_fn, swap, step, ischange):
    '''
    A*算法
    start: 起始状态
    end: 终止状态
    distance_fn: 距离函数
    generate_child_fn: 产生孩子节点的函数
    '''

    root = State(0, 0, start, hash(str(BLOCK)), None)  # 根节点
    end_state = State(0, 0, end, hash(str(GOAL)), None)  # 终止节点
    if root == end_state:
        return 0,[],''

    openlist.append(root)
    heapq.heapify(openlist) #将列表转换为堆
    node_hash_set = set()  # 存储节点的哈希值
    node_hash_set.add(root.hash_value)

    while len(openlist) != 0:
        # 删除并返回最小值结点
        top = heapq.heappop(openlist)

        # 如果获取节点为最后的节点,表示算法结束,获取输出路径
        # 同时将强制交换的步数传入print_path函数,用来获取自选交换的序列
        if top == end_state:
            return print_path(top, step)

        # 产生孩子节点,孩子节点加入openlist
        # 当进行到一定步数时进行强制交换,如果之前已经强制交换过,就不进行操作
        if top.gn == step and ischange == 0:
            top.state = exchange(swap, top.state)
            # 强制交换结束之后,判断当前是否有解,如果无解就进行自选交换
            status = getStatus(top.state)
            if status % 2 != 0:
                top.state, selfswap = selfchange(top.state, end)
                #将自选交换序列加入到当前结点的属性中
                top.setchange(selfswap)
        #生成当前结点的子结点并加入堆中
        generate_child_fn(cur=top, end=end_state, hash_set=node_hash_set,
                          openlist=openlist, distance=distance_fn)
def generate_child(cur, end, hash_set, openlist, distance):
    '''
    生成子结点函数
    cur:  当前节点
    end:  最终状态节点
    hash_set:  哈希表,用于判重
    distance: 距离函数
    '''
    if cur == end:
        # 往堆中加入一个新的值
        heapq.heappush(openlist, end)
        return
    num = len(cur.state)
    for i in range(0, num):
        for j in range(0, num):
            if cur.state[i][j] != 0:
                continue
            for d in direction:  # 四个偏移方向
                if d[0] == 0 and d[1] == 1:
                    dir = 'd'
                if d[0] == 0 and d[1] == -1:
                    dir = 'a'
                if d[0] == 1 and d[1] == 0:
                    dir = 's'
                if d[0] == -1 and d[1] == 0:
                    dir = 'w'
                x = i + d[0]
                y = j + d[1]
                if x < 0 or x >= num or y < 0 or y >= num:  # 越界了
                    continue

                state = copy.deepcopy(cur.state)  # 复制父节点的状态
                state[i][j], state[x][y] = state[x][y], state[i][j]  # 交换位置
                h = hash(str(state))  # 哈希时要先转换成字符串
                if h in hash_set:  # 结点重复了
                    continue
                hash_set.add(h)  # 加入哈希表
                gn = cur.gn + 1  # 已经走的距离
                hn = distance(cur.state, end.state)  # 启发的距离函数
                node = State(gn, hn, state, h, cur, dir)  # 新建节点
                cur.child.append(node)  # 加入到孩子队列
                heapq.heappush(openlist, node)  # 加入到堆中
  • 性能分析与改进
    刚开始的时候当初始结点无解的时,选择在强制交换前进行随机交换,但是对于最后的结果影响很大,随机性很大。后面改为采用广域搜索,获得所有可能的结果,然后根据启发式函数选择最优的一种情况,再进行后面的A*算法的计算。

  • 描述你改进的思路
    取消随机交换造成的不确定性,使用耗时高但是结果精度高的广搜去解决初始结点无解的情况。同时将自由交换也改成启发式函数最优的情况作为最终结果。

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


  • 展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路
    使用测试接口对代码进行测试

def getproblem():
    #接口测试获取题目
    url = "http://47.102.118.1:8089/api/challenge/start/4f198e1d-a7aa-4851-bfac-644597afb8fa"
    text = json.loads(gethtml(url))
    # print(text.keys())#dict_keys(['img', 'step', 'swap', 'uuid'])
    # text["img"] = "none" #{'img': 'none', 'step': 0, 'swap': [7, 7], 'uuid': '3bc827e5008d460b893e5cb28769e6bf'}
    img_base64 = text["img"]
    step = text["step"]
    swap = text["swap"]
    uuid = text["uuid"]
    img = base64.b64decode(img_base64)
    # 获取接口的图片并写入本地
    with open("E:/python/软工实践/结对编程/photo.jpg", "wb") as fp:
        fp.write(img)  # 900*900
    return step,swap,uuid
def postAnswer(uuid, opertions, swap):
    #接口测试提交
    url = "http://47.102.118.1:8089/api/answer"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3941.4 Safari/537.36',
        'Content-Type': 'application/json'
    }
    data_json = json.dumps({
        "uuid": uuid,
        "answer": {
            "operations": opertions,
            "swap": swap}
    })
    r = requests.post(url, headers=headers, data=data_json)
    print(r.text)

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


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

  • 问题描述
    对初始结点无解的情况,不能很好的运行代码。
  • 解决尝试
    使用随机变换到强制交换为止,再等强制交换之后进行自由交换。但是效果很差,后面改为使用广搜并选择最优情况。
  • 是否解决
    解决了初始无解的情况。
  • 有何收获
    对代码整体的结构有了进一步的理解,同时对整体的逻辑思路更加清晰。

3.4、评价你的队友。

  • 值得学习的地方
    学习效率高,做事认真、耐心。
  • 需要改进的地方
    没啥需要改进的了。

3.5、提供此次结对作业的PSP和学习进度条。

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
第一周 125 125 6 6 学习了如何将图片切割,并且将乱序的图片转成数字矩阵
第二周 230 355 8 16 学习了A*算法,复习了队列,堆,哈希表的使用
第三周 235 590 10 26 解决了初始矩阵无解的情况,加入了强制交换和自由交换的功能
第四周 60 650 2 28 将各种接口的代码实现出来
PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 600 600
· Estimate · 估计这个任务需要多少时间 600 600
Development 开发 1130 1170
· Analysis · 需求分析 (包括学习新技术) 540 540
· Design Spec · 生成设计文档 30 30
· Design Review · 设计复审 30 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 30
· Design · 具体设计 60 60
· Coding · 具体编码 300 300
· Code Review · 代码复审 30 60
· Test · 测试(自我测试,修改代码,提交修改) 120 120
Reporting 报告 120 120
· Test Repor · 测试报告 60 60
· Size Measurement · 计算工作量 30 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 30
· 合计 1850 1890

四、Github使用相关演示:

再次贴出github的链接:雨文丶丶队伍的GitHub

4.1、README

对自己这个项目的简单介绍

4.2、.gitignore

配置不被允许push的文件后缀,在创建新文件之后可以git会帮助你根据语言和项目选择配置,我选择的是python

4.3、开源协议

4.4、持续集成

需要使用额外的插件Travis CI

4.5、Issues模板

设置了一个BUG模板

posted @ 2020-10-19 22:04  苏镜泽  阅读(84)  评论(0编辑  收藏  举报