Форум » » Протокол UCI-1 команды от GUI движку » Ответить

Протокол UCI-1 команды от GUI движку

bankuss: UCI (универсальный шахматный интерфейс) Описание UCI: * Движок – exe файл, консольное или обычное приложение windows. * Связь осуществляется через стандартный ввод/вывод простыми текстовыми командами. * Загруженный движок должен ждать команду от GUI - "isready" или команду "setoption", чтобы инициализировать свои параметры. Процесс начальной загрузки должен быть максимально быстр. * Движок должен уметь обрабатывать входящие данные от stdin, даже при размышлении. * Все команды, которые получает движок, заканчиваются '\n '. Также все команды, которые GUI получает от движка, должны заканчиваться '\n '. * Движок не должен начинать играть или рассчитывать без команды “go”. * Движок не должен совершать ход на внутренней шахматной доске без запроса от GUI, т.е. движок не должен выполнять лучший ход после поиска. * Прежде, чем движок начнет поиск в позиции, он должен принять текущую позицию. * Все дебютные библиотеки сделаны через GUI, Но имеется опция для движка для использования собственной ДБ (опция "OwnBook", см. ниже) Формат хода: Формат хода использует длинную алгебраическою нотацию: Примеры: e2e4, e7e5, e1g1 (короткая рокировка), e7e8q (превращение пешки) Команды от GUI к движку: * UCI Сообщить движку об использовании протокола uci. После команды “uci” движок посылает команды о себе и настройках. Т.е. передает команду "option" с параметрами. После этого движок должен послать "uciok". Если uciok не послан в пределах некоторого периода времени, то движок будет выгружен! * DEBUG [on | off] Переключить способ отладки движка вкл. и выкл. По умолчанию этот параметр должен быть выключенным! В этом режиме движок может посылать дополнительную информации оболочке. * ISREADY Команда используется для синхронизации движка и оболочки. После ее посылки оболочка ждет готовность движка. Этой команде нужно всегда отвечать "readyok". * SETIPTION NAME <id> [value <x>] Передается движку, когда пользователь хочет изменить внутренние настройки движка. Пример: setoption name Hash value 12 setoption name NalimovCache value 4 setoption name OwnBook value true setoption name NalimovPath value C:\Tbase setoption name Ponder value false setoption name book_during_analysis value true setoption name book_learning value false * POSITION [fen <fenstring> | startpos ] moves <move1> .... <movei> Передать позицию. * GO Дать команду на вычисление текущей позиции. Имеется множество команд, которые могут следовать за этой командой. * wtime <x> Белые x мсек на часах * btime <x> Черные x мсек на часах * winc <x> приращение на ход в мсек, если x> 0 * binc <x> приращение на ход в мсек, если x> 0 * movestogo <x> Имеются ходы x к следующему контролю, Послано если x> 0. * depth <x> Искать на x глубину. * nodes <x> Искать x узлов. * mate <x> Искать мат. * movetime <x> Искать точно x мсек. * infinite Поиск до команды "stop". Не выходите из поиска без выключения этого режима! * STOP Остановка поиска. Не забывайте команду "bestmove" по окончании поиска! * PONDERHIT Пользователь делает ожидаемый ход. * QUIT Выйти из программы. Вольный перевод by bankuss 2004

Ответов - 29, стр: 1 2 All

NS_Serg: Про ponder вроде не до конца перевёл...

bankuss: NS_Serg может... я кратко и самое нужное :)

Freeman: * Движок должен уметь обрабатывать входящие данные от stdin, даже при размышлении. Как замутить такое на делфи?


bankuss: Freeman при игре движков это не особо важно. скорее всего здесь имеется ввиду обработка команды STOP (или FORCE в xboard), чтоб движок прервал вычисления и выдал ход до которого додумался. ну и QUIT естественно...

NS_Serg: Раз в 10000 nodes, если прошло определенное время с предыдущей проверки (например 10мс) вызываешь функцию PeekNamedPipe, и если что-то есть, и это что-то - stop - то аварийно выходишь из перебора. В принципе - для турнира это не нужно. Если poner-а нет.

