本人性情温合,偏于内向。每遇事,凡欲究其理。理不达者,乃心不甘。
[置顶]值得珍藏一辈子的80句话(经典语句) 2008-05-26 14:54
| 0.原理 Huffman编码是一种可变长编码方式,是由美国数学家David Huffman创立的,是二叉树的一种特殊转化形式。编码的原理是:将使用次数多的代码转换成长度较短的代码,而使用次数少的可以使用较长的编码,并且保持编码的唯一可解性。Huffman算法的最根本的原则是:累计的(字符的统计数字*字符的编码长度)为最小,也就是权值(字符的统计数字*字符的编码长度)的和最小。 1.Huffman树 Huffman树是二叉树的一种特殊转化形式。以下是构件Huffman树的例子: 比如有以下数据, ABFACGCAHGBBAACECDFGFAAEABBB 先进行统计A(8) B(6) C(4) D(1) E(2) F(3) G(3) H(1) 括号里面的是统计次数 生成Huffman树:每次取最小的那两个节点(node)合并成一个节点(node),并且将累计数值相加作为新的接点的累计数值,最顶层的是根节点(root) 注:列表中最小节点的是指包括合并了的节点在内的所有节点,已经合并的节点不在列表中 运算的过程如下: 1:D+H(2) 2:DE+H(4) 3:F+G(6) 4:C+DEH(8) 5:B+FG(12) 6:A+CDEH(16) 7:ACDEH+BFG(28) 那么转化为Huffman树就是 Huffman树 层数 Root ┌┴┐ ACDEH BFG 1 ┌┴┐┌┴┐ CDEH A B FG 2 ┌┴┐ ┌┴┐ DEH C F G 3 ┌┴┐ DH E 4 ┌┴┐ D H 5 取左面是1 右面是0 则有。 注:层数就是位数或者说是代码长度,权值=代码长度*该字的统计次数。 代码 位数 权值 A = 10 2 16 B = 01 2 12 C = 110 3 12 D = 11111 5 5 E = 1110 4 8 F = 001 3 9 G = 000 2 6 H = 11110 5 5 可以看出Huffman代码是唯一可解的(uniquely decodable),如果你读到110就一定是C ,不会有任何一个编码是以110开始的。 如果不使用Huffman算法,而使用普通的编码,结果是什么呢? Huffman树 层数 Root ┌┴┐ ABCD EFGH 1 ┌┴┐ ┌┴┐ AB CD EF GH 2 ┌┴┐┌┴┐┌┴┐ ┌┴┐ A B C D E F G H 3 取左面是1 右面是0 则有 代码 位数 权值 A = 111 3 24 B = 110 3 18 C = 101 3 12 D = 100 3 3 E = 011 3 6 F = 010 3 9 G = 001 3 9 H = 000 3 3 利用Huffman编码得到的权值累计是 73,如果利用普通定长编码的话,则要用84字符长度。从这个比较,你可以看出,Huffman是怎么进行压缩的。 2.编码和解码 编码:将ABCDEFGH用Huffman树产生的编码对应着写到文件中,并且保留原始的Huffman树,主要是编码段的信息。一般要编码256个元素的话需要511个单位来储存Huffman树,每个Huffman树都必须有以下的结构:code,char,left,right,probability(出现次数),通常情况是利用一个数组结构。因为在解码的时候只需要用到code,所以只需要记录每个元素的编码就可以了。 解码:利用文件中保存的Huffman编码,一一对应,解读编码,把可变长编码转换为定长编码。 3.发展 由于Huffman编码需要扫描两次,第一次是统计数字,第二次是编码写文件,大大影响了速度,因此有人发明了enhanced Huffman aglorithm。这种算法只扫描一遍文件,动态产生Huffman树,即每读n个字节就重新编码一次Huffman树,以达到提高速度的目的。在解码的过程中使用动态还原技术。 |
| 在60年代末和70年代,关于goto语句的争论是比较激烈的。 主张从高级语言中去掉goto语句的人认为:goto语句是对程序结构影响最大的一种有害语句;他们的主要理由是:goto语句使程序的静态结构和程序的动态执行之间有很大的差别,这样使程序难以阅读,难以查错。对一个程序来说,人们最关心的是他运行的正确与否,去掉goto语句后,可以直接从程序结构上反映程序的运行过程。这样,不仅使程序的结构清晰、便于阅读,便于查错,而且也有利于程序正确性的证明。 持不同意见者认为,goto语句使用起来比较灵活,而且有些情形能够提高程序的效率。如果一味强调删除goto语句,有些情形反而会使程序过于复杂,增加一些不必要的计算量。 1974年, D.E.Knuth (算法界的超级大牛,The art of computer programming 的作者)对于goto语句的争论作了全面的公正的评述,他的基本观点是:不加限制地使用goto语句,特别是使用往回跳的goto语句,会使程序的结构难于理解,这种情形应该尽量避免使用goto语句;另外,为了提高程序的效率,同时又不破坏程序的良好结构,有控制地使用一些goto语句是有必要的。用他的话来说:“有些情形,我主张废除转向语句,有些情形我主张引进转向语句。”(见D.E.Knuth的大作:《带有转向语句的结构化程序设计》) 进一步讲,goto语句能不能消除呢?或者说goto语句这一语言成分能不能从程序设计语言中取消呢?回答是肯定的。1966年,G.Jacopini和C.Bohm从理论上证明了:任何程序都可以用序列结构、条件结构和循环结构表示出来。具体消除goto语句的方法有:增加辅助变量或者改变程序执行顺序。这方面的具体内容你可以参考程序设计理论方面的资料。 需要指出的是,虽然关于结构化程序设计的讨论是从废除goto语句开始的,但是绝不能认为结构程序设计就是避免goto语句的程序设计方法。事实上,结构程序设计讨论的是一种新的程序设计的方法和风格,他所关注的焦点是得到的程序的结构的好坏,而有无goto语句并不是一个程序结构好坏的标志。也就是说,限制和避免goto语句是得到结构化程序的一个手段,而不是我们的目的。 再稍微谈一下结构化程序设计。好的结构的程序一般由7种结构组成: 一种序列结构; 三种选择结构: 1.if-then; 2.if-then-else; 3.分支选择: pascal中是“case .. of ..., ”;C,C++,java中是“switch (..) case...:...”; 三种循环结构: 1.while循环: 先判断条件P,如果为真则不断地执行循环体A; 2.repeat循环:先执行循环体A,然后判断条件P,如果P成立则重新回到入口处执行循环体A; 在pascal中就是“repeat..until..”;在C,C++,java中是“do {...} while(..);”; 3.N+1/2循环: 从入口开始先执行A,然后判断P,如果P成立则执行B,然后回到入口执行A;如果P不成立则到达出口;这种循环在一般的程序设计语言中就是for循环 这七种结构都有一个特点:每一种结构都严格遵守“一个入口,一个出口”的原则。这一原则是结构化程序设计中的一个非常重要的原则。也正是由于遵循了这个原则,一个复杂的程序才可以被分解成若干个结构以及若干层子结构,从而使程序的结构层次分明、清晰易懂。 使用这7种结构编写的程序可以采用“自顶向下,逐步细化”的程序设计方法来设计程序。该方法按照先全局后局部、先整体后细节、先抽象后具体的过程组织人们的思维活动,使得编写的程序结构清晰、容易阅读和修改。同时还可以结构逐步求精的过程进行程序的正确性验证,即采取边设计边验证的方法,以简化程序正确性的验证。 |
| QBASIC中有一个SCREEN函数,它的调用形式为SCREEN(row%,c olumn% [,colorflag%])?本函数功能为返回当前文本方式下 row行column列处字符或属性,当colorflag%参数省略或等于0时返回 字符,当colorfiag%参数为1时返回该字符的属性?此函数实在很有 用,能否也给TURBOC增加一个类似的函数呢?答案是肯定的,有两种 编程方法? 方法一:调用BIOS显示中断? /*文件名为SCREEN1.C*/ #include<dos.h> #include<conio.h> #include<stdio.h> int screen(int x,int v,int colorflag) { int oldx,oldy; union REGS r; if(x>80||x<1||y>25||y<1) return -1; oldx=wherex() oldy=wherey() gotoxy(x,y); r.h.ah=8; r.h.bh=0; int86(0x10,&r,&r); gotoxy(oldx,oldy); if(colorflag)return r.h.ah; else return r.h.al; } 方法二:直接操纵硬件编程? /*文件名为SCREEN2.C*/ int screen(int x,int y,int colorfiag) { char far *t=(char far *)0xb8000000;/*硬件直接 写屏地址*/ if(x>80||x<1||y>25||y<1) return -1; t+=(x-1)*2+(y-1)*80*2; if(colorflag)t++; return (*t); } 使用本函数时,需带三个参数x?y?colorfag,当colorflag值为 真时返回x列y行处字符的属性,否则返回该字符的ASCII值,参数值不 符合要求时返回失败值-1?两种方法各有优缺点?方法一由于调用中 断,故兼容性非常好,但速度慢且代码(这里的代码指编译后的二进 制代码,非源程序代码)所占空间大;方法二直接操纵硬件编程,虽 速度快,代码短,但兼容性差,只适用于80列彩显文本方式?读者可 修改直接写屏地址使之适用于单显?以上程序在TURBO C++3.0的C 方式下通过? |
| 物理过程所引起的差错,在某些介质中通常是突发的而不是单个的。网络设计者已经研究出两种基本的策略来处理差错。一种方法是在每一个要发送的数据块上附加足够的冗余信息,使接收方能够推导出已发出的字符应该是什么。另一种方法是只加足够的冗余位,使接收方知道差错发生,但不知道是什么样的差错,然后要求接收方重新进行传输。前者的策略是使用纠错码(error-correcting code),而后者则使用检错码(error-detecting code)。 1.纠错码 在了解纠错码之前,先了解一个基本概念:海明距离。通常一帧包括m个数据(报文)位和r个冗余位或者校验位。设整个长度为n(即n=m+r),则此长度为n的单元通常被称作n位码字(codeword)。 给出任意两个码字,如10001001和10110001,可以确定它们有多少个对应位不同。在此例中有3位不同。为了确定有多少位不同,只须对两个码字做异或运算,然后计算结果中1的个数。两个码字中不同位的个数,称为海明距离(Hamming Distance)。其重要性在于,假如两个码字具有海明距离d,则需要d个位差错才能将其中一个码字转换成另一个。 一种编码的校验和纠错能力取决于它的海明距离。为检测出d比特错,需要使用d+1的编码;因为d个单比特错决不可能将一个有效的码字转变成另一个有效的码字。当接收方看到无效的码字,它纠能明白发生传输错误。同样,为了纠正d比特错,必须使用距离为2d+1的编码,这是因为有效码字的距离远到即使发生d个变化,这个发生了变化的码字仍然比其它码字都接近原始码字。作为纠错码的一个简单例子,考虑如下只有4个有效码字的代码: 0000000000、0000011111、1111100000和1111111111 这种代码的距离为5,也就是说,它能纠正双比特错。假如码字0000000111到达后,接收方知道原始码字应该为0000011111。但是,如果出现了三位错,而将0000000000变成了0000000111,则差错将不能正确地纠正。 2.检错码 检错码有时也用于数据传输。例如,当信道为单工方式,无法要求重传的情况下,大多数采用检错码加重传的方式。 假设信道的出错是孤立的,信道的误码率为每位10-6。数据块的大小为100位。为1000位的数据块纠错,需要10个校验位;1兆的数据位将需要10000个校验位。若只需要检测一个数据块的一位错误,每块一个奇偶位就够了。每传送1000个数据块就需要额外传送一个数据块。错误检错+重传方式的整个开销,仅仅是每兆数据只有2001位,而海明码为10000位。 假若在一个块上只加一个奇偶位,那么块的长的突发错误的检测率就会很糟糕,能够检测到差错的概率只有0.5,这是难以接受的。改进的措施可以采取将每个数据块组成n位宽k行高的长方形矩阵进行发送。对每一列的奇偶位分别进行计算,附加在矩阵上,作为矩阵的最后一行,然后按行进行发送。当块到达后,接收方检测所有的奇偶位。如果其中任何一个出错了,就需要重新传送整个块。 这种方法能够检测到单个程度为n的突发错误,因为每一列只有一位改变了。然而如果第一位变反,最后一位变反,且所有其它位都正确,则长度为n+1的突发差错将不会被检测到。假如一个块被一个长的突发差错或者短的突发差错所破坏,n列中的每一列的奇偶值碰巧正确的概率为0.5,那么这个出错块被接受的概率不应该是2-n。 虽然上述方法有时已经足够了,但是在实践中,另一种方法正在被广泛使用,即多项式编码(也叫循环冗余码,或CRC码)。多项式编码是基于将位串看成是系数为0或1的多项式,一个k位帧可以看成是从Xk-1到X0的k-1次多项式的系数序列。如果采用多项式编码的方式,发送方和接收方必须事先商定一个生成多项式G(x),生成多项式的高位和低位必须是1。要计算m位的帧M(x)的校验和,生成多项式必须比该多项式短。基本思想是:将校验和加在帧的末尾,使这个带校验和的帧的多项式能被G(x)除尽。当接收方收到带校验和的帧时,用G(x)去除它,如果有余数,则传输出错。 计算校验和的算法如下: ①.设G(x)为r阶,在帧的末尾附加r个零,使帧为m+r位,则相应的多项式是XrM(x)。 ②.按模2除法用对应于G(x)的位串去除对应于XrM(x)的位串。 ③.按模2减法从对应于XrM(x)的位串中减去余数。结果就是要传送带校验和的帧,叫多项式T(x)。 以下三个多项式已经成为国际标准: crc -12 = x^12+x^11+x^3+x^2+x+1 crc -16 = x^16+x^15+x^2+1 crc -ccitt = x^16+x^12+x^5+1 这三个多项式都包含了x+1作为基本因子。当字符串长度为6位时,使用CRC-12;其余两个多项式用在字符串长度为8位的情况下。一个16位的校验和,如CRC-16或CRC-CCITT,可以捕捉到所有的单位差错和双位差错,所有奇数位数的差错,所有长度小于或等于16位的突发差错,99.997%的长度为17位的突发差错,以及99.998%的长度为18位或多于18位的突发差错。 虽然计算校验和的计算方法看起来相当复杂,但Peterson和Brown已经给出了一种简单的移位寄存器电路来进行计算,并用硬件来完成对校验和的校验。在实际应用中,几乎都在使用此硬件。 |
| C中的指针是最方便和灵活的,也是最头疼的 。在链表的建立过程中,大家一般都用指针,那么请看 下面一段程序: struct item_t { typenameSomeinfo; item_t * Next; //下一个结构的指针。 } int built (item_t * head) //以head为头建立一个链表 { item_t *Temp; temp=Head; for (int i=0;i<ITEMNUM;i++) temp=(item_t *) malloc (sizeof (item_t)); if (temp==NULL) return 0; temp=temp->Next; } return 1; } 短短的一段程序,想当然的写成了这样,其中有将近四个错误 一是传进来的 head 在函数里没有任何改变。二是就算 head 在函数里被改变,可对于调用者 built (pointer) 来说, 在函数调用结束之后pointer的值并没有任何改变!!第三, 让我们来看看建立过程,先为temp分配一段空间,然后再将temp 置为temp->next,我们不妨在这儿将程序改为 temp1 =temp;//新增加的语句 temp=temp->next; 然后又循环过来,又给temp分配空间,注意!!Temp1->next的 值并没有改变,程序所做的只是将temp重新赋了一个值而已! 这样的程序只有出毛病的份了。 现将上一次的程序加上一个函数 int add (item_t * obj); 功能是将obj指向的结构放在链表的尾端,函数体如下: int add (item_t * obj) { item_t *Temp; if (obj==NULL) return 0; Temp=head;//head为一全局变量,为队列的头指针。 while (Temp->Next!=NULL) { Temp=Temp->Next; } Temp->Next =obj; return 1; } 这里首先有一个问题:如果队列为空如何处理? 于是需要加入如下程序段: if (head==NULL) { head=obj; return 0; } 可是运行这样的程序是要冒极大的风险的,因为函数包括 了以下的几个约定: 1:所有的item_t类型的元素被初始化时,他的 Next 指针必须被初始化为 NULL. 2:所有传递给 add (item_t *) 的指针必须是 不同元素的地址!而且最好是用动态分配的。 如果这两条没有被很好的遵守的话,麻烦就来了,看如下 的调用: : : for (int i=0;i<10;i++) { item_t test; test.Someinfo =make_a_new_info (…..); test.Next =NULL; add (&test); } : : 你试着想象一下结果好吗? 再有如下的例子: voidadd_some_item (void) { item_t test; test.someinfo =make_a_new_info (….); test.Next =NULL; add (&test); } 在函数执行完毕之后,test的内存将被释放掉,也就是说,在 以head为头的链表中,有一个悬空的指针!!!这会造成系统 的崩溃!!! 指针的错误是举不胜举的。 再看下面一个: ;C语言里,数组名是被看作指针来使用的, 一维数组是指针,二维数组是指向指针的指针,三 维是……… 看下面的例子: ;voi;show (int * * info,int x,int y)//打印一个x*y的数组的内容 ;{ ;in; I,j; ;fo; (i=0;ibr>;fo; (j=0;jbr>;printf ("%d ",info); ;} ;printf ("\n"); ;} ;} 在进行如下调用之后,你的系统有崩溃的可能! ;voi;Function (void) ;{ ;in; as [10][10]; ; : ; : ;sho;(as,10,10); ; : ; : -- |
1. 如何在指定矩形框内水平/垂直显示文字 /////////////////////////////////////////////////////////////////////////////////////////////////////// //说明: // 在矩形框中水平或垂直显示文字,jingzhou xu. // lMode: 排列方式,0:水平方式; 1:垂直对齐 // lHori: 水平对齐方式, 0:左对齐; 1:居中; 2:右对齐; 3:自定义 // lVert: 垂直对齐方式, 0:顶对齐; 1:居中; 2:底对齐; 3:自定义 ////////////////////////////////////////////////////////////////////////////////////////////////////// CRect DrawTitleInRect(CDC *pDC, LPCTSTR lpszString, LPRECT lpRect, long lMode, long lHori, long lVert) { TEXTMETRIC tm; pDC->GetTextMetrics(&tm); int tmpWidth=tm.tmMaxCharWidth; CRect rcInner(lpRect); if(lMode==0) { rcInner.left+=tmpWidth; rcInner.right-=tmpWidth; rcInner.top-=tmpWidth; rcInner.bottom+=tmpWidth; } if(lMode==1) { rcInner.left+=tmpWidth; rcInner.right=rcInner.left+tmpWidth; rcInner.top-=tmpWidth; rcInner.bottom+=tmpWidth; } pDC->DrawText(lpszString, rcInner, DT_WORDBREAK|DT_LEFT|DT_CALCRECT); switch(lHori) { case 0: break; case 1: { long xOutCent=(lpRect->right+lpRect->left)/2; long xInnCent=(rcInner.right+rcInner.left)/2; rcInner.left+=xOutCent-xInnCent; rcInner.right+=xOutCent-xInnCent; } break; case 2: { long lInWidth=rcInner.right-rcInner.left; rcInner.right=lpRect->right-tmpWidth; rcInner.left=rcInner.right-lInWidth; } break; default: break; } switch(lVert) { case 0: break; case 1: { long yOutCent=(lpRect->bottom+lpRect->top)/2; long yInnCent=(rcInner.bottom+rcInner.top)/2; rcInner.top-=yInnCent-yOutCent; rcInner.bottom-=yInnCent-yOutCent; } break; case 2: { long lInHeigh=rcInner.top-rcInner.bottom; rcInner.bottom=lpRect->bottom+tmpWidth; rcInner.top=rcInner.bottom+lInHeigh; } break; default: break; } if(lHori==0) pDC->DrawText(lpszString, rcInner, DT_WORDBREAK|DT_LEFT); else if(lHori==1) pDC->DrawText(lpszString, rcInner, DT_WORDBREAK|DT_CENTER); else if(lHori==2) pDC->DrawText(lpszString, rcInner, DT_WORDBREAK|DT_RIGHT); return rcInner; } 2. 如何在指定矩形中旋转显示文字 /////////////////////////////////////////////////////// //说明: // 在矩形框中旋转方式显示文字,jingzhou xu //参数: // pDC: DC指针 // str: 显示文字 // rect: 显示范围 // angle: 旋转角度 // nOptions: ExtTextOut()中相应设置<ETO_CLIPPED 和 ETO_OPAQUE> /////////////////////////////////////////////////////// void DrawRotatedText(CDC* pDC, const CString str, CRect rect, double angle, UINT nOptions) { //按比例转换角度值 double pi = 3.141592654; double radian = pi * 2 / 360 * angle; //获取显示文字中心点 CSize TextSize = pDC->GetTextExtent(str); CPoint center; center.x = TextSize.cx / 2; center.y = TextSize.cy / 2; //计算显示文字新的中心点 CPoint rcenter; rcenter.x = long(cos(radian) * center.x - sin(radian) * center.y); rcenter.y = long(sin(radian) * center.x + cos(radian) * center.y); //绘制文字 pDC->SetTextAlign(TA_BASELINE); pDC->SetBkMode(TRANSPARENT); pDC->ExtTextOut(rect.left + rect.Width() / 2 - rcenter.x, rect.top + rect.Height() / 2 + rcenter.y, nOptions, rect, str, NULL); } 3. 如何将32 x 32像素图标转换为16 x 16像素值的图标 HICON Convert32x32IconTo16x16(HICON h32x32Icon) { HDC hMainDC, hMemDC1, hMemDC2; HICON h16x16Icon; BITMAP bmp; HBITMAP hOldBmp1, hOldBmp2; ICONINFO IconInfo32x32, IconInfo16x16; GetIconInfo(h32x32Icon, &IconInfo32x32); hMainDC = ::GetDC(m_hWnd); hMemDC1 = CreateCompatibleDC(hMainDC); hMemDC2 = CreateCompatibleDC(hMainDC); GetObject(IconInfo32x32.hbmColor, sizeof(BITMAP), &bmp); IconInfo16x16.hbmColor = CreateBitmap( 16, 16, bmp.bmPlanes, bmp.bmBitsPixel, NULL); hOldBmp1 = (HBITMAP) SelectObject( hMemDC1, IconInfo32x32.hbmColor); hOldBmp2 = (HBITMAP) SelectObject( hMemDC2, IconInfo16x16.hbmColor); StretchBlt(hMemDC2, 0, 0, 16, 16, hMemDC1, 0, 0, 32, 32, SRCCOPY ); GetObject(IconInfo32x32.hbmMask, sizeof(BITMAP), &bmp); IconInfo16x16.hbmMask = CreateBitmap( 16, 16, bmp.bmPlanes, bmp.bmBitsPixel, NULL); SelectObject(hMemDC1, IconInfo32x32.hbmMask); SelectObject(hMemDC2, IconInfo16x16.hbmMask); StretchBlt(hMemDC2, 0, 0, 16, 16, hMemDC1, 0, 0, 32, 32, SRCCOPY ); SelectObject(hMemDC1, hOldBmp1); SelectObject(hMemDC2, hOldBmp2); IconInfo16x16.fIcon = TRUE; h16x16Icon = CreateIconIndirect(&IconInfo16x16); DeleteObject(IconInfo32x32.hbmColor); DeleteObject(IconInfo16x16.hbmColor); DeleteObject(IconInfo32x32.hbmMask); DeleteObject(IconInfo16x16.hbmMask); DeleteDC(hMemDC1); DeleteDC(hMemDC2); ::ReleaseDC(m_hWnd, hMainDC); return h16x16Icon; } 4. 如何建立一个灰度级图标 HICON CreateGrayscaleIcon(HICON hIcon) { HICON hGrayIcon = NULL; HDC hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL; BITMAP bmp; HBITMAP hOldBmp1 = NULL, hOldBmp2 = NULL; ICONINFO csII, csGrayII; BOOL bRetValue = FALSE; bRetValue = ::GetIconInfo(hIcon, &csII); if (bRetValue == FALSE) return NULL; hMainDC = ::GetDC(m_hWnd); hMemDC1 = ::CreateCompatibleDC(hMainDC); hMemDC2 = ::CreateCompatibleDC(hMainDC); if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL) return NULL; if (::GetObject(csII.hbmColor, sizeof(BITMAP), & amp;bmp)) { csGrayII.hbmColor = ::CreateBitmap(csII.xHotspot*2, csII.yHotspot*2, bmp.bmPlanes, bmp.bmBitsPixel, NULL); if (csGrayII.hbmColor) { hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor); hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor); ::BitBlt(hMemDC2, 0, 0, csII.xHotspot*2, csII.yHotspot*2, hMemDC1, 0, 0, SRCCOPY); DWORD dwLoopY = 0, dwLoopX = 0; COLORREF crPixel = 0; BYTE byNewPixel = 0; for (dwLoopY = 0; dwLoopY < csII.yHotspot*2; dwLoopY++) { for (dwLoopX = 0; dwLoopX < csII.xHotspot*2; dwLoopX++) { crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY); byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114)); if (crPixel) ::SetPixel(hMemDC2, dwLoopX, dwLoopY, RGB(byNewPixel, byNewPixel, byNewPixel)); } // for } // for ::SelectObject(hMemDC1, hOldBmp1); ::SelectObject(hMemDC2, hOldBmp2); csGrayII.hbmMask = csII.hbmMask; csGrayII.fIcon = TRUE; hGrayIcon = ::CreateIconIndirect(&csGrayII); } // if ::DeleteObject(csGrayII.hbmColor); //::DeleteObject(csGrayII.hbmMask); } // if ::DeleteObject(csII.hbmColor); ::DeleteObject(csII.hbmMask); ::DeleteDC(hMemDC1); ::DeleteDC(hMemDC2); ::ReleaseDC(m_hWnd, hMainDC); return hGrayIcon; } 5. 如何按指定角度旋转显示内存位图(用法和BitBlt类似) void RotBlt(HDC destDC, int srcx1, int srcy1, int srcx2, int srcy2, HDC srcDC , int destx1, int desty1 ,int thetaInDegrees ,DWORD mode) { double theta = thetaInDegrees * (3.14159/180); //原图像原始大小 int width = srcx2 - srcx1; int height = srcy2 - srcy1; //原图像中心点 int centreX = int(float(srcx2 + srcx1)/2); int centreY = int(float(srcy2 + srcy1)/2); //判断出图像可以沿任意方向旋转的矩形框 if(width>height)height = width; else width = height; HDC memDC = CreateCompatibleDC(destDC); HBITMAP memBmp = CreateCompatibleBitmap(destDC, width, height); HBITMAP obmp = (HBITMAP) SelectObject(memDC, memBmp); //内存DC新在中心点 int newCentre = int(float(width)/2); //开始旋转 for(int x = srcx1; x<=srcx2; x++) for(int y = srcy1; y<=srcy2; y++) { COLORREF col = GetPixel(srcDC,x,y); int newX = int((x-centreX)*sin(theta)+(y-centreY)*cos(theta)); int newY = int((x-centreX)*cos(theta)-(y-centreY)*sin(theta)); SetPixel(memDC , newX + newCentre, newY + newCentre, col); } //复制到目标DC上 BitBlt(destDC, destx1, desty1, width, height, memDC, 0,0,mode); //释放内存 SelectObject(memDC, obmp); DeleteDC(memDC); DeleteObject(memBmp); } 用法: RotBlt(dc, 0,0,150,150,memDC,200,0, 45, SRCCOPY); 6. 如何将指定的窗体,以位图形式复制到系统剪切板上 void CScreenSnapDlg::toClipboard_Bio(CWnd * wnd, BOOL FullWnd) { CDC *dc; if(FullWnd) { /* 抓取整个窗口 */ dc = new CWindowDC(wnd); } /* 抓取整个窗口 */ else { /* 仅抓取客户区时 */ dc = new CClientDC(wnd); } /* 仅抓取客户区时 */ CDC memDC; memDC.CreateCompatibleDC(dc); CBitmap bm; CRect r; if(FullWnd) wnd->GetWindowRect(&r); else wnd->GetClientRect(&r); CString s; wnd->GetWindowText(s); CSize sz(r.Width(), r.Height()); bm.CreateCompatibleBitmap(dc, sz.cx, sz.cy); CBitmap * oldbm = memDC.SelectObject(&bm); memDC.BitBlt(0, 0, sz.cx, sz.cy, dc, 0, 0, SRCCOPY); //直接调用OpenClipboard(),而不用wnd->GetParent()->OpenClipboard(); wnd->OpenClipboard(); ::EmptyClipboard(); ::SetClipboardData(CF_BITMAP, bm.m_hObject); CloseClipboard(); //恢复原始环境 memDC.SelectObject(oldbm); bm.Detach(); delete dc; } |
| <script type="text/JavaScript"> alimama_pid="mm_11646100_1378680_3156860"; alimama_titlecolor="0000FF"; alimama_descolor ="000000"; alimama_bgcolor="FFFFFF"; alimama_bordercolor="E6E6E6"; alimama_linkcolor="008000"; alimama_bottomcolor="FFFFFF"; alimama_anglesize="0"; alimama_bgpic="0"; alimama_icon="0"; alimama_sizecode="14"; alimama_width=728; alimama_height=90; alimama_type=2; </script> <script src="http://a.alimama.cn/inf.js" type=text/javascript> </script> |
| /*4.3.3源程序*/ #include <graphics.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <dos.h> #define N 20/*迷宫的大小,可改变*/ int oldmap;/*递归用的数组,用全局变量节约时间*/ int yes=0;/*yes是判断是否找到路的标志,1找到,0没找到*/ int way[100][2],wayn=0;/*way数组是显示路线用的,wayn是统计走了几个格子*/ void Init(void);/*图形初始化*/ void Close(void);/*图形关闭*/ void DrawPeople(int *x,int *y,int n);/*画人工探索物图*/ void PeopleFind(int (*x));/*人工探索*/ void WayCopy(int (*x),int (*y));/*为了8个方向的递归,把旧迷宫图拷贝给新数组*/ int FindWay(int (*x),int i,int j);/*自动探索函数*/ void MapRand(int (*x));/*随机生成迷宫函数*/ void PrMap(int (*x));/*输出迷宫图函数*/ void Result(void);/*输出结果处理*/ void Find(void);/*成功处理*/ void NotFind(void);/*失败处理*/ void main(void)/*主函数*/ { int map; /*迷宫数组*/ char ch; clrscr(); printf("\n Please select hand(1) else auto\n");/*选择探索方式*/ scanf("%c",&ch); Init(); /*初始化*/ MapRand(map);/*生成迷宫*/ PrMap(map);/*显示迷宫图*/ if(ch=='1') PeopleFind(map);/*人工探索*/ else FindWay(map,1,1);/*系统自动从下标1,1的地方开始探索*/ Result();/*输出结果*/ Close(); } void Init(void)/*图形初始化*/ { int gd=DETECT,gm; initgraph(&gd,&gm,"c:\\tc"); } void DrawPeople(int *x,int *y,int n)/*画人工控制图*/ {/*如果将以下两句注释掉,则显示人工走过的路径,*/ setfillstyle(SOLID_FILL,WHITE); /*设置白色实体填充样式*/ bar(100+(*y)*15-6,50+(*x)*15-6,100+(*y)*15+6,50+(*x)*15+6); /*恢复原通路*/ switch(n)/*判断x,y的变化,8个方向的变化*/ { case 1: (*x)--;break; /*上*/ case 2: (*x)--;(*y)++;break ;/*右上*/ case 3: (*y)++;break; /*右*/ case 4: (*x)++;(*y)++;break; /*右下*/ case 5: (*x)++;break; /*下*/ case 6: (*x)++;(*y)--;break; /*左下*/ case 7: (*y)--;break; /*左*/ case 8: (*x)--;(*y)--;break; /*左上*/ } setfillstyle(SOLID_FILL,RED);/*新位置显示探索物*/ bar(100+(*y)*15-6,50+(*x)*15-6,100+(*y)*15+6,50+(*x)*15+6); } void PeopleFind(int (*map))/*人工手动查找*/ { int x,y; char c=0;/*接收按键的变量*/ x=y=1;/*人工查找的初始位置*/ setcolor(11); line(500,200,550,200); outtextxy(570,197,"d"); line(500,200,450,200); outtextxy(430,197,"a"); line(500,200,500,150); outtextxy(497,130,"w"); line(500,200,500,250); outtextxy(497,270,"x"); line(500,200,450,150); outtextxy(445,130,"q"); line(500,200,550,150); outtextxy(550,130,"e"); line(500,200,450,250); outtextxy(445,270,"z"); line(500,200,550,250); outtextxy(550,270,"c");/*以上是画8个方向的控制介绍*/ setcolor(YELLOW); outtextxy(420,290,"Press 'Enter' to end");/*压回车键结束*/ setfillstyle(SOLID_FILL,RED); bar(100+y*15-6,50+x*15-6,100+y*15+6,50+x*15+6);/*入口位置显示*/ while(c!=13)/*如果按下的不是回车键*/ { c=getch();/*接收字符后开始各个方向的探索*/ if(c=='w'&&map[x-1]!=1) DrawPeople(&x,&y,1);/*上*/ else if(c=='e'&&map[x-1][y+1]!=1) DrawPeople(&x,&y,2);/*右上*/ else if(c=='d'&&map[y+1]!=1) DrawPeople(&x,&y,3);/*右*/ else if(c=='c'&&map[x+1][y+1]!=1) DrawPeople(&x,&y,4);/*右下*/ else if(c=='x'&&map[x+1]!=1) DrawPeople(&x,&y,5);/*下*/ else if(c=='z'&&map[x+1][y-1]!=1) DrawPeople(&x,&y,6); /*左下*/ else if(c=='a'&&map[y-1]!=1) DrawPeople(&x,&y,7); /*左*/ else if(c=='q'&&map[x-1][y-1]!=1) DrawPeople(&x,&y,8); /*左上*/ } setfillstyle(SOLID_FILL,WHITE); /*消去红色探索物,恢复原迷宫图*/ bar(100+y*15-6,50+x*15-6,100+y*15+6,50+x*15+6); if(x==N-2&&y==N-2)/*人工控制找成功的话*/ yes=1; /*如果成功标志为1*/ } void WayCopy(int (*oldmap),int (*map))/*拷贝迷宫数组 */ { int i,j; for(i=0;i<N;i++) for(j=0;j<N;j++) oldmap=map; } int FindWay(int (*map),int i,int j)/*递归找路*/ { if(i==N-2&&j==N-2)/*走到出口*/ { yes=1;/*标志为1,表示成功*/ return; } map=1;/*走过的地方变为1*/ WayCopy(oldmap,map); /*拷贝迷宫图*/ if(oldmap[i+1][j+1]==0&&!yes)/*判断右下方是否可走*/ { FindWay(oldmap,i+1,j+1); if(yes)/*如果到达出口了,再把值赋给显示路线的way数组,也正是这个原因,所以具体路线是从最后开始保存*/ { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[i+1]==0&&!yes)/*判断下方是否可以走,如果标志yes已经是1也不用找下去了*/ { FindWay(oldmap,i+1,j); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[j+1]==0&&!yes)/*判断右方是否可以走*/ { FindWay(oldmap,i,j+1); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[i-1]==0&&!yes)/*判断上方是否可以走*/ { FindWay(oldmap,i-1,j); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[i-1][j+1]==0&&!yes)/*判断右上方是否可以走*/ { FindWay(oldmap,i-1,j+1); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[i+1][j-1]==0&&!yes)/*判断左下方是否可以走*/ { FindWay(oldmap,i+1,j-1); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[j-1]==0&&!yes)/*判断左方是否可以走*/ { FindWay(oldmap,i,j-1); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } WayCopy(oldmap,map); if(oldmap[i-1][j-1]==0&&!yes)/*判断左上方是否可以走*/ { FindWay(oldmap,i-1,j-1); if(yes) { way[0]=i; way[wayn++][1]=j; return; } } return; } void MapRand(int (*map))/*开始的随机迷宫图*/ { int i,j; cleardevice();/*清屏*/ randomize(); /*随机数发生器*/ for(i=0;i<N;i++) { for(j=0;j<N;j++) { if(i==0||i==N-1||j==0||j==N-1)/*最外面一圈为墙壁*/ map=1; else if(i==1&&j==1||i==N-2&&j==N-2)/*出发点与终点表示为可走的*/ map=0; else map=random(2);/*其它的随机生成0或1*/ } } } void PrMap(int (*map))/*输出迷宫图*/ { int i,j; for(i=0;i<N;i++) for(j=0;j<N;j++) if(map==0) { setfillstyle(SOLID_FILL,WHITE);/*白色为可走的路*/ bar(100+j*15-6,50+i*15-6,100+j*15+6,50+i*15+6); } else { setfillstyle(SOLID_FILL,BLUE);/*蓝色为墙壁*/ bar(100+j*15-6,50+i*15-6,100+j*15+6,50+i*15+6); } } void Find(void)/*找到通路*/ { int i; setfillstyle(SOLID_FILL,RED);/*红色输出走的具体路线*/ wayn--; for(i=wayn;i>=0;i--) { bar(100+way[1]*15-6,50+way[0]*15-6,100+ way[1]*15+6,50+way[0]*15+6); sleep(1);/*控制显示时间*/ } bar(100+(N-2)*15-6,50+(N-2)*15-6,100+ (N-2)*15+6,50+(N-2)*15+6); /*在目标点标红色*/ setcolor(GREEN); settextstyle(0,0,2);/*设置字体大小*/ outtextxy(130,400,"Find a way!"); } void NotFind(void)/*没找到通路*/ { setcolor(GREEN); settextstyle(0,0,2);/*设置字体大小*/ outtextxy(130,400,"Not find a way!"); } void Result(void)/*结果处理*/ { if(yes)/*如果找到*/ Find(); else/*没找到路*/ NotFind(); getch(); } void Close(void)/*图形关闭*/ { closegraph(); } |
| /*5.3.4 源程序*/ #include <graphics.h> #include <stdlib.h> #include <dos.h> #define LEFTPRESS 0xff01 #define LEFTCLICK 0xff10 #define LEFTDRAG 0xff19 #define MOUSEMOVE 0xff08 struct { int num;/*格子当前处于什么状态,1有雷,0已经显示过数字或者空白格子*/ int roundnum;/*统计格子周围有多少雷*/ int flag;/*右键按下显示红旗的标志,0没有红旗标志,1有红旗标志*/ }Mine[10][10]; int gameAGAIN=0;/*是否重来的变量*/ int gamePLAY=0;/*是否是第一次玩游戏的标志*/ int mineNUM;/*统计处理过的格子数*/ char randmineNUM[3];/*显示数字的字符串*/ int Keystate; int MouseExist; int MouseButton; int MouseX; int MouseY; void Init(void);/*图形驱动*/ void MouseOn(void);/*鼠标光标显示*/ void MouseOff(void);/*鼠标光标隐藏*/ void MouseSetXY(int,int);/*设置当前位置*/ int LeftPress(void);/*左键按下*/ int RightPress(void);/*鼠标右键按下*/ void MouseGetXY(void);/*得到当前位置*/ void Control(void);/*游戏开始,重新,关闭*/ void GameBegain(void);/*游戏开始画面*/ void DrawSmile(void);/*画笑脸*/ void DrawRedflag(int,int);/*显示红旗*/ void DrawEmpty(int,int,int,int);/*两种空格子的显示*/ void GameOver(void);/*游戏结束*/ void GameWin(void);/*显示胜利*/ int MineStatistics(int,int);/*统计每个格子周围的雷数*/ int ShowWhite(int,int);/*显示无雷区的空白部分*/ void GamePlay(void);/*游戏过程*/ void Close(void);/*图形关闭*/ void main(void) { Init(); Control(); Close(); } void Init(void)/*图形开始*/ { int gd=DETECT,gm; initgraph(&gd,&gm,"c:\\tc"); } void Close(void)/*图形关闭*/ { closegraph(); } void MouseOn(void)/*鼠标光标显示*/ { _AX=0x01; geninterrupt(0x33); } void MouseOff(void)/*鼠标光标隐藏*/ { _AX=0x02; geninterrupt(0x33); } void MouseSetXY(int x,int y)/*设置当前位置*/ { _CX=x; _DX=y; _AX=0x04; geninterrupt(0x33); } int LeftPress(void)/*鼠标左键按下*/ { _AX=0x03; geninterrupt(0x33); return(_BX&1); } int RightPress(void)/*鼠标右键按下*/ { _AX=0x03; geninterrupt(0x33); return(_BX&2); } void MouseGetXY(void)/*得到当前位置*/ { _AX=0x03; geninterrupt(0x33); MouseX=_CX; MouseY=_DX; } void Control(void)/*游戏开始,重新,关闭*/ { int gameFLAG=1;/*游戏失败后判断是否重新开始的标志*/ while(1) { if(gameFLAG)/*游戏失败后没判断出重新开始或者退出游戏的话就继续判断*/ { GameBegain(); /*游戏初始画面*/ GamePlay();/*具体游戏*/ if(gameAGAIN==1)/*游戏中重新开始*/ { gameAGAIN=0; continue; } } MouseOn(); gameFLAG=0; if(LeftPress())/*判断是否重新开始*/ { MouseGetXY(); if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85) { gameFLAG=1; continue; } } if(kbhit())/*判断是否按键退出*/ break; } MouseOff(); } void DrawSmile(void)/*画笑脸*/ { setfillstyle(SOLID_FILL,YELLOW); fillellipse(290,75,10,10); setcolor(YELLOW); setfillstyle(SOLID_FILL,BLACK);/*眼睛*/ fillellipse(285,75,2,2); fillellipse(295,75,2,2); setcolor(BLACK);/*嘴巴*/ bar(287,80,293,81); } void DrawRedflag(int i,int j)/*显示红旗*/ { setcolor(7); setfillstyle(SOLID_FILL,RED); bar(198+j*20,95+i*20,198+j*20+5,95+i*20+5); setcolor(BLACK); line(198+j*20,95+i*20,198+j*20,95+i*20+10); } void DrawEmpty(int i,int j,int mode,int color)/*两种空格子的显示*/ { setcolor(color); setfillstyle(SOLID_FILL,color); if(mode==0)/*没有单击过的大格子*/ bar(200+j*20-8,100+i*20-8,200+j*20+8,100+i*20+8); else if(mode==1)/*单击过后显示空白的小格子*/ bar(200+j*20-7,100+i*20-7,200+j*20+7,100+i*20+7); } void GameBegain(void)/*游戏开始画面*/ { int i,j; cleardevice(); if(gamePLAY!=1) { MouseSetXY(290,70); /*鼠标一开始的位置,并作为它的初始坐标*/ MouseX=290; MouseY=70; } gamePLAY=1;/*下次按重新开始的话鼠标不重新初始化*/ mineNUM=0; setfillstyle(SOLID_FILL,7); bar(190,60,390,290); for(i=0;i<10;i++)/*画格子*/ for(j=0;j<10;j++) DrawEmpty(i,j,0,8); setcolor(7); DrawSmile();/*画脸*/ randomize(); for(i=0;i<10;i++)/*100个格子随机赋值有没有地雷*/ for(j=0;j<10;j++) { Mine.num=random(8);/*如果随机数的结果是1表示这个格子有地雷*/ if(Mine.num==1) mineNUM++;/*现有雷数加1*/ else Mine.num=2; Mine.flag=0;/*表示没红旗标志*/ } sprintf(randmineNUM,"%d",mineNUM); /*显示这次总共有多少雷数*/ setcolor(1); settextstyle(0,0,2); outtextxy(210,70,randmineNUM); mineNUM=100-mineNUM;/*变量取空白格数量*/ MouseOn(); } void GameOver(void)/*游戏结束画面*/ { int i,j; setcolor(0); for(i=0;i<10;i++) for(j=0;j<10;j++) if(Mine.num==1)/*显示所有的地雷*/ { DrawEmpty(i,j,0,RED); setfillstyle(SOLID_FILL,BLACK); fillellipse(200+j*20,100+i*20,7,7); } } void GameWin(void)/*显示胜利*/ { setcolor(11); settextstyle(0,0,2); outtextxy(230,30,"YOU WIN!"); } int MineStatistics(int i,int j)/*统计每个格子周围的雷数*/ { int nNUM=0; if(i==0&&j==0)/*左上角格子的统计*/ { if(Mine[0][1].num==1) nNUM++; if(Mine[1][0].num==1) nNUM++; if(Mine[1][1].num==1) nNUM++; } else if(i==0&&j==9)/*右上角格子的统计*/ { if(Mine[0][8].num==1) nNUM++; if(Mine[1][9].num==1) nNUM++; if(Mine[1][8].num==1) nNUM++; } else if(i==9&&j==0)/*左下角格子的统计*/ { if(Mine[8][0].num==1) nNUM++; if(Mine[9][1].num==1) nNUM++; if(Mine[8][1].num==1) nNUM++; } else if(i==9&&j==9)/*右下角格子的统计*/ { if(Mine[9][8].num==1) nNUM++; if(Mine[8][9].num==1) nNUM++; if(Mine[8][8].num==1) nNUM++; } else if(j==0)/*左边第一列格子的统计*/ { if(Mine[j+1].num==1) nNUM++; if(Mine[i+1].num==1) nNUM++; if(Mine[i-1].num==1) nNUM++; if(Mine[i-1][j+1].num==1) nNUM++; if(Mine[i+1][j+1].num==1) nNUM++; } else if(j==9)/*右边第一列格子的统计*/ { if(Mine[j-1].num==1) nNUM++; if(Mine[i+1].num==1) nNUM++; if(Mine[i-1].num==1) nNUM++; if(Mine[i-1][j-1].num==1) nNUM++; if(Mine[i+1][j-1].num==1) nNUM++; } else if(i==0)/*第一行格子的统计*/ { if(Mine[i+1].num==1) nNUM++; if(Mine[j-1].num==1) nNUM++; if(Mine[j+1].num==1) nNUM++; if(Mine[i+1][j-1].num==1) nNUM++; if(Mine[i+1][j+1].num==1) nNUM++; } else if(i==9)/*最后一行格子的统计*/ { if(Mine[i-1].num==1) nNUM++; if(Mine[j-1].num==1) nNUM++; if(Mine[j+1].num==1) nNUM++; if(Mine[i-1][j-1].num==1) nNUM++; if(Mine[i-1][j+1].num==1) nNUM++; } else/*普通格子的统计*/ { if(Mine[i-1].num==1) nNUM++; if(Mine[i-1][j+1].num==1) nNUM++; if(Mine[j+1].num==1) nNUM++; if(Mine[i+1][j+1].num==1) nNUM++; if(Mine[i+1].num==1) nNUM++; if(Mine[i+1][j-1].num==1) nNUM++; if(Mine[j-1].num==1) nNUM++; if(Mine[i-1][j-1].num==1) nNUM++; } return(nNUM);/*把格子周围一共有多少雷数的统计结果返回*/ } int ShowWhite(int i,int j)/*显示无雷区的空白部分*/ { if(Mine.flag==1||Mine.num==0)/*如果有红旗或该格处理过就不对该格进行任何判断*/ return; mineNUM--;/*显示过数字或者空格的格子就表示多处理了一个格子,当所有格子都处理过了表示胜利*/ if(Mine.roundnum==0&&Mine.num!=1)/*显示空格*/ { DrawEmpty(i,j,1,7); Mine.num=0; } else if(Mine.roundnum!=0)/*输出雷数*/ { DrawEmpty(i,j,0,8); sprintf(randmineNUM,"%d",Mine.roundnum); setcolor(RED); outtextxy(195+j*20,95+i*20,randmineNUM); Mine.num=0;/*已经输出雷数的格子用0表示已经用过这个格子*/ return ; } /*8个方向递归显示所有的空白格子*/ if(i!=0&&Mine[i-1].num!=1) ShowWhite(i-1,j); if(i!=0&&j!=9&&Mine[i-1][j+1].num!=1) ShowWhite(i-1,j+1); if(j!=9&&Mine[j+1].num!=1) ShowWhite(i,j+1); if(j!=9&&i!=9&&Mine[i+1][j+1].num!=1) ShowWhite(i+1,j+1); if(i!=9&&Mine[i+1].num!=1) ShowWhite(i+1,j); if(i!=9&&j!=0&&Mine[i+1][j-1].num!=1) ShowWhite(i+1,j-1); if(j!=0&&Mine[j-1].num!=1) ShowWhite(i,j-1); if(i!=0&&j!=0&&Mine[i-1][j-1].num!=1) ShowWhite(i-1,j-1); } void GamePlay(void)/*游戏过程*/ { int i,j,Num;/*Num用来接收统计函数返回一个格子周围有多少地雷*/ for(i=0;i<10;i++) for(j=0;j<10;j++) Mine.roundnum=MineStatistics(i,j);/*统计每个格子周围有多少地雷*/ while(!kbhit()) { if(LeftPress())/*鼠标左键盘按下*/ { MouseGetXY(); if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85)/*重新来*/ { MouseOff(); gameAGAIN=1; break; } if(MouseX>190&&MouseX<390&&MouseY>90&&MouseY<290)/*当前鼠标位置在格子范围内*/ { j=(MouseX-190)/20;/*x坐标*/ i=(MouseY-90)/20;/*y坐标*/ if(Mine.flag==1)/*如果格子有红旗则左键无效*/ continue; if(Mine.num!=0)/*如果格子没有处理过*/ { if(Mine.num==1)/*鼠标按下的格子是地雷*/ { MouseOff(); GameOver();/*游戏失败*/ break; } else/*鼠标按下的格子不是地雷*/ { MouseOff(); Num=MineStatistics(i,j); if(Num==0)/*周围没地雷就用递归算法来显示空白格子*/ ShowWhite(i,j); else/*按下格子周围有地雷*/ { sprintf(randmineNUM,"%d",Num);/*输出当前格子周围的雷数*/ setcolor(RED); outtextxy(195+j*20,95+i*20,randmineNUM); mineNUM--; } MouseOn(); Mine.num=0;/*点过的格子周围雷数的数字变为0表示这个格子已经用过*/ if(mineNUM<1)/*胜利了*/ { GameWin(); break; } } } } } if(RightPress())/*鼠标右键键盘按下*/ { MouseGetXY(); if(MouseX>190&&MouseX<390&&MouseY>90&&MouseY<290)/*当前鼠标位置在格子范围内*/ { j=(MouseX-190)/20;/*x坐标*/ i=(MouseY-90)/20;/*y坐标*/ MouseOff(); if(Mine.flag==0&&Mine.num!=0)/*本来没红旗现在显示红旗*/ { DrawRedflag(i,j); Mine.flag=1; } else if(Mine.flag==1)/*有红旗标志再按右键就红旗消失*/ { DrawEmpty(i,j,0,8); Mine.flag=0; } } MouseOn(); sleep(1); } } } |