| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4306 人关注过本帖, 2 人收藏
标题:TC2.0版“连连看”游戏
只看楼主 加入收藏
hoodlum1980
Rank: 2
来 自:浙江大学
等 级:论坛游民
威 望:2
帖 子:289
专家分:23
注 册:2008-2-24
收藏(2)
 问题点数:0 回复次数:19 
TC2.0版“连连看”游戏
昨天想起这个问题。两个晚上进行编码,基本测试完成。核心算法的编码难度感觉还是比俄罗斯方块略大一些,但代码量并不很大。
算法:
   在纸上设计完成后,又简单baidu了下参考了网上某个blog提出的算法,和我设计相同。在两个方块之间寻找路径,主要是基于一种类似贪心策略(最快的找到一条路径,不求最优),又类似穷举法(枚举所有公垂线直到找到通路)。具体实现可见如下代码中的FindPath函数,这是这个小game中的核心算法。看了后面网友的一个回复,算法应该本质相同。因此形式上有很多类似。

重要函数:
FindPath:核心算法。用于查找两个方块之间是否可以消除。
DrawPath:函数接收4个点坐标,用于绘制程序搜索到的一条路径呈现给用户。
InitGame:初始化游戏。为了简单起见,只是采用了几种填充样式来绘制方块,界面美化上还可以更加提升。
DrawBorderRect:由于没有鼠标操作,因此这个函数用于绘制焦点框以提供用户反馈,按方向键可以移动该焦点框。

玩法:
主要功能按键:方向键 - 移动焦点框进行方块选中。被选中的方块用蓝色框框住。红色方框表示当前位置。
              回车键 - 确认选中当前位置的方块,或者尝试消去方块。
              ESC 键 - 结束游戏。

    由于经历有限,这里只完成了最关键的部分,因此需要改进和提升的空间也有很多:例如方块采用图像资源,操作支持鼠标操作,提供难度等级选择等。
代码如下:
程序代码:
/*

 * 连连看游戏(棋盘法)

 * Author:    hoodlum1980

 * Date:        2008.04.23

 * Email:        jinfd@*/

#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>

#define    true    1
#define false    0

/* ---------------------全局变量------------------------------------ */
int BkGndColor=BLACK;
int BorderColor=LIGHTGRAY;
int LineColor=LIGHTBLUE;/* 消除一对方块时时候的连线颜色 */
/* Pb - ProgressBar */
int PbColor=LIGHTGREEN;
int PbY=4;
int PbHeight=4;
int  PbValue;            /* 进度条百分比,初始值为100.*/
long StartTime;        /* 开始时间的秒数,只统计分钟,秒 */
long TotalTime;        /* 游戏总共的最大秒数!,*/

/* BoardDatas: a small-size board */
/* Board[x][y][0] - 0:empty, 1:filled */
/* Board[x][y][1] - cell's key; */
unsigned char Board[10][10][2];
int CellSize=30;
int BoardX=20;
int BoardY=60;
int BoardWidth=10;
int BoardHeight=10;
int CellColor=WHITE;
int SelColor=BLUE;    /* selCell's border rect color */
int CurColor=RED;        /* curCell's border rect color */
int EraColor=CYAN;    /* 用于擦除cell的颜色!*/
int PairsCount;        /* how much pairs we have put on board */

/* 用于存储逻辑坐标(索引) */
typedef struct _tagCELL
{
    char x;
    char y;
} CELL;

CELL selCell,curCell;/*缓存前一个被选中的位置以及当前所处位置!*/

/*Scan Codes Define*/
enum KEYCODES
{
    K_ESC                =0x011b,
    K_UP                =0x4800,        /* upward arrow */
    K_LEFT            =0x4b00,
    K_DOWN            =0x5000,
    K_RIGHT            =0x4d00,
    K_SPACE            =0x3920,
    K_P                    =0x1970,
    K_RETURN        =0x1c0d,        /* Enter */
};



/* ---------------------函数列表------------------------------------ */
void InitGame(char *bgiPath);
void PlayGame();
void QuitGame();
void InitProgressBar();
void UpdateProgressBar(int percent);
void DrawCell(int key,int x,int y,int color);
void EraseCell(int x,int y);
void DrawBorderRect(CELL *c,int color);
void DrawGameOver(char* info);
int  GetKeyCode();
int  FindPath(CELL *c1,CELL *c2);
/*绘制消除方块时候的连接路径!,用指定颜色!*/
void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color);

/* ----------------------函数实现----------------------------------- */

/* ----------------------[ 核心算法 ]---------------------------------

 * 先进行水平方向判断,找出两点所在的水平直线活动范围,

 * 算出这两条线段在垂直方向的共同区域!!!,

 * 遍历该区域判断能否在两线段间架起公垂线,能则两点连接上;

 * 接着进行垂直方向判断,类同。无论两点在不在一条直线上,

 * 都能使用该算法,因为两点同线只是两点作为矩形对角点的特例而已。

 */