NS_Serg: bankuss пишет: при игре движков это не особо важно. скорее всего здесь имеется ввиду обработка команды STOP (или FORCE в xboard), чтоб движок прервал вычисления и выдал ход до которого додумался. ну и QUIT естественно... команды маленькими буквами ;-) А тут мной была написана глупость ;-))) Кроме stop-a ничего больше не надо, при ponder всё равно сначала stop шлет. У меня самого ponder не сделан - для чемпионата СНГ он не нужен. Однопроцессорные машины будут. Без пондера будем играть. ;-))

Freeman: я так делал. procedure LPrint(msgs:string); var x1:Pchar; len:Cardinal; begin assignfile(f,'iolog.txt'); Append(f); writeln(f,'--> ',msgs); closefile(f); len:=length(msgs); x1:=pchar(msgs + #10); _lwrite(gHandleout,x1,len+1); end; function Input:string; var res:string; begin Input:=''; readln(res); if res='' then exit; assignfile(f,'iolog.txt'); Append(f); writeln(f,'<-- ',res); closefile(f); Input:=res; end; где и с какими параметрами юзать PeekNamedPipe ?

NS_Serg: var StdInPipeWrite,StdOutPipeRead:THandle; StdInPipeWrite:= GetStdHandle(STD_Output_HANDLE); StdOutPipeRead:=GetStdHandle(STD_INPUT_HANDLE); Это инициализация, один раз при запуске, остальные две процедуры в безобразном виде, даже стыдно выкладывать ;-))) (кривой текст) но это же не книга ;-)) function ReadNS:AnsiString; Var chBuf: Char; BufSize,i: DWORD; res:boolean; s:AnsiString; begin chbuf:=chr(0); BufSize:=0; Res:=PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BufSize, nil); Res:=Res and (BufSize > 0); If Res Then // Это нормально переписать надо - очень торопился, хотел посмотреть, как играет. while (chbuf>chr(13))or(chbuf=chr(0)) do begin s:=''; for I := 1 to Bufsize do Begin chBuf:=chr(0); ReadFile(StdOutPipeRead, chBuf, 1, BufSize, Nil); if chBuf>chr(13) then s:=s+chBuf; if chBuf=Chr(10) then break; end; Result:=s; end Else Result:=''; end; procedure WriteNS(Data: AnsiString); Var chBuf: PChar; BufSize,i: DWORD; begin chBuf:=PChar(Data+Chr($0D)+Chr($0A)); BufSize:=Length(chBuf); WriteFile(StdInPipeWrite, chBuf^, BufSize, i, Nil); end; // по MSDN-у писал ;-)) ни одного примера не нашел по форумам... Заодно написал для оболочки - для наоборот - ловить движок, и перехватывать его ввод/вывод - интересно?

Freeman: я из http://www.tim-mann.org/winboard/delphi.txt взял (из справки к винборду). Кинь для оболочки еще =)) может че-нить потом сделаю

NS_Serg: Freeman пишет: я из http://www.tim-mann.org/winboard/delphi.txt взял (из справки к винборду). Кинь для оболочки еще =)) может че-нить потом сделаю Там я как-то наткнулся - лажа конечно. Там поток дополнительный организуется, а у меня всё на одном потоке. Для оболочки: var sa: TSecurityAttributes; pi: TProcessInformation; si: TStartupInfo; StdOutPipeRead, StdOutPipeWrite, StdInPipeRead, StdInPipeWrite : THandle; procedure TForm1.Button1Click(Sender: TObject); begin sa.nLength := sizeof(sa); sa.bInheritHandle := TRUE; sa.lpSecurityDescriptor := nil; CreatePipe(StdOutPipeRead,StdOutPipeWrite,@SA,0); CreatePipe(StdInPipeRead,StdInPipeWrite,@SA,0); ZeroMemory(@SI, SizeOf(SI)); SI.cb := sizeof(SI); SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; SI.wShowWindow := SW_HIDE; SI.hStdInput := StdInPipeRead; SI.hStdOutput := StdOutPipeWrite; CreateProcess(nil, 'E:\crafty_1917_DC\crafty_1917_DC\Crafty-1917.exe', nil, nil, TRUE, 0, nil, nil, si, pi); а дальше - как я привел выше, только Handle полученные используешь.

