蚁群算法ACO (Ant Colony Optimization)
小小的蚂蚁总是能够找到食物,他们具有什么样的智能呢?设想,如果我们要为蚂蚁设计一个人工智能的程序,那么这个程序要多么复杂呢?首先,你要让蚂
蚁能够避开障碍物,就必须根据适当的地形给它编进指令让他们能够巧妙的避开障碍物,其次,要让蚂蚁找到食物,就需要让他们遍历空间上的所有点;再次,如果
要让蚂蚁找到最短的路径,那么需要计算所有可能的路径并且比较它们的大小,而且更重要的是,你要小心翼翼的编程,因为程序的错误也许会让你前功尽弃。这是
多么不可思议的程序!太复杂了,恐怕没人能够完成这样繁琐冗余的程序。
为什么这么简单的程序会让蚂蚁干这样复杂的事情?答案是:简单规则的涌现。事实上,每只蚂蚁并不是像我们想象的需要知道整个世界的信息,他们其实只 关心很小范围内的眼前信息,而且根据这些局部信息利用几条简单的规则进行决策,这样,在蚁群这个集体里,复杂性的行为就会凸现出来。这就是人工生命、复杂 性科学解释的规律!
下面就是实现如此复杂性的七条简单规则:
1、范围:
蚂蚁观察到的范围是一个方格世界,蚂蚁有一个参数为速度半径(一般是3),那么它能观察到的范围就是3*3个方格世界,并且能移动的距离也在这个范围之内。
2、环境:
蚂蚁所在的环境是一个虚拟的世界,其中有障碍物,有别的蚂蚁,还有信息素,信息素有两种,一种是找到食物的蚂蚁洒下的食物信息素,一种是找到窝的蚂蚁洒下的窝的信息素。每个蚂蚁都仅仅能感知它范围内的环境信息。环境以一定的速率让信息素消失。
3、觅食规则:
在
每只蚂蚁能感知的范围内寻找是否有食物,如果有就直接过去。否则看是否有信息素,并且比较在能感知的范围内哪一点的信息素最多,这样,它就朝信息素多的地
方走,并且每只蚂蚁多会以小概率犯错误,从而并不是往信息素最多的点移动。蚂蚁找窝的规则和上面一样,只不过它对窝的信息素做出反应,而对食物信息素没反
应。
4、移动规则:
每只蚂蚁都朝向信息素最多的方向移,并且,当周围没有信息素指引的时候,蚂蚁会按照自己原来运动的方向惯性的运动下去,并且,在运动的方向有一个随机的小的扰动。为了防止蚂蚁原地转圈,它会记住最近刚走过了哪些点,如果发现要走的下一点已经在最近走过了,它就会尽量避开。
5、避障规则:
如果蚂蚁要移动的方向有障碍物挡住,它会随机的选择另一个方向,并且有信息素指引的话,它会按照觅食的规则行为。
7、播撒信息素规则:
每只蚂蚁在刚找到食物或者窝的时候撒发的信息素最多,并随着它走远的距离,播撒的信息素越来越少。
下面的程序开始运行之后,蚂蚁们开始从窝里出动了,寻找食物;他们会顺着屏幕爬满整个画面,直到找到食物再返回窝。
其中,‘F’点表示食物,‘H’表示窝,白色块表示障碍物,‘+’就是蚂蚁了。
参数说明:
最大信息素:蚂蚁在一开始拥有的信息素总量,越大表示程序在较长一段时间能够存在信息素。信息素消减的速度:随着时间的流逝,已经存在于世界上的信息素会消减,这个数值越大,那么消减的越快。
错误概率表示这个蚂蚁不往信息素最大的区域走的概率,越大则表示这个蚂蚁越有创新性。
速度半径表示蚂蚁一次能走的最大长度,也表示这个蚂蚁的感知范围。
记忆能力表示蚂蚁能记住多少个刚刚走过点的坐标,这个值避免了蚂蚁在本地打转,停滞不前。而这个值越大那么整个系统运行速度就慢,越小则蚂蚁越容易原地转圈。
源代码如下:
1

/**//*ant.c*/2

3
#define SPACE 0×204
#define ESC 0×1b5
#define ANT_CHAR_EMPTY ‘+’6
#define ANT_CHAR_FOOD 1537
#define HOME_CHAR ‘H’8
#define FOOD_CHAR ‘F’9
#define FOOD_CHAR2 ‘f’10
#define FOOD_HOME_COLOR 1211
#define BLOCK_CHAR 17712

13
#define MAX_ANT 5014
#define INI_SPEED 315
#define MAXX 8016
#define MAXY 2317
#define MAX_FOOD 1000018
#define TARGET_FOOD 20019
#define MAX_SMELL 500020
#define SMELL_DROP_RATE 0.0521
#define ANT_ERROR_RATE 0.0222
#define ANT_EYESHOT 323
#define SMELL_GONE_SPEED 5024
#define SMELL_GONE_RATE 0.0525
#define TRACE_REMEMBER 5026
#define MAX_BLOCK 10027

