关闭

在传统连连看游戏的基础上设计出新游戏增量式的创新(结对编程)(2011212026徐颖 2011212023 裴乐)

773人阅读 评论(0) 收藏 举报

一.游戏简介

   游戏连连看顾名思义就是找出相关联的东西,这个连连看在网上基本是用在小游戏中,就是找出相同的两样东西,在一定的规则之内可以做为相关联处理。连连看的发展经历了从桌面游戏、在线游戏、社交游戏三个过程。 

二.游戏功能

本次设计连连看主要是在原连连看对战的基础上设计挑战模式,具体的功能如下所述:

  •  游戏运行界面简单美观,操作简单,运行稳定;
  • 能够根据不同的等级模式播放不同的游戏背景音乐,包括操作方向键、消行时的声音,音量由玩家操作控制;
  • 设计不同的游戏难度,当玩家达到一定的积分,可以进入相关难度的等级;

玩家可直接操作界面上的相关按钮来控制游戏的开始、暂停、设置、退出等功能。

 

2.1游戏功能需求

  本次设计是在传统的连连看上设计实现对战的连连看,玩家通过达到一定的积分来获得继续闯关的机会,还有机会开启神秘的应藏关,以此来增加游戏的可玩性。

   游戏的基本规则:程序随机产生任意成对的图片,当定点击开始游戏时,电脑根据时间参数随机生成固定的成对图片,游戏再次开始,玩家可通过鼠标上的左键,自由的点两张图片。如果点击两次时,两张图片相同,且满足程序的算法则这两张图片可消去。消去图片后,游戏可给玩家加分,若在规定的时间内,玩家没有消掉所有的图片则游戏失败。由于是闯关模式,达到一定分数的玩家可以继续挑战新的游戏,游戏的难度会相应增加,并且还增加了新玩法。具体的游戏功能如下:

   游戏界面需求:设计良好的游戏界面可以让玩家充分感受到游戏带来的娱乐性,游戏的背景取自网上中的图片,体现了游戏的挑战性。   

   鼠标处理事件需求:通过点击主窗体中相应的按钮,可以实现游戏的开始、暂停、结束,通过点击选项设置中相应的按钮,可设置声音的大小及方向键↓的功能。显示需求:当两次点击的图片相同且满足算法可以消去,当达到一定分数的时候,游戏会进入下一关,并有障碍了。

   游戏闯关设计需求:随着游戏的难度不同,玩法会发生改变,需要在游戏中设置障碍,蒙手游戏。如果玩家能到达并完成最后一关,则玩家挑战成功,游戏结束。

最后游戏效果如下:

三. 游戏总体设计

   3.1 总体设计

整体设计思想:进入游戏后,有三个按钮可供玩家选择:开始游戏,游戏设置,退出游戏,在进入相应子菜单后也可返回到主菜单,每个菜单的具体设计将在后面介绍。

 

    3.2游戏核心模块的设计

    3.2.1连连看所要求的是:

1.两个目标是相同的;

2.两个目标之间连接线的折点不超过两个。(连接线由x轴和y轴的平行线组成) 那么分析一下连接的情况可以看到,一般分三种情况:(1)直线相连;(2)一个折点;(3)两个折点。

可以发现,如果有折点,每个折点必定有且至少有一个坐标(x或者y)是和其中一个目标点是相同的,也就是说,折点必定在两个目标点所在的x方向或y方向的直线上。

所以设计思路就是:

假设目标点 p1 , p2 ,如果有两个折点分别为z1 , z2 那么,所要进行的是 

Ø 如果验证p1 , p2 直线连线,则连接成立 

Ø 搜索以p1,p2x,y方向四条直线(可能某两条直线会重合)上的有限点,每次取两点作为z1,z2 ,验证p1z1/z1z2/z2p2 是否都能直线相连 ,是则连接成立

 

3.2.2 连连看消去算法实现

在检验两张图片能否消掉的时候,我们要让两张图片同时满足两个条件才行,就是两者配对并且连线成功。分3种情况:(从下面的这三种情况,我们可以知道,需要三个检测,这三个检测分别检测一条直路经。这样就会有三条路经。若这三条路经上都是空按钮,那么就刚好是三种直线(两个转弯点)把两个按钮连接起来了)