NS_Serg: Для движка делаю в цикле - while true do begin sleep(1); s:=readNS(); if s='uci' then begin writeNS('id name Anechka 0.01'); writeNS('id author Sergei V. Nefedov'); writeNS('uciok'); end else if s='isready' then begin writeNS('readyok'); end else if s='stop' then writeNS('bestmove 0000') else if s='quit' then begin readNS(); CloseHandle(StdOutPipeRead); CloseHandle(StdInPipeWrite); exit; .... // на stop такой странный вывод // потому что ничего в это время не считаем... // readNS() - если движек нам ничего не посылал - выдает пустую строку // не задерживая выполнение программы В момент перебора - я уже описывал выше...

bankuss: NS_Serg Ты через winAPI делаешь, я тоже так делал. А когда под dotNET работал, то через класс system.console реализовал. Очень даже удобно вышло. Кстати тоже в одном потоке все организовал, неохота было с tread возится :) Единственное отличие парсинга команд от твоего - я через select case делал, и только 3-4 команды через if.

NS_Serg: Два потока всяко хуже, так как в турнирах может возникнуть подозрение, что программа просто откровенно жулит... Особенно при включенном Ponder.

boriz: А ссылки есть какие-нибудь на спецификации или популярные описания UCI в более подробном варианте? Вы, bankuss, где брали английскую версию?

NS_Serg: http://www.uciengines.de/UCI_Protocol/uci_protocol.html http://www.shredderchess.com/download.html

