从零开始学编程

 找回密码
 立即注册

QQ登录

只需一步,快速开始

界面工厂编程视频教程广告联系qq1031180668广告位
查看: 172|回复: 0

[源码分享] c语言连连看游戏源码

[复制链接]
  • ta_mind
    擦汗
    2016-3-2 13:17
  • classn_01: 5 classn_02

    [LV.2]偶尔看看I

    607

    主题

    617

    帖子

    686

    积分

    高级会员

    Rank: 4

    积分
    686
    发表于 2016-12-16 12:48:29 | 显示全部楼层 |阅读模式
    [C] syntaxhighlighter_viewsource syntaxhighlighter_copycode
    /*
    * 连连看游戏C语言源代码
    */
    
    #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;
    getch();
    }







    上一篇:求一份传智播客c++15期 完整未加密版
    下一篇:c语言播放音乐
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Archiver|小黑屋|sitemap|从零开始学编程 ( 豫ICP备15032706号-2 )

    GMT+8, 2017-5-24 23:35 , Processed in 0.093750 second(s), 35 queries .

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表