zoukankan      html  css  js  c++  java
  • 结对编程作业

    自己的博客链接 我的
    队友的博客链接 队友
    GitHub GitHub
    分工 031802103陈嘉龙:AI算法实现
    031802107陈子杰:原型设计与实现

    一、原型设计

    1.1原型的说明

    • 我们的原型包括三个部分,第一个 部分是游戏的主页登录界面,第二个界面是对华容道难度的选择,第三个页面就是华容道的游戏界面。我们采用墨刀这款原型设计软件。

      6

      • 游戏的主页面(因为华容道来源于三国,所以采用了水墨古风的设计)

      1

      • 选择难度的页面(不同的难度对应的格子数不同)

      2

      • 游戏的界面

      3

    1.2原型的实现

    • 实现的原型拥有的功能

      • 随机生成棋盘可以提供用户游玩

      • 提供了玩游戏时的背景音乐(四首),并且支持切歌的功能

      • 可以重新开始游戏

      • 在完成对图像的复原后有提示成功复原窗口

      • 可以查看历史成绩,并且历史成绩有排名(弹窗的形式出现)

      • 退出按钮

      • 左下角显示原来的图片

      • 无解时弹窗提醒

    • 原型实现的截图(换了张前女友的图)

      4

    • 原型里的代码示例

      def win():  #最终判断是不是成功还原了图形,通过对坐标轴的判断实现。
          for i in range(ROWS):
              for j in range(COLS):
                if board[i][j] is not None and board[i][j].center!=[150+300*j,150+i*300]:
                      return False
          return True
          
      def no_have():   #判断是不是无解
          anss=0
          for i in range(ROWS):
              for j in range(COLS):
                 if board[i][j] is not None and board[i][j].center==[150+300*j,150+i*300]:
                      anss=anss+1
          print(anss)
          if anss==6  and board[2][0].center==[450,750] and board[2][1].center==[150,750]:
                       return True
              
      def txtsort():      #把保存有步数的txt文件里的步数放到列表进行排序
          file = open("old.txt", "r")
          ar = []
          arr = []
          count = 1
          flag = 0
          for line in file:
              if '
      ' in line and flag == 0:
                  flag = 1
                  continue
              if '
      ' in line:
                  idx = line.index('
      ')
              else:
                  continue
              temp = int(line[:idx])
              ar.append(temp)
          for i in ar:
              if i not in arr:
                  arr.append(i)
          arr.sort()
          file = open("shuchu.txt", 'a') #在列表里完成排序之后输出到txt里
          for i in range(len(arr)):
              s = str(arr[i]).replace('[', '').replace(']', '')  # 去除[],这两行按数据不同,可以选择
              s = 'NO.' + str(count) + ':' + s.replace("'", '').replace(',', '') + '
      '  # 去除单引号,逗号,每行末尾追加换行符
              file.write(s)
              count = count + 1
          file.close()
          print("保存文件成功")
         
      def history_score():   #从已经对步数排名的txt里输出有排名的历史记录
          txtsort()
          window = Tk()
          window.title("成绩排名")
          window.geometry("600x600")
          sda = scrolledtext.ScrolledText(window, width=38, height=20, font=("宋体",20))
          sda.place(x=30, y=30)
          f = open("shuchu.txt", "r")
          s = f.read()
          sda.insert(END, s)
          with open("shuchu.txt", 'r+') as file:
               file.truncate(0)
          window.mainloop()
          
      def mouse_click(pos):   #鼠标每次点击后方块的移动
          """鼠标点击事件"""
          global steps
          # r为行数,c为列数
          r = int(pos[1] // image_size)
          c = int(pos[0] // image_size)
      
          if r < 3 and c < 3:
              # 点击到空白位置
              if board[r][c] is None:
                  return
              else:
                  # 依次检查当前图像位置的上下左右是否有空位置
                  current_square = board[r][c]
                  # 判断上面
                  if r - 1 >= 0 and board[r - 1][c] is None:
                      board[r][c] = None
                      board[r - 1][c] = current_square
                      #print(board[r-1][c].center)
                      steps += 1
                  # 判断下面
                  elif r + 1 <= 2 and board[r + 1][c] is None:
                      board[r][c] = None
                      board[r + 1][c] = current_square
                      #print(board[r+1][c].center)
                      steps += 1
                  # 判断在左边
                  elif c - 1 >= 0 and board[r][c - 1] is None:
                      board[r][c] = None
                      board[r][c - 1] = current_square
                      steps += 1
                  # 判断在右边
                  elif c + 1 <= 2 and board[r][c + 1] is None:
                      board[r][c] = None
                      board[r][c + 1] = current_square
                      #print(board[r][c+1].center)
                      steps += 1
                  if win():    #如果此时已经还原了图像
                      easygui.msgbox("成功还原","华容道","OK")
                      with open("old.txt", "a") as f:     #把数字的内容存入oldTXT中,之后对old里的数据进行排序
                          shuchu=str(steps)
                          f.write(shuchu)
                          f.write('
      ')
                  elif no_have():     #无解的情况
                       easygui.msgbox("恭喜你把坏运气用掉了!","华容道","好运来")
      

    1.3我们的讨论“摆拍图“(狗头)

    5

    1.4原型设计中遇到的困难解决方法以及收获

    •  刚开始甚至连原型叫什么**都不知道**,更别谈要用什么软件来设计了。在查阅了相关资料和询问有经验的同学后,我们对原型设计有了个初步的了解并且决定采用**“墨刀”**来原型设计(居然导出html要**氪金**)。刚开始设计的时候设计的原型真是一言难尽,充斥着满屏的土味,并且设计软件的相关操作都不是很熟悉。在不断的商量和学习后,才有了**最终的**设计结果。
      
    •  原型中**较为难的功能**是判断是不是成功还原、查看已经排序的历史成绩、无解的处理方法、鼠标操控图像。该过程中我们学习了**pygame**的相关知识、**easygui**的相关功能**simpleguitk**的相关功能、python对**txt文件**里字符串处理的操作。但是较为**遗憾**的是无法实现游戏直接生成有解华容道的功能,**解决的想法**是读入已经有解的情况再对图像进行上下左右打乱,无奈读取图片的方法不符难以实现,只能实现无解时输出“鼓励”的提示。
      
    •  这是我们打代码来第一次实现可视化界面,虽然从**清洁工**到造出“火箭”(勉勉强强算是个小火箭把)的过程磕磕碰碰充满坎坷,但是**学到的**东西是真实存在的,无比真实的感受到自己是个学**计算机**的人。
      

    二、AI与原型设计实现

    1、代码实现思路:

    (1)网络接口的使用

    import requests
    import json
    
    #start接口:开始获取题目信息
    
    def data(challengeUuid):
        url = 'http://47.102.118.1:8089/api/challenge/start/'+ challengeUuid
        id = 39
        token = "038bcb76-b65c-4641-9c7e-89a3c1b66a41"
        dit = {"teamid": id, "token": token}
        result = requests.post(url=url, json=dit).text
        result1 = json.loads(result)
        return result1
    
    
    #submit接口:提交答案
            msg = {"uuid": uuid, "teamid": id, "token": token, "answer": {"operations": ans_str, "swap": mySwap}}
            result = requests.post(url=url, json=msg)
            result1 = json.loads(result.text)
            print(result.text)
    
    import requests
    import json
    
    #problem接口:获取还未通过的题目
    
    def getUuid():
        url = "http://47.102.118.1:8089/api/team/problem/39"
        result = requests.get(url)
        data = result.json()
        return data
    
    import requests
    import json
    
    #rank接口:获取排行
    
    def getRank():
        url = "http://47.102.118.1:8089/api/rank"
        data = requests.get(url)
        result = data.json()
        print(result)
    
    import requests
    import json
    
    #创建赛题
    
    url = 'http://47.102.118.1:8089/api/challenge/create'
    id = 39
    letter = 'v'
    token = "038bcb76-b65c-4641-9c7e-89a3c1b66a41"
    dit = {"teamid": id,
           "data": {
               "letter": letter,
               "exclude": 5,
               "challenge": [
                   [1, 3, 2],
                   [9, 7, 0],
                   [8, 6, 4]
               ],
                "step": 4,
               "swap": [1,5],
           },
           "token": token
           }
    result = requests.post(url=url, json=dit)
    print(result.text)
    
    

    (2)主要代码实现

    #每个位置可交换的位置集合
    g_dict_shifts = {0:[1, 3], 1:[0, 2, 4], 2:[1, 5],
                     3:[0,4,6], 4:[1,3,5,7], 5:[2,4,8],
                     6:[3,7],  7:[4,6,8], 8:[5,7]}
    
    def swap_chr(a, i, j):
        if i > j:
            i, j = j, i
        if i == j:
            return a
        #得到ij交换后的数组
        b = a[:i] + a[j] + a[i+1:j] + a[i] + a[j+1:]
        return b
    
    def isSolve(srcLayout, destLayout):
        # 先进行判断srcLayout和destLayout逆序值是否同是奇数或偶数
        # 这是判断起始状态是否能够到达目标状态,同奇同偶时才是可达
        src = 0;
        dest = 0
        for i in range(1, 9):
            fist = 0
            for j in range(0, i):
                if srcLayout[j] > srcLayout[i] and srcLayout[i] != '0':  # 0是false,'0'才是数字
                    fist = fist + 1
            src = src + fist
    
        for i in range(1, 9):
            fist = 0
            for j in range(0, i):
                if destLayout[j] > destLayout[i] and destLayout[i] != '0':
                    fist = fist + 1
            dest = dest + fist
        if (src % 2) != (dest % 2):  # 一个奇数一个偶数,不可达
            return -1
    
    
    def sovleMethod(srcLayout, destLayout):		#初始状态、目标状态
        # 初始化字典
        g_dict_layouts = {}
        g_dict_layouts[srcLayout] = -1
        stack_layouts = []
        stack_layouts.append(srcLayout)  # 当前状态存入列表
        bFound = False
        while len(stack_layouts) > 0:
            # 广度搜索
            curLayout = stack_layouts.pop(0)  # 出队
            if curLayout == destLayout:  # 判断当前状态是否为目标状态
                break
    
            # 寻找0 的位置。
            ind_slide = curLayout.index("0")
            lst_shifts = g_dict_shifts[ind_slide]  # 当前可进行交换的位置集合
    
            for nShift in lst_shifts:
                newLayout = swap_chr(curLayout, nShift, ind_slide)
                if g_dict_layouts.get(newLayout) == None:  # 判断交换后的状态是否已经查询过
                    g_dict_layouts[newLayout] = curLayout
                    stack_layouts.append(newLayout)  # 存入集合
    
        lst_steps = []
        lst_steps.append(curLayout)
        while g_dict_layouts[curLayout] != -1:  # 存入路径
            curLayout = g_dict_layouts[curLayout]
            lst_steps.append(curLayout)
        lst_steps.reverse()
        return lst_steps
    
    def solvePuzzle_depth(srcLayout, destLayout):
        if isSolve(srcLayout, destLayout) == -1:
            return 1,sovleMethod(srcLayout, destLayout)
        else:
            return 0,sovleMethod(srcLayout, destLayout)
    
    def getAnswer(srcLayout, destLayout, step, swap):
        mark = 0
        mySwap = [0, 0]
        mySwap[0] = swap[0]
        mySwap[1] = swap[1]
        isChange, lst_steps = solvePuzzle_depth(srcLayout, destLayout)
        ans_str = ''  # 操作序列
        if len(lst_steps) > step + 1:
            rList = []
            rList.append(lst_steps[step])
    
        if (len(lst_steps) > step + 1 and isChange == 1):	#初始状态无解
            mark = 1
            lst_steps[step] = swap_chr(lst_steps[step], swap[0] - 1, swap[1] - 1)  # 进行强制交换
            BchangeStr = lst_steps[step]
            '''
            print("调换前:" + rList[0])
            print("调换后:" + lst_steps[step - 1])
            '''
            flagChange = isSolve(lst_steps[step], destLayout)
            if flagChange == -1:	#强制交换后仍然无解,需要再次交换
                i = lst_steps[step].index('0') + 1
                if i == 9:			#0所在位置为边界:‘1’或‘9’
                    mySwap[0] = 8
                    mySwap[1] = 6
                elif i == 1:
                    mySwap[0] = 2
                    mySwap[1] = 4
                else:
                    mySwap[0] = i + 1
                    mySwap[1] = i - 1
                lst_steps[step] = swap_chr(lst_steps[step], mySwap[0] - 1, mySwap[1] - 1)
                BchangeStr = lst_steps[step]
            else:		#强制交换后有解,不需再次交换
                mySwap = []
    
            isChange1, lst_steps1 = solvePuzzle_depth(lst_steps[step], destLayout)
            lst_steps = lst_steps[:step] + rList + lst_steps1[1:]		#序列拼接
        elif (len(lst_steps) > step and isChange == 0):		#初始状态有解
            if swap[0] == swap[1]:			#两个交换位置一样
                mySwap = []
            elif lst_steps[step][swap[0] - 1] == '0' or lst_steps[step][swap[1] - 1] == '0':#交换位置数字含有‘0’
                if abs(swap[0] - swap[1]) % 2 == 1:		#若相减的绝对值为奇数,仍有解
                    lst_steps[step] = swap_chr(lst_steps[step], swap[0] - 1, swap[1] - 1)
                    BchangeStr = lst_steps[step]
                    lst_steps1 = sovleMethod(lst_steps[step - 1], destLayout)
                    lst_steps = lst_steps[:step] + rList + lst_steps1[1:]	#序列拼接
                    mySwap = []
                    mark = 1
                else:		#若相减的绝对值为偶数,无解,需要再次交换,交换序列 = 强制交换的序列
                    mySwap[0] = swap[0]
                    mySwap[1] = swap[1]
    
        length = len(lst_steps) - 1
        #获得操作序列
        for i in range(length):
            if mark == 1 and i == step:
                if lst_steps[i + 1].index('0') - BchangeStr.index('0') == -3:
                    ans_str = ans_str + 'w'
                elif lst_steps[i + 1].index('0') - BchangeStr.index('0') == 3:
                    ans_str = ans_str + 's'
                elif lst_steps[i + 1].index('0') - BchangeStr.index('0') == -1:
                    ans_str = ans_str + 'a'
                elif lst_steps[i + 1].index('0') - BchangeStr.index('0') == 1:
                    ans_str = ans_str + 'd'
            elif lst_steps[i + 1].index('0') - lst_steps[i].index('0') == -3:
                ans_str = ans_str + 'w'
            elif lst_steps[i + 1].index('0') - lst_steps[i].index('0') == 3:
                ans_str = ans_str + 's'
            elif lst_steps[i + 1].index('0') - lst_steps[i].index('0') == -1:
                ans_str = ans_str + 'a'
            elif lst_steps[i + 1].index('0') - lst_steps[i].index('0') == 1:
                ans_str = ans_str + 'd'
        return  ans_str, mySwap, lst_steps
    
    • 主要思路是先运用广度优先搜索,在不进行交换的情况下,获取最少步数的移动路径以及记录每一步移动后的序列;接着,在指定的步数序列下,进行强制交换操作,对交换后的序列进行判断是否有解,得出mySwap的值,然后根据mySwap的值对此序列进行再一次操作,接着将此序列作为初始状态,进行广度优先搜索,得到的操作序列与初始状态的操作序列进行拼接,得到最终的操作序列。

    (3)性能分析图

    分析

    消耗最大的函数:

    函数

    (4)单元测试

    import solves
    import unittest
    
    class TestFuctions(unittest.TestCase):
    
        @classmethod
        def setUp(self):
            print("开始测试:")
        @classmethod
        def tearDown(self):
            print("测试结束")
    
        def test_1(self):
            print("初始状态有解,强制交换后仍有解:")
            srcLayout  = "108462935"        #初始状态
            destLayout = "123456089"        #目标状态
            step = 1
            swap = [1,1]
            ans_str, mySwap, lst_steps = solves.getAnswer(srcLayout, destLayout, step, swap)
            print("初始状态:")
            print(srcLayout)
            print("强制交换:")
            print(swap)
            print("我的交换:")
            print(mySwap)
            print("操作序列:%s"%ans_str)
            for nIndex in range(len(lst_steps)):
                print("step #" + str(nIndex))
                print(lst_steps[nIndex][:3])
                print(lst_steps[nIndex][3:6])
                print(lst_steps[nIndex][6:])
            print('移动步数:%d' % len(lst_steps))
        def test_2(self):
            print("初始状态有解,强制交换后无解:")
            srcLayout  = "108462935"        #初始状态
            destLayout = "123456089"        #目标状态
            step = 1
            swap = [1,2]
            ans_str, mySwap, lst_steps = solves.getAnswer(srcLayout, destLayout, step, swap)
            print("初始状态:")
            print(srcLayout)
            print("强制交换:")
            print(swap)
            print("我的交换:")
            print(mySwap)
            print("操作序列:%s"%ans_str)
            for nIndex in range(len(lst_steps)):
                print("step #" + str(nIndex))
                print(lst_steps[nIndex][:3])
                print(lst_steps[nIndex][3:6])
                print(lst_steps[nIndex][6:])
            print('移动步数:%d' % len(lst_steps))
    
    
        def test_3(self):
            print("初始状态无解,强制交换后有解:")
            srcLayout = "801462935"  # 初始状态
            destLayout = "123456089"  # 目标状态
            step = 1
            swap = [1, 3]
            ans_str, mySwap, lst_steps = solves.getAnswer(srcLayout, destLayout, step, swap)
            print("初始状态:")
            print(srcLayout)
            print("强制交换:")
            print(swap)
            print("我的交换:")
            print(mySwap)
            print("操作序列:%s" % ans_str)
            for nIndex in range(len(lst_steps)):
                print("step #" + str(nIndex))
                print(lst_steps[nIndex][:3])
                print(lst_steps[nIndex][3:6])
                print(lst_steps[nIndex][6:])
            print('移动步数:%d' % len(lst_steps))
    
    
        def test_4(self):
            print("初始状态无解,强制交换后仍无解:")
            srcLayout = "108462935"  # 初始状态
            destLayout = "123456089"  # 目标状态
            step = 1
            swap = [1, 2]
            ans_str, mySwap, lst_steps = solves.getAnswer(srcLayout, destLayout, step, swap)
            print("初始状态:")
            print(srcLayout)
            print("强制交换:")
            print(swap)
            print("我的交换:")
            print(mySwap)
            print("操作序列:%s" % ans_str)
            for nIndex in range(len(lst_steps)):
                print("step #" + str(nIndex))
                print(lst_steps[nIndex][:3])
                print(lst_steps[nIndex][3:6])
                print(lst_steps[nIndex][6:])
            print('移动步数:%d' % len(lst_steps))
    
    if __name__ == "__main__":
        unittest.main()
    
    • 编写了4个测试样例,分别是:初始状态有解,强制交换后仍有解;初始状态有解,强制交换后无解;初始状态无解,强制交换后有解;初始状态无解,强制交换后仍无解。这里展示初始状态有解,强制交换后仍有解的测试情况。

      测试

    2、Github的commit信息

    3、 遇到的困难

    • 对图片的操作不了解,例如存取,切割,比对等,但其实主要还是文件的IO操作,不得不说百度真的啥都有,关于Python各种各样的包,函数,极大的简便了自己的工作量,几行代码就能实现数百张图片的切割、匹配。
    • 在设计AI的时候,对一些特殊情况没有考虑周到,导致False,最后和一些hxd讨论后,完善了AI,解决了问题。

    4、评价你的队友

    陈嘉龙对队友的评价

    • 子杰在完成原型的设计与实现上,效率非常高,基本想到一个idea就能在一个下午的时间内实现出来,妥妥的前端大佬!

    • 容易钻牛角尖,想一个问题容易陷进去,此时最好停下来,做点其他事,过一会儿再思考。

    陈子杰对队友的评价

    • 嘉龙非常强,超强的自学能力还有一流的逻辑能力让我自愧不如,带着我这个小菜鸡上分!
    • 能有啥缺点= =,游戏打得好读书还能读,我和我舍友都傻了。

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

    • PSP

      PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
      Estimate 估计这个任务需要多少时间 40 40
      Analysis 需求分析 (包括学习新技术) 480 540
      Design Spec 生成设计文档 40 60
      Design Review 设计复审 40 30
      Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 50
      Design 具体设计 40 40
      Coding 具体编码 460 480
      Code Review 代码复审 30 30
      Test 测试(自我测试,修改代码,提交修改) 200 240
      Test Report 测试报告 30 20
      Size Measurement 计算工作量 30 20
      Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 20 30
      合计 1470 1580
    • 学习进度条:

    第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
    1 100 100 4 4 熟悉文件处理、图片比对操作,学会了啥是原型,并且用墨刀进行设计。并且熟悉python语言
    2 100 200 4 8 通过面向百度学习了simpleguitk和easygui进行界面绘制
    3 200 400 5 13 AI算法的实现与完善,还是面向百度学会了对界面里切割后图片的定位,了解了一些pygame的功能
    4 645 1045 18 31 熟悉接口的开发与测试,这次还是面向百度学会了Python对txt文档字符串里数字的读取和排序

    6、贴出commit信息

  • 相关阅读:
    git 常用命令
    最近任务 && react文章列表
    markdown 常用格式API
    webpack 插件怎么写
    iframe
    重置浏览器滚动条css
    webpack4
    vscode插件开发
    vscode插件
    react router 的push replace
  • 原文地址:https://www.cnblogs.com/bergscl/p/13843574.html
Copyright © 2011-2022 走看看