首页
社区
课程
招聘
[原创]俄罗斯方块作弊~
发表于: 2010-4-15 13:53 11785

[原创]俄罗斯方块作弊~

2010-4-15 13:53
11785

标 题: 【原创】 俄罗斯方块作弊~
工 具:Turbo C 2.0编译通过。(其他编译器未知)
下面是俄罗斯方块(小时候就开始玩的游戏,现在终于知道里面的秘密了)C语言学了这么长时间了,试着研究了一下俄罗斯方块,看到程序能运行出来,心里边是很高兴的(虽然不能算是我写自己的程序)。
W键翻转方块,
A键左移方块,
S键加速下落,
D键右移方块
作弊键:
Q键和E键,Q键会获得一个正方形的大方块,E键会获得一个长条,
雅俗共赏,网上搜索的代码,
自己研究了一番,加了作弊键,Q,E;
也算是crack吧,汗~
Q键对应的是函数void fangkuai() 如下:
void changtiao()
{   
    int i, x, y;
    i =0;          /*I的值对应着不同的形状,I=0,就对应着长条。*/
    for(y = 0; y < 5; y++)      
        for(x = 0; x < 5; x++)
            nextbox[y][x] = box[i][y][x];   
}

E键对应的是函数void changtiao() :
void fangkuai()
{     
    int i, x, y;
    i =6;          /*I=6,对应着方块。*/
    for(y = 0; y < 5; y++)   
        for(x = 0; x < 5; x++)
            nextbox[y][x] = box[i][y][x];   
}

须放在TC根目录下才能正常运行。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <bios.h>      /*这里须要读取系统运行时间来作为定时器*/
#include <graphics.h>  /*很不幸,TC2的简单图形,让我放弃了用*/
#include <conio.h>     /*win32+openGL来讲解.*/

#define MAX_X       14   /*可见最大X*/
#define MAX_Y       21   /*可见最大Y*/
                       /*我们定义了最大的可见X和Y,那么即还有不
                         可见的部分,事实上地图(大盒子)里的左右
                         两侧和底部各两行都被1填充,这样大大简化
                         出界的判断,事实上,在本例中没有这样的
                         代码,因为旁边有一圈1阻止小盒子越出大
                         盒子的按制范围
                        */
#define MAX_C       7    /*最大种类,这个无须解释*/

#define KEY_UP      'w'  /*定义上下左右按按键*/
#define KEY_DOWN    's'
#define KEY_LEFT    'a'
#define KEY_RIGHT   'd'
#define KEY_ESC     27   /*退出*/
#define KEY_CHANGTIAO   'e'
#define KEY_FANGKUAI   'q'

typedef int BOOL;
#define FALSE 0
#define TRUE 1           /*这几个TC中没有...自己定义一下吧:)*/

/*时钟结构*/
typedef struct {           /*时钟结构*/
    BOOL enabled;          /*时钟是否开启*/
    unsigned int intervel; /*定时间隔*/
    unsigned int lasttime; /*这个属于内部使用变量*/
} Timer;

int GetTickCount();        /*返回电脑或操作系统运行逝去的时间*/
           /*在win32环境下已包含在windows.h里边,返回的是4byte*/
           /*在DOS(本代码)环境下,要自己编写,使用到BIOS.h内容*/
int setTimer(Timer *t, unsigned int intv, BOOL en);
           /*设置时钟t,参数分别为时钟指针,时间间隔,是否活动*/
           /*时间间隔,win32下为毫秒,DOS下为1/18秒(有点低)*/
BOOL testTimer(Timer *t);  /*测试时钟t是否到达定时时间*/
           /*如下面这段代码:*/
           /*
           setTimer(&t, 1, 1); 设置1个单位的间隔
           while(1) {
               if(testTimer(&t)) printf("Active!\n");
           }
           将会定时(1个单位)在屏幕上打印Active!
           一般来说testTimer必须放在循环中反复执行,激活时返回1
           */
void render(void);         /*唯一的绘图函数*/
           /*注意,此函数重画整个地图,根据地图中的点阵,以及根据
             小盒在地图的中坐标在恰当位置画出小盒子*/
           /*DOS的图形当然是很低的,但,全屏绘图在这里还是过得去
             的,我用的是双缓冲,交换绘图,这样感觉好点*/
void initMap(void);        /*初始化地图(大盒子)*/
           /*之前提到过在这个两维数组中有一圈为1的东西来阻止
             小盒子出界,这就是生成这一圈的函数*/
