原文出处:http://tech.ddvip.com/2009-04/1239243667114090.html,转载请注明原始出处。
程序开始运行,蚂蚁们开始从窝里出动了,寻找食物;他们会顺着屏幕爬满整个画面,直到找到食物再返回窝。
其中,‘F’点表示食物,‘H’表示窝,白色块表示障碍物,‘+’就是蚂蚁了。
预期的结果:各个蚂蚁在没有事先告诉他们食物在什么地方的前提下开始寻找食物。当一只找到食物以后,它会向环境释放一种信息素,吸引其他的蚂蚁过来,这样越来越多的蚂蚁会找到食物!有些蚂蚁并没有象其它蚂蚁一样总重复同样的路,他们会另辟蹊径,如果令开辟的道路比原来的其他道路更短,那么,渐渐,更多的蚂蚁被吸引到这条较短的路上来。最后,经过一段时间运行,可能会出现一条最短的路径被大多数蚂蚁重复着。
原理:为什么小小的蚂蚁能够找到食物?他们具有智能么?设想,如果我们要为蚂蚁设计一个人工智能的程序,那么这个程序要多么复杂呢?首先,你要让蚂蚁能够避开障碍物,就必须根据适当的地形给它编进指令让他们能够巧妙的避开障碍物,其次,要让蚂蚁找到食物,就需要让他们遍历空间上的所有点;再次,如果要让蚂蚁找到最短的路径,那么需要计算所有可能的路径并且比较它们的大小,而且更重要的是,你要小心翼翼的编程,因为程序的错误也许会让你前功尽弃。这是多么不可思议的程序!太复杂了,恐怕没人能够完成这样繁琐冗余的程序。
然而,事实并没有你想得那么复杂,上面这个程序每个蚂蚁的核心程序编码不过100多行!为什么这么简单的程序会让蚂蚁干这样复杂的事情?答案是:简单规则的涌现。事实上,每只蚂蚁并不是像我们想象的需要知道整个世界的信息,他们其实只关心很小范围内的眼前信息,而且根据这些局部信息利用几条简单的规则进行决策,这样,在蚁群这个集体里,复杂性的行为就会凸现出来。这就是人工生命、复杂性科学解释的规律!那么,这些简单规则是什么呢?
下面详细说明:
1、范围:蚂蚁观察到的范围是一个方格世界,蚂蚁有一个参数为速度半径(一般是3),那么它能观察到的范围就是3*3个方格世界,并且能移动的距离也在这个范围之内。
2、环境:蚂蚁所在的环境是一个虚拟的世界,其中有障碍物,有别的蚂蚁,还有信息素,信息素有两种,一种是找到食物的蚂蚁洒下的食物信息素,一种是找到窝的蚂蚁洒下的窝的信息素。每个蚂蚁都仅仅能感知它范围内的环境信息。环境以一定的速率让信息素消失。
3、觅食规则:在每只蚂蚁能感知的范围内寻找是否有食物,如果有就直接过去。否则看是否有信息素,并且比较在能感知的范围内哪一点的信息素最多,这样,它就朝信息素多的地方走,并且每只蚂蚁多会以小概率犯错误,从而并不是往信息素最多的点移动。蚂蚁找窝的规则和上面一样,只不过它对窝的信息素做出反应,而对食物信息素没反应。
4、移动规则:每只蚂蚁都朝向信息素最多的方向移,并且,当周围没有信息素指引的时候,蚂蚁会按照自己原来运动的方向惯性的运动下去,并且,在运动的方向有一个随机的小的扰动。为了防止蚂蚁原地转圈,它会记住最近刚走过了哪些点,如果发现要走的下一点已经在最近走过了,它就会尽量避开。
5、避障规则:如果蚂蚁要移动的方向有障碍物挡住,它会随机的选择另一个方向,并且有信息素指引的话,它会按照觅食的规则行为。
6、播撒信息素规则:每只蚂蚁在刚找到食物或者窝的时候撒发的信息素最多,并随着它走远的距离,播撒的信息素越来越少。
根据这几条规则,蚂蚁之间并没有直接的关系,但是每只蚂蚁都和环境发生交互,而通过信息素这个纽带,实际上把各个蚂蚁之间关联起来了。比如,当一只蚂蚁找到了食物,它并没有直接告诉其它蚂蚁这儿有食物,而是向环境播撒信息素,当其它的蚂蚁经过它附近的时候,就会感觉到信息素的存在,进而根据信息素的指引找到了食物。
问题:说了这么多,蚂蚁究竟是怎么找到食物的呢?
在没有蚂蚁找到食物的时候,环境没有有用的信息素,那么蚂蚁为什么会相对有效的找到食物呢?这要归功于蚂蚁的移动规则,尤其是在没有信息素时候的移动规则。首先,它要能尽量保持某种惯性,这样使得蚂蚁尽量向前方移动(开始,这个前方是随机固定的一个方向),而不是原地无谓的打转或者震动;其次,蚂蚁要有一定的随机性,虽然有了固定的方向,但它也不能像粒子一样直线运动下去,而是有一个随机的干扰。这样就使得蚂蚁运动起来具有了一定的目的性,尽量保持原来的方向,但又有新的试探,尤其当碰到障碍物的时候它会立即改变方向,这可以看成一种选择的过程,也就是环境的障碍物让蚂蚁的某个方向正确,而其他方向则不对。这就解释了为什么单个蚂蚁在复杂的诸如迷宫的地图中仍然能找到隐蔽得很好的食物。
当然,在有一只蚂蚁找到了食物的时候,其他蚂蚁会沿着信息素很快找到食物的。
蚂蚁如何找到最短路径的?这一是要归功于信息素,另外要归功于环境,具体说是计算机时钟。信息素多的地方显然经过这里的蚂蚁会多,因而会有更多的蚂蚁聚集过来。假设有两条路从窝通向食物,开始的时候,走这两条路的蚂蚁数量同样多(或者较长的路上蚂蚁多,这也无关紧要)。当蚂蚁沿着一条路到达终点以后会马上返回来,这样,短的路蚂蚁来回一次的时间就短,这也意味着重复的频率就快,因而在单位时间里走过的蚂蚁数目就多,洒下的信息素自然也会多,自然会有更多的蚂蚁被吸引过来,从而洒下更多的信息素……;而长的路正相反,因此,越来越多地蚂蚁聚集到较短的路径上来,最短的路径就近似找到了。也许有人会问局部最短路径和全局最短路的问题,实际上蚂蚁逐渐接近全局最短路的,为什么呢?这源于蚂蚁会犯错误,也就是它会按照一定的概率不往信息素高的地方走而另辟蹊径,这可以理解为一种创新,这种创新如果能缩短路途,那么根据刚才叙述的原理,更多的蚂蚁会被吸引过来。
引申跟着蚂蚁的踪迹,你找到了什么?通过上面的原理叙述和实际操作,我们不难发现蚂蚁之所以具有智能行为,完全归功于它的简单行为规则,而这些规则综合起来具有下面两个方面的特点:
1、多样性2、正反馈多样性保证了蚂蚁在觅食的时候不置走进死胡同而无限循环,正反馈机制则保证了相对优良的信息能够被保存下来。我们可以把多样性看成是一种创造能力,而正反馈是一种学习强化能力。正反馈的力量也可以比喻成权威的意见,而多样性是打破权威体现的创造性,正是这两点小心翼翼的巧妙结合才使得智能行为涌现出来了。[Page]引申来讲,大自然的进化,社会的进步、人类的创新实际上都离不开这两样东西,多样性保证了系统的创新能力,正反馈保证了优良特性能够得到强化,两者要恰到好处的结合。如果多样性过剩,也就是系统过于活跃,这相当于蚂蚁会过多的随机运动,它就会陷入混沌状态;而相反,多样性不够,正反馈机制过强,那么系统就好比一潭死水。这在蚁群中来讲就表现为,蚂蚁的行为过于僵硬,当环境变化了,蚂蚁群仍然不能适当的调整。
既然复杂性、智能行为是根据底层规则涌现的,既然底层规则具有多样性和正反馈特点,那么也许你会问这些规则是哪里来的?多样性和正反馈又是哪里来的?我本人的意见:规则来源于大自然的进化。而大自然的进化根据刚才讲的也体现为多样性和正反馈的巧妙结合。而这样的巧妙结合又是为什么呢?为什么在你眼前呈现的世界是如此栩栩如生呢?答案在于环境造就了这一切,之所以你看到栩栩如生的世界,是因为那些不能够适应环境的多样性与正反馈的结合都已经死掉了,被环境淘汰了!
参数说明:最大信息素:蚂蚁在一开始拥有的信息素总量,越大表示程序在较长一段时间能够存在信息素。信息素消减的速度:随着时间的流逝,已经存在于世界上的信息素会消减,这个数值越大,那么消减的越快。
错误概率表示这个蚂蚁不往信息素最大的区域走的概率,越大则表示这个蚂蚁越有创新性。
速度半径表示蚂蚁一次能走的最大长度,也表示这个蚂蚁的感知范围。
记忆能力表示蚂蚁能记住多少个刚刚走过点的坐标,这个值避免了蚂蚁在本地打转,停滞不前。而这个值越大那么整个系统运行速度就慢,越小则蚂蚁越容易原地转圈。
代码如下:
1 /*ant.c*/ 2 3 4 #define SPACE 0x20 5 6 #define ESC 0x1b 7 8 #define ANT_CHAR_EMPTY '+' 9 10 #define ANT_CHAR_FOOD 153 11 12 #define HOME_CHAR 'H' 13 14 #define FOOD_CHAR 'F' 15 16 #define FOOD_CHAR2 'f' 17 18 #define FOOD_HOME_COLOR 12 19 20 #define BLOCK_CHAR 177 21 22 23 #define MAX_ANT 50 24 25 #define INI_SPEED 3 26 27 #define MAXX 80 28 29 #define MAXY 23 30 31 #define MAX_FOOD 10000 32 33 #define TARGET_FOOD 200 34 35 #define MAX_SMELL 5000 36 37 #define SMELL_DROP_RATE 0.05 38 39 #define ANT_ERROR_RATE 0.02 40 41 #define ANT_EYESHOT 3 42 43 #define SMELL_GONE_SPEED 50 44 45 #define SMELL_GONE_RATE 0.05 46 47 #define TRACE_REMEMBER 50 48 49 #define MAX_BLOCK 100 50 51 52 #define NULL 0 53 54 #define UP 1 55 56 #define DOWN 2 57 58 #define LEFT 3 59 60 #define RIGHT 4 61 62 #define SMELL_TYPE_FOOD 0 63 64 #define SMELL_TYPE_HOME 1 65 66 67 #include "stdio.h" 68 69 #include "conio.h" 70 71 #include "dos.h" 72 73 #include "stdlib.h" 74 75 #include "dos.h" 76 77 #include "process.h" 78 79 #include "ctype.h" 80 81 #include "math.h" 82 83 84 void WorldInitial(void); 85 86 void BlockInitial(void); 87 88 void CreatBlock(void); 89 90 void SaveBlock(void); 91 92 void LoadBlock(void); 93 94 void HomeFoodInitial(void); 95 96 void AntInitial(void); 97 98 void WorldChange(void); 99 100 void AntMove(void); 101 102 void AntOneStep(void); 103 104 void DealKey(char key); 105 106 void ClearSmellDisp(void); 107 108 void DispSmell(int type); 109 110 int AntNextDir(int xxx,int yyy,int ddir); 111 112 int GetMaxSmell(int type,int xxx,int yyy,int ddir);[Page] 113 114 int IsTrace(int xxx,int yyy); 115 116 int MaxLocation(int num1,int num2,int num3); 117 118 int CanGo(int xxx,int yyy,int ddir); 119 120 int JudgeCanGo(int xxx,int yyy); 121 122 int TurnLeft(int ddir); 123 124 int TurnRight(int ddir); 125 126 int TurnBack(int ddir); 127 128 129 int MainTimer(void); 130 131 char WaitForKey(int secnum); 132 133 void DispPlayTime(void); 134 135 int TimeUse(void); 136 137 void HideCur(void); 138 139 void ResetCur(void); 140 141 142 /* --------------- */ 143 144 struct HomeStruct 145 146 { 147 148 int xxx,yyy; 149 150 int amount; 151 152 int TargetFood; 153 154 }home; 155 156 157 struct FoodStruct 158 159 { 160 161 int xxx,yyy; 162 163 int amount; 164 165 }food; 166 167 168 struct AntStruct 169 170 { 171 172 int xxx,yyy; 173 174 int dir; 175 176 int speed; 177 178 int SpeedTimer; 179 180 int food; 181 182 int SmellAmount[2]; 183 184 int tracex[TRACE_REMEMBER]; 185 186 int tracey[TRACE_REMEMBER]; 187 188 int TracePtr; 189 190 int IQ; 191 192 }ant[MAX_ANT]; 193 194 int AntNow; 195 196 int timer10ms; 197 198 struct time starttime,endtime; 199 200 int Smell[2][MAXX+1][MAXY+1]; 201 202 int block[MAXX+1][MAXY+1]; 203 204 int SmellGoneTimer; 205 206 int SmellDispFlag; 207 208 int CanFindFood; 209 210 int HardtoFindPath; 211 212 213 /* ----- Main -------- */ 214 215 void main(void) 216 217 { 218 219 char KeyPress; 220 221 int tu; 222 223 224 clrscr(); 225 226 HideCur(); 227 228 WorldInitial(); 229 230 do 231 232 { 233 234 timer10ms = MainTimer(); 235 236 if(timer10ms) AntMove(); 237 238 if(timer10ms) WorldChange(); 239 240 tu = TimeUse(); 241 242 if(tu>=60&&!CanFindFood) 243 244 { 245 246 gotoxy(1,MAXY+1); 247 248 printf("Can not find food, maybe a block world."); 249 250 WaitForKey(10); 251 252 WorldInitial(); 253 254 } 255 256 if(tu>=180&&home.amount<100&&!HardtoFindPath) 257 258 { 259 260 gotoxy(1,MAXY+1); 261 262 printf("God! it is so difficult to find a path.");[Page] 263 264 if(WaitForKey(10)==0x0d) WorldInitial(); 265 266 else 267 268 { 269 270 HardtoFindPath = 1; 271 272 gotoxy(1,MAXY+1); 273 274 printf(" "); 275 276 } 277 278 } 279 280 if(home.amount>=home.TargetFood) 281 282 { 283 284 gettime(&endtime); 285 286 KeyPress = WaitForKey(60); 287 288 DispPlayTime(); 289 290 WaitForKey(10); 291 292 WorldInitial(); 293 294 } 295 296 else if(kbhit()) 297 298 { 299 300 KeyPress = getch(); 301 302 DealKey(KeyPress); 303 304 } 305 306 else KeyPress = NULL; 307 308 } 309 310 while(KeyPress!=ESC); 311 312 gettime(&endtime); 313 314 DispPlayTime(); 315 316 WaitForKey(10); 317 318 clrscr(); 319 320 ResetCur(); 321 322 } 323 324 325 /* ------ general sub process ----------- */ 326 327 int MainTimer(void) 328 329 /* output: how much 10ms have pass from last time call this process */ 330 331 { 332 333 static int oldhund,oldsec; 334 335 struct time t; 336 337 int timeuse; 338 339 340 gettime(&t); 341 342 timeuse = 0; 343 344 if(t.ti_hund!=oldhund) 345 346 { 347 348 if(t.ti_sec!=oldsec)[Page] 349 350 { 351 352 timeuse+=100; 353 354 oldsec = t.ti_sec; 355 356 } 357 358 timeuse+=t.ti_hund-oldhund; 359 360 oldhund = t.ti_hund; 361 362 } 363 364 else timeuse = 0; 365 366 return (timeuse); 367 368 } 369 370 371 char WaitForKey(int secnum) 372 373 /* funtion: if have key in, exit immediately, else wait 'secnum' senconds then exit 374 375 input: secnum -- wait this senconds, must < 3600 (1 hour) 376 377 output: key char, if no key in(exit when timeout), return NULL */ 378 379 { 380 381 int secin,secnow; 382 383 int minin,minnow; 384 385 int hourin,hournow; 386 387 int secuse; 388 389 struct time t; 390 391 392 gettime(&t); 393 394 secin = t.ti_sec; 395 396 minin = t.ti_min; 397 398 hourin = t.ti_hour; 399 400 401 do 402 403 { 404 405 if(kbhit()) return(getch()); 406 407 gettime(&t); 408 409 secnow = t.ti_sec; 410 411 minnow = t.ti_min; 412 413 hournow = t.ti_hour; 414 415 416 417 418 if(hournow!=hourin) minnow+=60; 419 420 if(minnow>minin) secuse = (minnow-1-minin) + (secnow+60-secin); 421 422 else secuse = secnow - secin; 423 424 425 /* counting error check */ 426 427 if(secuse<0) 428 429 { 430 431 gotoxy(1,MAXY+1); 432 433 printf("Time conuting error, any keyto exit..."); 434 435 getch(); 436 437 exit(3); 438 439 } 440 441 } 442 443 while(secuse<=secnum); 444 445 return (NULL); 446 447 } 448 449 450 void DispPlayTime(void) 451 452 { 453 454 int ph,pm,ps; 455 456 457 ph = endtime.ti_hour - starttime.ti_hour;[Page] 458 459 pm = endtime.ti_min - starttime.ti_min; 460 461 ps = endtime.ti_sec - starttime.ti_sec; 462 463 464 if(ph<0) ph+=24; 465 466 if(pm<0) { ph--; pm+=60; } 467 468 if(ps<0) { pm--; ps+=60; } 469 470 471 gotoxy(1,MAXY+1); 472 473 printf("Time use: %d hour- %d min- %d sec ",ph,pm,ps); 474 475 } 476 477 478 int TimeUse(void) 479 480 { 481 482 int ph,pm,ps; 483 484 485 gettime(&endtime); 486 487 ph = endtime.ti_hour - starttime.ti_hour; 488 489 pm = endtime.ti_min - starttime.ti_min; 490 491 ps = endtime.ti_sec - starttime.ti_sec; 492 493 494 if(ph<0) ph+=24; 495 496 if(pm<0) { ph--; pm+=60; } 497 498 if(ps<0) { pm--; ps+=60; } 499 500 501 return(ps+(60*(pm+60*ph))); 502 503 } 504 505 506 507 void HideCur(void) 508 509 { 510 511 union REGS regs0; 512 513 regs0.h.ah=1; 514 515 regs0.h.ch=0x30; 516 517 regs0.h.cl=0x31; 518 519 int86(0x10,®s0,®s0); 520 521 } 522 523 524 void ResetCur(void) 525 526 { 527 528 union REGS regs0; 529 530 regs0.h.ah=1; 531 532 regs0.h.ch=0x06; 533 534 regs0.h.cl=0x07; 535 536 int86(0x10,®s0,®s0); 537 538 } 539 540 541 /* ------------ main ANT programe ------------- */ 542 543 void WorldInitial(void) 544 545 { 546 547 int k,i,j; 548 549 randomize(); 550 551 clrscr(); 552 553 HomeFoodInitial(); 554 555 for(AntNow=0;AntNow<MAX_ANT;AntNow++) 556 557 { 558 559 AntInitial(); 560 561 } /* of for AntNow */; 562 563 564 BlockInitial(); 565 566 for(k=0;k<=1;k++) 567 568 /* SMELL TYPE FOOD and HOME */ 569 570 for(i=0;i<=MAXX;i++) 571 572 for(j=0;j<=MAXY;j++) 573 574 Smell[k][i][j] = 0; 575 576 SmellGoneTimer = 0; 577 578 gettime(&starttime); 579 580 SmellDispFlag = 0; 581 582 CanFindFood = 0; 583 584 HardtoFindPath = 0; 585 586 } 587 588 589 void BlockInitial(void) 590 591 { 592 593 int i,j; 594 595 int bn; 596 597 598 for(i=0;i<=MAXX;i++) 599 600 for(j=0;j<=MAXY;j++)[Page] 601 602 block[i][j] = 0; 603 604 605 bn = 1+ MAX_BLOCK/2 + random(MAX_BLOCK/2); 606 607 for(i=0;i<=bn;i++) CreatBlock(); 608 609 } 610 611 612 void CreatBlock(void) 613 614 { 615 616 int x1,y1,x2,y2; 617 618 int dx,dy; 619 620 int i,j; 621 622 623 x1 = random(MAXX)+1; 624 625 y1 = random(MAXY)+1; 626 627 628 dx = random(MAXX/10)+1; 629 630 dy = random(MAXY/10)+1; 631 632 633 x2 = x1+dx; 634 635 y2 = y1+dy; 636 637 638 if(x2>MAXX) x2 = MAXX; 639 640 if(y2>MAXY) y2 = MAXY; 641 642 643 if(food.xxx>=x1&&food.xxx<=x2&&food.yyy>=y1&&food.yyy<=y2) return; 644 645 if(home.xxx>=x1&&home.xxx<=x2&&home.yyy>=y1&&home.yyy<=y2) return; 646 647 648 for(i=x1;i<=x2;i++) 649 650 for(j=y1;j<=y2;j++) 651 652 { 653 654 block[i][j] = 1; 655 656 gotoxy(i,j); 657 658 putch(BLOCK_CHAR); 659 660 } 661 662 } 663 664 665 void SaveBlock(void) 666 667 { 668 669 FILE *fp_block; 670 671 char FileNameBlock[20]; 672 673 int i,j; 674 675 676 gotoxy(1,MAXY+1); 677 678 printf(" "); 679 680 gotoxy(1,MAXY+1); 681 682 printf("Save to file...",FileNameBlock); 683 684 gets(FileNameBlock); 685 686 if(FileNameBlock[0]==0) strcpy(FileNameBlock,"Ant.ant"); 687 688 else strcat(FileNameBlock,".ant"); 689 690 691 if ((fp_block = fopen(FileNameBlock, "wb")) == NULL) 692 693 { gotoxy(1,MAXY+1); 694 695 printf("Creat file %s fail...",FileNameBlock); 696 697 getch(); 698 699 exit(2); 700 701 } 702 703 gotoxy(1,MAXY+1); 704 705 printf(" "); [Page] 706 707 708 fputc(home.xxx,fp_block); 709 710 fputc(home.yyy,fp_block); 711 712 fputc(food.xxx,fp_block); 713 714 fputc(food.yyy,fp_block); 715 716 717 for(i=0;i<=MAXX;i++) 718 719 for(j=0;j<=MAXY;j++) 720 721 fputc(block[i][j],fp_block); 722 723 724 fclose(fp_block); 725 726 } 727 728 729 void LoadBlock(void) 730 731 { 732 733 FILE *fp_block; 734 735 char FileNameBlock[20]; 736 737 int i,j,k; 738 739 740 gotoxy(1,MAXY+1); 741 742 printf(" "); 743 744 gotoxy(1,MAXY+1); 745 746 printf("Load file...",FileNameBlock); 747 748 gets(FileNameBlock); 749 750 if(FileNameBlock[0]==0) strcpy(FileNameBlock,"Ant.ant"); 751 752 else strcat(FileNameBlock,".ant"); 753 754 755 if ((fp_block = fopen(FileNameBlock, "rb")) == NULL) 756 757 { gotoxy(1,MAXY+1); 758 759 printf("Open file %s fail...",FileNameBlock); 760 761 getch(); 762 763 exit(2); 764 765 } 766 767 768 clrscr(); 769 770 home.xxx = fgetc(fp_block); 771 772 home.yyy = fgetc(fp_block); 773 774 food.xxx = fgetc(fp_block); 775 776 food.yyy = fgetc(fp_block); 777 778 gotoxy(home.xxx,home.yyy); putch(HOME_CHAR); 779 780 gotoxy(food.xxx,food.yyy); putch(FOOD_CHAR); 781 782 food.amount = random(MAX_FOOD/3)+2*MAX_FOOD/3+1; 783 784 /* food.amount = MAX_FOOD; */ 785 786 home.amount = 0; 787 788 home.TargetFood = (food.amount<TARGET_FOOD)?food.amount:TARGET_FOOD; 789 790 791 for(AntNow=0;AntNow<MAX_ANT;AntNow++) 792 793 { 794 795 AntInitial(); 796 797 } /* of for AntNow */; 798 799 800 for(i=0;i<=MAXX;i++) 801 802 for(j=0;j<=MAXY;j++) 803 804 { 805 806 block[i][j] = fgetc(fp_block); 807 808 if(block[i][j]) 809 810 { 811 812 gotoxy(i,j); 813 814 putch(BLOCK_CHAR); 815 816 } 817 818 }[Page] 819 820 821 for(k=0;k<=1;k++) 822 823 /* SMELL TYPE FOOD and HOME */ 824 825 for(i=0;i<=MAXX;i++) 826 827 for(j=0;j<=MAXY;j++) 828 829 Smell[k][i][j] = 0; 830 831 SmellGoneTimer = 0; 832 833 gettime(&starttime); 834 835 SmellDispFlag = 0; 836 837 CanFindFood = 0; 838 839 HardtoFindPath = 0;