1)相邻  

2) 若不相邻的先在第一个按钮的同行找一个空按钮。1).找到后看第二个按钮横向到这个空按钮所在的列是否有按钮。2).没有的话再看第一个按钮到与它同行的那个空按钮之间是否有按钮。3).没有的话,再从与第一个按钮同行的那个空按钮竖向到与第二个按钮的同行看是否有按钮。没有的话路经就通了,可以消了

     (3)若2失败后,再在第一个按钮的同列找一个空按钮。1).找到后看第二个按钮竖向到这个空按钮所在的行是否有按钮 2).没有的话,再看第一个按钮到与它同列的那个空按钮之间是否有按钮。3).没有的话,再从与第一个按钮同列的那个空按钮横向到与第二个按钮同列看是否有按钮。没有的话路经就通了,可以消了。

      若以上三步都失败,说明这两个按钮不可以消去。

四. 具体方案

 

4.1视图层设计

4.1.1图形的产生

加载图块图片资源,调用图片库用函数DrawArea::loadPixmap()来实现。

函数如下设计:

void DrawArea::loadPixmap()

{

    background.load(":/background/background.png");

    background=background.scaled(size());

    QPixmap pix(":/pattern/pattern.png");

    int num=pix.height()/PIX_SIZE;

   for(int i=1;i<num;++i){

        qreal y=PIX_SIZE*i;

        QPixmap p=pix.copy(0,y,PIX_SIZE,PIX_SIZE);

        pixmap.push_back(p);

    }

}

4.1.2 判段消掉图片

如果两个图片一样,我们进行消块,并进行加分操作。消块操作如下:

if(hitTimer)

       killTimer(hitTimer);

    hitTimer =startTimer(INTERVAL_HIT_TIMER);

    ++multiHit;

    emit hit(multiHit);

   lineTimer=startTimer(INTERVAL_LINE_TIMER);

 

4.2 逻辑层设计

 僵局考虑

    判断是否已经进入死局,死局条件:

在回合尚未结束的情况下遍历面板,无法找到一对可销图块则判定为死局。若找到一对可销图块,则将其记录为hintA和hintB,以供hint()函数利用。设计代码如下:

bool DrawArea::isDead()

{

    int i,j,x,y;

    if(!pairLeft)

        return true;

    for(i=0;i<xMax;++i){

        for(j=0;j<yMax;++j){

            if(board[i][j]){

                for(x=i;x<xMax;++x){

                    if(x==i)    y=j+1;

                    else y=0;

                    for(;y<yMax;++y){

                        if(board[x][y]==board[i][j]){

                            if(isPosLinkable(i,j,x,y)){//如果消块成功,那么这里就变成了0

                                hintA.x=i;

                                hintA.y=j;

                                hintB.x=x;

                                hintB.y=y;

                                return false;

                            }

                        }

                    }

                }

            }

        }

    }

    return true;

}

 

4.3 其它相关技术的实现 

键盘事件响应

连连看是通过鼠标左键来控制游戏的运行,那么是具体如何实现的呢?这就需要用到键盘的左击事件,通过响应鼠标的按下事件来实现。玩家通过鼠标左键来控制图片的点击。具体代码实现:通过重新实现虚函数GameWindow::keyPressEvent(QKeyEvent *event)来响应相应的键盘按键事件。

 

 

 

五. 游戏的测试

 

5.1 选项按钮的功能测试 

    (1)点击“游戏开始”:游戏正常开始,结果正常;

    (2)点击“退出游戏”:游戏正常退出,结果正常;

    (3)点击“暂停”:游戏停止,“暂停”变为“取消暂停”,再点击“取消暂停”:游戏继续,结果正常;

    (4)点击“返回主菜单”:游戏退回到主菜单界面,结果正常;

 

5.2 按键事件的功能测试 

    (1)两次点击相同图片,若满足算法,图片消失,则结果正常;

    (2)图片点击测试:游戏过程中,点击鼠标左键:图片在没有其他图片阻挡的情况下可变色,结果正常;

 

