contributor

快乐分享,一起学习进步~

动态立体方块

一个绘图程序。 执行效果如下: 完整源代码如下: /*********************************************** * 程序名称:动态立体方块 * * 编译环境:Visual C++ 6.0 / EasyX冬至版 * * 作者:Kenny <499508968@qq.com> * * 最后修改:2015.05.21 * ***********************************************/ #include <graphics.h> #include <conio.h> #include <math.h> void Block(int length); // 画方块函数声明 void StrongBlock(); // 动态立体方块函数声明 // 主函数 int main() { StrongBlock(); return 0; } // 画方块函数定义 void Block(int length, COLORREF color) { setorigin(getwidth() / 2, getheight() / 2); // 设置坐标原点为窗口中心 POINT a[4][6]; // 定义二维数组存放点,4条边,每条边分5段,也就是6个点 int i, j; // 顺时针初始化点坐标,第一条边为坐标原点左上方的边 for (j = 0; j < 4; j++) { for (i = 0; i < 6; i++) // 初始化每条边上的6个点坐标 { a[j][i].x = (int)pow(-1, j / 2 + j % 2 + 1) * length * i / 5; a[j][i].y = (int)pow(-1, j / 2 + 1) * length * (5 - i) / 5; } } setlinecolor(color); // 设置线条颜色 for (i = 0, j = 5; i < 6; i++, j--) { line(a[0][i].x, a[0][i].y, a[2][j].x, a[2][j].y); // 连接第一条和第三条边上的6对点坐标 line(a[1][i].x, a[1][i].y, a[3][j].x, a[3][j].y); // 连接第二条和第四条边上的6对点坐标 } } // 动态立体方块函数定义 void StrongBlock() { initgraph(800,800); int length; float H, S, L; while (!kbhit()) { length = 10; H = 0; S = 1; L = 0.5; while (length <= getwidth() / 2) { Block(length, HSLtoRGB(H, S, L)); Sleep(150); length += 4; // 长度递增 H += (float)1.8; // 改变颜色 } length = 400; H = 360; S = 1; L = 0.5; while (length > 10) { Block(length, HSLtoRGB(H, S, L)); Sleep(150); length -= 4; // 长度递减 H -= (float)1.8; // 改变颜色 } } getch(); closegraph(); } 作者:Kenny作者 QQ:499508968

多个小球在方框内的碰撞运动