Igrok88: Эксперты очень вас прошу приписать uci код к следующему работающему коду: /* FirstChess - Freeware, by Pham Hong Nguyen Version: beta */ /* * BASIC PARTS: * * Some definitions * * Board representation and main varians * * Move generator * * Evaluation for current position * * Make and Take back a move, IsInCheck * * Search function - a typical alphabeta * * Utility * * Main program * */ #include <stdio.h> #include <string.h> #include <assert.h> /* **************************************************************************** * Some definitions * **************************************************************************** */ #define PAWN 0 #define KNIGHT 1 #define BISHOP 2 #define ROOK 3 #define QUEEN 4 #define KING 5 #define EMPTY 6 #define WHITE 0 #define BLACK 1 #define VALUE_PAWN 100 #define VALUE_KNIGHT 300 #define VALUE_BISHOP 300 #define VALUE_ROOK 500 #define VALUE_QUEEN 900 #define VALUE_KING 10000 #define MATE 10000 /* equal value of King, losing King==mate */ #define COL(pos) ((pos)&7) #define ROW(pos) (((unsigned)pos)>>3) /* **************************************************************************** * Board representation and main varians * **************************************************************************** */ /* Board representation */ int piece[64] = { ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK }; int color[64] = { BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE }; int side; /* side to move, value = BLACK or WHITE */ /* For move generation */ #define MOVE_TYPE_NONE 0 #define MOVE_TYPE_NORMAL 1 #define MOVE_TYPE_CASTLE 2 #define MOVE_TYPE_ENPASANT 3 #define MOVE_TYPE_PROMOTION_TO_QUEEN 4 #define MOVE_TYPE_PROMOTION_TO_ROOK 5 #define MOVE_TYPE_PROMOTION_TO_BISHOP 6 #define MOVE_TYPE_PROMOTION_TO_KNIGHT 7 typedef struct tag_MOVE { int from, dest, type; } MOVE; /* For storing all moves of game */ typedef struct tag_HIST { MOVE m; int cap; } HIST; HIST hist[6000]; /* Game length < 6000 */ int hdp; /* Current move order */ /* For searching */ int nodes; /* Count all visited nodes when searching */ int ply; /* ply of search */ /* **************************************************************************** * Move generator * * Lack: no enpassant, no castle * **************************************************************************** */ void Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount) { MOVE move; move.from = from; move.dest = dest; move.type = type; pBuf[*pMCount] = move; *pMCount = *pMCount + 1; } void Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount) { Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount); } /* Pawn can promote */ void Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount) { if (dest > 7 && dest < 56) Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount); else { Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount); Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount); Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount); Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount); } } /* Gen all moves of current_side to move and push them to pBuf, return number of moves */ int Gen(int current_side, MOVE * pBuf) { int i, k, y, row, col, movecount; movecount = 0; for (i = 0; i < 64; i++) /* Scan all board */ if (color[i] == current_side) { switch (piece[i]) { case PAWN: col = COL(i); row = ROW(i); if (current_side == BLACK) { if (color[i + 8] == EMPTY) Gen_PushPawn(i, i + 8, pBuf, &movecount); if (row == 1 && color[i + 8] == EMPTY && color[i + 16] == EMPTY) Gen_PushNormal(i, i + 16, pBuf, &movecount); if (col && color[i + 7] == WHITE) Gen_PushNormal(i, i + 7, pBuf, &movecount); if (col < 7 && color[i + 9] == WHITE) Gen_PushNormal(i, i + 9, pBuf, &movecount); } else { if (color[i - 8] == EMPTY) Gen_PushPawn(i, i - 8, pBuf, &movecount); if (row == 6 && color[i - 8] == EMPTY && color[i - 16] == EMPTY) Gen_PushNormal(i, i - 16, pBuf, &movecount); if (col && color[i - 9] == BLACK) Gen_PushNormal(i, i - 9, pBuf, &movecount); if (col < 7 && color[i - 7] == BLACK) Gen_PushNormal(i, i - 7, pBuf, &movecount); } break; case QUEEN: /* == BISHOP+ROOK */ case BISHOP: for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) { /* go left up */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) { /* go right up */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (y = i + 9; y < 64 && COL(y) != 0; y += 9) { /* go right down */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (y = i + 7; y < 64 && COL(y) != 7; y += 7) { /* go right down */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } if (piece[i] == BISHOP) break; /* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */ case ROOK: col = COL(i); for (k = i - col, y = i - 1; y >= k; y--) { /* go left */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (k = i - col + 7, y = i + 1; y <= k; y++) { /* go right */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (y = i - 8; y >= 0; y -= 8) { /* go up */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } for (y = i + 8; y < 64; y += 8) { /* go down */ if (color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); if (color[y] != EMPTY) break; } break; case KNIGHT: col = COL(i); y = i - 6; if (y >= 0 && col < 6 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i - 10; if (y >= 0 && col > 1 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i - 15; if (y >= 0 && col < 7 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i - 17; if (y >= 0 && col > 0 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i + 6; if (y < 64 && col > 1 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i + 10; if (y < 64 && col < 6 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i + 15; if (y < 64 && col > 0 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); y = i + 17; if (y < 64 && col < 7 && color[y] != current_side) Gen_PushNormal(i, y, pBuf, &movecount); break; case KING: col = COL(i); if (col && color[i - 1] != current_side) Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */ if (col < 7 && color[i + 1] != current_side) Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */ if (i > 7 && color[i - 8] != current_side) Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */ if (i < 56 && color[i + 8] != current_side) Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */ if (col && i > 7 && color[i - 9] != current_side) Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */ if (col < 7 && i > 7 && color[i - 7] != current_side) Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */ if (col && i < 56 && color[i + 7] != current_side) Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */ if (col < 7 && i < 56 && color[i + 9] != current_side) Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */ break; default: puts("piece type unknown"); assert(false); } } return movecount; } /* **************************************************************************** * Evaluation for current position - main "brain" function * * Lack: almost no knowlegde * **************************************************************************** */ int Eval() { int value_piece[6] = {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING}; int i, score = 0; for (i = 0; i < 64; i++) { if (color[i] == WHITE) score += value_piece[piece[i]]; else if (color[i] == BLACK) score -= value_piece[piece[i]]; } if (side == WHITE) return -score; return score; } /* **************************************************************************** * Make and Take back a move, IsInCheck * **************************************************************************** */ /* Check and return 1 if side is in check */ int IsInCheck(int current_side) { int k, h, y, row, col, xside; xside = (WHITE + BLACK) - current_side; /* opposite current_side, who may be checking */ /* Find King */ for (k = 0; k < 64; k++) if (piece[k] == KING && color[k] == current_side) break; row = ROW(k), col = COL(k); /* Check attacking of Knight */ if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT) return 1; if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT) return 1; if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT) return 1; if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT) return 1; if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT) return 1; if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT) return 1; if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT) return 1; if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT) return 1; /* Check horizontal and vertical lines for attacking of Queen, Rook, King */ /* go down */ y = k + 8; if (y < 64) { if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] == EMPTY) for (y += 8; y < 64; y += 8) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] != EMPTY) break; } } /* go left */ y = k - 1; h = k - col; if (y >= h) { if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] == EMPTY) for (y--; y >= h; y--) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] != EMPTY) break; } } /* go right */ y = k + 1; h = k - col + 7; if (y <= h) { if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] == EMPTY) for (y++; y <= h; y++) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] != EMPTY) break; } } /* go up */ y = k - 8; if (y >= 0) { if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] == EMPTY) for (y -= 8; y >= 0; y -= 8) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK)) return 1; if (piece[y] != EMPTY) break; } } /* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */ /* go right down */ y = k + 9; if (y < 64 && COL(y) != 0) { if (color[y] == xside) { if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) return 1; if (current_side == BLACK && piece[y] == PAWN) return 1; } if (piece[y] == EMPTY) for (y += 9; y < 64 && COL(y) != 0; y += 9) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP)) return 1; if (piece[y] != EMPTY) break; } } /* go left down */ y = k + 7; if (y < 64 && COL(y) != 7) { if (color[y] == xside) { if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) return 1; if (current_side == BLACK && piece[y] == PAWN) return 1; } if (piece[y] == EMPTY) for (y += 7; y < 64 && COL(y) != 7; y += 7) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP)) return 1; if (piece[y] != EMPTY) break; } } /* go left up */ y = k - 9; if (y >= 0 && COL(y) != 7) { if (color[y] == xside) { if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) return 1; if (current_side == WHITE && piece[y] == PAWN) return 1; } if (piece[y] == EMPTY) for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP)) return 1; if (piece[y] != EMPTY) break; } } /* go right up */ y = k - 7; if (y >= 0 && COL(y) != 0) { if (color[y] == xside) { if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP) return 1; if (current_side == WHITE && piece[y] == PAWN) return 1; } if (piece[y] == EMPTY) for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) { if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP)) return 1; if (piece[y] != EMPTY) break; } } return 0; } int MakeMove(MOVE m) { int r; hist[hdp].m = m; hist[hdp].cap = piece[m.dest]; piece[m.dest] = piece[m.from]; piece[m.from] = EMPTY; color[m.dest] = color[m.from]; color[m.from] = EMPTY; if (m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) { /* Promotion */ switch (m.type) { case MOVE_TYPE_PROMOTION_TO_QUEEN: piece[m.dest] = QUEEN; break; case MOVE_TYPE_PROMOTION_TO_ROOK: piece[m.dest] = ROOK; break; case MOVE_TYPE_PROMOTION_TO_BISHOP: piece[m.dest] = BISHOP; break; case MOVE_TYPE_PROMOTION_TO_KNIGHT: piece[m.dest] = KNIGHT; break; default: puts("impossible to get here..."); assert(false); } } ply++; hdp++; r = !IsInCheck(side); side = (WHITE + BLACK) - side; /* After making move, give turn to * opponent */ return r; } void TakeBack() /* undo what MakeMove did */ { side = (WHITE + BLACK) - side; hdp--; ply--; piece[hist[hdp].m.from] = piece[hist[hdp].m.dest]; piece[hist[hdp].m.dest] = hist[hdp].cap; color[hist[hdp].m.from] = side; if (hist[hdp].cap != EMPTY) color[hist[hdp].m.dest] = (WHITE + BLACK) - side; else color[hist[hdp].m.dest] = EMPTY; if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) /* Promotion */ piece[hist[hdp].m.from] = PAWN; } /* **************************************************************************** * Search function - a typical alphabeta, main search function * * Lack: no any technique for move ordering * **************************************************************************** */ int Search(int alpha, int beta, int depth, MOVE * pBestMove) { int i, value, havemove, movecnt; MOVE moveBuf[200], tmpMove; nodes++; /* visiting a node, count it */ havemove = 0; pBestMove->type = MOVE_TYPE_NONE; movecnt = Gen(side, moveBuf); /* generate all moves for current position */ /* loop through the moves */ for (i = 0; i < movecnt; ++i) { if (!MakeMove(moveBuf[i])) { TakeBack(); continue; } havemove = 1; if (depth - 1 > 0) /* If depth is still, continue to search deeper */ value = -Search(-beta, -alpha, depth - 1, &tmpMove); else /* If no depth left (leaf node), go to evalute that position */ value = Eval(); TakeBack(); if (value > alpha) { /* This move is so good and caused a cutoff */ if (value >= beta) return beta; alpha = value; *pBestMove = moveBuf[i]; /* so far, current move is the best reaction * for current position */ } } if (!havemove) { /* If no legal moves, that is checkmate or * stalemate */ if (IsInCheck(side)) return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */ else return 0; } return alpha; } MOVE ComputerThink(int max_depth) { MOVE m; int score; /* reset some values before searching */ ply = 0; nodes = 0; /* search now */ score = Search(-MATE, MATE, max_depth, &m); /* after searching, print results */ printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n", 'a' + COL(m.from), 8 - ROW(m.from), 'a' + COL(m.dest), 8 - ROW(m.dest), nodes, score ); return m; } /* **************************************************************************** * Utilities * **************************************************************************** */ void PrintBoard() { char pieceName[] = "PNBRQKpnbrqk"; int i; for (i = 0; i < 64; i++) { if ((i & 7) == 0) { printf(" +---+---+---+---+---+---+---+---+\n"); if (i <= 56) { printf(" %d |", 8 - (((unsigned)i) >> 3)); } } if (piece[i] == EMPTY) printf(" |"); else { printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]); } if ((i & 7) == 7) printf("\n"); } printf(" +---+---+---+---+---+---+---+---+\n a b c d e f g h\n"); } /* **************************************************************************** * Main program * **************************************************************************** */ void main() { char s[256]; int from, dest, i; int computer_side; int max_depth; /* max depth to search */ MOVE moveBuf[200]; int movecnt; printf("First Chess, by Pham Hong Nguyen\n"); printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n"); side = WHITE; computer_side = BLACK; /* Human is white side */ max_depth = 7; hdp = 0; for (;;) { if (side == computer_side) { /* computer's turn */ /* Find out the best move to react the current position */ MOVE bestMove = ComputerThink(max_depth); MakeMove(bestMove); continue; } /* get user input */ printf("fc> "); if (scanf("%s", s) == EOF) /* close program */ return; if (!strcmp(s, "d")) { PrintBoard(); continue; } if (!strcmp(s, "quit")) { printf("Good bye!\n"); return; } /* maybe the user entered a move? */ from = s[0] - 'a'; from += 8 * (8 - (s[1] - '0')); dest = s[2] - 'a'; dest += 8 * (8 - (s[3] - '0')); ply = 0; movecnt = Gen(side, moveBuf); /* loop through the moves to see if it's legal */ for (i = 0; i < movecnt; i++) if (moveBuf[i].from == from && moveBuf[i].dest == dest) { if (piece[from] == PAWN && (dest < 8 || dest > 55)) { /* Promotion move? */ switch (s[4]) { case 'q': moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN; break; case 'r': moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK; break; case 'b': moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP; break; case 'n': moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT; break; default: puts("promoting to a McGuffin..., I'll give you a queen"); moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN; } } if (!MakeMove(moveBuf[i])) { TakeBack(); printf("Illegal move.\n"); } break; } } } Это поможет мне понять как uci работает в условиях обдумывания хода.