5.3 图片消失测试

    (1)当点击两张相同图片:两站图片同时消失,结果正常;

    (2)当图片消失,且满足一条直线时分数增加10分。

 

5.4 声音和显示测试 

    (1)进入游戏时:背景音乐正常播放,图片消失时,有背景音乐播放;

2)在游戏过程中,游戏区域背景颜色不断改变;在开始最后一关时:游戏区域越来越大,结果正常;

 

5.5 测试结果分析 

经过测试,本游戏实现了基本的连连看的功能,运行比较稳定,不过有些细节方面可能需要改进,游戏在很多方面还需要进一步完善。

 

六. 小结

    

    游戏设计与实践是一项复杂而庞大的工作,在选题之后,我和我的队友才意识到过程的艰难,因为以前从来都没有接触过游戏设计,刚开始有点迷茫和彷徨。后来通过翻阅书籍和在网上查阅资料,逐渐找到了一些感觉。

    本次实验因为有一定的难度,所以我和我的队友并没有明确的分工,而是全程相互帮助,相互理解,一起完成了这个项目。

   本次设计让我们初步懂得了电子游戏涉及到的有关技术、方法,包括电子游戏选题、构思、设计步骤等。并实现一些可演示的游戏软件,其中有很多应用了学习的相关技术,并且做到了界面、声音都能实际演示。此次设计过程中印象最深的收获有:1学到了很多新知识,并且对老知识进行了回顾。经过长时间的学习,更进一步熟悉了Qt编程、通过不断上机实验,调试程序,总结经验,从对课题的不理解到能够开始动手去做,提出新问题并自己想办法去解决问题,自己多实践,所以增强了动手能力。2、提高了中、英文资料的检索能力。这次专业设计过程中我查阅了多资料,包括一些期刊、杂志,还有网络中的电子文档、电子书籍、网页及下载的视频教学课程;不但有中文资料还有英文资料。这些资料,使我的眼界更开阔,对课题的认识更加深刻,编写程序的时候思路更加清楚,少走了很多弯路。

   回顾此次设计过程,我学到了许多书本上没有学到的知识。通过这次自己制作的软件,丰富了自己的实践技能,扩张了本专业的知识面,使我受益匪浅,同时也体验到了搞软件开发的难度。在这次设计的同时,由于我对这样的软件开发还只是一个开始,了解的不多,这其中或许还有很多的不足,有些模块做得不是很好,有些功能还不能够完全的实现,如播放背景音乐时,只能播放一遍,因为游戏Qt类库中封装的东西太多,有些函数它底层的具体实现可能还没有真正的理解,所以,这也许就是本次游戏设计的不足之处。

七. 源码(部分代码):

/*drawarea.cpp*/

#include "drawarea.h"

#include <iostream>

#include <QMouseEvent>

#include <QTimerEvent>

#include <QPainter>

#include <QLabel>

#include <QDir>

#include <QFileInfo>

#include <stdio.h>

#include <assert.h>

 

const int INTERVAL_LINE_TIMER=200;

const int INTERVAL_HIT_TIMER =2000;

const int PIX_SIZE   = 46;

const int AREA_WIDTH  = Y_MAX*PIX_SIZE;

const int AREA_HEIGHT = X_MAX*PIX_SIZE;

 

 

DrawArea::DrawArea(QWidget *parent) :

    QWidget(parent)

{

    loadPixmap();

    drawArea = new QLabel(this);

    drawArea->setGeometry(0,0,AREA_WIDTH,AREA_HEIGHT);

    drawArea->setPixmap(background);

    isHintUsed=false;

}

 

QSize DrawArea::size() const

{

    return QSize(AREA_WIDTH,AREA_HEIGHT);

}

 

QSize DrawArea::sizeHint() const

{

    return size();

}

 

/* 初始化关卡 */

void DrawArea::initLevel(const Map &mapData)