本程序模拟了多个小球在方框内的碰撞运动。 源代码如下: /////////////////////////////////////////////////// // 程序名称:多个小球在方框内的碰撞运动 // 编译环境:Visual C++ 6.0,EasyX 2013冬至版 // 作  者:可可 // 最后修改:2014-03-18 // #include <graphics.h> #include <conio.h> #include <math.h> #define XN 640 #define YN 480 // 设置图形窗口的大小 #define N 40 // 设置球的个数,最多 90 个 #define V 20 // 设置球的速度 // 画出一个球 void Ball(int x, int y) { fillcircle(x, YN - y, 20); // 转换成常用的坐标 } // 判定是否发生二维平面小球完全弹性碰撞(速度较大) // (当速度很小时,不服从。因为计算后的结果因为保留有限位而比真实情况小,很快衰减到 0) int PerfectElasticCollision(float v1[2], float v2[2], float u[2]) { float t, v11[2], v12[2], v21[2], v22[2]; // 保存球心连线上和垂直于连线的速度分量 v11[0] = (v1[0] * u[0] + v1[1] * u[1]) * u[0] / (u[0] * u[0] + u[1] * u[1]); v11[1] = (v1[0] * u[0] + v1[1] * u[1]) * u[1] / (u[0] * u[0] + u[1] * u[1]); v12[0] = v1[0] - v11[0]; v12[1] = v1[1] - v11[1]; v21[0] = (v2[0] * u[0] + v2[1] * u[1]) * u[0] / (u[0] * u[0] + u[1] * u[1]); v21[1] = (v2[0] * u[0] + v2[1] * u[1]) * u[1] / (u[0] * u[0] + u[1] * u[1]); v22[0] = v2[0] - v21[0]; v22[1] = v2[1] - v21[1]; if( ( ((fabs(v11[0]) <= fabs(v21[0])) && (v11[0] * u[0] >= 0) && (v11[0] * v21[0] >= 0)) || ((v11[0] * v21[0] <= 0) && (v21[0] * u[0] >= 0)) || ((fabs(v11[0]) >= fabs(v21[0])) && (v21[0] * u[0] >= 0) && (v11[0] * v21[0] >= 0)) ) && ( ((fabs(v11[1]) <= fabs(v21[1])) && (v11[1] * u[1] >= 0) && (v11[1] * v21[1] >= 0)) || ((v11[1] * v21[1] <= 0) && (v21[1] * u[1] >= 0)) || ((fabs(v11[1]) >= fabs(v21[1])) && (v21[1] * u[1] <= 0) && (v11[1] * v21[1] >= 0)) ) ) return 0; // 不会发生碰撞的情况就直接返回 // 在球心连线上速度交换 t = v11[0]; v11[0] = v21[0]; v21[0] = t; t = v11[1]; v11[1] = v21[1]; v21[1] = t; // 得到新的速度 v1[0] = v11[0] + v12[0]; v1[1] = v11[1] + v12[1]; v2[0] = v21[0] + v22[0]; v2[1] = v21[1] + v22[1]; return 1; } // 最小时间单位内的位移变化 int BallMove(float x[], float y[], float a[], float b[], int n) { for(int i = 0; i < n; i++) { x[i] += a[i] / 100; // 对最小长度(这里指一个像素点的抽象的边长)的分割 y[i] += b[i] / 100; } return 0; } // 碰撞判定 void Judge(float x[], float y[], float a[], float b[], int n) { int i = 0, j = 0; float v1[2], v2[2], u[2]; // 保存相碰两小球的初速度和碰撞方向 while(i < n) // 小球是否相碰 { for(j = i + 1; j < n; j++) { if(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) <= 1600)) { u[0] = x[j] - x[i]; // 保存两小球的初速度和碰撞方向 u[1] = y[j] - y[i]; v1[0] = a[i]; v1[1] = b[i]; v2[0] = a[j]; v2[1] = b[j]; // 判定两相切小球是否相碰 if(PerfectElasticCollision(v1, v2, u)) { a[i] = v1[0]; // 碰撞后两小球的速度的改变 b[i] = v1[1]; a[j] = v2[0]; b[j] = v2[1]; } } } i++; } i = 0; while(i < n) // 小球是否碰壁 { if((x[i] - 21) <= 0 || ((XN - 21) - x[i]) <= 0) if((y[i] - 21) <= 0 || (y[i] - (YN-21)) >= 0) { a[i] = -a[i]; b[i] = -b[i]; } else a[i] = -a[i]; if((y[i] - 21) <= 0 || (y[i] - (YN - 21)) >= 0) b[i] = -b[i]; i++; } return; } // 主函数 void main() { int i = 0, j = 0, n = N; float x[N] = {0}, y[N] = {0}, a[N] = {0}, b[N] = {0}; // 初始化坐标位置(x[], y[])和速度向量(a[], b[]), 速度向量 for(i = 0; i < n; i += 1) { x[i] = (float) 50 * (i % 10) + 50; y[i] = (float) 50 * (i / 10) + 50; a[i] = (float) V; b[i] = (float) -V * (i % 2); } initgraph(XN, YN); BeginBatchDraw(); setrop2(R2_XORPEN); setfillcolor(RED); while(true) { for(i=0; i<n; i++) Ball((int)x[i], (int)y[i]); FlushBatchDraw(); Sleep(1); for(i=0; i<n; i++) Ball((int)x[i], (int)y[i]); Judge(x, y, a, b, n); // 判定是否相碰或碰壁,若有,改变速度向量 BallMove(x, y, a, b, n); // 最小时间单位坐标位置的变动 } EndBatchDraw(); getch(); closegraph(); } 作者:可可博客:<跳转至博客>

物理程序:引力模拟

