连连看游戏,2点是否可消除算法分析

现在在看郁金香的VC外挂教程,其中对于连连看外挂
在此感谢这位兄弟http://bbs.pediy.com/showthread.php?...8%8B+%E7%A8%8B
提供的下载地址,现在学习中……

言归正传,这个外挂的最难的就是检查2点是不是可以联通的算法,我们就来研究这一点
这个游戏,发现2点之间连接线段数需要满足 <= 3 这个条件
如图1:


我们先来谈谈3条线段的情况,先假设,棋盘上除了这2点以外全部为空,这2点分别用p1,p2表示,并显示坐标,那么在连接线段数<= 3 的情况下,一共有多少种路径呢?
如图2:


我们来思考一下,以下是所有路径,如图3:

(路径用绿线表示)可以看到这不是一两种的问题,而是由很多种,其中我用深颜色的线画出了几条有代表性的路径,

仔细的看图就会发现其中有规律可寻,看图4:

我标出了其中比较重要的4个点!~

这4个点分别是p1,p2在坐标轴上的投影,分别用 px1,px2(表示在x轴上的投影),py1,py2(表示y轴上的投影) 如图5:

先来分析px1,px2可以从图3上清楚的看到,联通路径上的有一部分就是就是线段px1,px2,或者是它的平行线!~
再分析py1,py2 也是一样的道理

我们再来分析一下px1,px2,py1,py2的坐标情况,如果已知p1(x1,y1),p2(x2,y2)的坐标,那么px1,px2,py1,py2坐标是什么呢?
只要有几何的初步知识就可以知道px1(x1,0),px2(x2,0),py1(0,y1),py2(0,y2)

那么分析上面的一大堆对于我们有什么用呢?
答案是肯定有用!~

看图6:



图中连通的路径由3条线段,有4个点组成,只要判断线段1,2,3,是否连通,就可以判断2点是否可以连通了!~

实际上分析,每个人都可以分析的头头是道,编程最难的就是怎么样把分析好的数学模型通过编程来实现,分析是不需要考虑很多的细节问题的,而编程实现需要考虑很多的细节问题!~

那这样的话,就需要先写一个判断2点是否可以连通的函数了!~
好了我们下面来实现这个函数:
注:我用的是VC6.0

代码:
bool LineIfConnect(POINT Point1, POINT Point2, byte ChessData[10][18])
{
    /* 功能   :检查Point1,Point2是否连通(2点之间连线的数值是不是为NULL,包括这2点自身)
     * 
     * 参数1  :第1点
     * 参数2  :第2点
     * 对于参数的要求:Point1.x == Point2.x || Point1.y == Point2.y
     * 参数3  :检测2点所在的数组(棋盘)
     * 
     * 返回值 :true 表示可以连通,false 表示不可以连通
     * */
    int i;
    if ((Point1.x == Point2.x) && (Point1.y != Point2.y))    // 横坐标相同,纵坐标不同
    {
        if (Point1.y < Point2.y)    // point1 在 point2 上方
        {
            for (i = Point1.y; i <= Point2.y; i++)    // for循环检测2点之间的所有元素
                if (ChessData[i][Point1.x] != NULL)
                    return false;
        }
        else if (Point1.y > Point2.y)    // point1 在 point2 下方
        {
            for (i = Point2.y; i <= Point1.y; i++)    // for循环检测2点之间的所有元素
                if (ChessData[i][Point1.x] != NULL)
                    return false;
        }
    }
    else if ((Point1.x != Point2.x) && (Point1.y == Point2.y))    // 横坐标不同,纵坐标相同
    {
        if (Point1.x < Point2.x)    // point1 在 point2 左边
        {
            for (i = Point1.x; i <= Point2.x; i++)
                if (ChessData[Point1.y][i] != NULL)
                    return false;
        }
        else if (Point1.x > Point2.x)    // // point1 在 point2 右边
        {
            for (i = Point2.x; i <= Point1.x; i++)    // for循环检测2点之间的所有元素
                if (ChessData[i][Point1.x] != NULL)
                    return false;
        }
    }
    else if ((Point1.x == Point2.x) && (Point1.y == Point2.y))  // 2点为同一点的情况
        return true;
    else
        return false;

    return true;
}
有了上面这个函数,我们就可以真正编写qq连连看中2点是否可以消除了的函数了,代码如下:
代码:
bool DecideChessIfRemove(POINT Point1, POINT Point2, byte ChessData[10][18])
{
    /* 功能   :检查Point1,Point2是否可以消除
     * 
     * 参数1  :第1点
     * 参数2  :第2点
     * 参数3  :检测2点所在的数组(棋盘)
     * 
     * 返回值 :true 表示可以消除,false 表示不可以消除
     * */
    int x1 = Point1.x;
    int y1 = Point1.y;     // Point1 == (x1, y1)
    int x2 = Point2.x;
    int y2 = Point2.y;     // Point2 == (x2, y2)
    int i, j;
    POINT p1, p2;
    byte point1 = ChessData[Point1.y][Point1.x];
    byte point2 = ChessData[Point2.y][Point2.x];
    ChessData[Point1.y][Point1.x] = ChessData[Point2.y][Point2.x] = NULL;      // 2点在数组的位置设为NULL
    p1.y = y1;
    p2.y = y2;
    for (i = 0; i <= 18; i++)   // 横坐标在变 下面的两个for循环是关键,线段py1,py2在平移
    {
        p1.x = i;    // p1 = (i, y1)
        p2.x = i;    // p2 = (i, y2)
        if (LineIfConnect(p1, p2, ChessData))
            if ((LineIfConnect(Point1, p1, ChessData)) && (LineIfConnect(Point2, p2, ChessData)))
            {
                ChessData[Point1.y][Point1.x] = point1;
                ChessData[Point2.y][Point2.x] = point2;
                return true;
            }
    }
    
    p1.x = x1;
    p2.x = x2;
    for (j = 0; j <=10; j++)    // 纵坐标在变 , 线段px1,px2 在平移
    {
        p1.y = j;   // p1 = (x1, j)
        p2.y = j;   // p2 = (x2, j)
        if (LineIfConnect(p1, p2, ChessData))
            if ((LineIfConnect(Point1, p1, ChessData)) && (LineIfConnect(Point2, p2, ChessData)))
            {
                ChessData[Point1.y][Point1.x] = point1;
                ChessData[Point2.y][Point2.x] = point2;
                return true;
            }
    }
                
    ChessData[Point1.y][Point1.x] = point1;
    ChessData[Point2.y][Point2.x] = point2;
    return false;   // 没有找到连通的路径
}
有了前面的一大堆分析,代码中也有注释,
好了函数的编写告一段落,实际 上写程序最为艰难就是调试阶段