void newGame();            /*新建一个游戏*/
           /*这个函数初始化一几个时钟和建造第一个下落的小盒子*/
           /*当然建造完后要生成一个个的预览*/

void rotateBox(int box1[5][5], int box2[5][5]);
           /*核心函数成员,把box1逆时针旋转90度,并保存到box2中*/
void rebuidNext();
           /*核心函数成员,生成下一个方块*/
int drop();
           /*核心函数成员,将下落的盒子向下移(实际上增加下落盒
             子的Y值而已,当然要判断是否与地图点阵重叠*/
           /*与地图重叠,无法完成下落操作,返回0*/
void putBox();
           /*在这之上,下落的盒子与地图之前是独立的两个两维数*/
           /*当下落失败后,小盒子要回到顶端再次重新执行下落,这*/
           /*时原来的盒子内容当然就要变成地图上的内容了,putBox
             就是将下落盒子的内容根据XY写到地图上*/
void clear();
           /*这个函数在下落失败并putBox后执行,扫描整个地图*/
           /*清除掉满行的点阵,具体细节在函数内讲*/
int move(int dir);
           /*左右移动下落盒子,dir指出向左还是向右,这个与drop
             是一样的*/
int test(int mx, int my, int box[5][5]);
           /*这个比较重点,判断box在mx,my为坐标上,与地图上的
             非空点阵是否有重叠.很通用的一个函数*/
int rotate();
           /*旋转下落的盒子,当然如果转了之后与地图有冲突,会
             取消转动,返回0,但返回的值好像没什么用~*/
int newfall();
int map[MAX_Y+4][MAX_X+4]; /*地图\大盒子...MAX_X,Y是可见面积*/
                           /*我已说过需要在外面布两圈"卫兵"*/
int curbox[5][5];          /*当前下落的盒子*/
int curx, cury;            /*保存着当前活动盒子在地图上的位置*/
int nextbox[5][5];         /*保存着下一个形状的盒子*/

/*以上就是这么几个盒子和坐标了*/

/*这里列出了标准七种俄罗斯方块图形点阵,用到时它们会被复制到相*/
/*应的盒子...:)*/
int box[MAX_C][5][5] = {     /*MAX_C(7)种预定义的盒子*/
            {
                {0,0,0,0,0},
                {0,0,0,0,0},
                {1,1,1,1,0},
                {0,0,0,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,0,1,0,0},
                {0,1,1,1,0},
                {0,0,0,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,1,1,0,0},
                {0,0,1,1,0},
                {0,0,0,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,0,1,1,0},
                {0,1,1,0,0},
                {0,0,0,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,1,1,0,0},
                {0,0,1,0,0},
                {0,0,1,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,0,1,1,0},
                {0,0,1,0,0},
                {0,0,1,0,0},
                {0,0,0,0,0}
            },
            
            {
                {0,0,0,0,0},
                {0,0,1,1,0},
                {0,0,1,1,0},
                {0,0,0,0,0},
                {0,0,0,0,0}
            }
    };
/******************************************************\
*                      时钟                          *
\******************************************************/
/*时钟部分也非常理解的,一个用到设置时钟,一个用来测试时钟激活态*/

Timer tDown;               /*正常下落定时时钟intervel会比较大*/
Timer tFast;               /*按KEY_DOWN时使用的快速下落*/
int speed = 13;            /*控制下落时间间隔*/
#define FAST_INTV    1     /*快时钟的间隔*/

int GetTickCount() {       /*读取BIOS时钟*/
    int ret;
    ret = peek(0x0,0x46e); /*实际上读取了内存0:046e处的内容*/
    ret <<= 8;             /*这个地方是$%#$^$%&^*/
    ret += peek(0x0,0x46c);  /*太多新的东西了,找点书看一看吧*/
    return (ret);
}

int setTimer(Timer *t, unsigned int intv, BOOL en) {
    t -> enabled = en;              /*设置一个时钟罗*/
    t -> intervel = intv;
    t -> lasttime = GetTickCount(); /*lasttime记录的是上一个*/
                                    /*tickcount返回的东西*/
                   /*这样当再一次测试时间时新的tickcount产生了
                     它来减去上一次的tickcount就得出了一个时间
                     间隔,这个就可以和intervel比较从而得出是否
                     激活了
                   */
    return 0;
}

    BOOL testTimer(Timer *t)
        {          /*在上面6行的地方解释了:)*/
            unsigned int tmp, dt;
            if (!(t -> enabled)) return FALSE;
            tmp = GetTickCount();
            dt = tmp - (t -> lasttime);
            if(dt >= t -> intervel)
                {
                t -> lasttime = tmp;
                return TRUE;
                }
            return FALSE;
            }