{

    lastX=mapData.xMax;

    lastY=mapData.yMax;

    lineTimer=0;

    hitTimer =0;

    multiHit =0;

    pairLeft =0;

    xMax=mapData.xMax;

    yMax=mapData.yMax;

    for(int i=0;i<xMax;++i)

        for(int j=0;j<yMax;++j){

            board[i][j]=mapData.map[i][j];

            if(board[i][j])

                ++pairLeft;

        }

    if(pairLeft%2!=0){

        emit errorNotify(tr("地图数据错误,地图存在不成对的块数"));

        return;

    }

    if(pairLeft==0){

        emit errorNotify(tr("地图数据为空"));

        return;

    }

    pairLeft =pairLeft/2;

 

    disorder(mapData.disorderCount);

    //刚开局就判断死局,一个是初始化上帝之手,

    //再一个最主要原因是为hint图块对赋值

    //上帝之手的初始化必须在地图数据加载之后进行

    if(isDead()){

        godTouch=true;

        emit godTouchOn();

    }else

        godTouch=false;

 

    isLevelOver = false;

    drawBoard();

}

 

 

//[Test]从文件加载地图及相关配置信息。

void DrawArea::loadMapFromFile(string fileName)

{

    int nDisorder;

    FILE *mapFile;

    mapFile=fopen(fileName.c_str(),"r");

    if(!mapFile)

        exit(-1);

    if(fscanf(mapFile,"%d %d",&nDisorder,&pairLeft)==EOF){

        emit errorNotify(tr("Test:地图数据加载失败"));

        return;

    }

    for(int i=0;i<xMax;++i)

    for(int j=0;j<yMax;++j){

        if(fscanf(mapFile,"%d",&board[i][j])==EOF){

            emit errorNotify(tr("Test:地图数据无法成功加载"));

            return;

        }

    }

    fclose(mapFile);

    disorder(nDisorder);

}

 

//根据指定的打乱次数 nDisorder对面板内的非零数据进行交换

void DrawArea::disorder(int nDisorder)

{

    srand(clock());

    //基本实现:将非零数据加入到一个足够长的数组中,随机产生两个

    //坐标进行交换

    int pos[xMax*yMax][2];

    int nBlock=0;

    for(int i=0;i<xMax;++i)

    for(int j=0;j<yMax;++j){

        if(board[i][j]){

            pos[nBlock][0]=i;

            pos[nBlock][1]=j;

            ++nBlock;

        }

    }

 

    for(int i=nDisorder;i;--i){

        int pos1=rand()%nBlock;

        generatePos2:

        int pos2=rand()%nBlock;

        if(pos1==pos2)

            goto generatePos2;

 

        int x1=pos[pos1][0];

        int y1=pos[pos1][1];

        int x2=pos[pos2][0];

        int y2=pos[pos2][1];

        std::swap(board[x1][y1],board[x2][y2]);

    }

    drawBoard();

}

 

/* 加载图块图片资源 */

void DrawArea::loadPixmap()

{

    background.load(":/background/background.png");

    background=background.scaled(size());

    QPixmap pix(":/pattern/pattern.png");

    int num=pix.height()/PIX_SIZE;

    for(int i=1;i<num;++i){

        qreal y=PIX_SIZE*i;

        QPixmap p=pix.copy(0,y,PIX_SIZE,PIX_SIZE);

        pixmap.push_back(p);

    }

}

 

//给玩家生成一对提示,并将其高亮显示

void DrawArea::hint()

{

    isHintUsed=true;

    //将找到的一对图块画上边框

    lastX=hintA.x;

    lastY=hintB.y;

    drawBoard();

}

 

/* Timer events.

 */

void DrawArea::timerEvent(QTimerEvent *event)

{

    if(event->timerId()==lineTimer){

        killTimer(lineTimer);

        lineTimer =0;

        drawBoard();

    }

    if(event->timerId()==hitTimer){

        multiHit=0;

        killTimer(hitTimer);

        hitTimer =0;

        drawBoard();

    }

 

}

 

/* 接受鼠标按下的消息并将其发生的相对屏幕坐标转换成数组坐标

 * 传入clickPos进行判断,同时将其画上选中标志。

 */

void DrawArea::mousePressEvent(QMouseEvent *event)