一个模拟引力的程序。可以在程序中创建不同质量和初始速度的天体,天体按照万有引力定律运行。 左键创建天体。按下左键不松开,天体质量会增加;然后移动,会给天体赋值初始速度,然后松开左键。 右键删除天体。 超出屏幕、碰撞后的天体不会消失。 程序的运行截图如下: 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:有时的迷惘https://www.baidu.com/p/有时的迷惘

实现水波纹显示效果

当鼠标滑过时,可以在屏幕上实现漂亮的水波纹效果。 执行效果如下: 源代码如下: /**************************************************** * 程序名称:实现水波纹显示 * * 编译环境:Visual C++ 6.0,EasyX 20130114(beta) * * 作  者:豪 (QQ: 415051674) * * 核心算法:参考网上算法 * * 最后修改:2013/3/20 * ****************************************************/ #include <graphics.h> #include <conio.h> #include <stdio.h> #define PIC_HEIGHT 600 #define PIC_WIDTH 800 void FrameFun(); // 帧逻辑函数,处理每一帧的逻辑 void RenderFun(); // 帧渲染函数,输出每一帧到显示设备 IMAGE src_img; // 原位图 IMAGE dest_img(PIC_WIDTH, PIC_HEIGHT); // 处理后显示的位图 DWORD *img_ptr1; // 原图片片内存指针 DWORD *img_ptr2; // 处理后显示的位图内存指针 // 以下两个 buf 为每一个点的波幅,前者为当前波幅,后者为下一个时刻的波幅。 short *buf = new short[PIC_HEIGHT*PIC_WIDTH+PIC_WIDTH]; short *buf2 = new short[PIC_HEIGHT*PIC_WIDTH+PIC_WIDTH]; void main() { // 初始化设备,加载图片 initgraph(PIC_WIDTH, PIC_HEIGHT); SetWindowText(GetHWnd(), "Wave-水波纹效果(点击产生一个水波纹。移动鼠标连续产生水波纹)"); loadimage(&src_img, "water.jpg"); // 加载图片,大小:800*600 setbkmode(TRANSPARENT); settextcolor(BLACK); setfont(25, 0, "Arial"); // 获得内存指针 img_ptr1 = GetImageBuffer(&src_img); img_ptr2 = GetImageBuffer(&dest_img); // 初始化波幅数组 memset(buf, 0, (PIC_HEIGHT*PIC_WIDTH+PIC_WIDTH) * sizeof(short)); memset(buf2, 0, (PIC_HEIGHT*PIC_WIDTH+PIC_WIDTH) * sizeof(short)); // Let's Go! BeginBatchDraw(); // 双缓冲,闪屏时需要 while(true) { FrameFun(); RenderFun(); FlushBatchDraw(); Sleep(1); } EndBatchDraw(); } // 计算出下一个时刻所有点的波幅 void nextFrame() { for(int i = PIC_WIDTH; i < PIC_HEIGHT*(PIC_WIDTH-1); i++) { // 公式:X0'= (X1+X2+X3+X4) / 2 - X0 buf2[i] = ((buf[i-PIC_WIDTH] + buf[i+PIC_WIDTH] + buf[i-1] + buf[i+1]) >> 1) - buf2[i]; // 波能衰减 buf2[i] -= buf2[i] >> 5; } short *ptmp = buf; buf = buf2; buf2 = ptmp; } // 处理当前时刻波幅影响之后的位图,保存在 dest_img 中 void RenderRipple() { int i = 0; for (int y = 0; y < PIC_HEIGHT; y++) { for (int x = 0; x < PIC_WIDTH; x++) { short data = 1024 - buf[i]; // 偏移 int a = ((x - PIC_WIDTH / 2) * data / 1024) + PIC_WIDTH / 2; int b = ((y - PIC_HEIGHT / 2) * data / 1024) + PIC_HEIGHT / 2; // 边界处理 if (a >= PIC_WIDTH) a = PIC_WIDTH - 1; if (a < 0) a = 0; if (b >= PIC_HEIGHT) b = PIC_HEIGHT - 1; if (b < 0) b = 0; // 处理偏移 img_ptr2[i] = img_ptr1[a + (b * PIC_WIDTH)]; i++; } } } // 鼠标模拟投石头 // 参数说明: // (x, y): 鼠标坐标 // stonesize: “石头”的大小 // stoneweight: 投“石头”的力度 // Ps: 如果产生错误,一般就是数组越界所致,请酌情调整“石头”的大小和“石头”的力度 void disturb(int x, int y, int stonesize, int stoneweight) { // 突破边界不处理 if ((x >= PIC_WIDTH - stonesize) || (x < stonesize) || (y >= PIC_HEIGHT - stonesize) || (y < stonesize)) return; for (int posx=x-stonesize; posx<x+stonesize; posx++) { for (int posy=y-stonesize; posy<y+stonesize; posy++) { if ((posx-x)*(posx-x) + (posy-y)*(posy-y) < stonesize*stonesize) { buf[PIC_WIDTH*posy+posx] += stoneweight; } } } } // 计算fps float getFps() { #define FPS_COUNT 8 static i = 0; static oldTime = GetTickCount(); static float fps; if (i > FPS_COUNT) { i = 0; int newTime = GetTickCount(); int elapsedTime = newTime - oldTime; fps = FPS_COUNT / (elapsedTime / 1000.0f); oldTime = newTime; } i++; return fps; } // 渲染 void RenderFun() { RenderRipple(); putimage(0, 0, &dest_img); char s[5]; sprintf(s, "%.1f", getFps()); outtextxy(0, 0, s); } // 逻辑 void FrameFun() { // 鼠标 if(MouseHit()) { MOUSEMSG msg = GetMouseMsg(); if(msg.uMsg == WM_MOUSEMOVE) { disturb(msg.x, msg.y, 3, 256); } else if(msg.uMsg == WM_LBUTTONDOWN) { disturb(msg.x, msg.y, 3, 2560); } FlushMouseMsgBuffer(); } // 计算下一帧的波幅 nextFrame(); } 完整源代码、图片及编译后的可执行文件请【点击这里下载】。 作者:豪QQ: 415051674