/* 找到两个CELL之间的路径,成功返回true */
int FindPath(CELL *c1,CELL *c2)
{
    int i,j,path,min1,max1,min2,max2,left,right,top,bottom;
    /*---------------(0)判断是否点中相同块! ------------*/
    if(Board[c1->x][c1->y][1] != Board[c2->x][c2->y][1])
        return false;
    /*---------------(1)查找水平方向公共区域!-----------*/
    min1=max1=c1->x;
    min2=max2=c2->x;
    while(min1-1>=0 && Board[min1-1][c1->y][0]==0) min1--;
    while(min2-1>=0 && Board[min2-1][c2->y][0]==0) min2--;
    left=max(min1,min2);    /* 左边界 */
    while(max1+1<BoardWidth && Board[max1+1][c1->y][0]==0) max1++;
    while(max2+1<BoardWidth && Board[max2+1][c2->y][0]==0) max2++;
    right=min(max1,max2); /* 右边界 */

    /* 检查两条水平线之间是否有公垂线连通!*/
    /* 可以在边缘连通 */
    if(left==0)
    {
        /* 左边缘连通 */
        DrawPath(c1->x,c1->y,  -1,c1->y,  -1,c2->y,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  -1,c1->y,  -1,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        return true;
    }
    if(right==(BoardWidth-1))
    {
        DrawPath(c1->x,c1->y,  BoardWidth,c1->y,  BoardWidth,c2->y,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  BoardWidth,c1->y,  BoardWidth,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        return true;
    }

    for(i=left;i<=right;i++)
    {
        path=0;/*统计垂直的公垂线长度!*/
        for(j=min(c1->y,c2->y)+1;j<max(c1->y,c2->y);j++)
        {
            path+=Board[i][j][0];
            if(path>0) break;
        }
        if(path==0)
        {
            DrawPath(c1->x,c1->y,  i,c1->y,  i,c2->y,  c2->x,c2->y, LineColor);
            delay(6000);
            DrawPath(c1->x,c1->y,  i,c1->y,  i,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
            return true;
        }
    }

    /*---------------(2)查找垂直方向公共区域!-----------*/
    min1=max1=c1->y;
    min2=max2=c2->y;
    while(min1-1>=0 && Board[c1->x][min1-1][0]==0) min1--;
    while(min2-1>=0 && Board[c2->x][min2-1][0]==0) min2--;
    top=max(min1,min2);
    while(max1+1<BoardHeight && Board[c1->x][max1+1][0]==0) max1++;
    while(max2+1<BoardHeight && Board[c2->x][max2+1][0]==0) max2++;
    bottom=min(max1,max2);

    /* 检查两条垂直线之间是否有公垂线连通!*/
    /* 可以在边缘连通 */
    if(top==0)
    {
        /* 同在顶端消除 */
        DrawPath(c1->x,c1->y,  c1->x,-1,  c2->x,-1,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  c1->x,-1,  c2->x,-1,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        return true;
    }
    if(bottom==(BoardHeight-1))
    {
        DrawPath(c1->x,c1->y,  c1->x,BoardHeight,  c2->x,BoardHeight,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  c1->x,BoardHeight,  c2->x,BoardHeight,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        return true;
    }

    for(j=top;j<=bottom;j++)
    {
        path=0;/*统计水平的公垂线长度!*/
        for(i=min(c1->x,c2->x)+1; i<max(c1->x,c2->x); i++)
        {
            path+=Board[i][j][0];
            if(path>0) break;
        }
        if(path==0)
        {
            /* 水平公垂线 */
            DrawPath(c1->x,c1->y,  c1->x,j,  c2->x,j,  c2->x,c2->y, LineColor);
            delay(6000);
            DrawPath(c1->x,c1->y,  c1->x,j,  c2->x,j,  c2->x,c2->y, BkGndColor);/*插除线条!*/
            return true;
        }
    }

    /* 到达这里说明没有任何通路 */
    return false;
}
/*Get Key Code */
int GetKeyCode()
{
    int key=0;
    if(bioskey(1))
    {
        key=bioskey(0);
    }
    return key;
}

/*绘制消除方块时候的连接路径!,用指定颜色!,坐标是CELL逻辑坐标!*/
void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color)
{
    setcolor(color);
    moveto(BoardX+CellSize/2+CellSize*x1,BoardY+CellSize/2+CellSize*y1);
    lineto(BoardX+CellSize/2+CellSize*x2,BoardY+CellSize/2+CellSize*y2);
    lineto(BoardX+CellSize/2+CellSize*x3,BoardY+CellSize/2+CellSize*y3);
    lineto(BoardX+CellSize/2+CellSize*x4,BoardY+CellSize/2+CellSize*y4);
}


/* congratulations info,the user has success finish the game ! */
void DrawGameOver(char* info)
{
        /*计算棋盘的中心点*/
    int cx=BoardX+CellSize*BoardWidth/2;
    int cy=BoardY+CellSize*BoardHeight/2;
    struct textsettingstype textInfos;
    /*获取此前的文字信息*/
    gettextsettings(&textInfos);
    setcolor(DARKGRAY);
    setfillstyle(SOLID_FILL,BLUE);
    /* 文字居中 */
    rectangle(cx-102,cy-22,cx+102,cy+22);
    floodfill(cx,cy,DARKGRAY);
    rectangle(cx-100,cy-20,cx+100,cy+20);
    settextjustify(CENTER_TEXT,CENTER_TEXT);
    setcolor(LIGHTBLUE);
    outtextxy(cx,cy,info);
    /*restore orignal text settings */
    settextjustify(textInfos.horiz, textInfos.vert);
}

/* draw a focus rect on the cell with the color */
/* 用制定颜色绘制一个选中的外边框 */
void DrawBorderRect(CELL *c,int color)
{
    setcolor(color);
    rectangle(BoardX+(c->x)*CellSize+1, BoardY+(c->y)*CellSize+1, BoardX+(c->x+1)*CellSize-2, BoardY+(c->y+1)*CellSize-2);
    rectangle(BoardX+(c->x)*CellSize,   BoardY+(c->y)*CellSize,   BoardX+(c->x+1)*CellSize-1, BoardY+(c->y+1)*CellSize-1);
}

/* 在x,y处用指定颜色绘制键为key的 CELL,key在2,3,4,5,6,7,8,9,10,11之间随机 */
void DrawCell(int key,int x,int y,int color)
{
    setcolor(color);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
    setfillstyle(key, color);
    floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,color);
}

/* 擦除CELL */
void EraseCell(int x,int y)
{
    setcolor(EraColor);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
    setfillstyle(SOLID_FILL, BkGndColor);
    floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,EraColor);
    setcolor(BkGndColor);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
}


/* 初始化进度条 */
void InitProgressBar()
{
    int width=CellSize*BoardWidth;
    /* progress bar border rect */
    setcolor(BorderColor);
    rectangle(BoardX-2,PbY-2,BoardX+width+2,PbY+PbHeight+2);

    /* draw a value = 100% progress bar */
    setcolor(PbColor);
    rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);
    setfillstyle(SOLID_FILL,PbColor);
    floodfill(BoardX+1,PbY+1,PbColor);
}

/* 更新进度条,设置为某个百分比 */
void UpdateProgressBar(int percent)
{
    int p=percent;
    int width;
    if(percent<0) p=0;
    else if(percent>100) p=100;
    width=BoardWidth*percent/100*CellSize;

    setfillstyle(SOLID_FILL,BkGndColor);
    floodfill(BoardX+1,PbY+1,BorderColor);

    if(width<2) return;/* too small value? */
    setcolor(PbColor);
    rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);
    setfillstyle(SOLID_FILL,PbColor);
    floodfill(BoardX+1,PbY+1,PbColor);
}