来写一个程序测试一下:
代码:
#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdisp.h>        // MFC Automation classes
#include <afxdtctl.h>        // MFC support for Internet Explorer 4 Common Controls
#include <afxcmn.h>            // MFC support for Windows Common Controls


#include <stdio.h>
#include <stdlib.h>
#include "function.h"

int main()
{
    printf("开始 测试\r\n\n\n");

    
    byte ChessData[10][18];
    int i,j;
    for (j = 0; j <= 10; j++)
    {
        for (i = 0; i <= 18; i++)
        {
            ChessData[j][i] = rand()%2;
            printf("%2d  ",ChessData[j][i]);
        }
        printf("\r\n");
    }

    POINT p1;  // p1的位置
    p1.x = 13;
    p1.y = 5;

    POINT p2; // p2的位置
    p2.x = 14;
    p2.y = 0;

    if (DecideChessIfRemove(p1, p2, ChessData))
        printf("2点相连\n\n");
    else
        printf("2点不相连!~\n\n");

    for (j = 0; j <= 10; j++)
    {
        for (i = 0; i <= 18; i++)
        {
            printf("%2d  ",ChessData[j][i]);
        }
        printf("\r\n");
    }

    return 0;
}
程序输出的,图7:


上面是可以联通的情况,那找一个不可以联通的情况试验一下:
代码:
#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxdisp.h>        // MFC Automation classes
#include <afxdtctl.h>        // MFC support for Internet Explorer 4 Common Controls
#include <afxcmn.h>            // MFC support for Windows Common Controls


#include <stdio.h>
#include <stdlib.h>
#include "function.h"

int main()
{
    printf("开始 测试\r\n\n\n");

    
    byte ChessData[10][18];
    int i,j;
    for (j = 0; j <= 10; j++)
    {
        for (i = 0; i <= 18; i++)
        {
            ChessData[j][i] = rand()%2;
            printf("%2d  ",ChessData[j][i]);
        }
        printf("\r\n");
    }

    POINT p1;  // 这里改了
    p1.x = 7;
    p1.y = 7;

    POINT p2;  // 这里改了
    p2.x = 10;
    p2.y = 6;

    if (DecideChessIfRemove(p1, p2, ChessData))
        printf("2点相连\n\n");
    else
        printf("2点不相连!~\n\n");

    for (j = 0; j <= 10; j++)
    {
        for (i = 0; i <= 18; i++)
        {
            printf("%2d  ",ChessData[j][i]);
        }
        printf("\r\n");
    }

    return 0;
}
程序输出,图8:


好了大功告成,说明我们的函数还是有些用的
最后感谢大家能看我一篇文章

最后请看图9:


谁能给我分析一下,为什么2个图标红线处不一样呢?
我没有深入的进行调试,对不起了大家,如果用我的代码写外挂,有什么bug,我有免责申明啊
免key版,511U盘资源,速度很快!经测试全部可下 课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的调mouse_event,GetWindowRect,SetCursorPos,FindWindow,SendMessage) CE5.4工具的使用方法 中级篇内容:调试工具的使用技巧,功能CALL的概念 调试工具OD1.1的使用技巧(如硬件断,条件断,内存断。 常用汇编指令与对应高级语言的转换。 游戏功能CALL概念 找第一个功能CALL 外挂框架的构建(通用) 进阶篇内容:分析游戏内部数据,分析常用功能CALL 游戏数据实践找各种功能CALL(如打怪,选怪,物品使用,技能栏之类)及相应的代码编写 高级篇内容:编写完整外挂 完成一个相对完整的外挂,实现 自动挂机,打怪,存放物品之类的功能 1 入门篇.以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最简单的外挂(实现游戏开局) a、鼠拟鼠标单击mouse_event b、鼠标指针移动还原 c、集成到startgame函数里 1.2、用CE查找棋盘数据 1.2.1、CE中的数据类型 a、数据类型:Bit,Byte,Word,Dword,float,double b、用CE查找出坐位号; c、保存分析数据 1.2.2、编程读出坐位号; a、远程读取进程数据 b、打开远程进程 c、读取远程进程数据 1.2.3、用CE查出棋盘基址; a、找棋盘数据基址 b、分析棋盘数据结构 1.2.4、读出当前棋盘数据 a、编程读出棋盘数据 b、棋盘数据显示出来 1.3、用模拟技术编制外挂 1.3.1 分析棋子与棋盘坐标关系 a、鼠标软件模拟,函数SendMessage b、分析窗口内棋子相对坐标X,Y c、软件模拟击棋盘坐标x,y处的棋子 1.3.2 消掉一对棋子的算法框架 a、遍历棋盘同类型棋子配对 b、构建算法框架 1.3.3 (Check2p)大致框架(算法核心) a、在这一对棋子间找相通路径的原理 b、(Check2p函数)框架代码 c、(CheckLine函数)检测2是否有连通. 1.3.4 CheckLine实现 a、CheckLine函数实现 b、Check2p核心代码架构 1.3.5 Check2p完整代码实现 1.3.6 编写完整外挂,界面美化 1.4、游戏加速.去掉对动画效果.非HOOK 1.4.1:用OD找出 动画延时代码 1.4.2:写代码去掉延时,实现游戏加速 2 中级篇 以热血江湖为例 2.1、分析前的准备..CALL简介: 2.1.1、CALL调用示例分析.远程代码注入器 2.1.2、调试工具OD简介,血值,魔力值,坐标偏移; 2.1.3、游戏基址概念; 2.1.4、常用汇编指令详解 2.1.5、内联汇编编程实例 2.2游戏分析利器OD(OllyDbg) 2.2.1、分析角色基址 2.2.2、找打坐CALL 2.2.3、读出角色当前血值 2.2.4、远程注入代码,调用打坐CALL; 2.2.5、实例分析:找技能栏对象数组基址+偏移: 2.2.6: 拦截F1-F8功能CALL 2.3、外挂框架构建 2.3.1、DLL动态链接库构建,与调用 2.3.2、API与回调函数 2.3.3、DLL中构建窗口 2.4、用OD分析游戏功能CALL.《热血江湖》为例:主要是找CALL 2.4.1、选怪CALL 2.4.2、找游戏物品背包的基址+偏移 2.4.3、 吃红药(补血)CALL 2.4.4、 吃蓝(补魔)CALL 2.4.5、 技能CALL1 2.4.6、技能CALL2 2.4.7、所有技能CALL 2.4.8、捡物CALL 2.4.9、所有动作CALL 3、进阶篇 主要讲功能CALL的参数分析 汇编浮指令/浮运行/浮数整数转换/汇编里的指针 3.1、喊话功能 3.2、走路 3.3、 怪物过滤 3.3.1、怪物属性分析 3.3.2、怪物列表关键代码分析 3.3.3、怪物列表基址+大小 3.3.4、怪物列表编写代码 3.3.5、怪物过滤 3.4、 物品过滤 3.4.1、物品属性分析 3.4.2、物品列表关键代码分析 3.4.3、找出物品列表基址+偏移 3.4.4、物品过滤(编程读出物品列表数据) 3.5、 组队相关 3.5.1、 玩家列表 3.5.2、 组队功能 3.5.3、 离队功能 3.6、购物/售物 3.6.1、与NPC对话框 3.6.2、打开购物/售物对话框 3.6.3、购物功能 3.6.4、售物功能 3.7、 摆摊.开店 a、开店CALL参数分析 b、写代码测试 4、高级篇 4.1、编写完整的外挂 4.2游戏更新后的外挂更新 4.3、脚本功能 4.4、游戏多开实现 4.5、盗号的实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值