三辆行驶的小车

本程序模拟了以不同速度形式的三辆小车。 源代码如下: //////////////////////////////////////////// // 程序名称:3 辆行驶的小车 // 编译环境:Visual C++ 6.0,EasyX_20120603(beta) // 程序编写:E_SHARE <501748772@qq.com> // 编写时间:2012-6-26 //////////////////////////////////////////// #include <graphics.h> #include <conio.h> #include <stdlib.h> #include <stdio.h> // 声明需要使用的函数 void carstart(int x, int y, int z); void drawbus(); void init(); // 定义全局变量 IMAGE img; //////////////////////////////////////////// void main() { init(); int x=0, y=0, z=0; BeginBatchDraw(); while(!kbhit()) { x += 2; y++; z += 3; if (x > 600) x = -200; if (y > 600) y = -200; if (z > 600) z = -200; carstart(x, y, z); FlushBatchDraw(); Sleep(5); } EndBatchDraw(); closegraph(); } //////////////////////////////////////////// // 初始化函数,初始化窗口大小,获取所画图片 void init() { // 初始化窗口大小 initgraph(600, 600); outtextxy(70, 250, "大家好,新手来报到,希望大家多多指教"); outtextxy(70, 270, "下面你们会看到我程序的效果,程序很简单"); outtextxy(70, 290, "希望以后再跟大家的交流中学到更多,希望自己以后能编出更好的程序"); outtextxy(70, 320, "请按任意键进观看程序执行效果"); // 等待按键按下 getch(); cleardevice(); // 清除上面的文字进入运行效果画面 drawbus(); // 调用绘图函数,绘制 BUS getimage(&img, 80, 40, 180, 90); // 获取 BUS 图片位置,保存在 img 变量中 } ////////////////////////////////////////////////////////////// // 车辆行驶程序,通过 putimge 函数,改变移动的像素来达到图片移动 void carstart(int x, int y, int z) { cleardevice(); putimage(x, 40, &img); setlinestyle(PS_SOLID, NULL, 10); //设置画线的大小 line(0, 135, 600, 135); putimage(y, 220, &img); line(0, 315, 600, 315); putimage(z, 380, &img); line(0, 475, 600, 475); } ////////////////////////////////////////////////////////////// // 绘制 BUS 函数,通过画一些线条,组合它们的位置,组合成一辆小车 void drawbus() { setcolor(RED); setfillstyle(BLUE); fillcircle(120, 120, 10); // 画车的轮胎 fillcircle(200, 120, 10); // 画车的轮胎 line(80, 120, 110, 120); // 画车的底部车板 line(80, 40, 80, 120); // 画车的四周车板 line(130, 120, 190, 120); // 画车的底部车板 line(210, 120, 250, 120); // 画车的底部车板 line(250, 40, 250, 120); // 画车的四周车板 line(80, 40, 250, 40); // 画车的顶部车板 // 画车窗 for(int x = 90, y = 100; x < 190 && y < 190; x += 15, y += 15) { rectangle(x, 60, y, 70); } // 画车门 rectangle(220, 60, 240, 120); line(230, 60, 230, 120); circle(230, 90, 5); } 作者:E_SHAREEmail:501748772@qq.com