/* 初始化程序 */
void InitGame(char *bgiPath)
{
    int gdriver=DETECT,gmode,i,x,y,key;
    struct time sysTime;
    /*清空棋盘数据!*/
    memset(Board,0,sizeof(Board[0][0][0]*BoardWidth*BoardHeight*2));
    /* set new seed! */
    gettime(&sysTime);
    srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec);

    /* enter graphics mode */
    initgraph(&gdriver,&gmode,bgiPath);
    PairsCount=BoardWidth*BoardHeight/4;
    for(i=0; i<PairsCount; i++)
    {
        key=random(10)+2;
        /* fill first cell of pair */
        do
        {
            x=random(BoardWidth);
            y=random(BoardHeight);
        }
        while(Board[x][y][0]!=0);
        DrawCell(key,x,y,CellColor);
        Board[x][y][0]=1;
        Board[x][y][1]=key;

        /* fill second cell of pair */
        do
        {
            x=random(BoardWidth);
            y=random(BoardHeight);
        }
        while(Board[x][y][0]!=0);
        DrawCell(key,x,y,CellColor);
        Board[x][y][0]=1;
        Board[x][y][1]=key;
    }
    setcolor(YELLOW);
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+30,"Press ESC to Exit!");
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+42,"ArrowKeys to move, Enter to Confirm.");
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+54,"--by Hoodlum1980");
    PbValue=100;
    TotalTime=3*60; /*  Total minutes. */
    gettime(&sysTime);
    StartTime=sysTime.ti_min*60+sysTime.ti_sec;
}

/* 游戏进行 */
void PlayGame()
{
    int key,percent;
    long curTime;
    struct time sysTime;
    curCell.x = curCell.y = 0;/*当前所处位置!*/
    selCell.x = selCell.y = -1;/*为-1表示当前未选中*/
    DrawBorderRect(&curCell, CurColor);

    /*用一个循环检测按键!*/
    while(key!=K_ESC)
    {
        /* wait until a key pressed */
        while(!(key=GetKeyCode()))
        {
            gettime(&sysTime);
            curTime=sysTime.ti_min*60+sysTime.ti_sec;
            percent=(int)((1-(curTime-StartTime)*1.0/TotalTime)*100);
            if(percent<=1)
            {
                DrawGameOver("YOU HAVE LOSE!");
                return;
            }
            else if(percent!=PbValue)
            {
                UpdateProgressBar(percent);
                PbValue=percent;/* update cache PbValue */
            }
            delay(1000);
        }
        /* 这时用户按下了某个键 */

        /*需要恢复的是此前选中的cell!*/
        if(curCell.x==selCell.x && curCell.y==selCell.y)
            DrawBorderRect(&curCell, SelColor); /*恢复选中cell的focus痕迹 */
        else
            DrawBorderRect(&curCell, BkGndColor); /*擦除此前的focus痕迹 */
        switch(key)
        {
            case K_LEFT:
                curCell.x--;
                if(curCell.x < 0) curCell.x += BoardWidth;
                break;
            case K_RIGHT:
                curCell.x++;
                if(curCell.x >= BoardWidth) curCell.x -= BoardWidth;
                break;
            case K_UP:
                curCell.y--;
                if(curCell.y < 0) curCell.y += BoardHeight;
                break;
            case K_DOWN:
                curCell.y++;
                if(curCell.y >= BoardHeight) curCell.y -= BoardHeight;
                break;

            /* 对回车键 */
            case K_RETURN:
                /* 如果此处没有任何cell,不处理! */
                if(Board[curCell.x][curCell.y][0]==0)
                    break;
                /* 与此前选中的位置重合,则不处理 */
                if(curCell.x==selCell.x && curCell.y==selCell.y)
                    break;
                /*如果此前没有任何选中,则设置改点为选中位置*/
                if(selCell.x<0 || selCell.y<0)
                {
                    selCell.x=curCell.x;
                    selCell.y=curCell.y;
                    DrawBorderRect(&selCell,SelColor);
                    continue;
                }
                /*如果此前已有选中,则判断是否可以消除!*/
                if(FindPath(&selCell,&curCell))
                {
                    /* 消除这两个cell!*/
                    EraseCell(selCell.x,selCell.y);
                    EraseCell(curCell.x,curCell.y);
                    /* 清除棋盘数据 */
                    Board[selCell.x][selCell.y][0]=0;
                    Board[selCell.x][selCell.y][1]=0;
                    Board[curCell.x][curCell.y][0]=0;
                    Board[curCell.x][curCell.y][1]=0;
                    /* 清除selCell */
                    DrawBorderRect(&selCell,BkGndColor);
                    selCell.x=selCell.y=-1;
                    /* decrease the pairs count */
                    PairsCount--;
                    if(PairsCount==0)
                    {
                        DrawGameOver("CONGRATULATIONS!");
                        return;
                    }
                }
                else
                {
                    /* 不能消除这两个cell!*/
                    /* erase the selCell's focus rect!*/
                    DrawBorderRect(&selCell,BkGndColor);
                    selCell.x=selCell.y=-1;
                }
                break;
            case K_ESC:
                DrawGameOver("GAME OVER!");
                break;
            default:
                break;
        }
        /*绘制当前focus位置*/
        DrawBorderRect(&curCell, CurColor);
    }
}