void render(void) {
    int x, y;
    static int cPage = 0;    /*当前页,换页用*/

#define STARTX    50         /*定义几个常量*/
#define STARTY    0
#define LEN       18

    setactivepage(cPage=(cPage == 0?1:0));  /*选择页*/
    cleardevice();                          /*清屏*/
    setcolor(15);
    rectangle(    STARTX + LEN * 2 - 2,
            STARTY + LEN * 3 - 2,
            STARTX + LEN * (MAX_X - 2) + 2,
            STARTY + LEN * (MAX_Y - 2) + 2);
                                  /*用白色画一个外框*/
    setfillstyle(SOLID_FILL, 5);
    for(y = 3; y < MAX_Y - 2; y++) {        /*画地图 */
        for(x = 2; x < MAX_X - 2; x++) {
            if(map[y][x]) {   
                rectangle(    x * LEN + STARTX,
                        y * LEN + STARTY,
                        x * LEN + STARTX + LEN,
                        y * LEN + STARTY + LEN);
                bar(    x * LEN + STARTX + 1,
                    y * LEN + STARTY + 1,
                    x * LEN + STARTX + LEN - 2,
                    y * LEN + STARTY + LEN - 2);
            }
        }
    }

/*绘图操作就不要作太复杂的介绍了,这只写作用*/
/*以上段,根据地图上的点阵情况将地图反映到屏幕上*/

    for(y = 0; y < 5; y++) {        /*画下落物*/
        for(x = 0; x < 5; x++) {
            if(curbox[y][x]) {
                if(y + cury > 2) {
                    rectangle(    (x + curx) * LEN + STARTX,
                            (y + cury) * LEN + STARTY,
                            (x + curx) * LEN + STARTX + LEN,
                            (y + cury) * LEN + STARTY + LEN);
                    bar(    (x + curx) * LEN + STARTX + 1,
                        (y + cury) * LEN + STARTY + 1,
                        (x + curx) * LEN + STARTX + LEN - 2,
                        (y + cury) * LEN + STARTY + LEN - 2);
                }
            }
        }
    }

/*以上将下落的盒子按昭它在地图上的坐标,画到对应的区域里*/
    for(y = 0; y < 5; y++) {        /*画下一个*/
        for(x = 0; x < 5; x++) {
            if(nextbox[y][x]) {
                rectangle(    x * LEN + 320,
                        y * LEN + 10,
                        x * LEN + 338,
                        y * LEN + 28);
                bar(    x * LEN + 321,
                    y * LEN + 11,
                    x * LEN + 336,
                    y * LEN + 26);
            }
        }
    }
   
/*这个画出下一个盒子的预览*/
    setvisualpage(cPage);          /*确认在cPage页里画好了*/
                                   /*将它显示出来*/
}/******************************************************\
*                  初始化部分                        *
\******************************************************/
/*提供newGame()初始化新游戏*/

void initMap(void) {            /*初始化地图*/
    int x, y;                   /*我们须要一圈卫兵...*/
    for(y = 0; y < MAX_Y; y++) {
        for(x = 0; x < MAX_X; x++) {
            if(x < 2 || x > MAX_X - 3 || y > MAX_Y - 3)
                map[y][x] = 1;
            else map[y][x] = 0;
        }
    }                           /*这里初始化出这个形状*/
}                               /*当然是无盖的...*/

void newGame() {                /*新建游戏*/
    int x, y;
    initMap();                  /*初始化地图*/
    srand(GetTickCount());      /*初始化随机发生器*/
    rebuidNext();               /*建立下一个*/
    setTimer(&tDown, speed, 1); /*启动时钟(快慢两个)*/
    setTimer(&tFast, FAST_INTV, 1);
    newfall();                  /*对下落的盒子操作一下*/
                                /*这样第一个下落的方块
                                  就在地图顶部准备好了*/
}/******************************************************\
*                    核心函数                        *
\******************************************************/

void rotateBox(int box1[5][5], int box2[5][5]) {
                                /*旋转box1输出到box2*/
    int x, y;
    for(x = 0; x < 5; x++)      /*这个函数可以须要实际*/
        for(y = 4; y >= 0; y--) /*编写一下才能印像深刻*/
            box2[y][x] = box1[x][4 - y];
}

