Пример #1
0
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;
}
Пример #2
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
	}
}
Пример #3
0
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);
}
Пример #4
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
	}
	
}
Пример #5
0
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
}
Пример #6
0
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;
}
Пример #7
0
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);
}
Пример #8
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 */
}
Пример #9
0
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);
}
Пример #10
0
// 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;
}
Пример #11
0
// 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;
}
Пример #12
0
/*
********************************************************************************
*                                                                              *
*   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);
  }
}