/* 退出程序 */
void QuitGame()
{
    closegraph();
}

/* Entry Point */
int main(int argc,char *argv[])
{
    InitGame("");
    InitProgressBar();
    PlayGame();
    getch();
    QuitGame();
    return 0;
}


[[it] 本帖最后由 hoodlum1980 于 2008-4-25 10:14 编辑 [/it]]

连连看TC_hoodlum1980.rar (56.77 KB)


程序截图.JPG (21.9 KB)
图片附件: 游客没有浏览图片的权限,请 登录注册
搜索更多相关主题的帖子: 连连看 游戏 
2008-04-24 23:33
moonwalker
Rank: 1
等 级:新手上路
威 望:1
帖 子:909
专家分:2
注 册:2007-3-2
收藏
得分:0 
支持一下

“视频教程网”免费提供教学资源
C不限制你的自由!
条件是自己承担滥用自由的恶果!
2008-04-24 23:42
雨中飛燕
Rank: 1
等 级:新手上路
帖 子:765
专家分:0
注 册:2007-10-13
收藏
得分:0 
哈哈,找最优(最短连线)其实好简单的
有方向限制的BFS

" border="0" />[color=white]

[[it] 本帖最后由 雨中飛燕 于 2008-4-24 23:47 编辑 [/it]]
2008-04-24 23:46
雨中飛燕
Rank: 1
等 级:新手上路
帖 子:765
专家分:0
注 册:2007-10-13
收藏
得分:0 
/*
* 连连看游戏(棋盘法)
* Author:    hoodlum1980
* Date:      2008.04.23
* Email:     jinfd@
*/

#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>

#define true     1
#define false    0

/* ---------------------全局变量------------------------------------ */
int BkGndColor=BLACK;
int BorderColor=LIGHTGRAY;
int LineColor=LIGHTBLUE;/* 消除一对方块时时候的连线颜色 */
/* Pb - ProgressBar */
int PbColor=LIGHTGREEN;
int PbY=4;
int PbHeight=4;
int  PbValue;          /* 进度条百分比,初始值为100.*/
long StartTime;        /* 开始时间的秒数,只统计分钟,秒 */
long TotalTime;        /* 游戏总共的最大秒数!,*/

/* BoardDatas: a small-size board */
/* Board[x][y][0] - 0:empty, 1:filled (unselected) 2: filled (selected); */
/* Board[x][y][1] - cell's key; */
/* 请注意边缘留空了,为了绘制路径 */
unsigned char Board[10][10][2];
int CellSize=30;
int BoardX=20;
int BoardY=60;
int BoardWidth=10;
int BoardHeight=10;
int CellColor=WHITE;
int SelColor=BLUE;      /* selCell's border rect color */
int CurColor=RED;       /* curCell's border rect color */
int EraColor=CYAN;      /* 用于擦除cell的颜色!*/
int PairsCount;         /* how much pairs we have put on board */

/* 用于存储逻辑坐标(索引) */
typedef struct _tagCELL
{
    char x;
    char y;
} CELL;

CELL selCell,curCell;/*缓存前一个被选中的位置以及当前所处位置!*/

/*Scan Codes Define*/
enum KEYCODES
{
    K_ESC               =0x011b,
    K_UP                =0x4800,        /* upward arrow */
   
K_LEFT              =0x4b00,
    K_DOWN              =0x5000,
    K_RIGHT             =0x4d00,
    K_SPACE             =0x3920,
    K_P                 =0x1970,
    K_RETURN            =0x1c0d,        /* Enter */
};



/* ---------------------函数列表------------------------------------ */
void InitGame(char *bgiPath);
void PlayGame();
void QuitGame();
void InitProgressBar();
void UpdateProgressBar(int percent);
void DrawCell(int key,int x,int y,int color);
void EraseCell(int x,int y);
void DrawBorderRect(CELL *c,int color);
void DrawGameOver(char* info);
int  GetKeyCode();
int  FindPath(CELL *c1,CELL *c2);
/*绘制消除方块时候的连接路径!,用指定颜色!*/
void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color);