28
#define NULL 029
#define UP 130
#define DOWN 231
#define LEFT 332
#define RIGHT 433
#define SMELL_TYPE_FOOD 034
#define SMELL_TYPE_HOME 135

36
#include “stdio.h”37
#include “conio.h”38
#include “dos.h”39
#include “stdlib.h”40
#include “dos.h”41
#include “process.h”42
#include “ctype.h”43
#include “math.h”44

45
void WorldInitial(void);46
void BlockInitial(void);47
void CreatBlock(void);48
void SaveBlock(void);49
void LoadBlock(void);50
void HomeFoodInitial(void);51
void AntInitial(void);52
void WorldChange(void);53
void AntMove(void);54
void AntOneStep(void);55
void DealKey(char key);56
void ClearSmellDisp(void);57
void DispSmell(int type);58
int AntNextDir(int xxx,int yyy,int ddir);59
int GetMaxSmell(int type,int xxx,int yyy,int ddir);60
int IsTrace(int xxx,int yyy);61
int MaxLocation(int num1,int num2,int num3);62
int CanGo(int xxx,int yyy,int ddir);63
int JudgeCanGo(int xxx,int yyy);64
int TurnLeft(int ddir);65
int TurnRight(int ddir);66
int TurnBack(int ddir);67

68
int MainTimer(void);69
char WaitForKey(int secnum);70
void DispPlayTime(void);71
int TimeUse(void);72
void HideCur(void);73
void ResetCur(void);74

75

/**//* ————— */76
struct HomeStruct77


{78
int xxx,yyy;79
int amount;80
int TargetFood;81
}home;82

83
struct FoodStruct84


{85
int xxx,yyy;86
int amount;87
}food;88

89
struct AntStruct90


{91
int xxx,yyy;92
int dir;93
int speed;94
int SpeedTimer;95
int food;96
int SmellAmount[2];97
int tracex[TRACE_REMEMBER];98
int tracey[TRACE_REMEMBER];99
int TracePtr;100
int IQ;101
}ant[MAX_ANT];102
int AntNow;103
int timer10ms;104
struct time starttime,endtime;105
int Smell[2][MAXX+1][MAXY+1];106
int block[MAXX+1][MAXY+1];107
int SmellGoneTimer;108
int SmellDispFlag;109
int CanFindFood;110
int HardtoFindPath;111

112

/**//* —– Main ——– */113
void main(void)114


{115
char KeyPress;116
int tu;117

118
clrscr();119
HideCur();120
WorldInitial();121
do122

{123
timer10ms = MainTimer();124
if(timer10ms) AntMove();125
if(timer10ms) WorldChange();126
tu = TimeUse();127
if(tu>=60&&!CanFindFood)128

{129
gotoxy(1,MAXY+1);130
printf(“Can not find food, maybe a block world.”);131
WaitForKey(10);132
WorldInitial();133
}134
if(tu>=180&&home.amount<100&&!HardtoFindPath)135

{136
gotoxy(1,MAXY+1);137
printf(“God! it is so difficult to find a path.”);138
if(WaitForKey(10)==0×0d) WorldInitial();139
else140

{141
HardtoFindPath = 1;142
gotoxy(1,MAXY+1);143
printf(” “);144
}145
}146
if(home.amount>=home.TargetFood)147

{148
gettime(&endtime);149
KeyPress = WaitForKey(60);150
DispPlayTime();151
WaitForKey(10);152
WorldInitial();153
}154
else if(kbhit())155

{156
KeyPress = getch();157
DealKey(KeyPress);158
}159
else KeyPress = NULL;160
}161
while(KeyPress!=ESC);162
gettime(&endtime);163
DispPlayTime();164
WaitForKey(10);165
clrscr();166
ResetCur();167
}168

169

/**//* —— general sub process ———– */170
int MainTimer(void)171

/**//* output: how much 10ms have pass from last time call this process */172


{173
static int oldhund,oldsec;174
struct time t;175
int timeuse;176

177
gettime(&t);178
timeuse = 0;179
if(t.ti_hund!=oldhund)180

{181
if(t.ti_sec!=oldsec)182

{183
timeuse+=100;184
oldsec = t.ti_sec;185
}186
timeuse+=t.ti_hund-oldhund;187
oldhund = t.ti_hund;188
}189
else timeuse = 0;190
return (timeuse);191
}192

193
char WaitForKey(int secnum)194

/**//* funtion: if have key in, exit immediately, else wait ’secnum’ senconds then exit195
input: secnum — wait this senconds, must < 3600 (1 hour)196
output: key char, if no key in(exit when timeout), return NULL */197


{198
int secin,secnow;199
int minin,minnow;200
int hourin,hournow;201
int secuse;202
struct time t;203

204
gettime(&t);205
secin = t.ti_sec;206
minin = t.ti_min;207
hourin = t.ti_hour;208

209
do210

{211
if(kbhit()) return(getch());212
gettime(&t);213
secnow = t.ti_sec;214
minnow = t.ti_min;215
hournow = t.ti_hour;216

217
if(hournow!=hourin) minnow+=60;218
if(minnow>minin) secuse = (minnow-1-minin) + (secnow+60-secin);219
else secuse = secnow - secin;220

221

/**//* counting error check */222
if(secuse<0)223

{224
gotoxy(1,MAXY+1);225
printf(“Time conuting error, any keyto exit…”);226
getch();227
exit(3);228
}229
}230
while(secuse<=secnum);231
return (NULL);232
}233