void rebuidNext() {    /*新建下一个形状并放到nextbox中*/
    int i, x, y;
    i = random(MAX_C);          /*从几种方块里面选一种*/
    for(y = 0; y < 5; y++)      /*并复制过来*/
        for(x = 0; x < 5; x++)
            nextbox[y][x] = box[i][y][x];   /*复制*/
}
void changtiao()
{    /*新建下一个形状并放到nextbox中*/
    int i, x, y;
    i =0;          /*从几种方块里面选一种*/
    for(y = 0; y < 5; y++)      /*并复制过来*/
        for(x = 0; x < 5; x++)
            nextbox[y][x] = box[i][y][x];   /*复制*/
}
void fangkuai() {    /*新建下一个形状并放到nextbox中*/
    int i, x, y;
    i =6;          /*从几种方块里面选一种*/
    for(y = 0; y < 5; y++)      /*并复制过来*/
        for(x = 0; x < 5; x++)
            nextbox[y][x] = box[i][y][x];   /*复制*/
}

int drop() {                    /*下落,返回成功与否*/
    int newy;                   /*盒子要下落的新位置*/
    newy = cury + 1;            /*为当前Y位置+1*/
    if(test(curx, newy, curbox)) {
        cury = newy;            /*测试下落盒在这个位置*/
        return 1;               /*上是否有冲突,没有的话*/
    }                           /*直接设置cury*/
    return 0;
}

void putBox() {                /*将curbox填充到地图上*/
    int x, y;
    for(y = 0; y < 5; y++)     /*这个也简单,主要是要根*/
        for(x = 0; x < 5; x++) /*据curx,cury指出位置  */
            if(curbox[y][x])
                map[y + cury][x + curx] = curbox[y][x];
}
   
void clear() {                 /*清除掉满行*/
                /*这个函数实际上效率也很低的,为了简便
                  它从头到尾作了测试*/
/*具体的算法为:
  从第0行开始到最后一行,测试地图点阵是否为满,如果是的话
  从当前行算起,之上的地图向下掉一行*/
    int x, y;
    int dx, dy;
    int fullflag;
    for(y = 0; y < MAX_Y - 2; y++) {  /*最后两行保留行*/
        fullflag = 1;                 /*假设为满*/
        for(x = 2; x < MAX_X - 2; x++) {    /*保留列~*/
            if(!map[y][x]) {
                fullflag = 0;
                break;
            }
        }
        if(fullflag) {               /*向下移动一行*/
            for(dy = y; dy > 0; dy--)
                for(dx = 2; dx < MAX_X - 2; dx++)
                    map[dy][dx] = map[dy - 1][dx];
            for(dx = 2; dx < MAX_X - 2; dx++)
                map[0][dx] = 0;
                          /*并清除掉第一行*/
        }
    }
}

int move(int dir) {            /*返回成功与否*/
    int newx;
    if(dir) newx = curx + 1;
                      /*与drop一样,准备移动后的坐标*/
    else newx = curx - 1;
    if(test(newx, cury, curbox)) { /*测试是否冲突*/
        curx = newx;           /*可以的话切换curx*/
        return 1;
    }
    return 0;
}

int test(int mx, int my, int box[5][5]) {
                /*测试box在map里mx,my位置上是否能着陆*/
/*这个是最关键的一个函数,它判断是否产生非空冲突*/
/*但算法还是很简单的*/
    int x, y;
    for(y = 0; y < 5; y++)
        for(x = 0; x < 5; x++)
            if(map[y + my][x + mx] && box[y][x])
                return 0;
    return 1;
}

int rotate() {
    int x, y;
    int newbox[5][5];    /*我们必须将当前盒子转动到新的盒子*/
                         /*再对这个新的盒子的冲突作测试*/
    rotateBox(curbox, newbox);    /*转动到新的盒子*/
    if(test(curx, cury, newbox)) {
                         /*并且新的盒子能放到地图上而不冲突*/
        for(y = 0; y < 5; y++)
            for(x = 0; x < 5; x++)
                curbox[y][x] = newbox[y][x];     /*复制进来*/
        return 1;
    }
    else return 0;
}