图片转化为 ASCII 图,就是很多字符组成图片的那种

本程序实现将图片转换为 ascii 字符的效果。 使用说明 支持 bmp / jpg / gif / emf / wmf / ico 类型的图片。gif 类型的图片仅加载第一帧,不支持透明。我只测试过jpg格式。请把要转换的图片复制到exe程序所在的文件夹,并确保图片名中没有中文等无法输入的字符。运行exe文件即可转换。因为txt文件的行距,字符间距等原因,为了达到最好效果,请先把图片的高度压缩到原来的1/2(宽度不变)转换根据图片的实际大小操作,如果图片过大,请修改图片尺寸,或者手工修改txt中字符的尺寸,以便能够完全显示 备注 这仅仅是一个demo,里边存在不少问题,比如ASCII灰度实际上是按照8*16像素扫描的;实际使用的ASCII灰度值我修改过,并非原来的灰度等等 为了更精确的控制字体的尺寸,间距,行距,html文件是个不错的选择,如果你愿意的话,你可以选择完善这个demo,做成一个很实用的小小的软件,但是让一个东西变得更加精致,并不是我的兴趣所在,所以估计今后我也不会再修改这个程序了。 为了方便你的完善,我给你写了一段灰度扫描的程序,有自己的main(),可以独立的运行。 如果在本程序的基础上修改完善,请保留文件头部的作者信息 联系我 有问题的话,可以给我发邮件:Geodesic <geodesicwl-cpro@yahoo.cn> 因为垃圾邮件的原因,我的邮箱经常的变换,所以请确保你发送的是我最新的地址 更多下载:http://code.google.com/p/c-programming-language/downloads/list 玩的开心o(∩_∩)o 执行效果如图 原图片: 生成的文本效果: 完整源代码 ///////////////////////////////////////////////////// // 程序名称:图片转ASCII点阵demo // 编译环境:Visual C++ 6.0,EasyX 2012-5-1测试版 // 作  者:Geodesic <Geodesicwl-cpro@yahoo.cn> // 最后修改:2012-5-16 ///////////////////////////////////////////////////// //若提示缺少graphics.h(Easyx)头文件,请到这里下载: //www.easyx.cn ///////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <graphics.h> /***********************宏定义***********************/ #define ASC_HEIGHT 8 #define ASC_WIDTH 8 #define ASCII_NUM 32 /*********************结构体定义*********************/ struct ascii { char asc[ASCII_NUM]; int gray[ASCII_NUM]; }as = {' ', '`', '.', '^', ',', ':', '~', '"', '<', '!', 'c', 't', '+', '{', 'i', '7', '?', 'u', '3', '0', 'p', 'w', '4', 'A', '8', 'D', 'X', '%', '#', 'H', 'W', 'M', 0, 5, 7, 9, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 59, 61, 63, 66, 68, 70}; /**********************函数声明***********************/ char SearchAsc(struct ascii as, int gray); void Pic2Asc(struct ascii as, char filename[]); /***********************主函数***********************/ int main(void) { char filename[256]; system("title, 图片转化为ASCII图画demo"); printf("请输入文件名(含扩展名)\n\n"); gets(filename); system("cls"); Pic2Asc(as, filename); printf("转换完成,任意键退出\n\n"); system("pause"); return 0; } /***********************函数体***********************/ //图片转化为ASCII点阵,并保存到txt和html文件中 void Pic2Asc(struct ascii as, char filename[]) { int height, width, gray; IMAGE img; FILE *fpAscPicText; //图像设备初始化 loadimage(&img, filename); SetWorkingImage(&img); height = getheight() / ASC_HEIGHT; width = getwidth() / ASC_WIDTH; if((fpAscPicText = fopen("ASC_PIC.txt", "w")) == NULL) { printf("文件打开失败\n"); exit(0); } //开始转化并保存结果 for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { gray = 0; //扫描每一小块的灰度,并计算出平均灰度 for(int h = 0; h < ASC_HEIGHT; h++) for(int w = 0; w < ASC_WIDTH; w++) { gray += GetRValue(RGBtoGRAY(getpixel(j * ASC_WIDTH + w, i * ASC_HEIGHT + h))); } gray /= (ASC_HEIGHT * ASC_WIDTH); gray = (255- gray) * 90 / 255; fputc(SearchAsc(as, gray), fpAscPicText); } fputc('\n', fpAscPicText); } fclose(fpAscPicText); } //二分法查找ASCII字符,就低不就高 char SearchAsc(struct ascii as, int gray) { int lower = 0; int higher = ASCII_NUM; int mid; if(gray <= as.gray[0]) { return as.asc[0]; } else if (gray >= as.gray[ASCII_NUM - 1]) { return as.asc[ASCII_NUM - 1]; } else { while((higher - lower) > 1) { mid = (lower + higher) >> 1; if(gray > as.gray[mid]) { lower = mid; } else { higher = mid; } } return as.asc[lower]; } } 作者:GeodesicEmail:Geodesicwl-cpro@yahoo.cn

