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

    个人博客园链接

    队友博客园链接

    Github项目地址

    具体分工

    个人 队友
    前端 原型图 编写文档 后端 AI算法 接口 打榜

    原型设计

    1.设计说明

    原型设计包括开始页面,开始按钮,重置按钮,暂停按钮。其中还包含了计时函数和计算步数的函数,后面更是添加了保存最佳成绩的具体实现函数,能够清晰的看出自己的操作的过程中实现拼图的最短步数。

    开始页面的代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type"   //防止乱码
           content="text/html; charset=utf-8"/>
       <title>华容道开始界面</title>    
    </head>
    <body>
    <p>请点击图片链接进入游戏界面
       <a href="华容道2.html">             //开始页面的图片地址,运行后要自己改图片的位置
       <img border="0" src="./A.jpg"  width="200" height="200">
    </a></p>
    </body>
    </html>
    

    游戏代码:

    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>九宫格拼图</title>
        <style>
    
            *{
                padding: 0;
                margin: 0;
                border: 0;
            }
            /* *是通配符,给所有的元素去掉默认样式,因为有的浏览器会默认加上一些样式,这可能会给布局带来问题 */
            body{
                 100%;
                height: 100%;
            }
            /* 给body设置100%的高度和宽度,这样就会根据浏览器屏幕大小自动适配 */
            #container{
                position: relative;
                 620px;
                height: 450px;
                margin: 0 auto;
                margin-top: 100px;
                border-radius: 1px;
            }
            /* 这是包裹所有元素的DIV,给他设置620px的宽和450px的高,这个大小可以设置为更大,但是不能小,至少要能包含里面所有的元素 */
            #game{
                position: absolute;
                 450px;
                height: 450px;
                border-radius: 5px;
                display: inline-block;
                background-color: white;
                box-shadow: 0 0 10px #ffe171;
            }
            /* 这是游戏区的DIV,这个大小是计算出来的,取决于你的小方块的大小。这里我们设置小方块的大小为150px 150px,所以这个大小是150px*3,为450px */
            /* 这里的background-color 设置为blue   */
            #game img{
                position: absolute;
                 149px;
                height: 149px;
                box-shadow: 1px 1px 2px #777;
                background-color: green;
                color: white;
                text-align: center;
                font-size: 150px;
                line-height: 150px;
                cursor: pointer;
                -webkit-transition: 0.3s;/*浏览器前缀,兼容其他浏览器 chrome*/
                   -moz-transition: 0.3s;/*firefox*/
                    -ms-transition: 0.3s;/*ie*/
                     -o-transition: 0.3s;/*opera*/
                        transition: 0.3s;
            }
            /* 这就是小方块的大小了,定位为绝对定位,这样改变位置不会影响其他元素的位置。宽高都是149px。注意了,我们还设置了box-shadow:1px 1px 2px #777 ;
            它还有边框阴影,所以149px 加上边框1px,它的总宽度是150px 下面的transition:0.3s是设置过渡时间,这是css3的属性,它会让属性改变呈现过渡动画,所以
            当我们改变方块的位置时,它会有一个动画,我们不必自己编写动画函数,这回让你疯狂*/
    
            #game img:hover{
                color: red;
            }
            /*给方块设置鼠标悬停动画,当鼠标悬停在元素上面时,会用这里的属性替换上面的属性,移开后又会变为原来的,这里我们是把字体颜色改变*/
            #control{
                 150px;
                height: 450px;
                display: inline-block;
                float: right;
            }
            /*控制区,display:inline-block会让元素呈现块状元素的特性,使得可以改变大小,同时也会具有行内元素的特性,使得不会占据一行空间,float:right让元素浮动到右边*/
            #control rowspan{
                height: 25px;
                font-size: 20px;
                color: #222;
                margin-top: 10px;
                font-family: KaiTi;
            }
            /*设置控制区按钮的共同样式*/
            #start{
                display: inline-block;
                font-size: 28px;
                 100px;
                height: 28px;
                background-color: #20a6fa;
                color: #ffe171;
                text-shadow: 1px 1px 2px #ffe171;
                border-radius: 5px;
                box-shadow: 2px 2px 5px #4c98f5;
                text-align: center;
                cursor: pointer;
            }
            /*给start按钮设置属性。cursor:pointer属性让鼠标移到元素上面时会显示不同的鼠标形状,pointer是手型*/
            #reset{
                display: inline-block;
                font-size: 28px;
                 100px;
                height: 28px;
                background-color: #20a6fa;
                color: #ffe171;
                text-shadow: 1px 1px 2px #ffe171;/*字体阴影*/
                border-radius: 5px;/*圆角属性*/
                box-shadow: 2px 2px 5px #4c98f5;/*盒子阴影*/
                text-align: center;/*文字居中*/
                cursor: pointer;
            }
            /*给Reset按钮设置属性*/
            #d1{
                left: 0px;
            }
            #d2{
                left: 150px;
            }
            #d3{
                left: 300px;
            }
            #d4{
                top: 150px;
            }
            #d5{
                top: 150px;
                left: 150px;
            }
            #d6{
                top: 150px;
                left: 300px;
            }
            #d7{
                top: 300px;
            }
            #d8{
                left: 150px;
                top: 300px;
            }
    
            /*这是预先给每个小方块按照顺序排好位置*/
            #result{
                font-family:"Times New Roman";
                font-size: 30px;
                text-align:center;
                color: red;
            }
        </style>
    </head>
    <body>
        <h1 style="text-align: center;">华容道游戏</h1>
        <h2 id="result">
        </h2>
        <div id="container">
        <!--最外面的DIV,用来包含里面的结构-->
    
            <!--游戏区,大DIV方块-->
                <div id="game">
                 <img src="1.png"  id="d1" width="150" height="150" onclick="move(1)"></img>
                 <img src="2.png"  id="d2" width="150" height="150" onclick="move(2)"></img>
                 <img src="3.png"  id="d3" width="150" height="150" onclick="move(3)"></img>
                 <img src="4.png"  id="d4" width="150" height="150" onclick="move(4)"></img>
                 <img src="5.png"  id="d5" width="150" height="150" onclick="move(5)"></img>
                 <img src="6.png"  id="d6" width="150" height="150" onclick="move(6)"></img>
                 <img src="7.png"  id="d7" width="150" height="150" onclick="move(7)"></img>
                 <img src="8.png"  id="d8" width="150" height="150" onclick="move(8)"></img>
                 <!-- <img src="D:pyimageX_9.jpg"  id="d9" width="150" height="150"> -->
                </div>
    
            <div id="control">
            <!--游戏控制区-->
    
                <p>
                    <img src="A.jpg" width="100" height="100"><br>
                    <rowspan id="timeText">总用时</rowspan>
                    <rowspan id="timer"></rowspan><br>
                    <rowspan id="walk"><b> 步数</b></rowspan>
                    <rowspan id="count"></rowspan><br>
                    <rowspan id="walk_min"><b>最短步数</b></rowspan>
                    <rowspan id="count_min"></rowspan>
                </p>
                <!--显示游戏时间区域-->
                <p>
                    <rowspan id="start" onclick="start()">开始</rowspan>
                    <rowspan id="reset" onclick="reset()">重来</rowspan>
                </p>
                <!--显示控制按钮区域-->
            </div>
        </div>
        <script>
            var count_min=99999;
            var conts=0; //有没有成功过
            if(count_min==99999){
                document.getElementById("count_min").innerHTML="无记录";
            }
            var count=0;//保存走过的步数
            var time=0; //保存定时时间
            var pause=true; //设置是否暂停标志,true表示暂停
            var set_timer; //设置定时函数
            var d=new Array(10); //保存大DIV当前装的小DIV的编号
            var d_direct=new Array(
                    [0],//为了逻辑更简单,第一个元素我们不用,我们从下标1开始使用
                    [2,4],//大DIV编号为1的DIV可以去的位置,比如第一块可以去2,4号位置
                    [1,3,5],
                    [2,6],
                    [1,5,7],
                    [2,4,6,8],
                    [3,5,9],
                    [4,8],
                    [5,7,9],
                    [6,8]
                ); //保存大DIV编号的可移动位置编号
            var d_posXY=new Array(
                    [0],//同样,我们不使用第一个元素
                    [0,0],//第一个表示left,第二个表示top,比如第一块的位置为let:0px,top:0px
                    [150,0],
                    [300,0],
                    [0,150],
                    [150,150],
                    [300,150],
                    [0,300],
                    [150,300],
                    [300,300]
                ); //大DIV编号的位置
            d[1]=1;d[2]=2;d[3]=3;d[4]=4;d[5]=5;d[6]=6;d[7]=7;d[8]=8;d[9]=0; //默认按照顺序排好,大DIV第九块没有,所以为0,我们用0表示空白块
    
            function move(id){
                //移动函数,前面我们已将讲了
                var i=1;
                for(i=1; i<10; ++i){
                    if( d[i] == id )
                        break;
                }
                //这个for循环是找出小DIV在大DIV中的位置
                var target_d=0;
                //保存小DIV可以去的编号,0表示不能移动
                target_d=whereCanTo(i);
                //用来找出小DIV可以去的位置,如果返回0,表示不能移动,如果可以移动,则返回可以去的位置编号
                if( target_d != 0){
                    d[i]=0;
                    //把当前的大DIV编号设置为0,因为当前小DIV已经移走了,所以当前大DIV就没有装小DIV了
                    d[target_d]=id;
                    //把目标大DIV设置为被点击的小DIV的编号
                    document.getElementById("d"+id).style.left=d_posXY[target_d][0]+"px";
                    document.getElementById("d"+id).style.top=d_posXY[target_d][1]+"px";
                    //最后设置被点击的小DIV的位置,把它移到目标大DIV的位置
                    count+=1
                    document.getElementById("count").innerHTML=count;
                }
                //如果target_d不为0,则表示可以移动,且target_d就是小DIV要去的大DIV的位置编号
                var finish_flag=true;
                //设置游戏是否完成标志,true表示完成
                for(var k=1; k<9; ++k){
                    if( d[k] != k){
                        finish_flag=false;
                        break;
                        //如果大DIV保存的编号和它本身的编号不同,则表示还不是全部按照顺序排的,那么设置为false,跳出循环,后面不用再判断了,因为只要一个不符,就没完成游戏
                    }
                }
                //从1开始,把每个大DIV保存的编号遍历一下,判断是否完成
                if(finish_flag==true){
                    if(!pause)
                        start();
                    if(count_min>count){
                        document.getElementById("count_min").innerHTML=count;
                        count_min=count;
                    }
                    if(count>count_min){
                            document.getElementById("count_min").innerHTML=count_min;
                        }
                    document.getElementById("result").innerHTML="(*//ω\*)Congratulation!!!!!!!!";
    
    <!--    alert("congratulation");-->
                }
                //如果为true,则表示游戏完成,如果当前没有暂停,则调用暂停韩式,并且弹出提示框,完成游戏。
                //start()这个函数是开始,暂停一起的函数,如果暂停,调用后会开始,如果开始,则调用后会暂停
            }
    
            function whereCanTo(cur_div){
                //判断是否可移动函数,参数是大DIV的编号,不是小DIV的编号,因为小DIV编号跟可以去哪没关系,小DIV是会动的
                var j=0;
                var move_flag=false;
                for(j=0; j<d_direct[cur_div].length; ++j){
                    //把所有可能去的位置循环遍历一下
                    if( d[ d_direct[cur_div][j] ] == 0 ){
                        move_flag=true;
                        break;
                    }
                    //如果目标的值为0,说明目标位置没有装小DIV,则可以移动,跳出循环
                }
                if(move_flag == true){
                    return d_direct[cur_div][j];
                }else{
                    return 0;
                }
                //可以移动,则返回目标位置的编号,否则返回0,表示不可移动
            }
    
            //定时函数,每一秒执行一次
            function timer(){
                time+=1;//一秒钟加一,单位是秒
                var min=parseInt(time/60);//把秒转换为分钟,一分钟60秒,取商就是分钟
                var sec=time%60;//取余就是秒
                document.getElementById("timer").innerHTML=min+"分"+sec+"秒";//然后把时间更新显示出来
            }
    
            //开始暂停函数
            function start(){
                if(pause){
                    document.getElementById("start").innerHTML="暂停";//把按钮文字设置为暂停
                    pause=false;//暂停表示设置为false
                    set_timer=setInterval(timer,1000);//启动定时
                    //如果当前是暂停,则开始
                }else{
                    document.getElementById("start").innerHTML="开始";
                    pause=true;
                    clearInterval(set_timer);
                }
            }
    
            //重置函数
            function reset(){
                count=0;
    
                time=0;//把时间设置为0
                random_d();//把方块随机打乱函数
                if(pause)//如果暂停,则开始计时
                    start();
                document.getElementById("result").innerHTML="";
                document.getElementById("count").innerHTML=0;
                if(count_min=99999)
                    if(finish_flag==true)//这样点重来就不会没有上次的记录
                       document.getElementById("count_min").innerHTML="无记录";
                if(count_min!=99999)
                    count_min=count_min;
    
    <!--            else-->
    <!--                document.getElementById("count_min").innerHTML=count_min;-->
    
            }
    
            //随机打乱方块函数,我们的思路是从第九块开始,随机生成一个数,然后他们两块对调一下
            function random_d(){
                for(var i=9; i>1; --i){
                    var to=parseInt(Math.random()*(i-1)+1);//产生随机数,范围为1到i,不能超出范围,因为没这个id的DIV
                    if(d[i]!=0){
                        document.getElementById("d"+d[i]).style.left=d_posXY[to][0]+"px";
                        document.getElementById("d"+d[i]).style.top=d_posXY[to][1]+"px";
                    }
                    //把当前的DIV位置设置为随机产生的DIV的位置
                    if(d[to]!=0){
                        document.getElementById("d"+d[to]).style.left=d_posXY[i][0]+"px";
                        document.getElementById("d"+d[to]).style.top=d_posXY[i][1]+"px";
                    }
                    //把随机产生的DIV的位置设置为当前的DIV的位置
                    var tem=d[to];
                    d[to]=d[i];
                    d[i]=tem;
                    //然后把它们两个的DIV保存的编号对调一下
                }
            }
    
            //初始化函数,页面加载的时候调用重置函数,重新开始
            window.onload=function(){
                reset();
            }
        </script>
    </body>
    </html>
    

    2.原型开发工具

    采用的是Axure来设计模型,尽量把拼图中所有涉及到的功能全都实现了一遍。




    3.结对过程

    在最开始的分工时,我们抱着一起做所有事情的心态去学习所需要用到的东西,包括pygame,html,css,js等等,后来发现时间赶不上才开始定下个人的小目标。虽然在此之前,起霖用pygame实现了拼图过程,但是后面了解到pygame实现不了网页的接口,于是我们又再次写了一份html的拼图游戏。最后在起霖的不断努力下,最终完成了AI大比拼中的算法实现。

    4.困难与解决方法

    我在最开始的html和js相结合的地方有许多疑惑的地方,后来请教了楚哥,霖哥等等大佬后,最终才完成了这一份html的代码块。中途在实现最佳成绩的函数时也遇到了想不到的bug,也是在其他人的帮助下得以解决。

    5.两人讨论细化的照片

    6.动态展示

    AI与原型设计实现

    1.代码实现思路

    2.相关算法以及代码

    最核心的A*算法原理:

    1.把起点加入 open表。

    2.重复如下过程:

    a. 遍历 open表,查找 F 值最小的节点,把它作为当前要处理的节点。

    b. 把这个节点移到 close表。

    c. 对当前方格的 4个方向相邻方格进行操作:

    ◆ 如果它是不可抵达的或者它在 close表中,忽略它。

    ◆ 如果它不在 open表中,把它加入 open表,并且把当前方格设置为它的父亲,记录该方格的 F,G 和H值。

    ◆ 如果它已经在 open表中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 H值作参考。更小的H值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它的 G 、H和 F 值。
    d. 判断是否出现以下情况,是就停止跳出循环:

    ◆ 把终点加入到了 open表中,此时路径已经找到了,或者

    ◆ 查找终点失败,并且 open表是空的,此时没有路径。

    3.保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。

    代码如下:

    def run_Axing():
        global swap
        global move
        #before:保存父节点的列表
        global before
        global cost
        global openList
        global closeList
        before = [0]
        cost = [0]
        openList = [[]]
        closeList = []
        #从image_compare获取被扣去的格子
        blank = image_compare.bk
        li_goal = list(range(1, 9 + 1))
        #    entry_num=int(entry_num)
    	#目标九宫格
        li_goal[blank - 1] = 0
        #print(li_goal)
        #起始状态
        li0 = image_compare.array
    
        #print('li0', li0)
        swap = []
        move = [-3, 3, -1, 1]
        maxcount=10000+81
        # 1. 把起始格添加到开启列表。
        openList[0]=li0[:]
        #print('openlist[0]', openList[0])
        cost[0]=H_cost(li_goal,openList[0])
        #print('cost[0]',cost[0])
        before[0]=0
        Gn = 0
     #   add_open(st[0])
        # 2.重复如下的工作:
        while len(closeList)<10000:
            # a) 寻找开启列表中H值最低的格子。我们称它为当前格。
            mc = cost.index(min(cost))
            if cmp(openList[mc][:],li_goal[:])==0:
                return mc
            x = openList[mc].index(0) + 1
            # b) 把它切换到关闭列表。
            closeList.append(openList[mc][:])
            cost[mc]=maxcount
    #        del openList[mc]
    #        del cost[mc]
            # c) 对相邻的4格中的每一个进行以下操作
    
            for i in range(0, 4):
                if bool_rules(x, x + move[i]):
                    temp = turn(x, x + move[i], openList[mc][:])[:]
                    if closeList.count([temp]) == 0:  # 如果它不可通过或者已经在关闭列表中,略过它。
                        if openList.count([temp]) == 0:
                            openList.append(temp)  # 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的H值。
                            c = H_cost(li_goal, openList[-1])+Gn
                            cost.append(c)
                            before.append(mc)
                            # 如果它已经在开启列表中,用H值为参考检查新的路径是否更好。
                            # 更低的H值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,
                            # 并且重新计算这一格的H值。
                        else:
                            t = openList.index(temp)
                            c = H_cost(li_goal, openList[t])+Gn
                            if c < cost[t]:
                                cost[t]=c
                                before[t] = mc
            Gn += 1
        #print(before)
        return -1
    

    结果传回run(),如果寻路有解,则我用step存储每一步变化的结果,从openList中获得。

    def run():
        global zero_location
        global way
        global swap
        swap = []
        way = str()
        mc = run_Axing()
        #step存储每一步变化完的九宫格
        global step
        step = []
        if mc > -1:
            zero_location = []
            num = 0
            step = [openList[mc]]
            new_list = []
            while mc > 0:
                mc = before[mc]
                step.append(openList[mc])
                num += 1
            #print('次数:', num)
            for i in range(0, num + 1):
                #print('step', i)
                b = 0
                list1 = []
    
                for j in range(0, 3):
                    list1 = list1 + (step[num - i][j * 3:j * 3 + 3])
                    #print(step[num - i][j * 3:j * 3 + 3])
    
                #print("list1", list1)
                b = get_zero_location(list1)
                zero_location.append(b)
            way = get_zero_path(zero_location)
    
        else:
            print('ERROR!')
        #print(way)
        #print('finsh')
        return way,swap
    

    对于空白格的移动,我写了get_zero_location和get_zero_path两个函数来分别获取每步空白格的位置以及空白格移动的方向。最后路径存储在way中返回给Post_Answer作为答案上传

    def get_zero_path(list):
        global zero_path
        zero_path = str()
        index = 0
        while index < len(list)-1:
            if list[index] - list[index+1] == 3:
                zero_path+=str('w')
            elif list[index] - list[index+1] == 1:
                zero_path+=str('a')
            elif list[index] - list[index + 1] == -3:
                zero_path+= str('s')
            elif list[index] - list[index + 1] == -1:
                zero_path+=str('d')
            index += 1
        return zero_path
    def get_zero_location(list):
        a = 0
        for i in list:
            if i == 0:
                a = list.index(i)+1
                print(a)
        return a
    

    3.性能分析与改进

    只能说好不容易写出个算法勉强能用已经是我的极限了,毕竟也是借鉴网上的代码,在性能改进上自己还是做不了啥的。

    4.性能分析图

    AI_Test中性能消耗最大的函数就是run()和run Aixing.

    5.对队友的评价

    起霖在AI算法的实现上想了很多也实现了很多,特别在是后来的接口和打榜,都是起霖一人扛起来这份大旗,虽然最后的结果不是很好,但是对我们来说,已经是很不错的成绩了。

    6.PSP和学习进度条

    何文龙

    第N周 新增代码(行) 累计代码(行) 本周学习耗时(h) 累计学习耗时(h) 重要成长
    1 15 15 10 10 了解前端和后端的基本特性
    2 64 79 24 学习并练习html,js,css语句
    3 251 320 16 40 继续学习html,js,css的写法,练习Axure的使用
    4 49 369 20 60 将js和css嵌入html当中(实现Axure)
    5 15 384 20 80 最终实现游戏的页面

    吴起霖

    第N周 新增代码(行) 累计代码(行) 本周学习耗时(h) 累计学习耗时(h) 重要成长
    1 0 0 2 2 了解题目需求
    2 250 250 20 22 用pygame实现了一个九宫格拼图游戏
    3 150 400 22 44 学习有关接口调用的相关知识,发现与自己上的爬虫课差不多,尝试了解AI测试
    4 200 600 20 60 了解AI大比拼的相关需求,寻找可用算法,学习A*算法
    5 300 900 20 80 实现A*算法,学会对接口得到的图片进行分割以及对比
    PSP(二人合计) Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 40 30
    Estimate 估计这个任务需要多少时间 20 20
    Development 开发 1500 1400
    Analysis 需求分析 (包括学习新技术) 600 450
    Design Spec 生成设计文档 30 30
    Design Review 设计复审 30 20
    Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 30
    Design 具体设计 30 30
    Coding 具体编码 700 500
    Code Review 代码复审 90 80
    Test 测试(自我测试,修改代码,提交修改) 150 150
    Reporting 报告 170 150
    Test Repor 测试报告 60 60
    Size Measurement 计算工作量 20 20
    Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30 30
    Total 合计 3530 285
  • 相关阅读:
    Q12:app在iPhone上执行正常,iPad上出现黑边问题解决方式
    SPOJ 104 Highways 最小生成树计数
    微信支付 常见报错
    oracle创建表空间、用户、和权限配置
    Android Matrix图像变换处理
    java项目部署到weblogic上后,某些浏览器无法取得session值
    简介redis以及ubuntu和windows下怎样安装redis和配置文件具体解释
    Melo作为程序猿的2016年
    软件架构,WEB
    软件架构,WEB
  • 原文地址:https://www.cnblogs.com/Fzu-hwl/p/13838329.html
Copyright © 2011-2022 走看看