/* ----------------------函数实现----------------------------------- */

/* ----------------------[ 核心算法 ]---------------------------------
* 先进行水平方向判断,找出两点所在的水平直线活动范围,
* 算出这两条线段在垂直方向的共同区域!!!,
* 遍历该区域判断能否在两线段间架起公垂线,能则两点连接上;
* 接着进行垂直方向判断,类同。无论两点在不在一条直线上,
* 都能使用该算法,因为两点同线只是两点作为矩形对角点的特例而已。
*/

/* 找到两个CELL之间的路径,成功返回true */
int FindPath(CELL *c1,CELL *c2)
{
    int i,j,path,min1,max1,min2,max2,left,right,top,bottom;
    /*---------------(0)判断是否点中相同块! ------------*/
   
if (Board[c1->x][c1->y][1] != Board[c2->x][c2->y][1])
        return false;
    /*---------------(1)查找水平方向公共区域!-----------*/
   
min1=max1=c1->x;
    min2=max2=c2->x;
    while (min1-1>=0 && Board[min1-1][c1->y][0]==0) min1--;
    while (min2-1>=0 && Board[min2-1][c2->y][0]==0) min2--;
    left=max(min1,min2);    /* 左边界 */
   
while (max1+1<BoardWidth && Board[max1+1][c1->y][0]==0) max1++;
    while (max2+1<BoardWidth && Board[max2+1][c2->y][0]==0) max2++;
    right=min(max1,max2); /* 右边界 */

    /* 检查两条水平线之间是否有公垂线连通!*/
    /* 可以在边缘连通 */
   
if (left==0)
    {
        /* 左边缘连通 */
        
DrawPath(c1->x,c1->y,  -1,c1->y,  -1,c2->y,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  -1,c1->y,  -1,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        
return true;
    }
    if (right==(BoardWidth-1))
    {
        DrawPath(c1->x,c1->y,  BoardWidth,c1->y,  BoardWidth,c2->y,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  BoardWidth,c1->y,  BoardWidth,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        
return true;
    }

    for (i=left;i<=right;i++)
    {
        path=0;/*统计垂直的公垂线长度!*/
        
for (j=min(c1->y,c2->y)+1;j<max(c1->y,c2->y);j++)
        {
            path+=Board[i][j][0];
            if (path>0) break;
        }
        if (path==0)
        {
            DrawPath(c1->x,c1->y,  i,c1->y,  i,c2->y,  c2->x,c2->y, LineColor);
            delay(6000);
            DrawPath(c1->x,c1->y,  i,c1->y,  i,c2->y,  c2->x,c2->y, BkGndColor);/*插除线条!*/
            
return true;
        }
    }

    /*---------------(2)查找垂直方向公共区域!-----------*/
   
min1=max1=c1->y;
    min2=max2=c2->y;
    while (min1-1>=0 && Board[c1->x][min1-1][0]==0) min1--;
    while (min2-1>=0 && Board[c2->x][min2-1][0]==0) min2--;
    top=max(min1,min2);
    while (max1+1<BoardHeight && Board[c1->x][max1+1][0]==0) max1++;
    while (max2+1<BoardHeight && Board[c2->x][max2+1][0]==0) max2++;
    bottom=min(max1,max2);

    /* 检查两条垂直线之间是否有公垂线连通!*/
    /* 可以在边缘连通 */
   
if (top==0)
    {
        /* 同在顶端消除 */
        
DrawPath(c1->x,c1->y,  c1->x,-1,  c2->x,-1,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  c1->x,-1,  c2->x,-1,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        
return true;
    }
    if (bottom==(BoardHeight-1))
    {
        DrawPath(c1->x,c1->y,  c1->x,BoardHeight,  c2->x,BoardHeight,  c2->x,c2->y, LineColor);
        delay(6000);
        DrawPath(c1->x,c1->y,  c1->x,BoardHeight,  c2->x,BoardHeight,  c2->x,c2->y, BkGndColor);/*插除线条!*/
        
return true;
    }

    for (j=top;j<=bottom;j++)
    {
        path=0;/*统计水平的公垂线长度!*/
        
for (i=min(c1->x,c2->x)+1; i<max(c1->x,c2->x); i++)
        {
            path+=Board[i][j][0];
            if (path>0) break;
        }
        if (path==0)
        {
            /* 水平公垂线 */
            
DrawPath(c1->x,c1->y,  c1->x,j,  c2->x,j,  c2->x,c2->y, LineColor);
            delay(6000);
            DrawPath(c1->x,c1->y,  c1->x,j,  c2->x,j,  c2->x,c2->y, BkGndColor);/*插除线条!*/
            
return true;
        }
    }

    /* 到达这里说明没有任何通路 */
   
return false;
}
/*Get Key Code */
int GetKeyCode()
{
    int key=0;
    if (bioskey(1))
    {
        key=bioskey(0);
    }
    return key;
}

/*绘制消除方块时候的连接路径!,用指定颜色!,坐标是CELL逻辑坐标!*/
void DrawPath(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,int color)
{
    setcolor(color);
    moveto(BoardX+CellSize/2+CellSize*x1,BoardY+CellSize/2+CellSize*y1);
    lineto(BoardX+CellSize/2+CellSize*x2,BoardY+CellSize/2+CellSize*y2);
    lineto(BoardX+CellSize/2+CellSize*x3,BoardY+CellSize/2+CellSize*y3);
    lineto(BoardX+CellSize/2+CellSize*x4,BoardY+CellSize/2+CellSize*y4);
}


/* congratulations info,the user has success finish the game ! */
void DrawGameOver(char* info)
{
    /*计算棋盘的中心点*/
   
int cx=BoardX+CellSize*BoardWidth/2;
    int cy=BoardY+CellSize*BoardHeight/2;
    struct textsettingstype textInfos;
    /*获取此前的文字信息*/
   
gettextsettings(&textInfos);
    setcolor(DARKGRAY);
    setfillstyle(SOLID_FILL,BLUE);
    /* 文字居中 */
   
rectangle(cx-102,cy-22,cx+102,cy+22);
    floodfill(cx,cy,DARKGRAY);
    rectangle(cx-100,cy-20,cx+100,cy+20);
    settextjustify(CENTER_TEXT,CENTER_TEXT);
    setcolor(LIGHTBLUE);
    outtextxy(cx,cy,info);
    /*restore orignal text settings */
   
settextjustify(textInfos.horiz, textInfos.vert);
}

/* draw a focus rect on the cell with the color */
/* 用制定颜色绘制一个选中的外边框 */
void DrawBorderRect(CELL *c,int color)
{
    setcolor(color);
    rectangle(BoardX+(c->x)*CellSize+1, BoardY+(c->y)*CellSize+1, BoardX+(c->x+1)*CellSize-2, BoardY+(c->y+1)*CellSize-2);
    rectangle(BoardX+(c->x)*CellSize,   BoardY+(c->y)*CellSize,   BoardX+(c->x+1)*CellSize-1, BoardY+(c->y+1)*CellSize-1);
}

/* 在x,y处用指定颜色绘制键为key的 CELL,key在2,3,4,5,6,7,8,9,10,11之间随机 */
void DrawCell(int key,int x,int y,int color)
{
    setcolor(color);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
    setfillstyle(key, color);
    floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,color);
}

/* 擦除CELL */
void EraseCell(int x,int y)
{
    setcolor(EraColor);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
    setfillstyle(SOLID_FILL, BkGndColor);
    floodfill(BoardX+x*CellSize+3, BoardY+y*CellSize+3,EraColor);
    setcolor(BkGndColor);
    rectangle(BoardX+x*CellSize+2, BoardY+y*CellSize+2, BoardX+(x+1)*CellSize-3, BoardY+(y+1)*CellSize-3);
}


/* 初始化进度条 */
void InitProgressBar()
{
    int width=CellSize*BoardWidth;
    /* progress bar border rect */
   
setcolor(BorderColor);
    rectangle(BoardX-2,PbY-2,BoardX+width+2,PbY+PbHeight+2);

    /* draw a value = 100% progress bar */
   
setcolor(PbColor);
    rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);
    setfillstyle(SOLID_FILL,PbColor);
    floodfill(BoardX+1,PbY+1,PbColor);
}

/* 更新进度条,设置为某个百分比 */
void UpdateProgressBar(int percent)
{
    int p=percent;
    int width;
    if (percent<0) p=0;
    else if (percent>100) p=100;
    width=BoardWidth*percent/100*CellSize;

    setfillstyle(SOLID_FILL,BkGndColor);
    floodfill(BoardX+1,PbY+1,BorderColor);

    if (width<2) return;/* too small value? */
   
setcolor(PbColor);
    rectangle(BoardX,PbY,BoardX+width,PbY+PbHeight);
    setfillstyle(SOLID_FILL,PbColor);
    floodfill(BoardX+1,PbY+1,PbColor);
}


/* 初始化程序 */
void InitGame(char *bgiPath)
{
    int gdriver=DETECT,gmode,i,x,y,key;
    struct time sysTime;
    /*清空棋盘数据!*/
   
memset(Board,0,sizeof(Board[0][0][0]*BoardWidth*BoardHeight*2));
    /* set new seed! */
   
gettime(&sysTime);
    srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec);

    /* enter graphics mode */
   
initgraph(&gdriver,&gmode,bgiPath);
    PairsCount=BoardWidth*BoardHeight/4;
    for (i=0; i<PairsCount; i++)
    {
        key=random(10)+2;
        /* fill first cell of pair */
        
do
        
{
            x=random(BoardWidth);
            y=random(BoardHeight);
        }
        while (Board[x][y][0]!=0);
        DrawCell(key,x,y,CellColor);
        Board[x][y][0]=1;
        Board[x][y][1]=key;

        /* fill second cell of pair */
        
do
        
{
            x=random(BoardWidth);
            y=random(BoardHeight);
        }
        while (Board[x][y][0]!=0);
        DrawCell(key,x,y,CellColor);
        Board[x][y][0]=1;
        Board[x][y][1]=key;
    }
    setcolor(YELLOW);
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+30,"Press ESC to Exit!");
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+42,"ArrowKeys to move, Enter to Confirm.");
    outtextxy(BoardX,BoardY+BoardHeight*CellSize+54,"--by Hoodlum1980");
    PbValue=100;
    TotalTime=3*60; /*  Total minutes. */
   