int newfall() {            /*创建下落元素失败返回0*/
    int x, y;
    curx = MAX_X / 2 - 2;  /*重新指定小盒位置*/
    cury = 0;
    for(y = 0; y < 5; y++)
        for(x = 0; x < 5; x++)
            curbox[y][x] = nextbox[y][x];/*将nextBox复制过来*/
    rebuidNext();          /*重建nextBox*/
    return test(curx, cury, curbox);
}

int main() {
    char key;             /*记录当前按键*/
    int i;
    int gd = VGA, gm = VGAMED; /*初始化的图形模式*/
    Timer *ptDown;        /*下落所指向的时钟(有快慢)*/
    Timer trender;        /*为了避免渲染给程序造成过大的负担*/
                          /*用一个时钟来控制渲染速度*/
                          /*把它设置interval = 1,*/
                          /*这样就是18 FPS了,当然无法达到标*/
                          /*准的60 FPS...毕竟这是DOS...*/
   
    setTimer(&trender, 1, 1);
    initgraph(&gd, &gm, ""); /*初始化图形*/
    newGame();            /*新游戏...*/

    while(1) {            /*主游戏循环*/
        if(kbhit()) {     /*如果键盘有按下*/
            key = getch();  /*读取一个按键值到key*/
        }
        else key = 0;
        
        switch(key) {     /*对读到的key进行判断*/
        case KEY_UP:
            rotate();     /*上,旋转下落盒子*/
            break;
        case KEY_DOWN:
            ptDown = &tFast;  /*使用tFast时钟 */
            break;
        case KEY_LEFT:
            move(0);      /*左移*/
            break;
        case KEY_RIGHT:
            move(1);      /*右移*/
            break;
        case KEY_ESC:
            closegraph(); /*结束游戏*/
            exit(0);
        case KEY_CHANGTIAO:
            changtiao();
            break;               
        case KEY_FANGKUAI:       
            fangkuai();
            break;
        default:
            ptDown = &tDown;      /*使用原来速度 */
        }
        
        if(testTimer(ptDown)) {  /*在上面已设置了下落要
                               使用的时钟在ptDown里*/
            if(!drop()) {        /*下落,失败返回0*/
                putBox();        /*写到地图里*/
                clear();         /*清除满行*/
                if(!newfall()) { /*新建下落,失败则游戏结束*/
                    closegraph();
                    exit(0);
                }
            }
        }
        if(testTimer(&trender)) /*最后...渲染...*/
            render();
    }
}

附件:压缩中的fangkuai.c就是源程序。TC.RAR解压到C:\下,进入TC文件夹,执行TC.EXE,再按F3,加载fangkuai.c就可以了。

PS:tc支持的显示模式有限,而且我也没有透彻理解图形模式设置部分,可能有的机器上不能正常运行。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (17)
雪    币: 182
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
沙发自己做~~~~
2010-4-15 13:54
0
雪    币: 65
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
太强了,居然是 用TC的。。。
2010-4-18 13:09
0
雪    币: 238
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
看到你的汉语拼音,我就笑了
2010-4-18 17:28
0
雪    币: 238
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
对了,你能编译成PE文件的形式吗
2010-4-18 17:28
0
雪    币: 3003
活跃值: (479)
能力值: ( LV15,RANK:1395 )
在线值:
发帖
回帖
粉丝
6
楼主太有才了,哈哈
2010-4-18 23:45
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
哈哈 不错啊 收藏下哈 哈哈
2010-5-3 12:05
0
雪    币: 182
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
我已经把压缩包放上去了,有兴趣的朋友们可以下载到电脑上运行一下,看一下效果。方块的形状可以自已定制~~~。就在数组里面修改就可以。
2010-5-15 12:25
0
雪    币: 182
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
PE文件不会弄~~~学习中~~~
2010-5-15 16:58
0
雪    币: 116
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
好强大
2010-5-15 19:35
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
真厲害.可是在DOS下看不習慣.是不是可以改成VC程式下
2010-8-20 16:35
0
雪    币: 421
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
支持的函数不一样,不能直接用VC编译的。
2010-8-20 17:34
0
雪    币: 478
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
先**再说。
2010-8-22 07:07
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
源代码作弊
2010-8-22 10:04
0
雪    币: 247
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
呵呵,都是新手,我们学习中。有空自己研究这样的小东西很有意思的。搞好了很有成就感
2010-8-22 20:13
0
雪    币: 20
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
mark!
like source code
2010-8-22 23:21
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
楼主用TC写的  佩服
2010-8-23 21:23
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
挺不错的~~
2010-8-24 15:43
0
游客
登录 | 注册 方可回帖
返回
//