{

    int y=(event->x()-drawArea->x())/PIX_SIZE;

    int x=(event->y()-drawArea->y())/PIX_SIZE;

 

    if(!isBlank(x,y)){

        emit select();

        isHintUsed = false;

        drawEmbrace(x,y);

        clickPos(x,y);

    }

}

 

/* 绘制面板,当回合未结束时,绘制面板上所有图块的内容。

 * 如果连击数不少于两次,则在屏幕正中心显示 "xN Hit"的字样

 */

void

DrawArea::drawBoard()

{

    store=background;

    QPainter painter(&store);

    if(!isLevelOver){

        painter.setCompositionMode(QPainter::CompositionMode_SourceOver);

        for(int i=0;i<xMax;++i)

            for(int j=0;j<yMax;++j){

            painter.save();

            painter.translate(j*PIX_SIZE,i*PIX_SIZE);

            if(!isBlank(i,j) && board[i][j]<pixmap.size())

                painter.drawPixmap(0,0,PIX_SIZE,PIX_SIZE,pixmap[board[i][j]-1]);

            painter.restore();

        }

        if(multiHit>1){

            QFont font;

            QPen pen(Qt::SolidLine);

            pen.setColor(QColor(255,255,255,220));

            font.setFamily("Comic Sans MS");

            font.setPixelSize(30);

            font.setBold(true);

            painter.setPen(pen);

            painter.setFont(font);

            painter.drawText(QPointF(0,AREA_HEIGHT-15),tr("x%1   连击!").arg(multiHit));

        }

    }

    painter.end();

    drawArea->setPixmap(store);

    if(isHintUsed){

        drawEmbrace(hintA.x,hintA.y);

        drawEmbrace(hintB.x,hintB.y);

    }else

        drawEmbrace(lastX,lastY);

}

 

/* 为选中的图块画上标志 */

void DrawArea::drawEmbrace(const int &x,const int &y)

{

    if(isValid(x,y) && board[x][y]){

        QPainter painter(&store);

        painter.setCompositionMode(QPainter::RasterOp_SourceAndDestination);

        QPen pen;

        pen.setWidth(5);

        pen.setColor(Qt::blue);

        painter.setPen(pen);

        painter.translate(y*PIX_SIZE,x*PIX_SIZE);

        painter.drawRect(0,0,PIX_SIZE,PIX_SIZE);

        painter.end();

        drawArea->setPixmap(store);

    }

}

 

/* 在指定的图块上画一个红色的叉号 */

void DrawArea::drawRedMark(const int &x, const int &y)

{

    QPainter painter(&store);

    QPen pen(Qt::white);

    pen.setWidth(5);

    painter.setPen(pen);

    painter.translate(y*PIX_SIZE,x*PIX_SIZE);

    painter.drawLine(0,0,PIX_SIZE,PIX_SIZE);

    painter.drawLine(0,PIX_SIZE,PIX_SIZE,0);

    painter.end();

    drawArea->setPixmap(store);

}

 

/* 在两个给定点之间画一条较粗的直线 */

void DrawArea::drawLine(const int &aX, const int &aY,

                        const int &bX, const int &bY)

{

    QPainter painter(&store);

    int x1=aY*PIX_SIZE+ PIX_SIZE/2;

    int y1=aX*PIX_SIZE+PIX_SIZE/2;

    int x2=bY*PIX_SIZE+PIX_SIZE/2;

    int y2=bX*PIX_SIZE+PIX_SIZE/2;

    QPen pen(Qt::blue);

    pen.setStyle(Qt::SolidLine);

    pen.setWidth(5);

    painter.setPen(pen);

    painter.drawLine(x1,y1,x2,y2);

    painter.end();

    drawArea->setPixmap(store);

}

 

void DrawArea::autoDestroy()

{

    lastX=hintA.x;

    lastY=hintA.y;

    clickPos(hintB.x,hintB.y);

}

 

/****************************************

 *连连看逻辑实现相关函数

 ****************************************/

 

/* 判断是否已经进入死局,死局条件:

 * 在回合尚未结束的情况下遍历面板,无法找到一对可销图块

 * 则判定为死局。若找到一对可销图块,则将其记录为hintA

 * 和hintB,以供hint()函数利用。

 */