gettime(&sysTime);
    StartTime=sysTime.ti_min*60+sysTime.ti_sec;
}

/* 游戏进行 */
void PlayGame()
{
    int key,percent;
    long curTime;
    struct time sysTime;
    curCell.x = curCell.y = 0;/*当前所处位置!*/
   
selCell.x = selCell.y = -1;/*为-1表示当前未选中*/
   
DrawBorderRect(&curCell, CurColor);

    /*用一个循环检测按键!*/
   
while (key!=K_ESC)
    {
        /* wait until a key pressed */
        
while (!(key=GetKeyCode()))
        {
            gettime(&sysTime);
            curTime=sysTime.ti_min*60+sysTime.ti_sec;
            percent=(int)((1-(curTime-StartTime)*1.0/TotalTime)*100);
            if (percent<=1)
            {
                DrawGameOver("YOU HAVE LOSE!");
                return;
            }
            else if (percent!=PbValue)
            {
                UpdateProgressBar(percent);
                PbValue=percent;/* update cache PbValue */
            
}
            delay(1000);
        }
        /* 这时用户按下了某个键 */

        /*需要恢复的是此前选中的cell!*/
        
if (curCell.x==selCell.x && curCell.y==selCell.y)
            DrawBorderRect(&curCell, SelColor); /*恢复选中cell的focus痕迹 */
        
else
            
DrawBorderRect(&curCell, BkGndColor); /*擦除此前的focus痕迹 */
        
switch (key)
        {
        case K_LEFT:
            curCell.x--;
            if (curCell.x < 0) curCell.x += BoardWidth;
            break;
        case K_RIGHT:
            curCell.x++;
            if (curCell.x >= BoardWidth) curCell.x -= BoardWidth;
            break;
        case K_UP:
            curCell.y--;
            if (curCell.y < 0) curCell.y += BoardHeight;
            break;
        case K_DOWN:
            curCell.y++;
            if (curCell.y >= BoardHeight) curCell.y -= BoardHeight;
            break;

            /* 对回车键 */
        
case K_RETURN:
            /* 如果此处没有任何cell,不处理! */
            
if (Board[curCell.x][curCell.y][0]==0)
                break;
            /* 与此前选中的位置重合,则不处理 */
            
if (curCell.x==selCell.x && curCell.y==selCell.y)
                break;
            /*如果此前没有任何选中,则设置改点为选中位置*/
            
if (selCell.x<0 || selCell.y<0)
            {
                selCell.x=curCell.x;
                selCell.y=curCell.y;
                DrawBorderRect(&selCell,SelColor);
                continue;
            }
            /*如果此前已有选中,则判断是否可以消除!*/
            
if (FindPath(&selCell,&curCell))
            {
                /* 消除这两个cell!*/
               
EraseCell(selCell.x,selCell.y);
                EraseCell(curCell.x,curCell.y);
                /* 清除棋盘数据 */
               
Board[selCell.x][selCell.y][0]=0;
                Board[selCell.x][selCell.y][1]=0;
                Board[curCell.x][curCell.y][0]=0;
                Board[curCell.x][curCell.y][1]=0;
                /* 清除selCell */
               
DrawBorderRect(&selCell,BkGndColor);
                selCell.x=selCell.y=-1;
                /* decrease the pairs count */
               
PairsCount--;
                if (PairsCount==0)
                {
                    DrawGameOver("CONGRATULATIONS!");
                    return;
                }
            }
            else
            
{
                /* 不能消除这两个cell!*/
                /* erase the selCell's focus rect!*/
               
DrawBorderRect(&selCell,BkGndColor);
                selCell.x=selCell.y=-1;
            }
            break;
        case K_ESC:
            DrawGameOver("GAME OVER!");
            break;
        default:
            break;
        }
        /*绘制当前focus位置*/
        
DrawBorderRect(&curCell, CurColor);
    }
}