bankuss: при обдумывании хода надо постоянно проверять входной поток, если появилась команда "stop" или "quit" или пондер, то прервать вычисления. я в своих первых версиях этого не делал - поэтому при остановке движок продолжает думать :) хорошо известную подпрограмму проверки можно взять из кода глаурунга (который взял ее из кода OliThink) называется bioskey()

Igrok88: Ребят ну не пожалейте 10 минут, припишите UCI к выложенному коду.

Granite116: Помогите разобраться. Как вообще происходит подключение движка? Какие команды движок должен понимать? Начнем сначала: Нажимаем добавить дживок и выбираем движок. Какая команда в этот момент посылается от GUI к движку? Как я понял GUI посылает сообщение uci. Как должен ответить движок? Движок должен передать свои параметры(здесь опишите подробно какие именно параметры) и вконце движок должен послать сообщение uciok. Дальше GUI отсылает команду isready? Движок должен послать команду readyok. Вобщем на данный момент задача минимум: Подключить движок к GUI(чтоб параметры определялись и т.д). Что должен уметь делать движок, чтоб сделать хоть 1ход без анализа(предположим за белых e2e4)? Анализ потом прикручу, на данный момент нужно разобраться как это все работает. Там где мои рассуждения неверны - поправте. И ответе на вопросы. Спасибо.

neutrino: Granite116 пишет: Помогите разобраться ... И ответе на вопросы. На сайте Кветки есть как раз нужное описания протокола на русском. И все сразу будет понятно если понаблюдать как Арена обращается с движками. В ней есть "Окно отладки движка" по F4



полная версия страницы