234
void DispPlayTime(void)235


{236
int ph,pm,ps;237

238
ph = endtime.ti_hour - starttime.ti_hour;239
pm = endtime.ti_min - starttime.ti_min;240
ps = endtime.ti_sec - starttime.ti_sec;241

242
if(ph<0) ph+=24;243

if(pm<0)
{ ph–; pm+=60; }244

if(ps<0)
{ pm–; ps+=60; }245

246
gotoxy(1,MAXY+1);247
printf(“Time use: %d hour- %d min- %d sec “,ph,pm,ps);248
}249

250
int TimeUse(void)251


{252
int ph,pm,ps;253

254
gettime(&endtime);255
ph = endtime.ti_hour - starttime.ti_hour;256
pm = endtime.ti_min - starttime.ti_min;257
ps = endtime.ti_sec - starttime.ti_sec;258

259
if(ph<0) ph+=24;260

if(pm<0)
{ ph–; pm+=60; }261

if(ps<0)
{ pm–; ps+=60; }262

263
return(ps+(60*(pm+60*ph)));264
}265

266
void HideCur(void)267


{268
union REGS regs0;269
regs0.h.ah=1;270
regs0.h.ch=0×30;271
regs0.h.cl=0×31;272
int86(0×10,®s0,®s0);273
}274

275
void ResetCur(void)276


{277
union REGS regs0;278
regs0.h.ah=1;279
regs0.h.ch=0×06;280
regs0.h.cl=0×07;281
int86(0×10,®s0,®s0);282
}283

284

/**//* ———— main ANT programe ————- */285
void WorldInitial(void)286


{287
int k,i,j;288
randomize();289
clrscr();290
HomeFoodInitial();291
for(AntNow=0;AntNow<MAX_ANT;AntNow++)292

{293
AntInitial();294

} /**//* of for AntNow */;295

296
BlockInitial();297
for(k=0;k<=1;k++)298

/**//* SMELL TYPE FOOD and HOME */299
for(i=0;i<=MAXX;i++)300
for(j=0;j<=MAXY;j++)301
Smell[k][i][j] = 0;302
SmellGoneTimer = 0;303
gettime(&starttime);304
SmellDispFlag = 0;305
CanFindFood = 0;306
HardtoFindPath = 0;307
}308

309
void BlockInitial(void)310


{311
int i,j;312
int bn;313

314
for(i=0;i<=MAXX;i++)315
for(j=0;j<=MAXY;j++)316
block[i][j] = 0;317

318
bn = 1+ MAX_BLOCK/2 + random(MAX_BLOCK/2);319
for(i=0;i<=bn;i++) CreatBlock();320
}321

322
void CreatBlock(void)323


{324
int x1,y1,x2,y2;325
int dx,dy;326
int i,j;327

328
x1 = random(MAXX)+1;329
y1 = random(MAXY)+1;330

331
dx = random(MAXX/10)+1;332
dy = random(MAXY/10)+1;333

334
x2 = x1+dx;335
y2 = y1+dy;336

337
if(x2>MAXX) x2 = MAXX;338
if(y2>MAXY) y2 = MAXY;339

340
if(food.xxx>=x1&&food.xxx<=x2&&food.yyy>=y1&&food.yyy<=y2) return;341
if(home.xxx>=x1&&home.xxx<=x2&&home.yyy>=y1&&home.yyy<=y2) return;342

343
for(i=x1;i<=x2;i++)344
for(j=y1;j<=y2;j++)345

{346
block[i][j] = 1;347
gotoxy(i,j);348
putch(BLOCK_CHAR);349
}350
}351

352
void SaveBlock(void)353


{354
FILE *fp_block;355
char FileNameBlock[20];356
int i,j;357

358
gotoxy(1,MAXY+1);359
printf(” “);360
gotoxy(1,MAXY+1);361
printf(“Save to file…”,FileNameBlock);362
gets(FileNameBlock);363
if(FileNameBlock[0]==0) strcpy(FileNameBlock,“Ant.ant”);364
else strcat(FileNameBlock,“.ant”);365

366
if ((fp_block = fopen(FileNameBlock, “wb”)) == NULL)367

{ gotoxy(1,MAXY+1);368
printf(“Creat file %s fail…”,FileNameBlock);369
getch();370
exit(2);371
}372
gotoxy(1,MAXY+1);373
printf(” “);374

375
fputc(home.xxx,fp_block);376
fputc(home.yyy,fp_block);377
fputc(food.xxx,fp_block);378
fputc(food.yyy,fp_block);379

380
for(i=0;i<=MAXX;i++)381
for(j=0;j<=MAXY;j++)382
fputc(block[i][j],fp_block);383

384
fclose(fp_block);385
}386

