int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, wchar *MatchedArg,uint MatchedArgSize) { if (MatchedArg!=NULL && MatchedArgSize>0) *MatchedArg=0; // if (wcslen(FileHead.FileName)>=NM) // return 0; bool Dir=FileHead.Dir; if (ExclCheck(FileHead.FileName,Dir,false,true)) return 0; #ifndef SFX_MODULE if (TimeCheck(FileHead.mtime)) return 0; if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) return 0; if (!Dir && SizeCheck(FileHead.UnpSize)) return 0; #endif wchar *ArgName; FileArgs.Rewind(); for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) if (CmpName(ArgName,FileHead.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; if (MatchedArg!=NULL) wcsncpyz(MatchedArg,ArgName,MatchedArgSize); return StringCount; } return 0; }
void watchNotAus(void) //Notaus wenn Taste gedrückt oder Fernsteueung ausgefallen { if((PIND & (1<<IxNotAus)) || ((RemoteSignalTest(RemoteStatus) & (1<<Fail))) || ((RemoteValue[5] < 140) && (RemoteValue[2] > 240))) { PORTB &= ~(1<<Qx_GenEin); //Fremderregung am Generator ausschalten PORTB &= ~(1<<Qx_MLP_GenOK); //Generatorlampe ausschalten OCR1AL = 0x00; //Traktion ausschalten links OCR1BL = 0x00; //Traktion ausschalten rechts while((PIND & (1<<IxNotAus)) || ((RemoteSignalTest(RemoteStatus) & (1<<Fail))) || ((RemoteValue[5] < 140) && (RemoteValue[2] > 235))) //Wenn und Solange Notaus betätigt oder Fernst aus { PORTD |= (1<<Qx_MLP_Stoer); //Störlampe einschalten PORTD &= ~(1<<Qx_BenzMotEin); //Benzinmotor ausschalten startRemoteIn(); } while(!(PINB & (1<<IxEntpan))) //Wenn NotAus normalisiert warten bis Enpannen gedrückt { if(TimeCheck(halfsnd) >= 0b00000001) //Störlampe blinken lassen mit ca. 1Hz { TimeReset(halfsnd); PORTD ^= (1<<Qx_MLP_Stoer); } } PORTD &= ~(1<<Qx_MLP_Stoer); //Störlampe ausschalten falls noch brennt if(operatingstates & (1<<warmstart)) //Wenn der Motor schonmal gelaufen { engineStart(); //Motorstart einleiten } //Beim Kaltstart wird die Prozedur von Main-Loop aufgerufen } }
int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType) { if (strlen(NewLhd.FileName)>=NM || wcslen(NewLhd.FileNameW)>=NM) return(0); bool Dir=(NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; if (ExclCheck(NewLhd.FileName,Dir,false,true)) return(0); #ifndef SFX_MODULE if (TimeCheck(NewLhd.mtime)) return(0); if ((NewLhd.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (NewLhd.FileAttr & InclFileAttr)==0) return(0); if (!Dir && SizeCheck(NewLhd.FullUnpSize)) return(0); #endif char *ArgName; wchar *ArgNameW; FileArgs->Rewind(); for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++) { #ifndef SFX_MODULE bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL && *ArgNameW!=0; if (Unicode) { wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW; bool CorrectUnicode=true; if (ArgNameW==NULL || *ArgNameW==0) { if (!CharToWide(ArgName,ArgW) || *ArgW==0) CorrectUnicode=false; ArgNameW=ArgW; } if ((NewLhd.Flags & LHD_UNICODE)==0) { if (!CharToWide(NewLhd.FileName,NameW) || *NameW==0) CorrectUnicode=false; NamePtr=NameW; } if (CmpName(ArgNameW,NamePtr,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=wcsicompc(ArgNameW,NamePtr)==0; return(StringCount); } if (CorrectUnicode) continue; } #endif if (CmpName(ArgName,NewLhd.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0; return(StringCount); } } return(0); }
void engineStart(void) { stopFahrmot(); //Fahrmotoren abschalten PORTD |= (1<<Qx_BenzMotEin); //Zündung freigeben while(!(PINB & (1<<IxGenStart))) //Warten bis Motor läuft { watchNotAus(); //Schauen ob Notaus anliegt if(TimeCheck(halfsnd) >= 0b00000001) //Generatorlampe blinken lassen mit ca. 1Hz { TimeReset(halfsnd); //Halbsekundenverzögerung auf Null setzen PORTB ^= (1<<Qx_MLP_GenOK); } } PORTB |= (1<<Qx_GenEin); //Fremderregung am Generator einschalten PORTB |= (1<<Qx_MLP_GenOK); //Generatorlampe dauernd einschalten TimeReset(fullsnd); //Sekundenverzögerung Null setzen while(!(TimeCheck(fullsnd) >= 0b00000010)) //1 Sekunde warten { watchNotAus(); //Währenddessen NotAus kontrollieren } //Ab hier geändert dass ständig erregung... 11.01.2014 //Normalisieren: Auskommentiertes rausnehmen, nächste if bedingnung wegnehmen und lampe immer löschen lassen!!! /*while(!(PINB & (1<<IxLadekon))) //Wenn Generator bis dahin nicht angesprungen weiter warten { watchNotAus(); //Währenddessen NotAus kontrollieren } */PORTB &= ~(1<<Qx_GenEin); //Fremderregung am Generator ausschalten if(!(PINB & (1<<IxLadekon))) { PORTB &= ~(1<<Qx_MLP_GenOK); //Generatorlampe dauernd ausschalten } }
void lamptest(void) { TimeReset(doublesnd); //Zweisekundenverzögerung Null setzen while(!(TimeCheck(doublesnd) >= 0b00000100)) { PORTB |= (1<<Qx_MLP_GenOK); //Generatorlampe einschalten PORTD |= (1<<Qx_MLP_Stoer); //Störungslampe einschalten } PORTB &= ~(1<<Qx_MLP_GenOK); //Generatorlampe ausschalten PORTD &= ~(1<<Qx_MLP_Stoer); //Störungslampe ausschalten }
static bool WipeFile(const string& Name, int TotalPercent, bool& Cancel, ConsoleTitle* DeleteTitle) { bool Result = false; os::SetFileAttributes(Name,FILE_ATTRIBUTE_NORMAL); os::fs::file_walker WipeFile; if(WipeFile.Open(Name, FILE_READ_DATA|FILE_WRITE_DATA, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_WRITE_THROUGH|FILE_FLAG_SEQUENTIAL_SCAN)) { const DWORD BufSize=65536; if(WipeFile.InitWalk(BufSize)) { static std::array<BYTE, BufSize> Buf; static bool BufInit = false; if(!BufInit) { Buf.fill(Global->Opt->WipeSymbol); // используем символ заполнитель BufInit = true; } time_check TimeCheck(time_check::immediate, GetRedrawTimeout()); do { size_t Written; WipeFile.Write(Buf.data(), WipeFile.GetChunkSize(), Written); if (TimeCheck) { if (CheckForEscSilent() && ConfirmAbortOp()) { Cancel=true; return false; } ShellDeleteMsg(Name, DEL_WIPEPROCESS, TotalPercent, WipeFile.GetPercent(), DeleteTitle); } } while(WipeFile.Step()); WipeFile.SetPointer(0,nullptr,FILE_BEGIN); WipeFile.SetEnd(); } WipeFile.Close(); string strTempName; FarMkTempEx(strTempName,nullptr,FALSE); Result = os::MoveFile(Name,strTempName) && os::DeleteFile(strTempName); } return Result; }
int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType) { if (strlen(NewLhd.FileName)>=NM || strlenw(NewLhd.FileNameW)>=NM) return(0); if (ExclCheck(NewLhd.FileName,false)) return(0); #ifndef SFX_MODULE if (TimeCheck(NewLhd.mtime)) return(0); #endif char *ArgName; wchar *ArgNameW; FileArgs->Rewind(); for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++) { #ifndef SFX_MODULE bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL; if (Unicode) { wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW; if (ArgNameW==NULL) { CharToWide(ArgName,ArgW); ArgNameW=ArgW; } if ((NewLhd.Flags & LHD_UNICODE)==0) { CharToWide(NewLhd.FileName,NameW); NamePtr=NameW; } if (CmpName(ArgNameW,NamePtr,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompcw(ArgNameW,NamePtr)==0; return(StringCount); } continue; } #endif if (CmpName(ArgName,NewLhd.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0; return(StringCount); } } return(0); }
void menu() { FILE *pMenuFile; int Key, IsANSI; char temp[81], *Input, *sMenuPathFileName, buf[81]; Input = calloc(PATH_MAX, sizeof(char)); sMenuPathFileName = calloc(PATH_MAX, sizeof(char)); Syslog('+', "Starting menu loop"); /* * Loop forever, this is what a BBS should do until a user logs out. */ while (TRUE) { WhosDoingWhat(BROWSING, NULL); /* * Open menufile, first users language menu, if it fails * try to open the default menu. */ snprintf(sMenuPathFileName, PATH_MAX, "%s/share/int/menus/%s/%s", getenv("FTND_ROOT"), lang.lc, Menus[MenuLevel]); if ((pMenuFile = fopen(sMenuPathFileName, "r")) == NULL) { snprintf(sMenuPathFileName, PATH_MAX, "%s/share/int/menus/%s/%s", getenv("FTND_ROOT"), CFG.deflang, Menus[MenuLevel]); pMenuFile = fopen(sMenuPathFileName,"r"); if (pMenuFile != NULL) Syslog('b', "Menu %s (Default)", Menus[MenuLevel]); } else { Syslog('b', "Menu %s (%s)", Menus[MenuLevel], lang.Name); } if (pMenuFile == NULL) { clear(); WriteError("Can't open menu file: %s", sMenuPathFileName); MenuError++; /* * Is this the last attempt to open the default menu? */ if (MenuError == 10) { WriteError("FATAL ERROR: Too many menu errors"); snprintf(temp, 81, "Too many menu errors, notifying Sysop\r\n\r\n"); PUTSTR(temp); sleep(3); die(FTNERR_CONFIG_ERROR); } /* * Switch back to the default menu */ MenuLevel = 0; strcpy(Menus[0], CFG.default_menu); } else { /* * Display Menu Text Fields and Perform all autoexec menus in order of menu file. * First check if there are any ANSI menus, if not, send a clearscreen first. */ IsANSI = FALSE; while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { if ( Le_Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= le_int(menus.Age))){ if ((le_int(menus.MenuType) == 5) || (le_int(menus.MenuType) == 19) || (le_int(menus.MenuType) == 20)) IsANSI = TRUE; } } fseek(pMenuFile, 0, SEEK_SET); if (! IsANSI) clear(); while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { if ( Le_Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= le_int(menus.Age))){ if (menus.AutoExec) { DoMenu( le_int(menus.MenuType) ); } DisplayMenu( ); } } /* * Check if the BBS closed down for Zone Mail Hour or * system shutdown. If so, we run the Goodbye show. */ if (CheckStatus() == FALSE) { fclose(pMenuFile); Syslog('+', "Kicking user out, the BBS is closed."); sleep(3); Good_Bye(FTNERR_OK); } /* * Check the upsdown semafore */ if (IsSema((char *)"upsdown")) { fclose(pMenuFile); Syslog('+', "Kicking user out, upsdown semafore detected"); snprintf(temp, 81, "System power failure, closing the bbs"); PUTSTR(temp); Enter(2); sleep(3); Good_Bye(FTNERR_OK); } /* * Check if SysOp wants to chat to user everytime user gets prompt. */ if (CFG.iChatPromptChk) { snprintf(buf, 81, "CISC:1,%d", mypid); if (socket_send(buf) == 0) { strcpy(buf, socket_receive()); if (strcmp(buf, "100:1,1;") == 0) { Syslog('+', "Forced sysop/user chat"); Chat(exitinfo.Name, (char *)"#sysop"); continue; } } } /* * Check users timeleft */ TimeCheck(); alarm_on(); if (exitinfo.HotKeys) { Key = Readkey(); snprintf(Input, 81, "%c", Key); Enter(1); } else { colour(CFG.InputColourF, CFG.InputColourB); GetstrC(Input, 80); } if ((strcmp(Input, "")) != 0) { fseek(pMenuFile, 0, SEEK_SET); while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { if ((strcmp(tu(Input), menus.MenuKey)) == 0) { if ((Le_Access(exitinfo.Security, menus.MenuSecurity)) && (UserAge >= le_int(menus.Age))) { Syslog('+', "Menu[%d] %d=(%s), Opt: '%s'", MenuLevel, le_int(menus.MenuType), menus.TypeDesc, menus.OptionalData); if (le_int(menus.MenuType) == 13) { /* * Terminate call, cleanup here */ free(Input); free(sMenuPathFileName); fclose(pMenuFile); } DoMenu(le_int(menus.MenuType)); break; } } } } fclose(pMenuFile); } /* If menu open */ } /* while true */ }
void DoMenu(int Type) { int Strlen, i, x; char *sPrompt, *sPromptBak, *temp; sPrompt = calloc(81, sizeof(char)); sPromptBak = calloc(81, sizeof(char)); temp = calloc(81, sizeof(char)); TimeCheck(); switch(Type) { case 0: /* Display Prompt Line Only */ break; case 1: /* Goto another menu */ strncpy(Menus[MenuLevel], menus.OptionalData, 14); break; case 2: /* Gosub another menu */ if (MenuLevel < 49) { MenuLevel++; strncpy(Menus[MenuLevel], menus.OptionalData, 14); } else Syslog('?', "More than 50 menu levels"); break; case 3: /* Return from gosub */ if (MenuLevel > 0) MenuLevel--; break; case 4: /* Return to top menu */ MenuLevel = 0; break; case 5: /* Display .a?? file with controlcodes */ DisplayFile(menus.OptionalData); break; case 6: /* Show menu prompt */ Strlen = strlen(menus.OptionalData); for (x = 0; x < Strlen; x++) { if (menus.OptionalData[x] == '~') { strcat(sPrompt, sUserTimeleft); } else { snprintf(temp, 81, "%c", menus.OptionalData[x]); strcat(sPrompt, temp); } } strcpy(sPromptBak, sPrompt); strcpy(sPrompt, ""); Strlen = strlen(sPromptBak); for (x = 0; x < Strlen; x++) { if (*(sPromptBak + x) == '@') strcat(sPrompt, sAreaDesc); else if (*(sPromptBak + x) == '^') strcat(sPrompt, sMsgAreaDesc); else if (*(sPromptBak + x) == '#') snprintf(sPrompt, 81, "%s%s", sPrompt, (char *) GetLocalHM()); else { snprintf(temp, 81, "%c", *(sPromptBak + x)); strcat(sPrompt, temp); } } if (le_int(menus.ForeGnd) || le_int(menus.BackGnd)) pout(le_int(menus.ForeGnd), le_int(menus.BackGnd), sPrompt); else pout(WHITE, BLACK, sPrompt); break; case 7: /* Run external program */ if (strlen(menus.DoorName) && !menus.HideDoor) { memset(temp, 0, sizeof(temp)); strcpy(temp, menus.DoorName); ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport, menus.NoSuid, menus.NoPrompt, menus.SingleUser, temp); } else { ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport, menus.NoSuid, menus.NoPrompt, menus.SingleUser, NULL); } break; case 8: /* Show product information */ cr(); break; case 9: /* display todays callers */ LastCallers(menus.OptionalData); break; case 10: /* display userlist */ UserList(menus.OptionalData); break; case 11: /* display time statistics */ TimeStats(); break; case 12: /* page sysop for chat */ Page_Sysop(menus.OptionalData); break; case 13: /* terminate call */ free(sPrompt); free(sPromptBak); free(temp); Good_Bye(FTNERR_OK); break; case 14: /* make a log entry */ LogEntry(menus.OptionalData); break; case 15: /* print text to screen */ if (exitinfo.Security.level >= le_int(menus.MenuSecurity.level)) { for (i = 0; i < strlen(menus.OptionalData); i++) if (*(menus.OptionalData + i) == '@') *(menus.OptionalData + i) = '\n'; snprintf(temp, 81, "%s\r\n", menus.OptionalData); PUTSTR(temp); } break; case 16: /* who's currently online */ WhosOn(menus.OptionalData); Pause(); break; case 17: /* comment to sysop */ SysopComment((char *)"Comment to Sysop"); break; case 18: /* send on-line message */ SendOnlineMsg(menus.OptionalData); break; case 19: /* display Textfile with more */ MoreFile(menus.OptionalData); break; case 20: /* display a?? file with controlcode and wait for enter */ DisplayFileEnter(menus.OptionalData); break; case 21: /* display menuline only */ break; case 22: /* Chat with any user */ Chat(NULL, NULL); break; case 101: FileArea_List(menus.OptionalData); break; case 102: File_List(); break; case 103: ViewFile(NULL); break; case 104: Download(); break; case 105: File_RawDir(menus.OptionalData); break; case 106: KeywordScan(); break; case 107: FilenameScan(); break; case 108: NewfileScan(TRUE); break; case 109: Upload(); break; case 110: EditTaglist(); break; case 111: /* View file in homedir */ break; case 112: DownloadDirect(menus.OptionalData, TRUE); break; case 113: Copy_Home(); break; case 114: List_Home(); break; case 115: Delete_Home(); break; /* 116 Unpack file in homedir */ /* 117 Pack files in homedir */ case 118: Download_Home(); break; case 119: Upload_Home(); break; case 201: MsgArea_List(menus.OptionalData); break; case 202: Post_Msg(); break; case 203: Read_Msgs(); break; case 204: CheckMail(); break; case 205: QuickScan_Msgs(); break; case 206: Delete_Msg(); break; case 207: MailStatus(); break; case 208: OLR_TagArea(); break; case 209: OLR_UntagArea(); break; case 210: OLR_ViewTags(); break; case 211: OLR_RestrictDate(); break; case 212: OLR_Upload(); break; case 213: OLR_DownBW(); break; case 214: OLR_DownQWK(); break; case 215: OLR_DownASCII(); break; case 216: Read_Email(); break; case 217: Write_Email(); break; case 218: Trash_Email(); break; case 219: Choose_Mailbox(menus.OptionalData); break; case 220: QuickScan_Email(); break; case 221: DisplayRules(); break; case 301: Chg_Protocol(); break; case 302: Chg_Password(); break; case 303: Chg_Location(); break; case 305: Chg_VoicePhone(); break; case 306: Chg_DataPhone(); break; case 307: Chg_News(); break; case 309: Chg_DOB(); break; case 310: Chg_Language(FALSE); break; case 311: Chg_Hotkeys(); break; case 312: Chg_Handle(); break; case 313: Chg_MailCheck(); break; case 314: Chg_Disturb(); break; case 315: Chg_FileCheck(); break; case 316: Chg_FsMsged(); break; case 317: Chg_FsMsgedKeys(); break; case 318: Chg_Address(); break; case 319: signature(); break; case 320: Chg_OLR_ExtInfo(); break; case 321: Chg_Charset(); break; case 322: Chg_Archiver(); break; case 401: Oneliner_Add(); break; case 402: Oneliner_List(); break; case 403: Oneliner_Show(); break; case 404: Oneliner_Delete(); break; case 405: Oneliner_Print(); break; default: Enter(1); pout(WHITE, BLACK, (char *) Language(339)); Enter(2); Syslog('?', "Option: %s -> Unknown Menu Type: %d on %s", menus.MenuKey, Type, Menus[MenuLevel]); Pause(); } free(sPrompt); free(sPromptBak); free(temp); }
// Cette routine est la racine de l'arbre de recherche. Elle doit etre separee // car plusieurs chose ne sont pas utile a la racine. Comme le null move et // le lookup dans la table de transposition. int SearchRacine(int depth, int wtm, int alpha, int beta) { register int Valeur, AlphaInitiale, extension = 0; AlphaInitiale = alpha; // Calculer le temps restant. if ( (iNodes & 0xFF ) == 0xFF ) { if ( TimeCheck() ) { timeabort = true; } // Verifier si il y a quelque chose dans le tampon // d'entree. if ( inter() ) { interrupted = true; } } // Maintenant, evaluer chaque coup. while( NextMoveRacine( cb, wtm ) && !g_bAbort ) { if ( g_bModeAnalyse ) { printf( "stat01: %d %d %d %d %d\n", (TempsCenti()-timestamp), iNodes, iProfondeurIteration, cb.MoveList[1].nbmove - cb.MoveList[1].currmove-1, cb.MoveList[1].nbmove ); } else if ( !xboard ) { printf( "\r [%d] (%2d/%d)", iProfondeurIteration, cb.MoveList[1].currmove+1, cb.MoveList[1].nbmove ); } // On execute le coup. iNodes++; MakeMove(1, cb.MoveList[1].CurrentMove(), wtm); // Mettre le coup dans le chemin actuel. cb.CurrentPath.moves[1] = cb.MoveList[1].moves[cb.MoveList[1].currmove]; // Si le coup met en echec etendre la recherche d'une profondeur // pour qu'il puisse en sortir. if ( Check(!wtm) ) { cb.inCheck[2] = true; extension = 1; cb.RaisonExtension[1] = EXTENSION_ECHEC; } else { extension = 0; cb.inCheck[2] = false; cb.RaisonExtension[1] = PAS_EXTENSION; } // On l'explore. // Si c'est la variation principale, Fenetre normale, sinon, // fenetre est n et n+1. if ( cb.MoveList[1].currmove == 0 ) { Valeur = -ABSearch(depth-1+extension, 2, !wtm, -beta, -alpha, true); } else { Valeur = -ABSearch(depth-1+extension, 2, !wtm, -alpha-1, -alpha, true); if ( Valeur > alpha && Valeur < beta ) { Valeur = -ABSearch(depth-1+extension, 2, !wtm, -beta, -alpha, true); } } // La nouvelle valeur. cb.CurrentPath.moves[1].Score = Valeur; cb.MoveList[1].moves[cb.MoveList[1].currmove].Score = Valeur; // On defait le coup. UnmakeMove(1, cb.MoveList[1].CurrentMove(), wtm); if (interrupted) return Valeur; #ifdef DEBUG Consistence( cb, cb.MoveList[1].CurrentMove() ); #endif // Est-elle meileur que notre valeur actuelle? if ( !timeabort || g_bModeAnalyse ) { if ( Valeur > alpha ) { pv[1][1] = cb.CurrentPath.moves[1]; pv_length[1] = pv_length[2]; memcpy( &pv[1][2], &pv[2][2], sizeof( TMove )*(pv_length[1]-1)); AffichePV(iProfondeurIteration); if ( Valeur >= beta ) { return Valeur; } alpha = Valeur; } else if ( cb.MoveList[1].currmove == 0 ) return alpha; } } // while return alpha; }
// Algorithme de recherche MinMax avec des coupes Alpha-Beta. int Search(int depth, int ply, int wtm, int alpha, int beta, bool do_null) { register int Valeur, AlphaInitiale, check_ext = 0, extension = 0, MoveCherche, danger = 0; if ( ply >= MAXPLY-1 ) return beta; iNodes++; // Si on n'est pas en mode Analyse, Reste-t-il du temps? if ( interrupted || (timeabort && !g_bModeAnalyse) ) { return beta; } AlphaInitiale = alpha; // Calculer le temps restant. if ( (iNodes & 0xFF ) == 0xFF ) { if ( TimeCheck() ) { timeabort = true; } // Verifier si il y a quelque chose dans le tampon // d'entree. if ( inter() ) { char buf[10]; int c = fgetc(stdin); if (c == 10) { c = fgetc(stdin); ungetc(c, stdin); if (c == '.') { scanf("%s", &buf); printf( "stat01: %d %d %d %d %d\n", (TempsCenti()-timestamp), iNodes, iProfondeurIteration, cb.MoveList[1].nbmove - cb.MoveList[1].currmove-1, cb.MoveList[1].nbmove ); journal.Log("received a dot\n"); } else { interrupted = true; } } else { ungetc(c, stdin); interrupted = true; } } } // Verifier si ce n'est pas une nulle. if (Repetition(wtm)) { //if ( 0 < beta ) { // pv[ply-1][ply-1] = cb.CurrentPath.moves[ply-1]; return 0; // if ( wtm ) { // return DRAWSCORE; // } // else { // return -DRAWSCORE; // } //} } // Regarder dans la table de transposition pour voir si cette position // n'a pas deja ete calculer. #ifdef TRANSPOSITION switch( TableTrans->Lookup( cb, ply, depth, wtm, alpha, beta, danger ) ) { case SCORE_EXACTE: return alpha; case BORNE_SUPERIEUR: return alpha; case BORNE_INFERIEUR: return beta; case EVITER_NULL: do_null = false; } #endif #ifdef NULL_MOVE // En premier, on essai le NULL MOVE. if ( do_null ) { int nbPiece = wtm?cb.TotalMaterielBlanc:cb.TotalMaterielNoir; if ( !cb.inCheck[ply] && nbPiece > 5 && depth > 3 && alpha == beta-1) { int EnPassantB = cb.EnPassantB[ply+1]; int EnPassantN = cb.EnPassantN[ply+1]; cb.EnPassantB[ply+1] = -1; cb.EnPassantN[ply+1] = -1; Valeur = -Search(depth-3, ply+1, !wtm, -beta, -beta+1, false); cb.EnPassantB[ply+1] = EnPassantB; cb.EnPassantN[ply+1] = EnPassantN; if ( Valeur >= beta ) { #ifdef TRANSPOSITION TableTrans->StoreRefutation( cb, ply, depth, wtm, Valeur, alpha, beta, danger ); #endif return Valeur; } if ( Valeur <= -MATE+50 ) danger = 1; } } #endif // Internal Iterative Deepening. /* if ( depth > 2 && ((!(ply&1) && alpha==root_alpha && beta==root_beta) || ((ply&1) && alpha==-root_beta && beta==-root_alpha)) && cb.HashMove[ply].From == 0 && cb.HashMove[ply].To == 0 ) { Valeur = ABSearch( cb, depth-2, ply, wtm, alpha, beta, true ); if ( Valeur <= alpha ) { Valeur = ABSearch( cb, depth-2, ply, wtm, -MATE, beta, true ); } else { if ( Valeur < beta ) { cb.HashMove[ply] = pv[ply-1][ply]; } else cb.HashMove[ply] = cb.CurrentPath.moves[ply]; } }*/ #ifdef TRANSPOSITION Phase[ply] = HASH_MOVE; #else // if ( ((!(ply&1) && alpha==root_alpha && beta==root_beta) || // ( (ply&1) && alpha==-root_beta && beta==-root_alpha)) ) Phase[ply] = PV_MOVE; // else // Phase[ply] = GENERATE_CAPTURE_MOVES; #endif // Maintenant, evaluer chaque coup. MoveCherche = 0; while( Phase[ply] != NO_MORE_MOVES && !interrupted ) { if ( NextMove( cb, ply, wtm ) ) { // Si // On execute le coup. MakeMove(ply, cb.MoveList[ply].CurrentMove(), wtm); // Mettre le coup dans le chemin actuel. cb.CurrentPath.moves[ply] = cb.MoveList[ply].moves[cb.MoveList[ply].currmove]; if (!Check(wtm)) { MoveCherche++; // Si le coup met en echec etendre la recherche d'une profondeur // pour qu'il puisse en sortir. if (Check(!wtm) ) { cb.inCheck[ply+1] = true; extension = 1; cb.RaisonExtension[ply] = EXTENSION_ECHEC; } else { extension = 0; cb.inCheck[ply+1] = false; cb.RaisonExtension[ply] = PAS_EXTENSION; } // Si le coup est une recapture // etendre la recherche d'une profondeur. if ( cb.CurrentPath.moves[ply].Capture && abs(ValeurPiece[cb.CurrentPath.moves[ply-1].Capture] - ValeurPiece[cb.CurrentPath.moves[ply].Capture]) <= 20 && (cb.CurrentPath.moves[ply-1].To == cb.CurrentPath.moves[ply].To) && cb.RaisonExtension[ply-1] != EXTENSION_RECAPTURE) { extension = 1; cb.RaisonExtension[ply] = EXTENSION_RECAPTURE; } // Si on est sur le point de promouvoir un pion, étendre la recherche // pour voir si c'est une menace. if ( extension == 0 && cb.CurrentPath.moves[ply].Piece == 1 && PromoteExtension[ cb.CurrentPath.moves[ply].To ] ) { extension = 1; cb.RaisonExtension[ply] = EXTENSION_PROMOTION; } // Si on pousse un pion passe, pousser la recherche plus // loin pour voir si c'est un danger. if ( cb.CurrentPath.moves[ply].Piece == pion ) if ( wtm ) { if ( cb.CurrentPath.moves[ply].To <= H5 ) if ( cb.PionPasseB[cb.CurrentPath.moves[ply].To&7] ) { extension = 1; cb.RaisonExtension[ply] = EXTENSION_PIONPASSE; } } else { if ( cb.CurrentPath.moves[ply].To >= A4 ) if ( cb.PionPasseN[cb.CurrentPath.moves[ply].To&7] ) { extension = 1; cb.RaisonExtension[ply] = EXTENSION_PIONPASSE; } } // Razoring trick. Idee prise dans Crafty. if ( depth == 2 && !cb.inCheck[ply] && extension == 0 ) { int valeur; if ( wtm ) valeur = Eval(ply, wtm, alpha, beta); else valeur = -Eval(ply, wtm, alpha, beta); if ( valeur+50 < alpha ) extension = -1; } // On l'explore. // Si c'est la variation principale, Fenetre normale, sinon, // fenetre est n et n+1. int inpv = 1; if (ply&1) { if ( alpha != root_alpha || beta != root_beta ) inpv = 0; } else { if ( alpha != -root_beta || beta != -root_alpha ) inpv = 0; } if ( inpv ) { Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -beta, -alpha, true); } else { Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -alpha-1, -alpha, true); if ( Valeur > alpha && Valeur < beta ) { pvsresearch++; Valeur = -ABSearch(depth-1+extension+danger, ply+1, !wtm, -beta, -alpha, true); } } } else { Valeur = -INFINI; } cb.MoveList[ply].CurrentMove().Score = Valeur; // On defait le coup. UnmakeMove(ply, cb.MoveList[ply].CurrentMove(), wtm); if (interrupted) return Valeur; #ifdef DEBUG Consistence( cb, cb.MoveList[ply].CurrentMove() ); #endif // Est-il meilleur que notre valeur actuelle? if ( Valeur > alpha ) { if ( Valeur >= beta ) { #ifdef TRANSPOSITION TableTrans->StoreRefutation( cb, ply, depth, wtm, Valeur, alpha, beta, check_ext ); #endif g_iRefutation++; // Verifier si on peu l'utiliser comme killer move. if ( Phase[ply] == NON_CAPTURE_MOVES ) { cb.AddKiller( &cb.CurrentPath.moves[ply-1], ply-1 ); } else { if ( Phase[ply] == KILLER_MOVE_2 ) cb.Killers[ply-1][0].Score++; else if ( Phase[ply] == GENERATE_NON_CAPTURE_MOVES ) cb.Killers[ply-1][1].Score++; } return Valeur; } pv[ply][ply] = cb.CurrentPath.moves[ply]; pv_length[ply] = pv_length[ply+1]; memcpy(&pv[ply][ply+1], &pv[ply+1][ply+1], sizeof(TMove)*(pv_length[ply]-ply)); alpha = Valeur; } } // if } // Verifier si il y a mat ou pat. if ( MoveCherche == 0 ) { if (!Check(wtm)) { pv[ply][ply] = cb.CurrentPath.moves[ply]; return 0; // if ( wtm ) { // return DRAWSCORE; // } // else { // return -DRAWSCORE; // } } else { if ( ply < iMateInPly ) iMateInPly = ply; alpha = -MATE+iMateInPly; } } #ifdef TRANSPOSITION TableTrans->StoreBest( cb, ply, depth, wtm, alpha, AlphaInitiale, danger ); #endif return alpha; }
/* ******************************************************************************** * * * Search() is the recursive routine used to implement the alpha/beta * * negamax search (similar to minimax but simpler to code.) Search() is * * called whenever there is "depth" remaining so that all moves are subject * * to searching, or when the side to move is in check, to make sure that this * * side isn't mated. Search() recursively calls itself until depth is ex- * * hausted, at which time it calls Quiesce() instead. * * * ******************************************************************************** */ int Search(int alpha, int beta, int wtm, int depth, int ply, int do_null) { register int first_move=1; register BITBOARD save_hash_key; register int initial_alpha, value; register int extensions; /* ---------------------------------------------------------- | | | check to see if we have searched enough nodes that it | | is time to peek at how much time has been used, or if | | is time to check for operator keyboard input. this is | | usually enough nodes to force a time/input check about | | once per second, except when the target time per move | | is very small, in which case we try to check the time | | at least 10 times during the search. | | | ---------------------------------------------------------- */ if (ply >= MAXPLY-2) return(beta); nodes_searched++; if (--next_time_check <= 0) { next_time_check=nodes_between_time_checks; if (CheckInput()) Interrupt(ply); time_abort+=TimeCheck(0); if (time_abort) { abort_search=1; return(0); } } /* ---------------------------------------------------------- | | | check for draw by repetition. | | | ---------------------------------------------------------- */ if (RepetitionCheck(ply,wtm)) { value=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if (value < beta) SavePV(ply,value,0); #if !defined(FAST) if(ply <= trace_level) printf("draw by repetition detected, ply=%d.\n",ply); #endif return(value); } /* ---------------------------------------------------------- | | | now call LookUp() to see if this position has been | | searched before. if so, we may get a real score, | | produce a cutoff, or get nothing more than a good move | | to try first. there are four cases to handle: | | | | 1. LookUp() returned "EXACT_SCORE" if this score is | | greater than beta, return beta. otherwise, return the | | score. In either case, no further searching is needed | | from this position. note that lookup verified that | | the table position has sufficient "draft" to meet the | | requirements of the current search depth remaining. | | | | 2. LookUp() returned "LOWER_BOUND" which means that | | when this position was searched previously, every move | | was "refuted" by one of its descendents. as a result, | | when the search was completed, we returned alpha at | | that point. we simply return alpha here as well. | | | | 3. LookUp() returned "UPPER_BOUND" which means that | | when we encountered this position before, we searched | | one branch (probably) which promptly refuted the move | | at the previous ply. | | | | 4. LookUp() returned "AVOID_NULL_MOVE" which means | | the hashed score/bound was no good, but it indicated | | that trying a null-move in this position will be a | | waste of time. | | | ---------------------------------------------------------- */ switch (LookUp(ply,depth,wtm,&alpha,beta)) { case EXACT_SCORE: if(alpha >= beta) return(beta); else { SavePV(ply,alpha,1); return(alpha); } case LOWER_BOUND: return(alpha); case UPPER_BOUND: return(beta); case AVOID_NULL_MOVE: do_null=0; } /* ---------------------------------------------------------- | | | now it's time to try a probe into the endgame table- | | base files. this is done if (a) the previous move was | | a capture or promotion, unless we are at very shallow | | plies (<4) in the search; (b) there are less than 5 | | pieces left (currently all interesting 4 piece endings | | are available.) | | | ---------------------------------------------------------- */ #if defined(TABLEBASES) if (TotalPieces < 5) do { register int wpawn, bpawn; int tb_value; if (TotalWhitePawns && TotalBlackPawns) { wpawn=FirstOne(WhitePawns); bpawn=FirstOne(BlackPawns); if (FileDistance(wpawn,bpawn) == 1) { if(((Rank(wpawn)==1) && (Rank(bpawn)>2)) || ((Rank(bpawn)==6) && (Rank(wpawn)<5)) || EnPassant(ply)) break; } } tb_probes++; if (EGTBScore(ply, wtm, &tb_value)) { tb_probes_successful++; alpha=tb_value; if (abs(alpha) > MATE-100) alpha+=(alpha > 0) ? -(ply-1) : +(ply-1); else if (alpha == 0) alpha=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if(alpha >= beta) return(beta); else { SavePV(ply,alpha,2); return(alpha); } } } while(0); # endif /* ---------------------------------------------------------- | | | initialize. | | | ---------------------------------------------------------- */ in_check[ply+1]=0; extended_reason[ply+1]=no_extension; initial_alpha=alpha; last[ply]=last[ply-1]; killer_count1[ply+1]=0; killer_count2[ply+1]=0; /* ---------------------------------------------------------- | | | first, we try a null move to see if we can get a quick | | cutoff with only a little work. this operates as | | follows. instead of making a legal move, the side on | | move 'passes' and does nothing. the resulting position | | is searched to a shallower depth than normal (usually | | one ply less but settable by the operator) this should | | result in a cutoff or at least should set the lower | | bound better since anything should be better than not | | doing anything. | | | | this is skipped for any of the following reasons: | | | | 1. the side on move is in check. the null move | | results in an illegal position. | | 2. no more than one null move can appear in succession | | or else the search will degenerate into nothing. | | 3. the side on move has little material left making | | zugzwang positions more likely. | | | ---------------------------------------------------------- */ # if defined(NULL_MOVE_DEPTH) if (do_null && !in_check[ply] && ((wtm) ? TotalWhitePieces : TotalBlackPieces)>2) { current_move[ply]=0; current_phase[ply]=NULL_MOVE; #if !defined(FAST) if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",0); #endif position[ply+1]=position[ply]; Rule50Moves(ply+1)++; save_hash_key=HashKey; if (EnPassant(ply)) { HashEP(EnPassant(ply+1),HashKey); EnPassant(ply+1)=0; } if ((depth-NULL_MOVE_DEPTH-INCREMENT_PLY) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth-NULL_MOVE_DEPTH-INCREMENT_PLY,ply+1,NO_NULL); else value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); HashKey=save_hash_key; if (abort_search) return(0); if (value >= beta) { StoreRefutation(ply,depth,wtm,beta); return(beta); } } # endif /* ---------------------------------------------------------- | | | if there is no best move from the hash table, and this | | is a PV node, then we need a good move to search | | first. while killers and history moves are good, they | | are not "good enough". the simplest action is to try | | a shallow search (depth-2) to get a move. note that | | when we call Search() with depth-2, it, too, will | | not have a hash move, and will therefore recursively | | continue this process, hence the name "internal | | iterative deepening." | | | ---------------------------------------------------------- */ next_status[ply].phase=FIRST_PHASE; if (hash_move[ply]==0 && (depth > 2*INCREMENT_PLY) && (((ply & 1) && alpha == root_alpha && beta == root_beta) || (!(ply & 1) && alpha == -root_beta && beta == -root_alpha))) { current_move[ply]=0; value=Search(alpha,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL); if (abort_search) return(0); if (value <= alpha) { value=Search(-MATE,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL); if (abort_search) return(0); } else if (value < beta) { if ((int) pv[ply-1].path_length >= ply) hash_move[ply]=pv[ply-1].path[ply]; } else hash_move[ply]=current_move[ply]; last[ply]=last[ply-1]; next_status[ply].phase=FIRST_PHASE; } /* ---------------------------------------------------------- | | | now iterate through the move list and search the | | resulting positions. note that Search() culls any | | move that is not legal by using Check(). the special | | case is that we must find one legal move to search to | | confirm that it's not a mate or draw. | | | ---------------------------------------------------------- */ while ((current_phase[ply]=(in_check[ply]) ? NextEvasion(ply,wtm) : NextMove(depth,ply,wtm))) { extended_reason[ply]&=check_extension; #if !defined(FAST) if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",current_phase[ply]); #endif /* ---------------------------------------------------------- | | | if two successive moves are capture / re-capture so | | that the material score is restored, extend the search | | by one ply on the re-capture since it is pretty much | | forced and easy to analyze. | | | ---------------------------------------------------------- */ extensions=-INCREMENT_PLY; if (Captured(current_move[ply]) && Captured(current_move[ply-1]) && To(current_move[ply-1]) == To(current_move[ply]) && (p_values[Captured(current_move[ply-1])+7] == p_values[Captured(current_move[ply])+7] || Promote(current_move[ply-1])) && !(extended_reason[ply-1]&recapture_extension)) { extended_reason[ply]|=recapture_extension; recapture_extensions_done++; extensions+=RECAPTURE; } /* ---------------------------------------------------------- | | | if we push a passed pawn, we need to look deeper to | | see if it is a legitimate threat. | | | ---------------------------------------------------------- */ if (Piece(current_move[ply])==pawn && !FutileAhead(wtm) && ((wtm && To(current_move[ply])>H5 && TotalBlackPieces<16 && !And(mask_pawn_passed_w[To(current_move[ply])],BlackPawns)) || (!wtm && To(current_move[ply])<A4 && TotalWhitePieces<16 && !And(mask_pawn_passed_b[To(current_move[ply])],WhitePawns)) || push_extensions[To(current_move[ply])]) && Swap(From(current_move[ply]),To(current_move[ply]),wtm) >= 0) { extended_reason[ply]|=passed_pawn_extension; passed_pawn_extensions_done++; extensions+=PASSED_PAWN_PUSH; } /* ---------------------------------------------------------- | | | now make the move and search the resulting position. | | if we are in check, the current move must be legal | | since NextEvasion ensures this, otherwise we have to | | make sure the side-on-move is not in check after the | | move to weed out illegal moves and save time. | | | ---------------------------------------------------------- */ MakeMove(ply,current_move[ply],wtm); if (in_check[ply] || !Check(wtm)) { /* ---------------------------------------------------------- | | | if the move to be made checks the opponent, then we | | need to remember that he's in check and also extend | | the depth by one ply for him to get out. | | | ---------------------------------------------------------- */ if (Check(ChangeSide(wtm))) { in_check[ply+1]=1; extended_reason[ply+1]=check_extension; check_extensions_done++; extensions+=IN_CHECK; } else { in_check[ply+1]=0; extended_reason[ply+1]=no_extension; } /* ---------------------------------------------------------- | | | now we toss in the "razoring" trick, which simply says | | if we are doing fairly badly, we can reduce the depth | | an additional ply, if there was nothing at the current | | ply that caused an extension. | | | ---------------------------------------------------------- */ if (depth < 3*INCREMENT_PLY && !in_check[ply] && extensions == -INCREMENT_PLY) { register int val=(wtm) ? Material : -Material; if (val+1500 < alpha) extensions-=INCREMENT_PLY; } /* ---------------------------------------------------------- | | | if there's only one legal move, extend the search one | | additional ply since this node is very easy to search. | | | ---------------------------------------------------------- */ if (first_move) { if (last[ply]-last[ply-1] == 1) { extended_reason[ply]|=one_reply_extension; one_reply_extensions_done++; extensions+=ONE_REPLY_TO_CHECK; } if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else { value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); } if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } first_move=0; } else { if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-alpha-1,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else { value=-Quiesce(-alpha-1,-alpha,ChangeSide(wtm),ply+1); } if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } if (value>alpha && value<beta) { if (depth+MaxExtensions(extensions) >= INCREMENT_PLY) value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL); else value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1); if (abort_search) { UnMakeMove(ply,current_move[ply],wtm); return(0); } } } if (value > alpha) { if(value >= beta) { HistoryRefutation(ply,depth,wtm); UnMakeMove(ply,current_move[ply],wtm); StoreRefutation(ply,depth,wtm,beta); return(beta); } alpha=value; } } UnMakeMove(ply,current_move[ply],wtm); } /* ---------------------------------------------------------- | | | all moves have been searched. if none were legal, | | return either MATE or DRAW depending on whether the | | side to move is in check or not. | | | ---------------------------------------------------------- */ if (first_move == 1) { value=(Check(wtm)) ? -(MATE-ply) : ((wtm==root_wtm) ? DrawScore() : -DrawScore()); if(value > beta) value=beta; else if (value < alpha) value=alpha; if (value >=alpha && value <beta) { SavePV(ply,value,0); #if !defined(FAST) if (ply <= trace_level) printf("Search() no moves! ply=%d\n",ply); #endif } return(value); } else { if (alpha != initial_alpha) { memcpy(&pv[ply-1].path[ply],&pv[ply].path[ply],(pv[ply].path_length-ply+1)*4); memcpy(&pv[ply-1].path_hashed,&pv[ply].path_hashed,3); pv[ply-1].path[ply-1]=current_move[ply-1]; HistoryBest(ply,depth,wtm); } StoreBest(ply,depth,wtm,alpha,initial_alpha); /* ---------------------------------------------------------- | | | if the 50-move rule is drawing close, then adjust the | | score to reflect the impending draw. | | | ---------------------------------------------------------- */ if (Rule50Moves(ply) > 99) { value=(wtm==root_wtm) ? DrawScore() : -DrawScore(); if (value < beta) SavePV(ply,value,0); #if !defined(FAST) if(ply <= trace_level) printf("draw by 50-move rule detected, ply=%d.\n",ply); #endif return(value); } return(alpha); } }