个人形象

自我介绍

本人性情温合,偏于内向。每遇事,凡欲究其理。理不达者,乃心不甘。

 

我关注的朋友

状态

  1. 积分:910分
  2. 魅力指数:100点
  3. 人气指数:1265点
  4. 留言评论:60条
 

我的更新

关于Huffman 压缩

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树,以达到提高速度的目的。在解码的过程中使用动态还原技术。

2008-09-01 07:19

关于goto语句的争论

在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种结构编写的程序可以采用“自顶向下,逐步细化”的程序设计方法来设计程序。该方法按照先全局后局部、先整体后细节、先抽象后具体的过程组织人们的思维活动,使得编写的程序结构清晰、容易阅读和修改。同时还可以结构逐步求精的过程进行程序的正确性验证,即采取边设计边验证的方法,以简化程序正确性的验证。

2008-09-01 07:18

给TURBO C增加一个Screen()函数

QBASIC中有一个SCREEN函数,它的调用形式为SCREEN(row%,c
olumn% [,colorflag%])?本函数功能为返回当前文本方式下
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
方式下通过?

2008-09-01 07:15

差错检测和纠正

物理过程所引起的差错,在某些介质中通常是突发的而不是单个的。网络设计者已经研究出两种基本的策略来处理差错。一种方法是在每一个要发送的数据块上附加足够的冗余信息,使接收方能够推导出已发出的字符应该是什么。另一种方法是只加足够的冗余位,使接收方知道差错发生,但不知道是什么样的差错,然后要求接收方重新进行传输。前者的策略是使用纠错码(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已经给出了一种简单的移位寄存器电路来进行计算,并用硬件来完成对校验和的校验。在实际应用中,几乎都在使用此硬件。

2008-08-31 07:05

编程中的细节--指针(fwd)

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);

; :
; :

--

2008-08-31 06:54

编程技巧15法之二



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;

}

2008-08-31 06:53

2008-08-29的日记

<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>

2008-08-29 15:46

迷宫问题

/*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();
}

2008-08-23 15:09

扫雷程序源码

/*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);
      }
  }
}

2008-08-23 15:08
 

留言

  1. 2010-06-22 16:51 
    com
  2. 2010-06-22 16:51 
    邮箱: zx543210@/sina ./cm
  3. 2010-06-22 16:48 
    设计一个模拟的时间条的程序
    1.系统库函数调用 
    #include <graphics.h> #include <conio.h>#include <dos.h>
    就是完成的百分之比怎么输出.
    谢谢  用C# 啊
  4. 2009-07-22 16:01 
    我一 个在社会上工作滴人 想多学习下电脑知识!! 请多多指教
  5. 2009-06-19 10:21 
    我是学计算机的学生,很想把编程能力更提高到一个层次!希望能向你学习!

查看更多留言