汉诺塔移动动画

这是经典问题汉诺塔的解题演示动画,代码如下: /////////////////////////////////////////////////// // 程序名称:汉诺塔移动动画 // 编译环境:Visual C++ 6.0,EasyX_20130506(beta) // 作  者:Ronald Email:ryl910527@gmail.com // 最后修改:2011-5-26 // #include <graphics.h> #include <conio.h> #include <stdio.h> #define MAX 64 // 圆盘的最大数目 #define NULL 0 // 定义栈 struct STKNODE { int a[4]; }; struct STK { STKNODE* stack[MAX]; int top; }; // 定义全局变量 STK s[3]; // 声明三个栈,分别代表一号二号三号钢针上圆盘的状态 int v = 5; // 调整速度 // 函数声明 void Initstk(STK* s); // 初始化栈 void Hannoi(int n, char a, char b, char c); // 汉诺塔递归 void start(); // 开始画面 void Move(int n, char a, char b); // 移动过程 int switchab(char a); // 返回钢针号 void adjust(); // 调整速度暂停 // 主函数 void main() { int n, ta[4] = {115, 500, 285, 518}; // 第一个圆盘的位置 printf("尽量小于16\n"); // 因为大于十六时就会显示有误,但程序可以正常运行 printf("请输入汉诺塔的层数(1~64):"); scanf("%d", &n); STKNODE** p; p = (STKNODE**)malloc(n * sizeof(STKNODE **)); // 声明一个元素为 n 个的动态 STKNODE 型指针数组 for (int i2 = 0; i2 < n; i2 ++) { p[i2] = (STKNODE *)malloc(sizeof(STKNODE)); // 为每一个指针申请空间 } Initstk(&s[0]); Initstk(&s[1]); Initstk(&s[2]); // 将三个栈初始化 start(); // 呈现开始画面 setfillcolor(GREEN); // 圆盘的颜色 for (int i=0; i < n; i++) { ta[0] += 5; ta[1] -= 20; ta[2] -= 5; ta[3] -= 20; solidrectangle(ta[0], ta[1], ta[2], ta[3]); // 画出n个从大到小一次叠放的黄色圆盘 ++s[0].top; // 进栈 for (int i1 = 0; i1 < 4; i1++) { p[i]->a[i1] = ta[i1]; s[0].stack[s[0].top] = p[i]; // 记录每个矩形的位置,top为圆盘的个数 } } Hannoi(n, 'a', 'b', 'c'); // 汉诺塔递归函数 system("pause"); printf("\t\t\t\tGame Over!\n"); } /////////////////////////////////////////////////// // 函数定义 // 汉诺塔的递归 void Hannoi(int n, char a, char b, char c) { if(n == 1) Move(1, a, c); else { Hannoi(n-1, a, c, b); Move(n, a, c); Hannoi(n-1, b, a, c); } } // 栈的初始化 void Initstk(STK *s) { int i; s->top = 0; for (i = 0; i <= MAX; i++) s->stack[++s->top] = NULL; s->top = 0; } // 移动过程 void Move(int n, char a, char b) { int i3, i4 = 0, i5 = 0; i3 = b - a; // 目的钢针与源钢针的位置差值 i4 = switchab(a); // 源钢针钢针号 i5 = switchab(b); // 目的钢针号 STKNODE *q1, *q0; // 两个中间结点用于源栈和目的栈间的值得传递,q1为目的栈,q0为源栈 q1 = (STKNODE *)malloc(sizeof(STKNODE)); q0 = (STKNODE *)malloc(sizeof(STKNODE)); // 源栈与目的栈值的传递 q0 = s[i4].stack[s[i4].top]; ++s[i5].top; // 进栈 q1->a[0] = q0->a[0] + i3 * 200; q1->a[1] = 500 - s[i5].top * 20; q1->a[2] = q0->a[2] + i3 * 200; q1->a[3] = 500 - s[i5].top * 20 + 18; s[i5].stack[s[i5].top] = q1; --s[i4].top; // 出栈 // 向上运动 while (q0->a[1] >= 100) { setfillcolor(GREEN); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); adjust(); // 调整函数 Sleep(10 * v); // 暂停(ms) setfillcolor(WHITE); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); setlinecolor(RED); line((q0->a[0] + q0->a[2]) / 2, q0->a[1], (q0->a[0] + q0->a[2]) / 2, q0->a[3]); // 重新画上被擦掉原有的红线 q0->a[1] -= 10; q0->a[3] -= 10; } // 向左或右运动,与 i3 的正负有关 while (q0->a[2] != q1->a[2]) { setfillcolor(GREEN); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); adjust(); Sleep(10 * v); setfillcolor(WHITE); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); if (i3 < 0) // i3<0向左移 { q0->a[0] -= 20; q0->a[2] -= 20; } else // i3>0向右移 { q0->a[0] += 20; q0->a[2] += 20; } } // 向下运动 while (q0->a[3] <= q1->a[3]) { setfillcolor(GREEN); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); adjust(); Sleep(10 * v); setfillcolor(WHITE); solidrectangle(q0->a[0], q0->a[1], q0->a[2], q0->a[3]); setlinecolor(RED); if (q0->a[1] > 100) // 重画被擦掉的红线 { line((q0->a[0] + q0->a[2]) / 2, q0->a[1], (q0->a[0] + q0->a[2]) / 2, q0->a[3]); } q0->a[1] += 10; q0->a[3] += 10; } // 在目的钢针上的相应位置绘制出黄色矩形块 setfillcolor(GREEN); solidrectangle(q1->a[0], q1->a[1], q1->a[2], q1->a[3]); } // 绘制开始界面 void start() { // 初始化画面大小 initgraph(800, 650); // 背景设为白色 setbkcolor(WHITE); // 用白色填充整个画面 cleardevice(); // 绘制彩虹,形成一道彩虹,摘自 easyx 帮助文档示例程序 float H, S, L; H = 0; // 色相 S = 1; // 饱和度 L = 0.5f; // 亮度 setlinestyle(PS_SOLID, NULL, 2); // 设置线宽为 2 for(int r = 600; r > 544; r--) { H += 5; setlinecolor( HSLtoRGB(H, S, L) ); circle(750, 900, r); } // 说明 settextstyle(50, 0, "华文楷体"); settextcolor(RED); outtextxy(200, 150, "汉诺塔移动动画"); settextstyle(20, 0, "黑体"); outtextxy(600, 200, "BY:Ronald"); outtextxy(500, 200, "版本V1.1"); settextstyle(50, 0, "黑体"); settextcolor(GREEN); outtextxy(200, 350, "随便按一个键开始吧!"); // 检测键盘敲击 getch(); // 清空开始界面 cleardevice(); // 绘制运动画面的的环境 setlinecolor(RED); // 三根红色线段作为钢针 line(400, 110, 400, 500); line(600, 110, 600, 500); line(200, 110, 200, 500); // 长方体形的底座 setfillcolor(LIGHTGRAY); fillrectangle(80, 501, 720, 510); // 暂停按钮 solidrectangle(360, 540, 440, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(370, 550, "暂停"); settextstyle(20, 0, "宋体"); settextcolor(RED); outtextxy(300, 580, "鼠标暂停后请按空格继续"); // 加速按钮 solidrectangle(160, 540, 240, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(170, 550, "加速"); settextstyle(20, 0, "宋体"); settextcolor(RED); outtextxy(170, 580, "请按 d"); // 减速按钮 solidrectangle(560, 540, 640, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(570, 550, "减速"); settextstyle(20, 0, "宋体"); settextcolor(RED); outtextxy(570, 580, "请按 a"); // 说明 settextstyle(50, 0, "宋体"); settextcolor(GREEN); outtextxy(10, 10, "正在进行中请欣赏:"); } // 判断目的钢针与源钢针的钢针号返回钢针号 int switchab(char a) { switch (a) { case 'a': return 0; case 'b': return 1; case 'c': return 2; default: return 0; } } // 调整函数,实现加速,减速,暂停 void adjust() { char f; // 接收键盘敲进去的按钮和鼠标点击时赋予的变化值 // 用 f 接受键盘的键入值 if(kbhit()) f = getch(); // 检测鼠标消息 if (MouseHit()==true) { // 接收鼠标消息 MOUSEMSG Mouse; Mouse = GetMouseMsg(); // 响应鼠标消息 if (Mouse.x >= 360 && Mouse.x <= 440 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) { f = ' '; } if (Mouse.x >= 160 && Mouse.x <= 240 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) { f = 'd'; } if (Mouse.x >= 560 && Mouse.x <= 640 && Mouse.y >= 540 && Mouse.y <= 580 && Mouse.mkLButton) { f = 'a'; } } // 作用于动画 switch(f) { // 暂停 case ' ': // 用‘继续’覆盖‘暂停’ settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(370, 550, "继续"); getch(); // 继续后变回显示‘暂停’ settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(370, 550, "暂停"); break; // 减速 case 'a': // 当被点击时,‘减速’位置震动一下 setfillcolor(LIGHTGRAY); solidrectangle(560, 540, 640, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(575, 545, "减速"); Sleep(30); // 减速 v++; // 回原位 setfillcolor(LIGHTGRAY); solidrectangle(560, 540, 640, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(570, 550, "减速"); break; // 加速 case 'd': setfillcolor(LIGHTGRAY); solidrectangle(160, 540, 240, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(165, 545, "加速"); Sleep(30); setfillcolor(LIGHTGRAY); solidrectangle(160, 540, 240, 580); settextstyle(30, 0, "黑体"); settextcolor(GREEN); outtextxy(170, 550, "加速"); // 加速 v--; // v 最小为1 if (v <= 0) { v = 1; } break; default: break; } f = 'r'; // f 初始化为 r FlushMouseMsgBuffer(); // 清空鼠标消息 } 作者:RonaldEmail:ryl910527@gmail.com