387
void LoadBlock(void)388


{389
FILE *fp_block;390
char FileNameBlock[20];391
int i,j,k;392

393
gotoxy(1,MAXY+1);394
printf(” “);395
gotoxy(1,MAXY+1);396
printf(“Load file…”,FileNameBlock);397
gets(FileNameBlock);398
if(FileNameBlock[0]==0) strcpy(FileNameBlock,“Ant.ant”);399
else strcat(FileNameBlock,“.ant”);400

401
if ((fp_block = fopen(FileNameBlock, “rb”)) == NULL)402

{ gotoxy(1,MAXY+1);403
printf(“Open file %s fail…”,FileNameBlock);404
getch();405
exit(2);406
}407

408
clrscr();409
home.xxx = fgetc(fp_block);410
home.yyy = fgetc(fp_block);411
food.xxx = fgetc(fp_block);412
food.yyy = fgetc(fp_block);413
gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);414
gotoxy(food.xxx,food.yyy); putch(FOOD_CHAR);415
food.amount = random(MAX_FOOD/3)+2*MAX_FOOD/3+1;416

/**//* food.amount = MAX_FOOD; */417
home.amount = 0;418
home.TargetFood =419
(food.amount<TARGET_FOOD)?food.amount:TARGET_FOOD;420

421
for(AntNow=0;AntNow<MAX_ANT;AntNow++)422

{423
AntInitial();424

} /**//* of for AntNow */;425

426
for(i=0;i<=MAXX;i++)427
for(j=0;j<=MAXY;j++)428

{429
block[i][j] = fgetc(fp_block);430
if(block[i][j])431

{432
gotoxy(i,j);433
putch(BLOCK_CHAR);434
}435
}436

437
for(k=0;k<=1;k++)438

/**//* SMELL TYPE FOOD and HOME */439
for(i=0;i<=MAXX;i++)440
for(j=0;j<=MAXY;j++)441
Smell[k][i][j] = 0;442
SmellGoneTimer = 0;443
gettime(&starttime);444
SmellDispFlag = 0;445
CanFindFood = 0;446
HardtoFindPath = 0;447

448
fclose(fp_block);449
}450

451
void HomeFoodInitial(void)452


{453
int randnum;454
int homeplace;455

/**//* 1 — home at left-up, food at right-down456
2 — home at left-down, food at right-up457
3 — home at right-up, food at left-down458
4 — home at right-down, food at left-up */459

460
randnum = random(100);461
if(randnum<25) homeplace = 1;462
else if (randnum>=25&&randnum<50) homeplace = 2;463
else if (randnum>=50&&randnum<75) homeplace = 3;464
else homeplace = 4;465

466
switch(homeplace)467

{468
case 1: home.xxx = random(MAXX/3)+1;469
home.yyy = random(MAXY/3)+1;470
food.xxx = random(MAXX/3)+2*MAXX/3+1;471
food.yyy = random(MAXY/3)+2*MAXY/3+1;472
break;473
case 2: home.xxx = random(MAXX/3)+1;474
home.yyy = random(MAXY/3)+2*MAXY/3+1;475
food.xxx = random(MAXX/3)+2*MAXX/3+1;476
food.yyy = random(MAXY/3)+1;477
break;478
case 3: home.xxx = random(MAXX/3)+2*MAXX/3+1;479
home.yyy = random(MAXY/3)+1;480
food.xxx = random(MAXX/3)+1;481
food.yyy = random(MAXY/3)+2*MAXY/3+1;482
break;483
case 4: home.xxx = random(MAXX/3)+2*MAXX/3+1;484
home.yyy = random(MAXY/3)+2*MAXY/3+1;485
food.xxx = random(MAXX/3)+1;486
food.yyy = random(MAXY/3)+1;487
break;488
}489

490
food.amount = random(MAX_FOOD/3)+2*MAX_FOOD/3+1;491

/**//* food.amount = MAX_FOOD; */492
home.amount = 0;493
home.TargetFood = (food.amount<TARGET_FOOD)?food.amount:TARGET_FOOD;494

495

/**//* data correctness check */496
if(home.xxx<=0||home.xxx>MAXX||home.yyy<=0||home.yyy>MAXY||497
food.xxx<=0||food.xxx>MAXX||food.yyy<=0||food.yyy>MAXY||498
food.amount<=0)499

{500
gotoxy(1,MAXY+1);501
printf(“World initial fail, any key to exit…”);502
getch();503
exit(2);504
}505

506
gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);507
gotoxy(food.xxx,food.yyy); putch(FOOD_CHAR);508
}509

510
void AntInitial(void)511

/**//* initial ant[AntNow] */512