/* 退出程序 */
void QuitGame()
{
    closegraph();
}

/* Entry Point */
int main(int argc,char *argv[])
{
    InitGame("");
    InitProgressBar();
    PlayGame();
    getch();
    QuitGame();
    return 0;
}


" border="0" />[color=white]

[[it] 本帖最后由 雨中飛燕 于 2008-4-24 23:53 编辑 [/it]]
2008-04-24 23:49
StarWing83
Rank: 8Rank: 8
来 自:仙女座大星云
等 级:贵宾
威 望:19
帖 子:3951
专家分:748
注 册:2007-11-16
收藏
得分:0 
inline int LLKCore::Search(Aspect f,LLKNode pbeg,LLKNode& pret)
{
    int bc=0;
    switch (f)
    {
    case LEFT:
        while (--pbeg.x>=-1 && Loc(N2L(pbeg)) == NOICON)
            if (++bc,pbeg.x==-1)break;
        break;
    case RIGHT:
        while (++pbeg.x<=cx && Loc(N2L(pbeg)) == NOICON)
            if (++bc,pbeg.x==cx)break;
        break;
    case UP:
        while (--pbeg.y>=-1 && Loc(N2L(pbeg)) == NOICON)
            if (++bc,pbeg.y==-1)break;
        break;
    case DOWN:
        while (++pbeg.y<=cy && Loc(N2L(pbeg)) == NOICON)
            if (++bc,pbeg.y==cy)break;
        break;
    }
    pret=pbeg;
    return bc;
}
inline int LLKCore::CheckHLine(LLKNode& p1,LLKNode &p2,pv& vec)
{
    LLKNode pp;
    int p1ub,p2ub,p1db,p2db,beg,end;
    p1ub=p1.y-Search(UP,p1,pp);
    p1db=p1.y+Search(DOWN,p1,pp);
    p2ub=p2.y-Search(UP,p2,pp);
    p2db=p2.y+Search(DOWN,p2,pp);

    //连通域不相交
    if (p1ub>p2db || p2ub>p1db)
        return false;

    //上界,选比较大的
    if (p1ub>p2ub) beg=p1ub;
    else beg=p2ub;
    //下界,选比较小的
    if (p1db<p2db) end=p1db;
    else end=p2db;

    for (int i=beg;i<=end;i++)
    {
        int step=Search(RIGHT,LLKNode(p1.x,i),pp);
        if (pp==p2 || (step && pp.x>p2.x) )
        {
            vec.clear();
            vec.push_back(p1);
            if (i!=p1.y)vec.push_back(LLKNode(p1.x,i));
            if (i!=p2.y)vec.push_back(LLKNode(p2.x,i));
            vec.push_back(p2);
            return true;
        }
    }
    return false;
}
inline int LLKCore::CheckVLine(LLKNode& p1,LLKNode &p2,pv& vec)
{
    LLKNode pp;
    int p1lb,p2lb,p1rb,p2rb,beg,end;
    p1lb=p1.x-Search(LEFT,p1,pp);
    p1rb=p1.x+Search(RIGHT,p1,pp);
    p2lb=p2.x-Search(LEFT,p2,pp);
    p2rb=p2.x+Search(RIGHT,p2,pp);

    //连通域不相交
    if (p1lb>p2rb || p2lb>p1rb)
        return false;

    //上界,选比较大的
    if (p1lb>p2lb) beg=p1lb;
    else beg=p2lb;
    //下界,选比较小的
    if (p1rb<p2rb) end=p1rb;
    else end=p2rb;

    for (int i=beg;i<=end;i++)
    {
        int step=Search(DOWN,LLKNode(i,p1.y),pp);
        if (pp==p2 || (step && pp.y>p2.y) )
        {
            vec.clear();
            vec.push_back(p1);
            if (i!=p1.x)vec.push_back(LLKNode(i,p1.y));
            if (i!=p2.x)vec.push_back(LLKNode(i,p2.y));
            vec.push_back(p2);
            return true;
        }
    }
    return false;
}
inline int LLKCore::Check(LLKNode& p1,LLKNode& p2,pv& vec)
{
    if (p1 == p2 || Loc(N2L(p1))!=Loc(N2L(p2)) || Loc(N2L(p1))==NOICON)
        return false;
    if (p1.x == p2.x)
    {
        if (abs(p2.y-p1.y) == 1)
        {
            vec.clear();
            vec.push_back(p1);
            vec.push_back(p2);
            return true;
        }
        if (p1.y > p2.y) //p2在p1上方
            return CheckVLine(p2,p1,vec);
        else //p2在p1下方
            return CheckVLine(p1,p2,vec);
    }
    else if (p1.y == p2.y)
    {
        if (abs(p2.x-p1.x) == 1)
        {
            vec.clear();
            vec.push_back(p1);
            vec.push_back(p2);
            return true;
        }
        if (p1.x > p2.x) //p2在p1的左边
            return CheckHLine(p2,p1,vec);
        else //p2在p1的右边
            return CheckHLine(p1,p2,vec);
    }
    else
    {
        if (p1.x > p2.x)
            if (p1.y > p2.y) //p2在p1的左上
                return CheckHLine(p2,p1,vec)
                       || CheckVLine(p2,p1,vec);
            else//p2在p1的左下
                return CheckHLine(p2,p1,vec)
                       || CheckVLine(p1,p2,vec);
        else
            if (p1.y > p2.y) //p2在p1的右上
                return CheckHLine(p1,p2,vec)
                       || CheckVLine(p2,p1,vec);
            else //p2在p1的右下
                return CheckHLine(p1,p2,vec)
                       || CheckVLine(p1,p2,vec);
    }
}