bool DrawArea::isDead()

{

    int i,j,x,y;

    if(!pairLeft)

        return true;

    for(i=0;i<xMax;++i){

        for(j=0;j<yMax;++j){

            if(board[i][j]){

                for(x=i;x<xMax;++x){

                    if(x==i)    y=j+1;

                    else y=0;

                    

                    for(;y<yMax;++y){

                        if(board[x][y]==board[i][j]){

                            if(isPosLinkable(i,j,x,y)){//如果消块成功,那么这里就变成了0

                                hintA.x=i;

                                hintA.y=j;

                                hintB.x=x;

                                hintB.y=y;

                                return false;

                            }

                        }

                    }

                }

            }

        }

    }

    return true;

}

 

/*  (x,y)位置发生了点击,如果上次点击的点花色与之相同且位置不同,

 * 对于上帝模式,直接销块。

 * 否则,尝试判断是否可连接,如果可连接则进行连线,

 * 并随后进行死局判断,如进入死局则开启上帝模式

 * 否则将这个点记为上次点击的点。

 * 每次成功销块之后,立即增加连击计数并启动一个连击定时器,如果连击

 * 定时器过期,则连击计数清零。

 */

void DrawArea::clickPos(int x,int y)

{

    assert( isValid(x,y)  );

    assert( !isBlank(x,y) );

 

    vector <Pos> posVec;

    int nPos=0;

    Pos pos1,pos2;

    if(lastX==x &&lastY==y)

        return;

    if(!isValid(lastX,lastY)||

        !isSame(x,y,lastX,lastY)||//isSame must be placed after "isValid"

        isBlank(lastX,lastY)){

        lastX=x;

        lastY=y;

        drawBoard();

        return;

    }

 

    if(godTouch){

        drawRedMark(x,y);

        drawRedMark(lastX,lastY);

        goto Destroy_Blocks;

    }

 

    if(isPosLinkable(x,y,lastX,lastY,&nPos,&pos1,&pos2)){

        Pos a(x,y);

        Pos b(lastX,lastY);

        posVec.push_back(a);

        if(nPos>=1){

            posVec.push_back(pos1);

            if(nPos==2)

            posVec.push_back(pos2);

        }

        posVec.push_back(b);

        for(unsigned int i=0;i<posVec.size()-1;++i){

            drawLine(posVec[i].x,posVec[i].y,posVec[i+1].x,posVec[i+1].y);

        }

 

        goto Destroy_Blocks;

    }else{

        lastX=x;

        lastY=y;

        drawBoard();

        emit sameYetUnlinkable();

        return;

    }

    

    Destroy_Blocks:

    //销块操作

    if(hitTimer)

        killTimer(hitTimer);

    hitTimer =startTimer(INTERVAL_HIT_TIMER);

    ++multiHit;

    emit hit(multiHit);

    lineTimer=startTimer(INTERVAL_LINE_TIMER);

 

    //连线操作

    board[x][y]=0;

    board[lastX][lastY]=0;

    --pairLeft;

    if(!pairLeft){

        isLevelOver =true;

        emit levelClear();

        puts("Game Over");//GameOver

    }else{

        if(isDead()){

            godTouch=true;

            emit godTouchOn();

        }else

            godTouch=false;

    }

}

 

/*  */

inline bool DrawArea::isBlank(const int &x,const int &y)

{

    assert(isValid(x,y));

    

    return board[x][y]==0;

}

 

/* Check whether the position is valid */

inline bool DrawArea::isValid(const int &x,const int &y)

{

    if(x>=xMax||y>=yMax)

        return false;

    return true;

}

 

/* Check whether the two points are the same */

inline bool DrawArea::isSame(const int &x1,const int &y1,

                const int &x2,const int &y2)

{

    assert(isValid(x1,y1));

    assert(isValid(x2,y2));

    

    return board[x1][y1] == board[x2][y2];

}

 

/*

 */

bool DrawArea::isPosLinkable(int x1_,int y1_,int x2_,int y2_,

                            int *nPos,Pos *pos1,Pos *pos2)