{513
int randnum;514
int i;515

516
ant[AntNow].xxx = home.xxx;517
ant[AntNow].yyy = home.yyy;518

519
randnum = random(100);520
if(randnum<25) ant[AntNow].dir = UP;521
else if (randnum>=25&&randnum<50) ant[AntNow].dir = DOWN;522
else if (randnum>=50&&randnum<75) ant[AntNow].dir = LEFT;523
else ant[AntNow].dir = RIGHT;524

525
ant[AntNow].speed = 2*(random(INI_SPEED/2)+1);526
ant[AntNow].SpeedTimer = 0;527
ant[AntNow].food = 0;528
ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = 0;529
ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = MAX_SMELL;530
ant[AntNow].IQ = 1;531

532
for(i=0;i<TRACE_REMEMBER;i++)533

{534
ant[AntNow].tracex[i] = 0;535
ant[AntNow].tracey[i] = 0;536
}537
ant[AntNow].TracePtr = 0;538

539

/**//* a sepecail ant */540
if(AntNow==0) ant[AntNow].speed = INI_SPEED;541
}542

543
void WorldChange(void)544


{545
int k,i,j;546
int smelldisp;547

548
SmellGoneTimer+=timer10ms;549
if(SmellGoneTimer>=SMELL_GONE_SPEED)550

{551
SmellGoneTimer = 0;552
for(k=0;k<=1;k++)553

/**//* SMELL TYPE FOOD and HOME */554
for(i=1;i<=MAXX;i++)555
for(j=1;j<=MAXY;j++)556

{557
if(Smell[k][i][j])558

{559
smelldisp = 1+((10*Smell[k][i][j])/(MAX_SMELL*SMELL_DROP_RATE));560
if(smelldisp>=30000||smelldisp<0) smelldisp = 30000;561
if(SmellDispFlag)562

{563
gotoxy(i,j);564
if((i==food.xxx&&j==food.yyy)||(i==home.xxx&&j==home.yyy))565

/**//* don’t over write Food and Home */;566
else567

{568
if(smelldisp>9) putch(‘#’);569
else putch(smelldisp+‘0′);570
}571
}572
Smell[k][i][j]-= 1+(Smell[k][i][j]*SMELL_GONE_RATE);573
if(Smell[k][i][j]<0) Smell[k][i][j] = 0;574
if(SmellDispFlag)575

{576
if(Smell[k][i][j]<=2)577

{578
gotoxy(i,j);579
putch(SPACE);580
}581
}582
}583

} /**//* of one location */584

} /**//* of time to change the world */585

} /**//* of world change */586

587
void AntMove(void)588


{589
int antx,anty;590
int smelltodrop,smellnow;591

592
for(AntNow=0;AntNow<MAX_ANT;AntNow++)593

{594
ant[AntNow].SpeedTimer+=timer10ms;595
if(ant[AntNow].SpeedTimer>=ant[AntNow].speed)596

{597
ant[AntNow].SpeedTimer = 0;598
gotoxy(ant[AntNow].xxx,ant[AntNow].yyy);599
putch(SPACE);600
AntOneStep();601
gotoxy(ant[AntNow].xxx,ant[AntNow].yyy);602

/**//* ant0 is a sepecail ant, use different color */603
if(AntNow==0) textcolor(0xd);604
if(ant[AntNow].food) putch(ANT_CHAR_FOOD);605
else putch(ANT_CHAR_EMPTY);606
if(AntNow==0) textcolor(0×7);607

608

/**//* remember trace */609
ant[AntNow].tracex[ant[AntNow].TracePtr] = ant[AntNow].xxx;610
ant[AntNow].tracey[ant[AntNow].TracePtr] = ant[AntNow].yyy;611
if(++(ant[AntNow].TracePtr)>=TRACE_REMEMBER) ant[AntNow].TracePtr = 0;612

613

/**//* drop smell */614
antx = ant[AntNow].xxx;615
anty = ant[AntNow].yyy;616

617
if(ant[AntNow].food)618

/**//* have food, looking for home */619

{620
if(ant[AntNow].SmellAmount[SMELL_TYPE_FOOD])621

{622
smellnow = Smell[SMELL_TYPE_FOOD][antx][anty];623
smelltodrop = ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]*SMELL_DROP_RATE;624
if(smelltodrop>smellnow) Smell[SMELL_TYPE_FOOD][antx][anty] = smelltodrop;625

/**//* else Smell[
] = smellnow */626
ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]-= smelltodrop;627
if(ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]<0) ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = 0;628

} /**//* of have smell to drop */629

} /**//* of have food */630
else631

/**//* no food, looking for food */632

{633
if(ant[AntNow].SmellAmount[SMELL_TYPE_HOME])634

{635
smellnow = Smell[SMELL_TYPE_HOME][antx][anty];636
smelltodrop = ant[AntNow].SmellAmount[SMELL_TYPE_HOME]*SMELL_DROP_RATE;637
if(smelltodrop>smellnow) Smell[SMELL_TYPE_HOME][antx][anty] = smelltodrop;638

/**//* else Smell[
] = smellnow */639
ant[AntNow].SmellAmount[SMELL_TYPE_HOME]-= smelltodrop;640
if(ant[AntNow].SmellAmount[SMELL_TYPE_HOME]<0) ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = 0;641

} /**//* of have smell to drop */642
}643

} /**//* of time to go */644

/**//* else not go */645

} /**//* of for AntNow */646

647
textcolor(FOOD_HOME_COLOR);648
gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);649
gotoxy(food.xxx,food.yyy);650
if(food.amount>0) putch(FOOD_CHAR);651
else putch(FOOD_CHAR2);652
textcolor(7);653

654
gotoxy(1,MAXY+1);655
printf(“Food %d, Home %d “,food.amount,home.amount);656
}657

658
void AntOneStep(void)659


{660
int ddir,tttx,ttty;661
int i;662

663
ddir = ant[AntNow].dir;664
tttx = ant[AntNow].xxx;665
ttty = ant[AntNow].yyy;666

667
ddir = AntNextDir(tttx,ttty,ddir);668

669
switch(ddir)670

{671
case UP: ttty–;672
break;673
case DOWN: ttty++;674
break;675
case LEFT: tttx–;676
break;677
case RIGHT: tttx++;678
break;679
default: break;680

} /**//* of switch dir */681

682
ant[AntNow].dir = ddir;683
ant[AntNow].xxx = tttx;684
ant[AntNow].yyy = ttty;685

686
if(ant[AntNow].food)687

/**//* this ant carry with food, search for home */688

{689
if(tttx==home.xxx&&ttty==home.yyy)690

{691
home.amount++;692
AntInitial();693
}694
if(tttx==food.xxx&&ttty==food.yyy)695
ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = MAX_SMELL;696

} /**//* of search for home */697
else698

/**//* this ant is empty, search for food */699

{700
if(tttx==food.xxx&&ttty==food.yyy)701

{702
if(food.amount>0)703

{704
ant[AntNow].food = 1;705
food.amount–;706
ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = MAX_SMELL;707
ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = 0;708
ant[AntNow].dir = TurnBack(ant[AntNow].dir);709
for(i=0;i<TRACE_REMEMBER;i++)710

{711
ant[AntNow].tracex[i] = 0;712
ant[AntNow].tracey[i] = 0;713
}714
ant[AntNow].TracePtr = 0;715
CanFindFood = 1;716

} /**//* of still have food */717
}718
if(tttx==home.xxx&&ttty==home.yyy)719
ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = MAX_SMELL;720

} /**//* of search for food */721
}722

723
void DealKey(char key)724


{725
int i;726
switch(key)727

{728
case ‘p’: gettime(&endtime);729
DispPlayTime();730
getch();731
gotoxy(1,MAXY+1);732
for(i=1;i<=MAXX-1;i++) putch(SPACE);733
break;734
case ‘t’: if(SmellDispFlag)735

{736
SmellDispFlag=0;737
ClearSmellDisp();738
}739
else SmellDispFlag = 1;740
break;741
case ‘1′: DispSmell(SMELL_TYPE_FOOD);742
getch();743
ClearSmellDisp();744
break;745
case ‘2′: DispSmell(SMELL_TYPE_HOME);746
getch();747
ClearSmellDisp();748
break;749
case ‘3′: DispSmell(2);750
getch();751
ClearSmellDisp();752
break;753
case ’s’: SaveBlock();754
break;755
case ‘l’: LoadBlock();756
break;757
default: gotoxy(1,MAXY+1);758
for(i=1;i<=MAXX-1;i++) putch(SPACE);759

} /**//* of switch */760
}761

762
void ClearSmellDisp(void)763


{764
int k,i,j;765

766
for(k=0;k<=1;k++)767

/**//* SMELL TYPE FOOD and HOME */768
for(i=1;i<=MAXX;i++)769
for(j=1;j<=MAXY;j++)770

{771
if(Smell[k][i][j])772

{773
gotoxy(i,j);774
putch(SPACE);775
}776

} /**//* of one location */777
}778

779
void DispSmell(int type)780

/**//* input: 0 — Only display food smell781
1 — Only display home smell782
2 — Display both food and home smell783
*/784


{785
int k,i,j;786
int fromk,tok;787
int smelldisp;788

789
switch(type)790

{791
case 0: fromk = 0;792
tok = 0;793
break;794
case 1: fromk = 1;795
tok = 1;796
break;797
case 2: fromk = 0;798
tok = 1;799
break;800
default:fromk = 0;801
tok = 1;802
break;803
}804
SmellGoneTimer = 0;805
for(k=fromk;k<=tok;k++)806

/**//* SMELL TYPE FOOD and HOME */807
for(i=1;i<=MAXX;i++)808
for(j=1;j<=MAXY;j++)809

{810
if(Smell[k][i][j])811

{812
smelldisp = 1+((10*Smell[k][i][j])/(MAX_SMELL*SMELL_DROP_RATE));813
if(smelldisp>=30000||smelldisp<0) smelldisp = 30000;814
gotoxy(i,j);815
if(i!=food.xxx||j!=food.yyy)816

{817
if((i==food.xxx&&j==food.yyy)||(i==home.xxx&&j==home.yyy))818

/**//* don’t over write Food and Home */;819
else820

{821
if(smelldisp>9) putch(‘#’);822
else putch(smelldisp+‘0′);823
}824
}825
}826

} /**//* of one location */827
}828

829
int AntNextDir(int xxx,int yyy,int ddir)830


{831
int randnum;832
int testdir;833
int CanGoState;834
int cangof,cangol,cangor;835
int msf,msl,msr,maxms;836
int type;837

838
CanGoState = CanGo(xxx,yyy,ddir);839
if(CanGoState==0||CanGoState==2||CanGoState==3||CanGoState==6) cangof = 1;840
else cangof = 0;841
if(CanGoState==0||CanGoState==1||CanGoState==3||CanGoState==5) cangol = 1;842
else cangol = 0;843
if(CanGoState==0||CanGoState==1||CanGoState==2||CanGoState==4) cangor = 1;844
else cangor = 0;845

846
if(ant[AntNow].food) type = SMELL_TYPE_HOME;847
else type = SMELL_TYPE_FOOD;848

849
msf = GetMaxSmell(type,xxx,yyy,ddir);850
msl = GetMaxSmell(type,xxx,yyy,TurnLeft(ddir));851
msr= GetMaxSmell(type,xxx,yyy,TurnRight(ddir));852
maxms = MaxLocation(msf,msl,msr);853

/**//* maxms - 1 - msf is MAX854
2 - msl is MAX855
3 - msr is MAX856
0 - all 3 number is 0 */857

858
testdir = NULL;859
switch(maxms)860

{861

case 0: /**//* all is 0, keep testdir = NULL, random select dir */862
break;863
case 1: if(cangof)864
testdir = ddir;865
else866
if(msl>msr) if(cangol) testdir = TurnLeft(ddir);867
else if(cangor) testdir = TurnRight(ddir);868
break;869
case 2: if(cangol)870
testdir = TurnLeft(ddir);871
else872
if(msf>msr) if(cangof) testdir = ddir;873
else if(cangor) testdir = TurnRight(ddir);874
break;875
case 3: if(cangor)876
testdir = TurnRight(ddir);877
else878
if(msf>msl) if(cangof) testdir =ddir;879
else if(cangol) testdir = TurnLeft(ddir);880
break;881
default:break;882

} /**//* of maxms */883

884
randnum = random(1000);885
if(randnum<SMELL_DROP_RATE*1000||testdir==NULL)886

/**//* 1. if testdir = NULL, means can not find the max smell or the dir to max smell can not go887
then random select dir888
2. if ant error, don’t follow the smell, random select dir889
*/890

{891
randnum = random(100);892
switch(CanGoState)893

{894
case 0: if(randnum<90) testdir = ddir;895
else if (randnum>=90&&randnum<95) testdir = TurnLeft(ddir);896
else testdir = TurnRight(ddir);897
break;898
case 1: if(randnum<50) testdir = TurnLeft(ddir);899
else testdir = TurnRight(ddir);900
break;901
case 2: if(randnum<90) testdir = ddir;902
else testdir = TurnRight(ddir);903
break;904
case 3: if(randnum<90) testdir = ddir;905
else testdir = TurnLeft(ddir);906
break;907
case 4: testdir = TurnRight(ddir);908
break;909
case 5: testdir = TurnLeft(ddir);910
break;911
case 6: testdir = ddir;912
break;913
case 7: testdir = TurnBack(ddir);914
break;915
default:testdir = TurnBack(ddir);916

} /**//* of can go state */917
}918
return(testdir);919
}920

921
int GetMaxSmell(int type,int xxx,int yyy,int ddir)922


{923
int i,j;924

int ms; /**//* MAX smell */925

926
ms = 0;927
switch(ddir)928

{929
case UP: for(i=xxx-ANT_EYESHOT;i<=xxx+ANT_EYESHOT;i++)930
for(j=yyy-ANT_EYESHOT;j<yyy;j++)931

{932
if(!JudgeCanGo(i,j)) continue;933
if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||934
(i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))935

{936
ms = MAX_SMELL;937
break;938
}939
if(IsTrace(i,j)) continue;940
if(Smell[type][i][j]>ms) ms = Smell[type][i][j];941
}942
break;943
case DOWN: for(i=xxx-ANT_EYESHOT;i<=xxx+ANT_EYESHOT;i++)944
for(j=yyy+1;j<=yyy+ANT_EYESHOT;j++)945

{946
if(!JudgeCanGo(i,j)) continue;947
if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||948
(i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))949

{950
ms = MAX_SMELL;951
break;952
}953
if(IsTrace(i,j)) continue;954
if(Smell[type][i][j]>ms) ms = Smell[type][i][j];955
}956
break;957
case LEFT: for(i=xxx-ANT_EYESHOT;i<xxx;i++)958
for(j=yyy-ANT_EYESHOT;j<=yyy+ANT_EYESHOT;j++)959

{960
if(!JudgeCanGo(i,j)) continue;961
if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||962
(i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))963

{964
ms = MAX_SMELL;965
break;966
}967
if(IsTrace(i,j)) continue;968
if(Smell[type][i][j]>ms) ms = Smell[type][i][j];969
}970
break;971
case RIGHT: for(i=xxx+1;i<=xxx+ANT_EYESHOT;i++)972
for(j=yyy-ANT_EYESHOT;j<=yyy+ANT_EYESHOT;j++)973

{974
if(!JudgeCanGo(i,j)) continue;975
if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||976
(i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))977

{978
ms = MAX_SMELL;979
break;980
}981
if(IsTrace(i,j)) continue;982
if(Smell[type][i][j]>ms) ms = Smell[type][i][j];983
}984
break;985
default: break;986
}987
return(ms);988
}989

990
int IsTrace(int xxx,int yyy)991


{992
int i;993

994
for(i=0;i<TRACE_REMEMBER;i++)995
if(ant[AntNow].tracex[i]==xxx&&ant[AntNow].tracey[i]==yyy) return(1);996
return(0);997
}998

999
int MaxLocation(int num1,int num2,int num3)1000


{1001
int maxnum;1002

1003
if(num1==0&&num2==0&&num3==0) return(0);1004

1005
maxnum = num1;1006
if(num2>maxnum) maxnum = num2;1007
if(num3>maxnum) maxnum = num3;1008

1009
if(maxnum==num1) return(1);1010
if(maxnum==num2) return(2);1011
if(maxnum==num3) return(3);1012
}1013

1014
int CanGo(int xxx,int yyy,int ddir)1015

/**//* input: xxx,yyy - location of ant1016
ddir - now dir1017
output: 0 - forward and left and right can go1018
1 - forward can not go1019
2 - left can not go1020
3 - right can not go1021
4 - forward and left can not go1022
5 - forward and right can not go1023
6 - left and right can not go1024
7 - forward and left and right all can not go1025
*/1026


{1027
int tx,ty,tdir;1028
int okf,okl,okr;1029

1030

/**//* forward can go ? */1031
tdir = ddir;1032
tx = xxx;1033
ty = yyy;1034
switch(tdir)1035

{1036
case UP: ty–;1037
break;1038
case DOWN: ty++;1039
break;1040
case LEFT: tx–;1041
break;1042
case RIGHT: tx++;1043
break;1044
default: break;1045

} /**//* of switch dir */1046
if(JudgeCanGo(tx,ty)) okf = 1;1047
else okf = 0;1048

1049

/**//* turn left can go ? */1050
tdir = TurnLeft(ddir);1051
tx = xxx;1052
ty = yyy;1053
switch(tdir)1054

{1055
case UP: ty–;1056
break;1057
case DOWN: ty++;1058
break;1059
case LEFT: tx–;1060
break;1061
case RIGHT: tx++;1062
break;1063
default: break;1064

} /**//* of switch dir */1065
if(JudgeCanGo(tx,ty)) okl = 1;1066
else okl = 0;1067

1068

/**//* turn right can go ? */1069
tdir = TurnRight(ddir);1070
tx = xxx;1071
ty = yyy;1072
switch(tdir)1073

{1074
case UP: ty–;1075
break;1076
case DOWN: ty++;1077
break;1078
case LEFT: tx–;1079
break;1080
case RIGHT: tx++;1081
break;1082
default: break;1083

} /**//* of switch dir */1084
if(JudgeCanGo(tx,ty)) okr = 1;1085
else okr = 0;1086

1087
if(okf&&okl&&okr) return(0);1088
if(!okf&&okl&&okr) return(1);1089
if(okf&&!okl&&okr) return(2);1090
if(okf&&okl&&!okr) return(3);1091
if(!okf&&!okl&&okr) return(4);1092
if(!okf&&okl&&!okr) return(5);1093
if(okf&&!okl&&!okr) return(6);1094
if(!okf&&!okl&&!okr) return(7);1095
return(7);1096
}1097

1098
int JudgeCanGo(int xxx,int yyy)1099

/**//* input: location to judeg1100
output: 0 — can not go1101
1 — can go1102
*/1103


{1104
int i,j;1105

1106
if(xxx<=0||xxx>MAXX) return(0);1107
if(yyy<=0||yyy>MAXY) return(0);1108
if(block[xxx][yyy]) return(0);1109
return(1);1110
}1111

1112
int TurnLeft(int ddir)1113


{1114
switch(ddir)1115

{1116
case UP: return(LEFT);1117
case DOWN: return(RIGHT);1118
case LEFT: return(DOWN);1119
case RIGHT: return(UP);1120
default: break;1121

} /**//* of switch dir */1122
}1123

1124
int TurnRight(int ddir)1125


{1126
switch(ddir)1127

{1128
case UP: return(RIGHT);1129
case DOWN: return(LEFT);1130
case LEFT: return(UP);1131
case RIGHT: return(DOWN);1132
default: break;1133

} /**//* of switch dir */1134
}1135

1136
int TurnBack(int ddir)1137


{1138
switch(ddir)1139

{1140
case UP: return(DOWN);1141
case DOWN: return(UP);1142
case LEFT: return(RIGHT);1143
case RIGHT: return(LEFT);1144
default: break;1145

} /**//* of switch dir */1146
}