很久很久以前写的……好像被我太监了……有时间再来改吧……

专心编程………
飞燕算法初级群:3996098
我的Blog
2008-04-25 00:02
hoodlum1980
Rank: 2
来 自:浙江大学
等 级:论坛游民
威 望:2
帖 子:289
专家分:23
注 册:2008-2-24
收藏
得分:0 
感谢楼上为代码上色。:)
2008-04-25 00:03
moonwalker
Rank: 1
等 级:新手上路
威 望:1
帖 子:909
专家分:2
注 册:2007-3-2
收藏
得分:0 
[bo]以下是引用 [un]雨中飛燕[/un] 在 2008-4-24 23:46 的发言:[/bo]

哈哈,找最优(最短连线)其实好简单的
有方向限制的BFS

http://blog.

这里不用找最短吧?有解即可。

“视频教程网”免费提供教学资源
C不限制你的自由!
条件是自己承担滥用自由的恶果!
2008-04-25 00:45
neverTheSame
Rank: 3Rank: 3
来 自:江西农业大学
等 级:新手上路
威 望:9
帖 子:1511
专家分:0
注 册:2006-11-24
收藏
得分:0 
真的很不错.
TOP

wap酷禾网(http://wap.),提供免费的、优质的、快捷的wap资源下载服务。
2008-04-25 01:35
awsw911
Rank: 1
等 级:新手上路
帖 子:19
专家分:0
注 册:2008-2-27
收藏
得分:0 
刚才都试了一下
都可以
好强悍的人啦 !
有空多教教我啊
2008-04-25 10:35
upperc
Rank: 1
等 级:新手上路
帖 子:17
专家分:7
注 册:2008-4-24
收藏
得分:0 
学习当中。。。。。。。。。。。。。。。。。。。。。。
2008-04-25 11:53
快速回复:TC2.0版“连连看”游戏
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.053988 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved