一、五子棋终结者算法

二、用C语言实现键盘画图

三、文件加密技术一例

四、用C语言实现艺术清屏

五、用C语言演绎“生命游戏” 
 

一、五子棋终结者算法

   任何一种棋类游戏其关键是对当前棋局是否有正确的评分,评分越准确则电脑的AI越高。五子棋游戏也是

如此,但在打分之前,我们先扫描整个棋盘,把每个空位从八个方向上的棋型填入数组gStyle(2, 15, 15, 

8, 2),其中第一个下标为1时表示黑棋,为2时表示白棋,第二和第三个下标表示(x,y),第四个下标表示8个

方向,最后一个下标为1时表示棋子数,为2时表示空格数,如:

gStyle(1,2,2,1,1)=3表示与坐标(2,2)在第1个方向上相邻的黑棋棋子数为3 
gstyle(1,2,2,1,2)=4表示与坐标(2,2)在第1个方向上的最近的空格数为4 
在定义方向时,也应该注意一定的技巧,表示两个相反的方向的数应该差4,在程序中我是这样定义的: 
Const DIR_UP = 1 
Const DIR_UPRIGHT = 2 
Const DIR_RIGHT = 3 
Const DIR_RIGHTDOWN = 4 
Const DIR_DOWN = 5 
Const DIR_DOWNLEFT = 6 
Const DIR_LEFT = 7 
Const DIR_LEFTUP = 8 
这样我们前四个方向可以通过加四得到另一个方向的值。请看下面的图: 
--------- 
--------- 
---oo---- 
-ox*xx--- 
--------- 
--------- 
图中的*点从标为(4,4),(打*的位置是空位),则: 
gStyle(2,4,4,1,1)=1在(4,4)点相邻的上方白棋数为1 
gStyle(2,4,4,1,2)=2在(4,4)点的上方距上方白棋最近的空格数为2 
gStyle(1,4,4,3,1)=2在(4,4)点相邻的右方黑棋数为2 
gStyle(1,4,4,3,2)=1在(4,4)点的右方距右方黑棋最近的空格数为3 
...

  一旦把所有空点的棋型值填完,我们很容易地得出黑棋水平方向上点(4,4)的价值,由一个冲1(我把有

界的棋称为冲)和活2(两边无界的 
棋称为活)组成的。对于而白棋在垂直方向上点(4,4)的价值是一个活1,而在/方向也是活1所以,只要我们

把该点的对于黑棋和白棋的价值算出 
来,然后我们就取棋盘上各个空点的这两个值的和的最大一点作为下棋的点。然而,对各种棋型应该取什么

值呢?我们可以先作如下假设: 
 Fn 表示先手n个棋子的活棋型,如:F4表示先手活四 
 Fn'表示先手n个棋子的冲棋型,如:F4'表示先手冲四 
 Ln 表示后手n个棋子的活棋型,如:L3表示后手活三 
 Ln'表示后手n个棋子的冲棋型,如:L3'表示后手冲三 
 . 
 . . 
  根据在一行中的棋型分析,得到如下关系: 
L1'<=F1'<L2'<=F2'<=L1<F1<L2<F2<L3'<=F3'<L4'<F4'=F4从这个关系包含了进攻和防守的关系(当然,这个

关系是由我定的,你可以自己定义这些关系)。对这些关系再进一步细化,如在一个可下棋的点,其四个方

向上都有活三,也比不上一个冲四,所以我们可以又得到4*F3<L4'这个关系,同样,我们还可以得到其它的

关系,如:4*F2<L3、4*L3<F3...,这些的关系由于你的定法和我的定法制可能不一样,这样计算机的AI也就

不一样,最后我们把分值最小的L1'值定为1,则我们就得到了下面各种棋型的分值,由C语言表示为: 
F[2][5]={{0,2,5,50,16000},{0,10,30,750,16000}}; 
L[2][5]={{0,1,5,50,3750},{0,10,30,150,4000}}; 
  F数组表示先手,第一个下标为0时表示冲型,第二个下标表示棋子数,则F2'对应F[0][2]L数组表示后手

,第一个下标为0时表示冲型,第二个下标表示棋子数,则L2对应F[1][2]Ok,棋型的分值关系确定好了以后

,我们把每一个可下点的四个方向的棋型值相加(包括先手和后手的分值),最后选择一个最大值,并把这

一点作为计算机要下的点就OK了:)。

后话: 
1、得到最大值也许不止一个点,但在我的程序中只选择第一个最大点,当然你可以用于个随机数来决定 
选择那一个最大值点,也可以对这些最大值点再作进一步的分析。 
2、在这个算法中我只考虑了周围有棋子的点,而其它点我没有考虑。 
3、可以再更进一步,用这个算法来预测以后的几步棋,再选择预测值最好的一步,这样电脑的AI就更高了 
4、这个算法没有考虑黑棋的禁手(双3、双四和多于五子的连棋)。因为在平时我下的五子棋是没有这些 
禁手的

二、用C语言实现键盘画图

程序中定义了几个特殊键: 
"V”:画笔提起 
"W”:开始画图 
"R”:开始擦图 
"S”:当前图形存入文件 
"E”:调出已有文件 
"C”:画圆 
  程序一运行,屏幕上出现一个黄色的边框来设定画图的区域,区域中间出现提起的画笔符号 ,当按下”

W“键时,画笔符号变为 ,此时可移动方向键(上、下、左、右、左上、左下、右上、右下)来画图;当按

下”R“键时,画笔符号变为 ,此时可移动方向键来擦图;在画图过程中,按下“C”键,可画出一个半径

为20个象素点的圆;当结束画图时,按下“S”键,将画好的图形存盘;按下“E”键可调出已有的图形进

行编辑。

源程序清单:

# include "graphics.h" 
# include "stdio.h" 
# include "fcntl.h" 
# include "stdlib.h" 
main()

void save(),load(); 
void *wg,*rg,*vg,*fy; 
int driver,mode; 
int c=RED; 
int x=320,y=225; 
int x1,y1,x2,y2; 
int k,k1,k2; 
/* initialize grapher */ 
detectgraph(&driver,&mode); 
initgraph(&driver,&mode,"c:\tc");

/* write the pen */ 
bar(200,10,206,16); 
line(203,7,200,10); 
line(203,7,206,10); 
line(243,7,240,16); 
line(243,7,246,16); 
line(283,7,280,10); 
line(283,7,286,10); 
line(283,7,283,16);

/* save the pen */ 
wg=malloc(imagesize(200,7,206,16)); 
rg=malloc(imagesize(240,7,246,16)); 
vg=malloc(imagesize(280,7,286,16)); 
fy=malloc(imagesize(200,7,206,16));

getimage(200,7,206,16,wg); 
getimage(240,7,246,16,rg); 
getimage(280,7,286,16,vg); 
cleardevice();

/* write the box */ 
setcolor(YELLOW); 
rectangle(4,19,637,447);

x1=x-3; 
y1=y+1; 
x2=x+3; 
y2=y+10; 
getimage(x1,y1,x2,y2,fy); 
putimage(x1,y1,vg,XOR_PUT);

/* receive the command */ 
for (;;)  
while (bioskey(1)==0); 
k=bioskey(0); 
putimage(x1,y1,fy,AND_PUT); 
if (((k&0x00ff)|0x00)==0)  
k1=k&0xff?0:k>>8; /* k1 is the specialkey value */ 
else  
k2=k&0x00ff; /* k2 is the non-specialkey value */ 
if (((k&0x00ff)|0x00)==0) /* Special key */ 
switch(k1)  
case 45: 
restorecrtmode(); 
exit(0); 
case 72: 
if (y>20)  
y=y-1; 
break; 
case 75: 
if (x>5)  
x=x-1; 
break; 
case 77: 
if (x<636)  
x=x+1; 
break; 
case 80: 
if (y<446)  
y=y+1; 
break; 
case 71: 
if ((x>5)&&(y>20))  
x=x-1; 
y=y-1; 
break; 
case 79: 
if ((x>5)&&(y<446))  
x=x-1; 
y=y+1; 
break; 
case 73: 
if ((x<636)&&(y>20))  
x=x+1; 
y=y-1; 
break; 
case 81: 
if ((x<636)&&(y<446))  
x=x+1; 
y=y+1; 
break;

 
x1=x-3; 
y1=y+1; 
x2=x+3; 
y2=y+10; 
getimage(x1,y1,x2,y2,fy); 
/* non-special key */ 
switch(k2)  
case 118: /* 'v' */ 
case 86: /* 'V' */ 
putimage(x1,y1,vg,OR_PUT); 
break; 
case 119: /* 'w' */ 
case 87: /* 'W' */ 
putimage(x1,y1,wg,OR_PUT); 
putpixel(x,y,c); 
break; 
case 114: /* 'r' */ 
case 82: /* 'R' */ 
putimage(x1,y1,rg,OR_PUT); 
putpixel(x,y,BLACK); 
break; 
case 115: /* 's' */ 
case 83: /* 'S' */ 
save("pic.dat"); 
break; 
case 101: /* 'e' */ 
case 69: /* 'E' */ 
load("pic.dat"); 
break; 
case 99: /*'c'*/ 
case 67: /*'C'*/ 
setcolor(RED); 
circle(x,y,20); 
break; 
default:continue;

 
/* function for screen picture save 
*/ 
void save(char *fname)

FILE *fp; 
int i; 
register long j; 
char far *ptr;

fp=fopen(fname,"wb"); 
for(i=0;i<4;i++)

outportb(0x3CE,4); 
outportb(0x3CF,i); 
ptr=(char far *) 0xA0000000L; 
for (j=0;j<38400L;j++) 
putc(*ptr,fp); 
ptr++;

 
fclose(fp); 
outportb(0x3CF,0);

 
/* function for screen picture display 
*/ 
void load(char *fname)

FILE *fp; 
register int i; 
int k4=1; 
register long j; 
char far *ptr;

fp=fopen(fname,"rb"); 
for (i=0;i<4;i++)

outportb(0x3C4,2); 
outportb(0x3C5,k4); 
ptr=(char far *)0xA0000000L; 
for (j=0;j<38400L;j++)

*ptr=getc(fp); 
ptr++;

k4*=2;

fclose(fp); 
outportb(0x3C5,0xF);

程序的演示及相关源码可以在http://www.secbeta.com/下载

三、文件加密技术一例

   给文件加密的技术很多,其中又分为不同等级,以适合不同场合的需要.这里给出最简单的文件加密技术,即

采用文件逐字节与密码异或方式对文件进行加密,当解密时,只需再运行一遍加密程序即可。

  下面是一个实例程序,能对任意一个文件进行加密,密码要求用户输入,限8位以内(当然你可以再更改).程

序有很好的容错设计,这是我们应该学习的.

/* Turbo 2.0 pass. give file a password! */

#include<stdio.h> 
#include<stdlib.h> 
#include<conio.h> 
#include<string.h>

void dofile(char *in_fname,char *pwd,char *out_fname);/*对文件进行加密的具体函数*/

void main(int argc,char *argv[])/*定义main()函数的命令行参数*/ 

char in_fname[30];/*用户输入的要加密的文件名*/ 
char out_fname[30]; 
char pwd[8];/*用来保存密码*/

if(argc!=4){/*容错处理*/ 
printf("\nIn-fname:\n"); 
gets(in_fname);/*得到要加密的文件名*/

printf("Password:\n"); 
gets(pwd);/*得到密码*/

printf("Out-file:\n"); 
gets(out_fname);/*得到加密后你要的文件名*/

dofile(in_fname,pwd,out_fname); 

else{/*如果命令行参数正确,便直接运行程序*/ 
strcpy(in_fname,argv[1]); 
strcpy(pwd,argv[2]); 
strcpy(out_fname,argv[3]); 
dofile(in_fname,pwd,out_fname); 
}


/*加密子函数开始*/ 
void dofile(char *in_fname,char *pwd,char *out_file) 

FILE *fp1,*fp2; 
register char ch; 
int j=0; 
int j0=0;

fp1=fopen(in_fname,"rb"); 
if(fp1==NULL){ 
printf("cannot open in-file.\n"); 
exit(1);/*如果不能打开要加密的文件,便退出程序*/ 

fp2=fopen(out_file,"wb"); 
if(fp2==NULL){ 
printf("cannot open or create out-file.\n"); 
exit(1);/*如果不能建立加密后的文件,便退出*/ 

while(pwd[++j0]); 
ch=fgetc(fp1);

/*加密算法开始*/ 
while(!feof(fp1)){ 
fputc(ch^pwd[j>=j0?j=0:j++],fp2);/*异或后写入fp2文件*/ 
ch=fgetc(fp1); 

fclose(fp1);/*关闭源文件*/ 
fclose(fp2);/*关闭目标文件*/ 
}*

/*程序结束*/

四、用c语言实现艺术清屏

   问题的提出:我们在编制程序时,经常要用到清屏处理,如dos下的cls,Turbo C下的clrscr()等都具有清屏

功能,但这些均为一般意义的清屏,并未显示其清屏规律.而有时为了达到清屏的艺术美观,往往对清屏有一些

具体要求,如:开幕清屏;闭幕清屏;上清屏;下清屏;中清屏.为此,这里用C语言编制了几个子函数,用于程序中

时,既可达到清屏的目的,有能增加屏幕的艺术美观.

子函数及演示程序:

#include<stdio.h> 
#include<dos.h> 
#include<conio.h>

void goto_xy(int x,int y); 
void dcls(int x1,int x2,int y1,int y2); 
void bcls(int x1,int x2,int y1,int y2); 
void kcls(int x1,int x2,int y1,int y2); 
void recls(int x1,int x2,int y1,int y2); 
void zcls(int x1,int x2,int y1,int y2); 
void puta(void);

 
/*--------------演示程序---------------------*/ 
main() 

puta(); 
getch(); 
dcls(0,4,0,79); 
getch(); 
puta(); 
getch(); 
bcls(0,25,0,79); 
getch(); 
puta(); 
getch(); 
zcls(0,25,0,79); 
getch(); 

/*********center clear screen(中心清屏)***********/ 
void zcls(int x1,int x2,int y1,int y2) 

int x00,y00,x0,y0,i,d; 
if((y2-y1)>(x2-x1)){ 
d=(x2-x1)/2; 
x0=(x1+x2)/2; 
y0=y1+d; 
y00=y2-d; 
for(i=0;i<(d+1);i++) 
recls((x0-i),(x00+i),(y0-i),(y00+i)); 
delay(10); 

else{ 
d=(y2-y1)/2; 
y0=(y1+y2)/2; 
x0=x1+d; 
x00=x2-d; 
for(i=0;i<d+1;i++) 
recls(x0-i,x00+i,y0-i,y00+i); 
delay(10); 

}

/************* clear rectangle side(矩形边清屏)***********************/

void recls(int x1,int x2,int y1,int y2) 

int i,j; 
for(i=y1;i<y2;i++){ 
goto_xy(x1,i); 
putchar(' '); 
goto_xy(x2,i); 
putchar(' '); 
delay(10); 

for(j=x1;j<x2;j++){ 
goto_xy(i,y1); 
putchar(' '); 
goto_xy(j,y2); 
putchar(' '); 
delay(10); 


/******************open screen clear(开屏式清屏)*********************/

void kcls(int x1,int x2,int y1,int y2) 

int t,s,i,j; 
t=s=(y1+y2)/2; 
for(;t<=y2;t++,s--) 
for(j=x1;j<x2;j++){ 
goto_xy(j,t); 
putchar(' '); 
goto_xy(j,s); 
putchar(' '); 
delay(10); 


/*****************close screen clear*****闭幕式清屏*******************/

void bcls(int x1,int x2,int y1,int y2) 

int t,s,j; 
t=y1; 
s=y2; 
for(t=y1;t<(y1+y2)/2;t++,s--) 
for(j=x1;j<x2;j++){ 
goto_xy(j,t); 
putchar(' '); 
goto_xy(j,s); 
putchar(' '); 
delay(10); 


/******************bottom screen clear(自下清屏)********************/

void dcls(int x1,int x2,int y1,int y2) 

int t,s,j,i; 
t=s=(y1+y2)/2; 
for(j=x2;j>x1;j--) 
for(i=y1;i<y2;i++){ 
goto_xy(j,i); 
putchar(' '); 
delay(10); 


/******************设置光标子函数******************/

void goto_xy(int x,int y) 

union REGS r; 
r.h.ah=2; 
r.h.dl=y; 
r.h.dh=x; 
r.h.bh=0; 
int86(0x10,&r,&r); 
}

/**********************在屏幕上打出一连串的a字母用于演示程序******************/

void puta(void) 

int i,j; 
for(i=0;i<24;i++){ 
for(j=0;j<79;j++){ 
goto_xy(i,j); 
printf("a"); 


}

演示及相关源码可以在http://www.secbeta.com/下载