{

    assert(isValid(x1_,y1_));

    assert(isValid(x2_,y2_));

    

    bool posFlag=false;//传入参数中是否有折点

    if(nPos){

        posFlag=true;

        if(!(pos1&&pos2))

            return false;

    }

    

    int x1=x1_;

    int x2=x2_;

    int y1=y1_;

    int y2=y2_;

    if(!isSame(x1,y1,x2,y2))

        return false;

        

    //First,check whether they can be directly linked

    if(isLineLinkable(x1,y1,x2,y2)){

        if(posFlag) *nPos=0;

        

        return true;

    }

    //Second,check whether they can be linked with one turning

    if(findinteractPoint(x1,y1,x2,y2)){

        if(posFlag){

            *nPos=1;

            pos1->x=x2;

            pos1->y=y2;

        }

        return true;

    }

    //Third,check x-direct point that can be linked with one turning

    for(int i=0;i<xMax;++i){

        if(isBlank(i,y1) && 

           isLineLinkable(i,y1,x1,y1) && 

           findinteractPoint(i,y1,x2,y2)){

               if(posFlag){

                    *nPos=2;

                    pos1->x=i;

                    pos1->y=y1;

                    pos2->x=x2;

                    pos2->y=y2;

                }

            return true;

        }

    }

    //Fourth,check y-direct point that can be linked with one turning

    for(int i=0;i<yMax;++i){

        if(isBlank(x1,i) && 

           isLineLinkable(x1,i,x1,y1) && 

           findinteractPoint(x1,i,x2,y2)){

               if(posFlag){

                    *nPos=2;

                    pos1->x=x1;

                    pos1->y=i;

                    pos2->x=x2;

                    pos2->y=y2;

                }

            return true;

        }

    }

    return false;

}

/* 

 * 寻找以 (x1,y1)和 (x2,y2)所在线段为对角线的矩形中对这两个点均可直线到达的顶点

 * 若找到,则将 (x2,y2)改写为该顶点,否则,返回false

 */

bool DrawArea::findinteractPoint(const int &x1,const int &y1,int &x2,int &y2)

{

    if(!board[x1][y2]){

        if(isLineLinkable(x1,y1,x1,y2) &&

            isLineLinkable(x2,y2,x1,y2)){

            x2=x1;

            return true;

        }

    }

    if(!board[x2][y1]){

            if(isLineLinkable(x1,y1,x2,y1)&&

                isLineLinkable(x2,y2,x2,y1)){

                y2=y1;

                return true;

            }

    }

    return false;

}

/*

 * 检验两点是否可以直线无障碍到达

 */

bool DrawArea::isLineLinkable(int x1,int y1,int x2,int y2)

{

    if(x1 == x2){

        if(y1>y2)    std::swap(y1,y2);

        

        for(y1+=1;y1<y2;++y1)

            if(board[x1][y1])

                return false;

            

    }else if(y1 == y2){

        if(x1>x2)    std::swap(x1,x2);

        

        for(x1+=1;x1<x2;++x1)

            if(board[x1][y1])

                return false;

    }else

        return false;

    

    return true;

}

 

 /// Test Functions

 void DrawArea::print()

 {

     puts("\n----------------Board Content----------------\n");

     printf("     ");

     for(int j=0;j<yMax;++j)printf("%2d ",j);

     printf("\n\n");

     for(int i=0;i<xMax;++i){

         printf("%2d   ",i);

         for(int j=0;j<yMax;++j){

             printf("%2d ",board[i][j]);

             if(j==yMax-1)

             printf("\n");

         }

     }

}

 

 

 

 

0
0

猜你在找
深度学习基础与TensorFlow实践
【在线峰会】前端开发重点难点技术剖析与创新实践
【在线峰会】一天掌握物联网全栈开发之道
【在线峰会】如何高质高效的进行Android技术开发
机器学习40天精英计划
Python数据挖掘与分析速成班
微信小程序开发实战
JFinal极速开发企业实战
备战2017软考 系统集成项目管理工程师 学习套餐
Python大型网络爬虫项目开发实战(全套)
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1036次
    • 积分:29
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档