├── .gitignore ├── LICENSE ├── PISKVORK.ICO ├── PISKVORK.cpp ├── README.md ├── READ_ME.txt ├── Release └── piskvork_renju.zip ├── checkforbid.cpp ├── game.cpp ├── hdr.h ├── lang.cpp ├── lang.h ├── netgame.cpp ├── nettur.cpp ├── pbrain ├── README.txt ├── README_CZ.txt ├── alfabeta.cpp ├── board.h ├── piskcomp.cpp └── pisktur.cpp ├── piskvork.h ├── piskvork.rc ├── protocol.cpp ├── renju ├── Class_line.cpp ├── Class_line4v.cpp ├── game.h └── global.cpp ├── resource.h ├── skelet ├── README_EN.txt ├── example.cpp ├── pisqpipe.cpp └── pisqpipe.h ├── skelet_Delphi ├── README_EN.txt ├── example.pas ├── header.pas ├── pisqpipe.pas └── skelet.dpr ├── skins └── pisq.bmp ├── taskbarprogress.cpp ├── taskbarprogress.h └── toolbar.bmp /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | ![Rr]elease/ 17 | [Rr]elease/* 18 | ![Rr]elease/*.zip 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | build/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | 27 | # Visual Studo 2015 cache/options directory 28 | .vs/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | *_i.c 44 | *_p.c 45 | *_i.h 46 | *.ilk 47 | *.meta 48 | *.obj 49 | *.pch 50 | *.pdb 51 | *.pgc 52 | *.pgd 53 | *.rsp 54 | *.sbr 55 | *.tlb 56 | *.tli 57 | *.tlh 58 | *.tmp 59 | *.tmp_proj 60 | *.log 61 | *.vspscc 62 | *.vssscc 63 | .builds 64 | *.pidb 65 | *.svclog 66 | *.scc 67 | 68 | # Chutzpah Test files 69 | _Chutzpah* 70 | 71 | # Visual C++ cache files 72 | ipch/ 73 | *.aps 74 | *.ncb 75 | *.opensdf 76 | *.sdf 77 | *.cachefile 78 | 79 | # Visual Studio profiler 80 | *.psess 81 | *.vsp 82 | *.vspx 83 | 84 | # TFS 2012 Local Workspace 85 | $tf/ 86 | 87 | # Guidance Automation Toolkit 88 | *.gpState 89 | 90 | # ReSharper is a .NET coding add-in 91 | _ReSharper*/ 92 | *.[Rr]e[Ss]harper 93 | *.DotSettings.user 94 | 95 | # JustCode is a .NET coding addin-in 96 | .JustCode 97 | 98 | # TeamCity is a build add-in 99 | _TeamCity* 100 | 101 | # DotCover is a Code Coverage Tool 102 | *.dotCover 103 | 104 | # NCrunch 105 | _NCrunch_* 106 | .*crunch*.local.xml 107 | 108 | # MightyMoose 109 | *.mm.* 110 | AutoTest.Net/ 111 | 112 | # Web workbench (sass) 113 | .sass-cache/ 114 | 115 | # Installshield output folder 116 | [Ee]xpress/ 117 | 118 | # DocProject is a documentation generator add-in 119 | DocProject/buildhelp/ 120 | DocProject/Help/*.HxT 121 | DocProject/Help/*.HxC 122 | DocProject/Help/*.hhc 123 | DocProject/Help/*.hhk 124 | DocProject/Help/*.hhp 125 | DocProject/Help/Html2 126 | DocProject/Help/html 127 | 128 | # Click-Once directory 129 | publish/ 130 | 131 | # Publish Web Output 132 | *.[Pp]ublish.xml 133 | *.azurePubxml 134 | # TODO: Comment the next line if you want to checkin your web deploy settings 135 | # but database connection strings (with potential passwords) will be unencrypted 136 | *.pubxml 137 | *.publishproj 138 | 139 | # NuGet Packages 140 | *.nupkg 141 | # The packages folder can be ignored because of Package Restore 142 | **/packages/* 143 | # except build/, which is used as an MSBuild target. 144 | !**/packages/build/ 145 | # Uncomment if necessary however generally it will be regenerated when needed 146 | #!**/packages/repositories.config 147 | 148 | # Windows Azure Build Output 149 | csx/ 150 | *.build.csdef 151 | 152 | # Windows Store app package directory 153 | AppPackages/ 154 | 155 | # Others 156 | *.[Cc]ache 157 | ClientBin/ 158 | [Ss]tyle[Cc]op.* 159 | ~$* 160 | *~ 161 | *.dbmdl 162 | *.dbproj.schemaview 163 | *.pfx 164 | *.publishsettings 165 | node_modules/ 166 | bower_components/ 167 | 168 | # RIA/Silverlight projects 169 | Generated_Code/ 170 | 171 | # Backup & report files from converting an old project file 172 | # to a newer Visual Studio version. Backup files are not needed, 173 | # because we have git ;-) 174 | _UpgradeReport_Files/ 175 | Backup*/ 176 | UpgradeLog*.XML 177 | UpgradeLog*.htm 178 | 179 | # SQL Server files 180 | *.mdf 181 | *.ldf 182 | 183 | # Business Intelligence projects 184 | *.rdl.data 185 | *.bim.layout 186 | *.bim_*.settings 187 | 188 | # Microsoft Fakes 189 | FakesAssemblies/ 190 | 191 | # Node.js Tools for Visual Studio 192 | .ntvs_analysis.dat 193 | 194 | # Visual Studio 6 build log 195 | *.plg 196 | 197 | # Visual Studio 6 workspace options file 198 | *.opt 199 | 200 | *.sln 201 | *.vc*proj 202 | *.vc*proj.* -------------------------------------------------------------------------------- /PISKVORK.ICO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/PISKVORK.ICO -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Piskvork for Renju 2 | ================== 3 | 4 | * Copyright (C) 2000-2015 Petr Lastovicka 5 | * Copyright (C) 2012-2016 Tianyi Hao 6 | 7 | Piskvork is a gomoku interface which could load a lot of gomoku AI engines, 8 | which has been used in the gomuku AI tournament [Gomocup](http://gomocup.org). 9 | 10 | The original Piskvork by Petr Lastovicka could been downloaded from: 11 | (http://sourceforge.net/projects/piskvork/files/piskvork.zip/download). 12 | The original C++ source code could been download from: 13 | (http://petr.lastovicka.sweb.cz/src/piskvork.zip). 14 | The protocol between a brain and Piskvork is at: 15 | (http://petr.lastovicka.sweb.cz/protocl2en.htm). 16 | 17 | Since the original Piskvork could not support the renju rule, a modification 18 | has been implied to it to support it. 19 | The command that Piskvork sends to the brain for renju rule is: 20 | 21 | INFO rule 4 22 | 23 | Usage: Just copy the files in the directory [Release](https://raw.github.com/wind23/piskvork_renju/master/Release/) 24 | in Piskvork for Renju to the original [Piskvork package](http://sourceforge.net/projects/piskvork/files/piskvork.zip/download) 25 | to replace the original files. 26 | 27 | This program is free software; you can redistribute it and/or 28 | modify it under the terms of the 29 | [GNU General Public License](http://www.gnu.org/licenses/gpl.html). 30 | If you use any part of it in your program, then you must publish 31 | all your source code too. 32 | -------------------------------------------------------------------------------- /READ_ME.txt: -------------------------------------------------------------------------------- 1 | This ZIP file is intended only for developers. It contains C++ source code which can be compiled by Microsoft Visual Studio. Translations, images, help and other data files are not included in this package. 2 | Installation ZIP file can be downloaded from http://petr.lastovicka.sweb.cz/indexEN.html or http://lastp.users.sourceforge.net/ 3 | -------------------------------------------------------------------------------- /Release/piskvork_renju.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/Release/piskvork_renju.zip -------------------------------------------------------------------------------- /checkforbid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | (C) 2015 Tianyi Hao 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "hdr.h" 20 | #pragma hdrstop 21 | #include "piskvork.h" 22 | #include "renju\game.h" 23 | 24 | int forbid(int board_[N][N], int pos, int size); 25 | bool checkforbid(Psquare px, Psquare board,int move,int size) 26 | { 27 | int board_[N][N]={0}; 28 | Psquare p; 29 | int moven=0; 30 | if(board) 31 | { 32 | for(p=board; p->nxt; p=p->nxt) 33 | { 34 | } 35 | for(;p;p=p->pre) 36 | { 37 | if(moven%2==0) 38 | { 39 | board_[p->x-1][p->y-1]=1; 40 | } 41 | else 42 | { 43 | board_[p->x-1][p->y-1]=-1; 44 | } 45 | moven++; 46 | if(moven>=moves) 47 | { 48 | break; 49 | } 50 | } 51 | } 52 | if(moven%2==0) 53 | { 54 | board_[px->x-1][px->y-1]=1; 55 | } 56 | else 57 | { 58 | board_[px->x-1][px->y-1]=-1; 59 | } 60 | moven++; 61 | return forbid(board_,px->x-1+(px->y-1)*S,size); 62 | } -------------------------------------------------------------------------------- /hdr.h: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_DEPRECATE 1 2 | 3 | #ifndef _WIN32_IE 4 | #define _WIN32_IE 0x0400 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | -------------------------------------------------------------------------------- /lang.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/lang.cpp -------------------------------------------------------------------------------- /lang.h: -------------------------------------------------------------------------------- 1 | /* 2 | (C) Petr Lastovicka 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #ifndef langH 18 | #define langH 19 | 20 | struct Txywh { 21 | int x,y,w,h,oldW,oldH; 22 | }; 23 | 24 | extern char lang[64]; 25 | 26 | #define Maccel 96 27 | extern ACCEL accel[Maccel]; 28 | extern int Naccel; 29 | 30 | char *lng(int i, char *s); 31 | void initLang(); 32 | int setLang(int cmd); 33 | HMENU loadMenu(char *name, int *subId); 34 | void loadMenu(HWND hwnd, char *name, int *subId); 35 | void changeDialog(HWND &wnd, Txywh &pos, LPCTSTR dlgTempl, DLGPROC dlgProc, HWND owner=0); 36 | void setDlgTexts(HWND hDlg); 37 | void setDlgTexts(HWND hDlg, int id); 38 | void getExeDir(char *fn, char *e); 39 | char *cutPath(char *s); 40 | inline const char *cutPath(const char *s){ return cutPath((char*)s); } 41 | void printKey(char *s, ACCEL *a); 42 | 43 | 44 | extern void langChanged(); 45 | extern void msg(char *text, ...); 46 | void msglng(int id, char *text, ...); 47 | extern HINSTANCE inst; 48 | 49 | #define sizeA(A) (sizeof(A)/sizeof(*A)) 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /netgame.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | (C) 2015 Tianyi Hao 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "hdr.h" 19 | #pragma hdrstop 20 | #include "piskvork.h" 21 | 22 | #define NETGAME_VERSION 2 23 | 24 | enum{ 25 | C_INIT1=147, C_INIT2=132, C_INIT_DENY=226, C_BUSY=235, 26 | C_INFO=193, C_INFO_OK=177, C_MSG=238, C_END=249, 27 | C_UNDO_REQUEST=230, C_UNDO_YES=243, C_UNDO_NO=246, 28 | C_NEW_REQUEST=198, C_NEW_YES=225, C_NEW_NO=218, 29 | }; 30 | 31 | bool isListening, isNetGame; 32 | int netGameVersion, undoRequest; 33 | HANDLE netGameThread; 34 | sockaddr_in netGameIP; 35 | 36 | struct TnetGameSettings { 37 | char width, height, begin, cont, rule5; 38 | }; 39 | //--------------------------------------------------------------- 40 | void newNetGame(LPARAM lP) 41 | { 42 | TnetGameSettings *b= (TnetGameSettings*)lP; 43 | killBrains(); 44 | players[0].isComp= players[1].isComp= 0; 45 | width=b->width; 46 | height=b->height; 47 | newGame(b->begin ? 1-NET_PLAYER : NET_PLAYER, false); 48 | if(ruleFive!=b->rule5){ 49 | ruleFive=b->rule5; 50 | wrLog(b->rule5==2? lng(988, "rule renju"):(b->rule5 ? lng(655, "Exactly five in a row win") : lng(654, "Five or more in a row win"))); 51 | } 52 | if(continuous!=b->cont){ 53 | continuous=b->cont; 54 | wrLog(b->cont ? lng(657, "Continuous game") : lng(656, "Single game")); 55 | } 56 | wrLog(b->begin ? lng(872, "You begin") : lng(873, "The other player begins")); 57 | resetScore(); 58 | } 59 | 60 | void netGameDone() 61 | { 62 | if(!netGameThread) return; 63 | closesocket(sock); 64 | sock=INVALID_SOCKET; 65 | WSACleanup(); 66 | wrLog(lng(869, "Disconnected")); 67 | CloseHandle(netGameThread); 68 | netGameThread=0; 69 | isNetGame=false; 70 | printLevel1(); 71 | } 72 | 73 | void postUndo() 74 | { 75 | PostMessage(hWin, WM_COMMAND, 990, 0); 76 | while(undoRequest) Sleep(50); 77 | } 78 | 79 | void postNewGame() 80 | { 81 | PostMessage(hWin, WM_COMMAND, 989, 0); 82 | while(undoRequest) Sleep(50); 83 | } 84 | 85 | DWORD WINAPI netGameLoop(void *param) 86 | { 87 | int len, c, x, y; 88 | Psquare p; 89 | TnetGameSettings *b; 90 | char *m, *u, *a; 91 | hostent *h; 92 | char buf[256]; 93 | 94 | if(!param){ 95 | buf[0]=(BYTE)C_INIT1; 96 | buf[1]=NETGAME_VERSION; 97 | wr(buf, 2); 98 | c=rd1(); 99 | if(c!=C_INIT2) goto le; 100 | c=rd1(); 101 | if(c<1) goto le; 102 | netGameVersion=c; 103 | SetForegroundWindow(hWin); 104 | h= gethostbyaddr((char*)&netGameIP.sin_addr, 4, netGameIP.sin_family); 105 | a= inet_ntoa(netGameIP.sin_addr); 106 | if(msg1(MB_YESNO|MB_ICONQUESTION, 107 | lng(868, "Do you want to play with %s [%s] ?"), 108 | (h && h->h_name) ? h->h_name : "???", a ? a : "???")!=IDYES){ 109 | wr1(C_INIT_DENY); 110 | goto le; 111 | } 112 | buf[0]=(BYTE)C_INFO; 113 | buf[1]=sizeof(TnetGameSettings); 114 | b= (TnetGameSettings*)(buf+2); 115 | b->width=(char)width; 116 | b->height=(char)height; 117 | b->begin= (player==1); 118 | b->rule5=(char)ruleFive; 119 | b->cont=(char)continuous; 120 | if(netGameVersion<2) b->rule5=b->cont=0; 121 | wr(buf, 2+sizeof(TnetGameSettings)); 122 | if(rd1()!=C_INFO_OK) goto le; 123 | b->begin= !b->begin; 124 | } 125 | else{ 126 | buf[0]=(BYTE)C_INIT2; 127 | buf[1]=NETGAME_VERSION; 128 | wr(buf, 2); 129 | c=rd1(); 130 | if(c==C_BUSY) wrLog(lng(874, "The other player is already playing with someone else")); 131 | if(c!=C_INIT1) goto le; 132 | c=rd1(); 133 | if(c<1) goto le; 134 | netGameVersion=c; 135 | wrLog(lng(871, "Connection established. Waiting for response...")); 136 | c=rd1(); 137 | if(c==C_INIT_DENY) wrLog(lng(870, "The other player doesn't want to play with you !")); 138 | if(c!=C_INFO) goto le; 139 | len=rd1(); 140 | b= (TnetGameSettings*)buf; 141 | memset(buf, 0, sizeof(TnetGameSettings)); 142 | if(len<2 || rd(buf, len)<0) goto le; 143 | wr1(C_INFO_OK); 144 | } 145 | SendMessage(hWin, WM_COMMAND, 992, (LPARAM)b); 146 | undoRequest=0; 147 | 148 | for(;;){ 149 | x=rd1(); 150 | switch(x){ 151 | case C_MSG: //message 152 | len=rd2(); 153 | if(len<=0) goto le; 154 | u=new char[2*len]; 155 | if(rd(u, 2*len)>=0){ 156 | m=new char[len+1]; 157 | WideCharToMultiByte(CP_ACP, 0, (WCHAR*)u, len, m, len, 0, 0); 158 | m[len]='\0'; 159 | wrLog("---> %s", m); 160 | delete[] m; 161 | SetWindowPos(logDlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_ASYNCWINDOWPOS|SWP_NOACTIVATE|SWP_SHOWWINDOW); 162 | } 163 | delete[] u; 164 | break; 165 | case C_UNDO_REQUEST: 166 | y=rd2(); 167 | if(y<=0 || y>moves) goto le; 168 | if(undoRequest){ 169 | //both players pressed undo simultaneously 170 | if(undoRequest<0) undoRequest=y; 171 | amax(undoRequest, y); 172 | postUndo(); 173 | } 174 | else{ 175 | c=msg1(MB_YESNO|MB_ICONQUESTION, 176 | lng(876, "The other player wants to UNDO the last move.\r\nDo you agree ?")); 177 | if(c==IDYES){ 178 | undoRequest=y; 179 | wr1(C_UNDO_YES); 180 | postUndo(); 181 | } 182 | else{ 183 | wr1(C_UNDO_NO); 184 | } 185 | } 186 | break; 187 | case C_NEW_REQUEST: 188 | if(undoRequest){ 189 | if(undoRequest<0){ 190 | //both players pressed NewGame simultaneously 191 | postNewGame(); 192 | } 193 | else{ 194 | postUndo(); 195 | } 196 | } 197 | else{ 198 | c=msg1(MB_YESNO|MB_ICONQUESTION, 199 | lng(877, "The other player wants to start a NEW game.\r\nDo you agree ?")); 200 | if(c==IDYES){ 201 | undoRequest=-1; 202 | wr1(C_NEW_YES); 203 | postNewGame(); 204 | } 205 | else{ 206 | wr1(C_NEW_NO); 207 | } 208 | } 209 | break; 210 | case C_UNDO_YES: 211 | if(undoRequest<=0) goto le; 212 | postUndo(); 213 | break; 214 | case C_UNDO_NO: 215 | if(undoRequest>0){ 216 | msglng(878, "Sorry, the other player does not allow to UNDO your move."); 217 | undoRequest=0; 218 | } 219 | break; 220 | case C_NEW_YES: 221 | if(undoRequest>=0) goto le; 222 | postNewGame(); 223 | break; 224 | case C_NEW_NO: 225 | if(undoRequest<0){ 226 | msglng(879, "Sorry, the other player does not allow to start a NEW game."); 227 | undoRequest=0; 228 | } 229 | break; 230 | default: //move or error 231 | if(x<0 || x>=width){ 232 | show(logDlg); 233 | goto le; 234 | } 235 | while(finished && (getTickCount()-lastTick<5000 || saveLock)){ 236 | Sleep(200); 237 | } 238 | if(finished) SendMessage(hWin, WM_COMMAND, 101, 0); 239 | y=rd1(); 240 | if(y<0 || y>=height) goto le; 241 | p=Square(x, y); 242 | p->time=rd4(); 243 | PostMessage(hWin, WM_COMMAND, 991, (LPARAM)p); 244 | } 245 | } 246 | le: 247 | EnterCriticalSection(&netLock); 248 | netGameDone(); 249 | LeaveCriticalSection(&netLock); 250 | return 0; 251 | } 252 | 253 | DWORD WINAPI listenNetGame(void *) 254 | { 255 | sockaddr_in sa; 256 | SOCKET sock_c; 257 | int sl; 258 | bool b; 259 | 260 | wrLog(lng(866, "Waiting for the other player")); 261 | for(;;){ 262 | sl= sizeof(sa); 263 | if((sock_c= accept(sock_l, (sockaddr *)&sa, &sl))==INVALID_SOCKET){ 264 | wrLog(lng(867, "Finished listening for requests from the internet")); 265 | break; 266 | } 267 | EnterCriticalSection(&netLock); 268 | b=isNetGame; 269 | isNetGame=true; 270 | LeaveCriticalSection(&netLock); 271 | if(b){ 272 | wr1(sock_c, C_BUSY); 273 | Sleep(1000); 274 | closesocket(sock_c); 275 | } 276 | else{ 277 | sock=sock_c; 278 | netGameIP=sa; 279 | initWSA(); 280 | DWORD id; 281 | ResumeThread(netGameThread=CreateThread(0, 0, netGameLoop, 0, CREATE_SUSPENDED, &id)); 282 | stopListen(); 283 | break; 284 | } 285 | } 286 | WSACleanup(); 287 | isListening=false; 288 | return 0; 289 | } 290 | 291 | int netGameStart() 292 | { 293 | int err=3; 294 | EnterCriticalSection(&netLock); 295 | if(isNetGame) err=4; 296 | else if(servername[0]) err= startConnection(); 297 | if(!err){ 298 | //connection succeeded 299 | isNetGame=true; 300 | DWORD id; 301 | ResumeThread(netGameThread=CreateThread(0, 0, netGameLoop, (void*)1, CREATE_SUSPENDED, &id)); 302 | } 303 | LeaveCriticalSection(&netLock); 304 | if(err==3){ 305 | //not connected, try listening 306 | err= startListen(); 307 | if(!err){ 308 | isListening=true; 309 | DWORD id; 310 | CloseHandle(CreateThread(0, 0, listenNetGame, 0, 0, &id)); 311 | } 312 | } 313 | return err; 314 | } 315 | 316 | void netGameEnd() 317 | { 318 | if(!isNetGame){ 319 | if(isListening) stopListen(); 320 | return; 321 | } 322 | wr1(C_END); 323 | undoRequest=0; 324 | for(int i=0; i<50; i++){ 325 | Sleep(200); 326 | if(!isNetGame) return; 327 | } 328 | EnterCriticalSection(&netLock); 329 | if(netGameThread){ 330 | wrLog("The other computer is not responding"); 331 | netGameDone(); 332 | TerminateThread(netGameThread, 1); 333 | } 334 | LeaveCriticalSection(&netLock); 335 | } 336 | 337 | void netGameMove(Psquare p) 338 | { 339 | if(player!=NET_PLAYER){ 340 | char buf[6]; 341 | buf[0]=char(p->x-1); 342 | buf[1]=char(p->y-1); 343 | buf[2]=char(p->time>>24); 344 | buf[3]=char(p->time>>16); 345 | buf[4]=char(p->time>>8); 346 | buf[5]=char(p->time); 347 | wr(buf, 6); 348 | } 349 | } 350 | 351 | void oldVersion() 352 | { 353 | msglng(880, "Sorry, the other player has older version of Piskvork.exe"); 354 | } 355 | 356 | void netGameUndo() 357 | { 358 | int i; 359 | char buf[3]; 360 | 361 | i=moves-1; 362 | if(player!=NET_PLAYER) i--; 363 | if(!undoRequest && i>0){ 364 | if(netGameVersion<2){ 365 | oldVersion(); 366 | } 367 | else{ 368 | buf[0]=(BYTE)C_UNDO_REQUEST; 369 | undoRequest=i; 370 | buf[1]=char(i>>8); 371 | buf[2]=char(i); 372 | wr(buf, 3); 373 | wrLog(lng(881, "Sending undo request...")); 374 | } 375 | } 376 | } 377 | 378 | void netGameNew() 379 | { 380 | if(!undoRequest && moves>0){ 381 | if(netGameVersion<2){ 382 | oldVersion(); 383 | } 384 | else{ 385 | undoRequest=-1; 386 | wr1(C_NEW_REQUEST); 387 | wrLog(lng(882, "Sending a new game request...")); 388 | } 389 | } 390 | } 391 | 392 | void netGameMsg() 393 | { 394 | int len; 395 | char *buf, *u; 396 | 397 | len= GetWindowTextLength(msgWnd); 398 | if(len){ 399 | buf= new char[len+1]; 400 | GetWindowText(msgWnd, buf, len+1); 401 | u= new char[len*2+4]; 402 | MultiByteToWideChar(CP_ACP, 0, buf, len, (WCHAR*)(u+4), len); 403 | u[1]=(BYTE)C_MSG; 404 | u[2]=char(len>>8); 405 | u[3]=char(len); 406 | wr(u+1, len*2+3); 407 | delete[] u; 408 | wrLog("< %s", buf); 409 | delete[] buf; 410 | SetWindowText(msgWnd, ""); 411 | SetFocus(msgWnd); 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /nettur.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | (C) 2015-2016 Tianyi Hao 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "hdr.h" 19 | #pragma hdrstop 20 | #ifndef TF_DISCONNECT 21 | #include 22 | #endif 23 | #include "piskvork.h" 24 | 25 | #define STATE_VERSION 0x805 26 | 27 | 28 | //info about game that is sent to a client 29 | struct TgameSettings { 30 | DWORD timeGame, timeMove, tolerance, memory; 31 | char width, height; 32 | char suspend; 33 | char sendMoves; 34 | char tieRepeat; 35 | char messages; 36 | char ruleFive; 37 | char openingData[1]; 38 | void fill(); 39 | void use(); 40 | }; 41 | 42 | //tournament state 43 | struct TturSettings { 44 | 45 | //STATE_VERSION 0x703 and less 46 | SYSTEMTIME date; 47 | int version; 48 | DWORD timeGame, timeMove, memory; 49 | char rule, autoBegin; 50 | char width, height; 51 | short id[2]; 52 | int playerStrLen; 53 | short repeat; 54 | short gameCount; 55 | short opening; 56 | short matchRepeat; 57 | char openingRandomShift; 58 | bool autoBeginForce; 59 | 60 | #if STATE_VERSION >=0x805 61 | int ruleFive; 62 | #endif 63 | 64 | void fill(); 65 | void use(); 66 | }; 67 | 68 | struct TstateClient { 69 | short player[2]; 70 | short repeatCount; 71 | short gameCount; 72 | u_long IP; 73 | }; 74 | 75 | bool isServer, isClient; 76 | SOCKET sock; //client socket 77 | SOCKET sock_l; //listening socket 78 | int port=3629; //TCP/IP port 79 | int pollDelay=1000; //interval of asking for next game in server threads 80 | TdirName AIfolder; //folder where AI are downloaded 81 | HANDLE clientThread; 82 | CRITICAL_SECTION netLock; 83 | Tclient clients[Mplayer]; //information about clients 84 | char servername[128]="localhost"; 85 | 86 | //--------------------------------------------------------------- 87 | int rd(SOCKET s, char *buf, int len) 88 | { 89 | int i, n; 90 | 91 | for(n=0; n0 && r>8) ^ crcTable[buf[i] ^ (crc & 0xFF)]; 252 | } 253 | } while(r); 254 | CloseHandle(h); 255 | crc= ~crc; 256 | result=crc; 257 | return 0; 258 | } 259 | //--------------------------------------------------------------- 260 | int recvFile(SOCKET s, const char *fn, int len) 261 | { 262 | HANDLE h; 263 | int i, n; 264 | DWORD w; 265 | char buf[4096]; 266 | 267 | h=CreateFile(fn, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 268 | if(h==INVALID_HANDLE_VALUE) return 2; 269 | 270 | for(n=0; nplayer[0]>=0){ 288 | result=true; 289 | } 290 | else if(turCurRepeat>0){ 291 | turNext(); 292 | if(turCurRepeat>0){ 293 | client->player[0]= players[0].turPlayerId; 294 | client->player[1]= players[1].turPlayerId; 295 | client->gameCount=0; 296 | client->repeatCount= turRepeat-turCurRepeat; 297 | result=true; 298 | } 299 | } 300 | if(!result){ 301 | for(int i=0; iplayer[0]>=0){ 304 | if(c->thread){ 305 | stillActive=true; 306 | } 307 | else{ 308 | client->player[0]= c->player[0]; 309 | client->player[1]= c->player[1]; 310 | client->repeatCount= c->repeatCount; 311 | client->gameCount= c->gameCount; 312 | c->player[0]=-1; 313 | result=true; 314 | break; 315 | } 316 | } 317 | } 318 | } 319 | win7TaskbarProgress.SetProgressState(hWin, TBPF_NORMAL); 320 | win7TaskbarProgress.SetProgressValue(hWin, turGamesCounter, turGamesTotal); 321 | 322 | if(!result && !stillActive){ 323 | wrLog(lng(850, "Tournament finished")); 324 | show(resultDlg); 325 | turNplayers=0; 326 | killBrains(); 327 | opening=turOpening + turMatchRepeat*turRepeat/2; 328 | executeCmd(cmdTurEnd); 329 | win7TaskbarProgress.SetProgressState(hWin, TBPF_NOPROGRESS); 330 | } 331 | client->opening= turOpening + (client->repeatCount*turMatchRepeat + client->gameCount)/2; 332 | players[0].isComp=players[1].isComp=1; 333 | players[1].timeMove=players[0].timeMove; 334 | players[1].timeGame=players[0].timeGame; 335 | } 336 | LeaveCriticalSection(&netLock); 337 | return result; 338 | } 339 | //--------------------------------------------------------------- 340 | void TgameSettings::use() 341 | { 342 | players[1].timeMove= players[0].timeMove= timeMove; 343 | players[1].timeGame= players[0].timeGame= timeGame; 344 | ::tolerance= tolerance; 345 | maxMemory= memory; 346 | ::width=width; 347 | ::height=height; 348 | suspendAI=suspend&1; 349 | debugAI=(suspend>>1)&1; 350 | turTieRepeat=tieRepeat; 351 | turLogMsg=messages; 352 | ::ruleFive=ruleFive; 353 | } 354 | 355 | void TgameSettings::fill() 356 | { 357 | timeGame=players[0].timeGame; 358 | timeMove=players[0].timeMove; 359 | tolerance=::tolerance; 360 | memory=maxMemory; 361 | width=(char)::width; 362 | height=(char)::height; 363 | suspend=(char)((suspendAI!=0)|((debugAI!=0)<<1)); 364 | sendMoves=(char)turRecord; 365 | tieRepeat=(char)turTieRepeat; 366 | messages=(char)turLogMsg; 367 | ruleFive=(char)::ruleFive; 368 | openingData[0]=0; 369 | } 370 | 371 | void TturSettings::use() 372 | { 373 | players[1].timeMove= players[0].timeMove= timeMove; 374 | players[1].timeGame= players[0].timeGame= timeGame; 375 | maxMemory= memory; 376 | ::width=width; 377 | ::height=height; 378 | turDateTime=date; 379 | players[0].turPlayerId=id[0]; 380 | players[1].turPlayerId=id[1]; 381 | turOpening=opening; 382 | ::autoBegin=autoBegin; 383 | turRule=rule; 384 | turGamesCounter=gameCount; 385 | amin(turRepeat, repeat); 386 | turCurRepeat=turRepeat-repeat; 387 | turMatchRepeat= matchRepeat ? matchRepeat : 2; 388 | openingRandomShiftT=openingRandomShift; 389 | ::autoBeginForce=autoBeginForce; 390 | ::ruleFive = ruleFive; 391 | } 392 | 393 | void TturSettings::fill() 394 | { 395 | version=STATE_VERSION; 396 | playerStrLen=strlen(turPlayerStr); 397 | timeGame=players[0].timeGame; 398 | timeMove=players[0].timeMove; 399 | memory=maxMemory; 400 | width=(char)::width; 401 | height=(char)::height; 402 | date=turDateTime; 403 | id[0]=(short)players[0].turPlayerId; 404 | id[1]=(short)players[1].turPlayerId; 405 | opening=(short)turOpening; 406 | autoBegin=(char)::autoBegin; 407 | rule=(char)turRule; 408 | gameCount=(short)turGamesCounter; 409 | repeat=(short)(turRepeat-turCurRepeat); 410 | matchRepeat=(short)turMatchRepeat; 411 | openingRandomShift=(char)openingRandomShiftT; 412 | autoBeginForce=::autoBeginForce; 413 | ruleFive = ::ruleFive; 414 | } 415 | 416 | //reload tournament state from a file 417 | int rdState() 418 | { 419 | FILE *f; 420 | int i, n, len, err=1; 421 | Tclient *c; 422 | char buf[512]; 423 | 424 | f=fopen(fnstate, "rb"); 425 | if(f){ 426 | { 427 | len=fgetc(f); 428 | if(len==EOF) goto le; 429 | memset(buf, 0, sizeof(TturSettings)); 430 | if(fread(buf, len, 1, f)!=1) goto le; 431 | TturSettings &ts=*(TturSettings*)buf; 432 | if(ts.version!=STATE_VERSION) goto le; 433 | ts.use(); 434 | if(ts.playerStrLen>=sizeof(turPlayerStr)) goto le; 435 | if(fread(turPlayerStr, ts.playerStrLen, 1, f)!=1) goto le; 436 | turPlayerStr[ts.playerStrLen]=0; 437 | } 438 | if(getNplayers()) goto le; 439 | n=fgetc(f); 440 | if(n>Mplayer) goto le; 441 | len=fgetc(f); 442 | if(len==EOF) goto le; 443 | for(i=0; iplayer[0]=sc.player[0]; 449 | c->player[1]=sc.player[1]; 450 | c->repeatCount= sc.repeatCount; 451 | c->gameCount= sc.gameCount; 452 | c->IP= sc.IP; 453 | } 454 | len=fgetc(f); 455 | if(len<0 || len>sizeof(TturPlayer)) goto le; 456 | memset(turTable, 0, turNplayers*sizeof(TturPlayer)); 457 | for(i=0; isizeof(TturCell)) goto le; 462 | memset(turCells, 0, turNplayers*turNplayers*sizeof(TturCell)); 463 | for(i=0; i=0) n++; 501 | } 502 | fputc(n, f); 503 | fputc(sizeof(TstateClient), f); 504 | for(i=0; iplayer[0]>=0){ 507 | sc.player[0]=(short)c->player[0]; 508 | sc.player[1]=(short)c->player[1]; 509 | sc.repeatCount=(short)c->repeatCount; 510 | sc.gameCount=(short)c->gameCount; 511 | sc.IP=c->IP; 512 | fwrite(&sc, sizeof(sc), 1, f); 513 | } 514 | } 515 | fputc(sizeof(TturPlayer), f); 516 | fwrite(turTable, sizeof(TturPlayer), turNplayers, f); 517 | fputc(sizeof(TturCell), f); 518 | fwrite(turCells, sizeof(TturCell), turNplayers*turNplayers, f); 519 | fputc(156, f); 520 | if(!fclose(f)){ 521 | strcpy(getTurDir(fn2), fnState); 522 | DeleteFile(fn2); 523 | MoveFile(fn, fn2); 524 | } 525 | } 526 | //--------------------------------------------------------------- 527 | //cleanup on client 528 | void clientDone() 529 | { 530 | EnterCriticalSection(&netLock); 531 | if(clientThread){ 532 | killBrains(); 533 | closesocket(sock); 534 | sock=INVALID_SOCKET; 535 | WSACleanup(); 536 | wrLog(lng(853, "Disconnected from server")); 537 | CloseHandle(clientThread); 538 | clientThread=0; 539 | isClient=false; 540 | turNplayers=0; 541 | } 542 | LeaveCriticalSection(&netLock); 543 | drawTitle(); 544 | } 545 | //--------------------------------------------------------------- 546 | //main function for a client thread 547 | DWORD WINAPI clientLoop(void *) 548 | { 549 | int i, j, len, x, y, c, pathLen; 550 | Tplayer *p; 551 | TgameSettings *b; 552 | DWORD crcC, crcS, fileSize; 553 | signed char *o; 554 | Psquare q; 555 | HANDLE h; 556 | char buf[512], *A, *s; 557 | char sendMoves; 558 | TfileName fnmsg; 559 | 560 | pathLen=(int)strlen(AIfolder); 561 | getMsgFn(fnmsg); 562 | lstart: 563 | for(;;){ 564 | killBrains(); 565 | //wait for server 566 | c=rd1(); 567 | if(c!=92) break; 568 | //receive players 569 | for(i=0; i<2; i++){ 570 | p=&players[i]; 571 | p->turPlayerId=i; 572 | p->isComp=1; 573 | if(rd(buf, 9)<0) goto lend; 574 | len=(unsigned char)buf[8]; 575 | if(!len) goto lstart; 576 | strcpy(p->brain, AIfolder); 577 | s=p->brain+pathLen; 578 | if(pathLen && s[-1]!='\\') *s++='\\'; 579 | if(pathLen+len+1>=sizeof(p->brain)){ 580 | wrLog("File name is too long"); 581 | wr1(0); 582 | goto lend; 583 | } 584 | if(rd(s, len)<0) goto lend; 585 | s[len]=0; 586 | len=*(DWORD*)buf; 587 | crcS=*(DWORD*)(buf+4); 588 | if(calcCRC(p->brain, crcC) || crcC!=crcS){ 589 | wr1(229); 590 | wrLog(lng(851, "Receiving %s"), p->brain); 591 | recvFile(sock, p->brain, len); 592 | if(calcCRC(p->brain, crcC) || crcC!=crcS){ 593 | p->brain2[0]=0; 594 | wr1(221); 595 | wrLog("Download failed"); 596 | goto lend; 597 | } 598 | } 599 | p->brainChanged(); 600 | wr1(118);//OK 601 | } 602 | //receive game settings 603 | c=rd1(); 604 | len=rd1(); 605 | if(c!=1 || len!=sizeof(TgameSettings)){ 606 | wrLog(lng(884, "Server is running different version of Piskvork than client")); 607 | show(logDlg); 608 | break; 609 | } 610 | if(rd(buf, len)<0) goto lend; 611 | b=(TgameSettings*)buf; 612 | j=b->openingData[0]; 613 | if(rd(buf+len, j*2)<0) goto lend; 614 | b->use(); 615 | sendMoves=b->sendMoves; 616 | //start game 617 | memset(turTable, 0, 2*sizeof(TturPlayer)); 618 | turTieCounter=0; 619 | DeleteFile(fnmsg); 620 | newGame(0, false); 621 | //automatic opening 622 | if(j){ 623 | o=(signed char*)b->openingData; 624 | for(; j>0; j--){ 625 | x= *++o; 626 | y= *++o; 627 | doMove1(Square(x, y)); 628 | } 629 | startMoves=moves; 630 | } 631 | resume(); 632 | //wait until the match is finished 633 | c=rd1(); 634 | if(c!=137) break; 635 | //send results 636 | wr1(sizeof(TturPlayer)); 637 | for(i=0; i<2; i++){ 638 | wr((char*)&turTable[i], sizeof(TturPlayer)); 639 | } 640 | //send board 641 | len=3; 642 | if(sendMoves){ 643 | len+=moves*6; 644 | } 645 | s=A=new char[len]; 646 | *s++=(char)(moves>>8); 647 | *s++=(char)moves; 648 | if(sendMoves && moves){ 649 | *s++=6; 650 | for(q=lastMove; q->nxt; q=q->nxt); 651 | for(; q; q=q->pre){ 652 | *s++= (char)q->x; 653 | *s++= (char)q->y; 654 | *(DWORD*)s= q->time; 655 | s+=4; 656 | } 657 | } 658 | else{ 659 | *s=0; 660 | } 661 | wr(A, len); 662 | delete[] A; 663 | //send messages 664 | fileSize=0; 665 | if(turLogMsg){ 666 | h=CreateFile(fnmsg, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); 667 | if(h!=INVALID_HANDLE_VALUE){ 668 | fileSize=GetFileSize(h, 0); 669 | wr((char*)&fileSize, 4); 670 | TransmitFile(sock, h, 0, 0, 0, 0, 0); 671 | } 672 | CloseHandle(h); 673 | } 674 | if(!fileSize) wr((char*)&fileSize, 4); 675 | } 676 | if(c==231) wrLog(lng(852, "Tournament aborted")); 677 | lend: 678 | clientDone(); 679 | return 0; 680 | } 681 | //--------------------------------------------------------------- 682 | //main function for server threads 683 | DWORD WINAPI serverLoop(void *param) 684 | { 685 | int clientId= (int)param; 686 | Tclient *client= &clients[clientId]; 687 | TturCell *ce; 688 | SOCKET sock_c; 689 | TturPlayer *tt[2], *rr[2], *t, *r; 690 | int i, c, len, len1, m, id[2], movesOld; 691 | DWORD w, fileSize; 692 | HANDLE h; 693 | TgameSettings *b; 694 | Psquare p, B, lastMoveOld; 695 | u_long u; 696 | char *s, *A, *q, *M; 697 | signed char *o1, *o2; 698 | char buf[512]; 699 | char *resultBuf[2]={buf, buf+256}; 700 | TfileName fn; 701 | 702 | for(;;){ 703 | //wait for a tournament 704 | while(!turNext(client)){ 705 | if(ioctlsocket(client->socket, FIONREAD, &u) || u) goto lend; 706 | Sleep(pollDelay); 707 | } 708 | sock_c= client->socket; 709 | if(wr1(sock_c, 92)<0) goto lend; 710 | //send players 711 | for(i=0; i<2; i++){ 712 | tt[i]=&turTable[client->player[i]]; 713 | const int H=9; 714 | s=buf+H; 715 | turGetBrain(client->player[i], fn, sizeof(fn), false); 716 | searchAI(fn, sizeof(buf)-H, s, 0); 717 | h=CreateFile(s, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); 718 | s=cutPath(s); 719 | if(h==INVALID_HANDLE_VALUE){ 720 | wrLog("Cannot open %s", fn); 721 | goto lend; 722 | } 723 | fileSize=GetFileSize(h, 0); 724 | len=(int)strlen(s); 725 | s[-1]=(char)len; 726 | *(DWORD*)(s-9)=fileSize; 727 | *(DWORD*)(s-5)=tt[i]->crc; 728 | wr(sock_c, s-H, len+H); 729 | c=rd1(sock_c); 730 | if(c==229){ 731 | //client does not have the AI 732 | wrLog(lng(854, "Transmit %s to Client %d, size=%u"), s, clientId, fileSize); 733 | TransmitFile(sock_c, h, 0, 0, 0, 0, 0); 734 | c=rd1(sock_c); 735 | } 736 | CloseHandle(h); 737 | if(c!=118) goto lend; 738 | } 739 | //older versions did not check TgameSettings length properly, this byte will disconnect them 740 | buf[0]=1; //must be less than 8 741 | //send game settings 742 | b=(TgameSettings*)(buf+2); 743 | buf[1]=sizeof(TgameSettings); 744 | b->fill(); 745 | //send opening 746 | if(autoBegin || autoBeginForce){ 747 | int x0, y0, r, j, x, y; 748 | o1= getOpening(client->opening); 749 | o2= (signed char*)b->openingData; 750 | j= *o2 = *o1; 751 | x0= width/2; 752 | y0= height/2; 753 | r= 0; 754 | if(openingRandomShiftT){ 755 | x0 += rnd(4)-2; 756 | y0 += rnd(4)-2; 757 | r = rnd(8); 758 | } 759 | for(; j>0; j--){ 760 | x= *++o1; 761 | y= *++o1; 762 | if(r&1) x=-x; 763 | if(r&2) y=-y; 764 | if(r&4) w=x, x=y, y=w; 765 | *++o2 = (signed char)(x0+x); 766 | *++o2 = (signed char)(y0+y); 767 | } 768 | } 769 | wr(sock_c, buf, 2+sizeof(TgameSettings)+2*b->openingData[0]); 770 | wrLog(lng(855, "Game started: players %d x %d, Client %d"), 771 | client->player[0], client->player[1], clientId); 772 | //wait 773 | if(rd1(sock_c)!=173) goto lend; 774 | wr1(sock_c, 137); 775 | //receive game results 776 | len=rd1(sock_c); 777 | if(len<0) goto lend; 778 | for(i=0; i<2; i++){ 779 | memset(resultBuf[i], 0, sizeof(TturPlayer)); 780 | if(rd(sock_c, resultBuf[i], len)<0) goto lend; 781 | r=rr[i]=(TturPlayer*)resultBuf[i]; 782 | if(unsigned(r->wins+r->winsE+r->losses+r->errors+r->timeouts)>1){ 783 | wrLog("Invalid result received !"); 784 | goto lend; 785 | } 786 | } 787 | //receive board 788 | m=(rd1(sock_c)<<8)|rd1(sock_c); 789 | len1=rd1(sock_c); 790 | if(len1<0) goto lend; 791 | len=m*len1; 792 | A=0; 793 | if(len>0){ 794 | A=new char[len]; 795 | if(rd(sock_c, A, len)<0){ delete[] A; goto lend; } 796 | } 797 | //receive messages 798 | if(rd(sock_c, (char*)&fileSize, 4)<0 || fileSize>16000000){ delete[] A; goto lend; } 799 | M=0; 800 | if(fileSize>0){ 801 | M=new char[fileSize]; 802 | if(rd(sock_c, M, fileSize)<0){ delete[] A; delete[] M; goto lend; } 803 | } 804 | //add game result to the tournament table 805 | EnterCriticalSection(&netLock); 806 | for(i=0; i<2; i++){ 807 | r=rr[i]; 808 | t=tt[i]; 809 | t->Ngames++; 810 | t->Nmoves+=r->Nmoves; 811 | t->time+=r->time; 812 | t->losses+=r->losses; 813 | t->losses1+=r->losses1; 814 | t->errors+=r->errors; 815 | t->timeouts+=r->timeouts; 816 | t->wins+=r->wins; 817 | t->wins1+=r->wins1; 818 | t->winsE+=r->winsE; 819 | amin(t->memory, r->memory); 820 | amin(t->maxTurnTime, r->maxTurnTime); 821 | ce= getCell(client->player[1-i], client->player[i]); 822 | if(r->wins) if(i==0) ce->start++; else ce->notStart++; 823 | if(r->winsE) ce->error++; 824 | } 825 | //save messages 826 | wrMsgNewGame(client->player[0], client->player[1]); 827 | if(M){ 828 | getMsgFn(fn); 829 | h=CreateFile(fn, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 830 | if(h!=INVALID_HANDLE_VALUE){ 831 | SetFilePointer(h, 0, 0, FILE_END); 832 | WriteFile(h, M, fileSize, &w, 0); 833 | CloseHandle(h); 834 | } 835 | delete[] M; 836 | } 837 | //save position 838 | if(A){ 839 | lastMoveOld=lastMove; 840 | movesOld=moves; 841 | B=new Tsquare[m]; 842 | q=A; 843 | p=B; 844 | for(i=0; inxt=p-1; 846 | p->pre=p+1; 847 | p->x=*(unsigned char*)q; 848 | p->y=*(unsigned char*)(q+1); 849 | p->time= (len1>2) ? *(DWORD*)(q+2) : 0; 850 | q+=len1; 851 | p++; 852 | } 853 | lastMove=p-1; 854 | lastMove->pre= B->nxt= 0; 855 | moves=m; 856 | player=m&1; 857 | for(i=0; i<2; i++){ 858 | id[i]= players[i].turPlayerId; 859 | players[i].turPlayerId=client->player[i]; 860 | turGetBrain(client->player[i], players[i].brain, sizeof(players[0].brain), false); 861 | players[i].brain2[0]=0; 862 | } 863 | // Tomas Kubes: I should save errCode in saveRec, 864 | // but it is not probably available on the server, 865 | // unless communication protocol is changed and I don't have any idea how to do it. 866 | // so I put -1, it means unavailable 867 | saveRec(-1, false); 868 | players[0].turPlayerId=id[0]; 869 | players[1].turPlayerId=id[1]; 870 | lastMove=lastMoveOld; 871 | moves=movesOld; 872 | delete[] B; 873 | delete[] A; 874 | } 875 | wrLog(lng(856, "Game finished: players %d x %d, Client %d, moves=%d"), 876 | client->player[0], client->player[1], clientId, m); 877 | //incr. game counter, update result window, save state and html table 878 | client->gameFinished(); 879 | LeaveCriticalSection(&netLock); 880 | Sleep(turDelay); 881 | } 882 | lend: 883 | EnterCriticalSection(&netLock); 884 | closesocket(client->socket); 885 | client->socket=INVALID_SOCKET; 886 | CloseHandle(client->thread); 887 | client->thread=0; 888 | wrLog(lng(857, "Client %d disconnected"), clientId); 889 | LeaveCriticalSection(&netLock); 890 | return 0; 891 | } 892 | //--------------------------------------------------------------- 893 | //main function for a listening thread on server 894 | DWORD WINAPI listenLoop(void *) 895 | { 896 | SOCKET sock_c; 897 | int i, sl; 898 | char *a; 899 | Tclient *c; 900 | struct sockaddr_in sa; 901 | 902 | wrLog(lng(858, "Server started")); 903 | for(;;){ 904 | sl= sizeof(sa); 905 | if((sock_c= accept(sock_l, (sockaddr *)&sa, &sl))==INVALID_SOCKET){ 906 | break; 907 | } 908 | for(i=0;; i++){ 909 | if(i==Mplayer){ 910 | for(i=0; iIP= sa.sin_addr.S_un.S_addr; 927 | c->socket=sock_c; 928 | DWORD id; 929 | ResumeThread(c->thread=CreateThread(0, 0, serverLoop, (void*)i, CREATE_SUSPENDED, &id)); 930 | } 931 | } 932 | if(sock_l!=INVALID_SOCKET) serverEnd(); 933 | WSACleanup(); 934 | isServer=false; 935 | drawTitle(); 936 | wrLog(lng(860, "Server terminated")); 937 | return 0; 938 | } 939 | //--------------------------------------------------------------- 940 | 941 | //send notification that a game finished on client 942 | void clientFinished() 943 | { 944 | wr1(173); 945 | } 946 | 947 | //disconnect client 948 | void clientEnd() 949 | { 950 | if(!isClient) return; 951 | wr1(0); 952 | for(int i=0; i<50; i++){ 953 | Sleep(200); 954 | if(!isClient) return; 955 | } 956 | EnterCriticalSection(&netLock); 957 | if(clientThread){ 958 | wrLog("Server is not responding"); 959 | clientDone(); 960 | TerminateThread(clientThread, 1); 961 | } 962 | LeaveCriticalSection(&netLock); 963 | } 964 | 965 | //disconnect client on server 966 | void killClient(int i) 967 | { 968 | HANDLE t, t2=0; 969 | 970 | if(i<0 || i>=Mplayer) return; 971 | Tclient *c=&clients[i]; 972 | EnterCriticalSection(&netLock); 973 | t= c->thread; 974 | if(t) DuplicateHandle(GetCurrentProcess(), t, GetCurrentProcess(), &t2, 0, FALSE, DUPLICATE_SAME_ACCESS); 975 | LeaveCriticalSection(&netLock); 976 | if(t){ 977 | wr1(c->socket, 231); 978 | closesocket(c->socket); 979 | c->socket=INVALID_SOCKET; 980 | WaitForSingleObject(t2, 30000); 981 | CloseHandle(t2); 982 | } 983 | } 984 | 985 | //cancel tournament on server, don't stop listening 986 | void turAbort() 987 | { 988 | EnterCriticalSection(&netLock); 989 | if(turNplayers) wrLog(lng(852, "Tournament aborted")); 990 | turNplayers=0; 991 | win7TaskbarProgress.SetProgressState(hWin, TBPF_NOPROGRESS); 992 | LeaveCriticalSection(&netLock); 993 | for(int i=0; ih_addr, he->h_length); 1094 | } 1095 | else{ 1096 | msglng(863, "Server not found"); 1097 | err=2; 1098 | goto le; 1099 | } 1100 | if((sock= socket(PF_INET, SOCK_STREAM, 0))==INVALID_SOCKET){ 1101 | msg("Error: socket"); 1102 | } 1103 | else{ 1104 | sa.sin_port = htons((u_short)port); 1105 | if(connect(sock, (sockaddr*)&sa, sizeof(sa))!=0){ 1106 | err=3; 1107 | } 1108 | else{ 1109 | return 0; 1110 | } 1111 | closesocket(sock); 1112 | } 1113 | le: 1114 | WSACleanup(); 1115 | } 1116 | return err; 1117 | } 1118 | 1119 | int clientStart() 1120 | { 1121 | int err=startConnection(); 1122 | if(err){ 1123 | if(err==3) msglng(864, "Cannot connect to server"); 1124 | return err; 1125 | } 1126 | isClient=true; 1127 | drawTitle(); 1128 | delete[] turTable; 1129 | turTable= new TturPlayer[turNplayers=2]; 1130 | delete[] turCells; 1131 | turCells= new TturCell[4]; 1132 | DWORD id; 1133 | ResumeThread(clientThread=CreateThread(0, 0, clientLoop, 0, CREATE_SUSPENDED, &id)); 1134 | return 0; 1135 | } 1136 | 1137 | -------------------------------------------------------------------------------- /pbrain/README.txt: -------------------------------------------------------------------------------- 1 | How to compile 2 | -------------- 3 | Create two C++ projects. The first project is Win32 Application and it contains files from the folder "source". You have to add library modules wsock32.lib mswsock.lib version.lib comctl32.lib. The output file is piskvork.exe which is a user interface and a tournament manager. The second project is Win32 Console Application and it contains files from the folder "source\pbrain" and a file pisqpipe.cpp from the folder "source\skelet". Rename the output file to pbrain-pela.exe. You have to select Multithreaded DLL or Multithreaded run-time library in both projects' options. 4 | 5 | Algorithm 6 | --------- 7 | The algorithm is based on a function evaluate. It calculates evaluation for all board squares. Computer regards only those squares which have high evaluation. It is calculated for both players and stored in members h[0] and h[1] in struct Tsquare. Evaluation is calculated for all directions (vertical, forward diagonal, horizontal, backward diagonal) and stored in members ps[0], ps[1], ps[2], ps[3] in struct Tprior. The sum of these four directions is stored in a member pv in struct Tprior. 8 | When a game begins, 1MB array K is created which contains evaluation for all possible patterns within a line. The evaluation depends on a count of own or opponent's symbols within a line. Each item in the array corresponds to a pattern of 9 squares. 9 | Squares which have high evaluation are placed in linked lists. The list goodMoves[1] contains squares with evaluation between 158 and 315. The list goodMoves[2] contains squares with evaluation between 316 and 2045. The list goodMoves[3] contains squares with evaluation higher then 2046. If all these lists are empty, then all the board is searched to find a suitable square. 10 | At first, the computer searches moves that make four symbols in a line. Depth of this search is unlimited. The opponent has only one possiblitity to defend if the attacker has four symbols. That's why there are not too many combinations. 11 | Most of the thinking time is spent in a function alfabeta that does depth search and backtracking. The depth depends on a time for a turn. It begins at depth 6 and then repeats the search for larger depths until time runs out. The search can be finished sooner in some special situations - if someone wins in a few moves or if all lines are occupied by both players and nobody has chance to attack. Unfortunately, time of a search grows exponentially with the depth. In order to decrease number of variations, distances between two consecutive moves must be less then 7. Moreover, two successive attacker's moves must be on one line. 12 | Offensive and defensive moves are search independently. 13 | If the depth is not large enough to find winning moves, the computer moves on a square which has the highest evaluation or almost highest. There is a little randomness so that a game is not the same each time. 14 | 15 | How to create your own AI 16 | ------------------------- 17 | Use files pisqpipe.cpp and pisqpipe.h that contain all neccessary communication between your AI and the game manager. Then implement functions brain_init, brain_restart, brain_turn, brain_my, brain_opponents, brain_block, brain_takeback, brain_end. Your EXE file must have a prefix pbrain-. 18 | The second possibility is to use obsolete file protocol which communicates through files Tah.dat, Plocha.dat, TimeOuts.dat, Info.dat, msg.dat. 19 | Visit http://gomocup.wz.cz where you will find more information about the protocol and tournament rules. 20 | -------------------------------------------------------------------------------- /pbrain/README_CZ.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/pbrain/README_CZ.txt -------------------------------------------------------------------------------- /pbrain/alfabeta.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2001-2005 Petr Lastovicka 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License. 6 | */ 7 | #include 8 | #pragma hdrstop 9 | #include 10 | #include "board.h" 11 | 12 | #define MOVE_NUM1 -3 //number of searched moves 13 | #define MOVE_NUM2 2 14 | #define DEFEND_MAX 20 //maximal number of defend moves 15 | #define LOST_DECR 140 16 | #define McurMoves 1024 //buffer size for searched moves 17 | 18 | Psquare 19 | curMoves[McurMoves]; //buffer for moves 20 | 21 | static bool careful; //search attacks of both players 22 | 23 | //------------------------------------------------------------------- 24 | 25 | #ifdef DEBUG 26 | int sl=0; //visualization (ms) 27 | 28 | void vis(Psquare p){ 29 | if(sl>0) paintSquare(p); 30 | if(sl>1) Sleep(sl); 31 | } 32 | #endif 33 | 34 | int distance(Psquare p1, Psquare p2) 35 | { 36 | return max(abs(p1->x - p2->x), abs(p1->y - p2->y)); 37 | } 38 | 39 | bool notInWinMove(Psquare p) 40 | { 41 | return !p || p->inWinMoves>=UwinMoves || *p->inWinMoves!=p; 42 | } 43 | 44 | void addWinMove(Psquare p) 45 | { 46 | if(p->inWinMoves>=UwinMoves || *p->inWinMoves!=p){ 47 | if(UwinMoves>=winMoves1+MwinMoves){ assert(0); return; } 48 | p->inWinMoves=UwinMoves; 49 | *UwinMoves++=p; 50 | } 51 | } 52 | 53 | //------------------------------------------------------------------- 54 | /* 55 | recursive function 56 | find out whether I win or lose 57 | set variable bestMove if dpth==0 58 | fill array winMoves1 if logWin==1 && y!=0 && strike==(y>0) 59 | strike:0=defend,1=attack 60 | */ 61 | int alfabeta(int player1, Psquare *UcurMoves, int logWin, Psquare last1, Psquare last2, int strike) 62 | { 63 | Psquare p, *q, *t, pDefend, *defendMoves1, *defendMoves2, *UwinMoves0, *badMoves; 64 | int y, m; 65 | int i, j, s, n; 66 | int pr, hr; 67 | int mustDefend, mustAttack, mayAttack; 68 | static int cnt; 69 | 70 | //check timeout 71 | if(--cnt<0){ 72 | cnt=1000; 73 | if(GetTickCount()>stopTime()){ 74 | terminate=2; 75 | #ifdef DEBUG 76 | printXY(55, 0, 100, "timeout"); 77 | #endif 78 | } 79 | } 80 | benchmark++; 81 | #ifdef DEBUG 82 | if(!(benchmark%3000)) printXY(60, 18, 130, "moves=%d", benchmark); 83 | #endif 84 | 85 | p=goodMoves[3][player1]; 86 | if(p){ 87 | //player1 has already four 88 | assert(dpth>0); 89 | if(logWin && strike) addWinMove(p); 90 | return 1000-dpth; //I win 91 | } 92 | int player2=1-player1; 93 | p=goodMoves[3][player2]; 94 | if(p){ 95 | //player2 has already four 96 | p->z=player1+1; 97 | #ifdef DEBUG 98 | vis(p); 99 | #endif 100 | evaluate(p); 101 | y= -alfabeta(player2, UcurMoves, logWin, last2, last1, strike^1); 102 | p->z=0; 103 | #ifdef DEBUG 104 | vis(p); 105 | #endif 106 | evaluate(p); 107 | assert(dpth>0); 108 | if(logWin && y && ((y>0) == strike)) addWinMove(p); 109 | return y; 110 | } 111 | 112 | //find reasonable moves and store them to array curMoves 113 | Psquare *Utahy0=UcurMoves; 114 | if(strike) hr=player1; else hr=player2; 115 | mustDefend= mustAttack= mayAttack= 0; 116 | pDefend=0; 117 | p=goodMoves[2][player1]; 118 | if(p){ 119 | mustAttack++; 120 | do{ 121 | if(!logWin && p->h[player1].pv >= H31){ 122 | //I have three in a line => I should win 123 | if(!dpth) bestMove=p; 124 | return 999-dpth; 125 | } 126 | if(UcurMoves==curMoves+McurMoves) break; 127 | //insert square p to sorted array curMoves 128 | pr=p->h[hr].pv; 129 | for(q=UcurMoves++; q>Utahy0 && (*(q-1))->h[hr].pv < pr; q--){ 130 | *q = *(q-1); 131 | } 132 | *q = p; 133 | p=p->h[player1].nxt; 134 | } while(p); 135 | } 136 | defendMoves1=UcurMoves; //beginning of defend moves 137 | 138 | for(p=goodMoves[2][player2]; p; p=p->h[player2].nxt){ 139 | if(p->h[player2].pv >= H30+H21){ 140 | //opponent has a triple => I must defend 141 | if(!mustDefend) mustDefend=1; 142 | if(p->h[player2].pv >= H31) mustDefend=2; 143 | } 144 | else{ 145 | //don't bother with opponent's two pairs if I have triple 146 | if(mustAttack) continue; 147 | } 148 | pDefend=p; 149 | if(UcurMoves==curMoves+McurMoves) break; //buffer overflow 150 | //insert square p to sorted array curMoves 151 | pr=p->h[hr].pv; 152 | for(q=UcurMoves++; q>defendMoves1 && (*(q-1))->h[hr].pv < pr; q--){ 153 | *q = *(q-1); 154 | } 155 | *q = p; 156 | } 157 | defendMoves2=UcurMoves; 158 | 159 | if(dpth>=depth){ 160 | depthReached=true; 161 | if(!mustAttack && !mustDefend) return 0; 162 | } 163 | else if(!terminate){ 164 | //defend 165 | if(pDefend){ 166 | //look around opponent's move 167 | for(i=0; i<8; i++){ 168 | s=diroff[i]; 169 | p=pDefend; nxtP(p, 1); 170 | for(j=0; j<4 && (p->z!=3); j++, nxtP(p, 1)){ 171 | if(p->h[player2].i==1){ 172 | if(UcurMoves==curMoves+McurMoves) break; //buffer overflow 173 | //insert square p to sorted array curMoves 174 | pr=p->h[hr].pv; 175 | for(q=UcurMoves++; q>defendMoves2 && (*(q-1))->h[hr].pv < pr; q--){ 176 | *q = *(q-1); 177 | } 178 | *q = p; 179 | } 180 | } 181 | } 182 | } 183 | else if(!strike){ 184 | for(p=goodMoves[1][player2]; p; p=p->h[player2].nxt){ 185 | if((!last2 || distance(p, last2)<7) 186 | && (!mustAttack || p->h[player2].pv >= H30)){ 187 | if(UcurMoves==curMoves+McurMoves) break; //buffer overflow 188 | //insert square p to sorted array curMoves 189 | pr=p->h[hr].pv; 190 | for(q=UcurMoves++; q>defendMoves2 && (*(q-1))->h[hr].pv < pr; q--){ 191 | *q = *(q-1); 192 | } 193 | *q = p; 194 | } 195 | } 196 | } 197 | defendMoves2=UcurMoves; //end of defend moves 198 | 199 | //attack 200 | if(strike || careful || !pDefend){ 201 | if(last1 && !mustDefend){ 202 | //look around my last move 203 | for(i=0; i<8; i++){ 204 | s=diroff[i]; 205 | p=last1; nxtP(p, 1); 206 | for(j=0; j<4 && (p->z!=3); j++, nxtP(p, 1)){ 207 | if(p->h[player1].i==1){ 208 | mayAttack=1; 209 | if(!mustDefend || p->h[player1].pv >= H30){ 210 | if(UcurMoves==curMoves+McurMoves) break; //buffer overflow 211 | //insert square p to sorted array curMoves 212 | pr=p->h[hr].pv; 213 | for(q=UcurMoves++; q>defendMoves2 && (*(q-1))->h[hr].pv < pr; q--){ 214 | *q = *(q-1); 215 | } 216 | *q = p; 217 | } 218 | } 219 | } 220 | } 221 | } 222 | else{ 223 | for(p=goodMoves[1][player1]; p; p=p->h[player1].nxt){ 224 | if(UcurMoves==curMoves+McurMoves) break; 225 | mayAttack=1; 226 | if(!mustDefend || p->h[player1].pv >= H30){ 227 | if(UcurMoves==curMoves+McurMoves) break; //buffer overflow 228 | //insert square p to sorted array curMoves 229 | pr=p->h[hr].pv; 230 | for(q=UcurMoves++; q>defendMoves2 && (*(q-1))->h[hr].pv < pr; q--){ 231 | *q = *(q-1); 232 | } 233 | *q = p; 234 | } 235 | } 236 | } 237 | } 238 | badMoves=UcurMoves; 239 | //low evaluated squares 240 | if(!last1 && !last2 && !pDefend && 241 | (UwinMoves==winMoves1 || !strike || player1)){ 242 | n= MOVE_NUM1+int(depth*MOVE_NUM2) - int(UcurMoves-Utahy0); 243 | if(n>0){ 244 | for(p=boardb; ph[hr].pv; 246 | if(pr>H11 && prz==0 && p->h[hr].i==0); 248 | //insert square p to sorted array curMoves 249 | for(q=UcurMoves; q>badMoves && (*(q-1))->h[hr].pv0){ 254 | UcurMoves++; 255 | n--; 256 | } 257 | } 258 | } 259 | } 260 | } 261 | } 262 | 263 | if(Utahy0==UcurMoves) return 0; //can't attack or I'm too deep 264 | if(strike && !mayAttack && pDefend && !mustAttack) return 0; 265 | 266 | #ifdef DEBUG 267 | //print buffer size 268 | if(UcurMoves-curMoves > mt){ 269 | mt=UcurMoves-curMoves; 270 | printXY(55, 0, 100, "buffer= %d", mt); 271 | } 272 | #endif 273 | 274 | //go through array curMoves (is sorted from high evaluation to low evaluation) 275 | UwinMoves0=UwinMoves; 276 | m=-0x7ffe; 277 | for(t=Utahy0; tz=player1+1; 282 | #ifdef DEBUG 283 | vis(p); 284 | #endif 285 | evaluate(p); 286 | dpth++; 287 | //recurse 288 | y= -alfabeta(player2, UcurMoves, logWin, last2, 289 | (t>=defendMoves1 && tz=0; 292 | #ifdef DEBUG 293 | vis(p); 294 | #endif 295 | evaluate(p); 296 | dpth--; 297 | if(y>0){ 298 | //I win 299 | if(!dpth) bestMove=p; 300 | if(!strike) UwinMoves=UwinMoves0; 301 | else if(logWin) addWinMove(p); 302 | return y; 303 | } 304 | if(y==0){ 305 | if(!strike){ 306 | //I hold 307 | UwinMoves=UwinMoves0; //delete win combination 308 | if(!dpth) bestMove=p; 309 | return y; 310 | } 311 | m=y; 312 | } 313 | else{ 314 | if(y>=m){ 315 | //I will probably lose, try other moves 316 | if(logWin && !strike) addWinMove(p); 317 | if(!dpth){ 318 | //choose move to lose not so soon 319 | if(y>m || p->h[player2].pv > bestMove->h[player2].pv) bestMove=p; 320 | } 321 | m=y; 322 | } 323 | } 324 | } 325 | return m; 326 | } 327 | 328 | int alfabeta(bool _careful, int strike, int player1, int logWin, Psquare last) 329 | { 330 | careful=_careful; 331 | return alfabeta(player1, curMoves, logWin, last, 0, strike); 332 | } 333 | //------------------------------------------------------------------- 334 | Psquare try4(int player1, Psquare last) 335 | { 336 | int i, j, s; 337 | Psquare p, p2=0, y=0, result=0; 338 | 339 | //attack 340 | last->z=player1+1; 341 | evaluate(last); 342 | if(!goodMoves[3][1-player1]){ 343 | p2=goodMoves[3][player1]; 344 | if(p2){ 345 | //defend - only one possibility 346 | p2->z=2-player1; 347 | evaluate(p2); 348 | 349 | p=goodMoves[3][player1]; 350 | if(p){ 351 | addWinMove(p); 352 | result=p; //player1 wins 353 | } 354 | else{ 355 | p=goodMoves[3][1-player1]; 356 | if(p){ 357 | if(p->h[player1].pv>=H30){ 358 | y=try4(player1, p); 359 | if(y) result=p; 360 | } 361 | } 362 | else{ 363 | //search triples around last move 364 | for(i=0; i<8; i++){ 365 | s=diroff[i]; 366 | p=last; nxtP(p, 1); 367 | for(j=0; j<4 && (p->z!=3); j++, nxtP(p, 1)){ 368 | if(p->h[player1].pv>=H30){ 369 | //recurse 370 | y=try4(player1, p); 371 | if(y){ 372 | result=p; 373 | goto e; 374 | } 375 | } 376 | } 377 | } 378 | } 379 | } 380 | e: 381 | p2->z=0; 382 | evaluate(p2); 383 | } 384 | } 385 | last->z=0; 386 | evaluate(last); 387 | if(result){ 388 | addWinMove(p2); 389 | addWinMove(last); 390 | } 391 | return result; 392 | } 393 | //------------------------------------------------------------------- 394 | //search only forced moves when attacker makes fours 395 | //depth of recursion is unlimited 396 | Psquare try4(int player1) 397 | { 398 | Psquare p, y=0, *t; 399 | int j; 400 | 401 | assert(!goodMoves[3][0] && !goodMoves[3][1]); 402 | 403 | //find triples of player1 404 | t=curMoves; 405 | for(j=1; j<=2; j++){ 406 | for(p=goodMoves[j][player1]; p; p=p->h[player1].nxt){ 407 | if(p->h[player1].pv>=H30){ 408 | if(t==curMoves+McurMoves) break; 409 | *t++=p; 410 | } 411 | } 412 | } 413 | for(t--; t>=curMoves; t--){ 414 | p=*t; 415 | y=try4(player1, p); 416 | if(y){ 417 | evalWinMoves(); 418 | return p; 419 | } 420 | } 421 | return 0; 422 | } 423 | //------------------------------------------------------------------- 424 | //try to move on squares from array winMoves1 425 | int defend() 426 | { 427 | Psquare p; 428 | int m, mv, mh, y, yh, Nwins, i, j, jm=0, e, mi; 429 | const int player1=0; 430 | const int player2=1; 431 | static int winIndex[MwinMoves]; 432 | 433 | dpth++; 434 | Nwins= UwinMoves-winMoves1; 435 | assert(Nwins>0); 436 | for(i=0; i0 && i=0; j--){ 445 | e= winEval[winIndex[j]]; 446 | if(e>mv){ mv=e; jm=j; } 447 | } 448 | if(mv < H12) break; 449 | //remove square from the list 450 | mi=winIndex[jm]; 451 | p= winMoves1[mi]; 452 | Nwins--; 453 | winIndex[jm]=winIndex[Nwins]; 454 | assert(p>=boardb && pz); 455 | p->z=player1+1; 456 | #ifdef DEBUG 457 | vis(p); 458 | #endif 459 | evaluate(p); 460 | //opponent's attack 461 | y = -alfabeta(carefulDefend, 1, player2, 0); 462 | p->z=0; 463 | #ifdef DEBUG 464 | vis(p); 465 | #endif 466 | evaluate(p); 467 | //evaluation 468 | yh= mv + y*20; 469 | if(yh>mh){ 470 | m=y; 471 | mh=yh; 472 | bestMove=p; 473 | if(y>0 || y==0 && !winMove[player1]){ 474 | holdMove=p; 475 | break; //I hold 476 | } 477 | } 478 | else if(y<0){ 479 | winEval[mi]-=LOST_DECR; 480 | } 481 | } 482 | if(m<0 && holdMove) bestMove=holdMove; 483 | dpth--; 484 | return m; 485 | } 486 | //------------------------------------------------------------------- 487 | -------------------------------------------------------------------------------- /pbrain/board.h: -------------------------------------------------------------------------------- 1 | /* 2 | (C) Petr Lastovicka 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License. 6 | */ 7 | 8 | #include "..\skelet\pisqpipe.h" 9 | 10 | const int //evaluation constants (very important) 11 | H10=2, H11=6, H12=10, 12 | H20=23, H21=158, H22=175, 13 | H30=256,H31=511, H4=2047; 14 | 15 | typedef int Tsymbol; 16 | struct Tsquare; 17 | typedef Tsquare *Psquare; 18 | 19 | struct Tprior 20 | { 21 | int pv,ps[4]; //evaluation in 4 directions and sum 22 | int i; //in which linked list 23 | Psquare nxt,*pre;//linked list pointers 24 | }; 25 | 26 | struct Tsquare 27 | { 28 | Tsymbol z; //0=nothing, 1=my, 2=opponent, 3=outside 29 | Tprior h[2]; //evaluation for both players 30 | short x,y; //coordinates 0..width-1, 0..height-1 31 | Psquare *inWinMoves; //pointer to winMoves1 array 32 | }; 33 | 34 | #define MwinMoves 512 //buffer size for win combination 35 | 36 | extern int diroff[9],moves,width,height,height2,depth,resulty,benchmark,mt,dpth,winEval[MwinMoves]; 37 | extern bool attackDone,defendDone,defendDone1,testDone,depthReached,carefulAttack,carefulDefend; 38 | extern Psquare board,boardb,boardk,resultMove,loss4,highestEval,lastMove,bestMove,holdMove,goodMoves[4][2],*UwinMoves,winMoves1[MwinMoves],winMove[2]; 39 | 40 | DWORD stopTime(); 41 | void paintSquare(Psquare p); 42 | void computer1(); 43 | void evaluate(Psquare p0); 44 | int alfabeta(bool _careful, int strike, int player1, int logWin, Psquare last=0); 45 | int defend(); 46 | void init(); 47 | bool doMove(Psquare p); 48 | void getBestEval(); 49 | void firstMove(); 50 | void evalWinMoves(); 51 | void addWinMove(Psquare p); 52 | bool notInWinMove(Psquare p); 53 | Psquare try4(int player1); 54 | Psquare Square(int x,int y); 55 | int getEval(int player,Psquare p); 56 | int getEval(Psquare p); 57 | void print(char *format, ...); 58 | void printXY(int x, int y, int w, char *format, ...); 59 | 60 | #define nxtQ(p,i) ((Psquare)(((char*)p)+(i*s))) 61 | #define prvQ(p,i) ((Psquare)(((char*)p)-(i*s))) 62 | #define nxtP(p,i) (p=(Psquare)(((char*)p)+(i*s))) 63 | #define prvP(p,i) (p=(Psquare)(((char*)p)-(i*s))) 64 | #define nxtS(p,s) ((Psquare)(((char*)p)+diroff[s])) 65 | #define nxtI(p,s,i) ((Psquare)(((char*)p)+diroff[((s)+(i))&7])) 66 | 67 | template inline void amin(T &x,int m){ if(x inline void amax(T &x,int m){ if(x>m) x=m; } 69 | template inline void aminmax(T &x,int l,int h){ 70 | if(xh) x=h; 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /pbrain/piskcomp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License. 6 | */ 7 | #include 8 | #pragma hdrstop 9 | #include 10 | #include "board.h" 11 | 12 | #define EVAL_RAND1 20 //randomness 13 | #define EVAL_RAND2 30 //maximal randomness for low evaluation 14 | #define AHEAD_DEPTH 4 //depth search to find good total evaluation 15 | #define AHEAD_IRRELEVANCE1 12 16 | #define AHEAD_IRRELEVANCE2 3 17 | #define NUM_GOOD0 100 18 | #define NUM_GOOD1 30 19 | #define OFFENSIVE 1 20 | #define DEFEND_HIGHEVAL 70 21 | 22 | int 23 | height2, //height+2 24 | moves, //moves counter 25 | depth, //maximal recursion depth (is increased until timeout) 26 | diroff[9]; //pointer difference to adjacent squares 27 | 28 | int 29 | winEval[MwinMoves], //evaluation of winMoves1 30 | winMoveDepth[2], //depth of win combination 31 | sum[2], //total evaluation for both players 32 | dpth=0; //current recursion depth 33 | 34 | Psquare 35 | board=0, //board array 36 | boardb, boardk, //pointer to the beginning and end of board 37 | loss4, //opponent can win through foursomes 38 | resultMove, //the best move 39 | highestEval, //square which has the best evaluation 40 | lastMove, 41 | holdMove; 42 | 43 | Psquare 44 | goodMoves[4][2], //linked lists of highly evaluated squares, for both players 45 | winMoves1[MwinMoves],//buffer for win combination 46 | *UwinMoves, 47 | winMove[2], //the first move of win combination 48 | bestMove; 49 | 50 | bool 51 | depthReached, //depth has beeb reached (and can be increased) 52 | attackDone, defendDone, defendDone1, testDone, 53 | carefulAttack, carefulDefend; 54 | 55 | const int priority[][3]={{0, 1, 1}, {H10, H11, H12}, {H20, H21, H22}, {H30, H31, 0}, {H4, 0, 0}}; 56 | 57 | #ifdef DEBUG 58 | int mt; //curMoves buffer utilization 59 | int resulty; //win/loss/unknown 60 | #endif 61 | int benchmark;//counter of searched moves 62 | 63 | //------------------------------------------------------------------- 64 | signed char data[]={ 65 | 15, 1, 4, 0, 0, 0, 1, 1, 2, 3, 2, 2, 4, 2, 5, 3, 3, 4, 3, 3, 5, 5, 4, 3, 3, 6, 4, 5, 6, 5, 5, 4, 3, 1, 66 | 11, 1, 1, 1, 0, 0, 2, 2, 3, 2, 3, 3, 1, 3, 2, 4, 1, 5, 3, 3, 3, 2, 5, 1, 4, 3, 67 | 11, 1, 1, 0, 0, 0, 1, 1, 3, 2, 2, 2, 2, 3, 3, 3, 2, 4, 2, 5, 1, 5, 1, 4, 0, 3, 68 | 9, 1, 0, 0, 0, 3, 0, 1, 1, 2, 0, 2, 2, 3, 3, 3, 3, 4, 2, 4, 1, 1, 69 | 9, 1, 1, 1, 0, 0, 2, 2, 3, 2, 3, 3, 2, 3, 1, 4, 1, 3, 1, 5, 2, 4, 70 | 9, 1, 1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 1, 2, 3, 1, 2, 0, 3, 1, 4, 71 | 9, 1, 0, 0, 2, 0, 1, 0, 1, 1, 0, 1, 2, 2, 3, 2, 3, 3, 2, 3, 0, 2, 72 | 9, 1, 1, 1, 0, 0, 2, 2, 0, 2, 2, 1, 3, 1, 1, 2, 1, 3, 0, 3, 3, 0, 73 | 9, 1, 0, 0, 2, 0, 1, 1, 1, 2, 2, 1, 1, 4, 3, 2, 4, 3, 2, 3, 0, 1, 74 | 8, 1, 0, 2, 1, 1, 1, 2, 2, 0, 2, 2, 3, 0, 3, 1, 3, 2, 4, 0, 75 | 8, 1, 1, 1, 3, 0, 0, 2, 3, 1, 1, 3, 2, 2, 2, 3, 1, 4, 3, 3, 76 | 7, 1, 0, 0, 1, 1, 0, 1, 2, 2, 3, 2, 3, 3, 2, 3, 0, 2, 77 | 7, 1, 3, 2, 2, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 2, 78 | 7, 1, 0, 0, 0, 1, 1, 0, 0, 3, 2, 1, 3, 2, 1, 2, 1, -1, 79 | 7, 1, 1, 0, 0, 1, 0, 2, 2, 2, 2, 1, 3, 2, 5, 2, 3, 0, 80 | 7, 1, 0, 0, 0, 1, 2, 0, 0, 3, 2, 1, 1, 3, 1, 2, 2, 3, 81 | 7, 1, 1, 0, 0, 0, 0, 1, 1, 1, 2, 2, 1, 2, 1, 3, 2, 3, 82 | 7, 1, 0, 1, 1, 1, 2, 0, 0, 2, 1, 2, 3, 4, 2, 3, 2, 1, 83 | 6, 1, 1, 0, 0, 0, 0, 2, 1, 1, 3, 3, 2, 2, 1, -1, 84 | 6, 1, 1, 0, 0, 0, 1, 1, 2, 1, 2, 2, 1, 2, 0, -1, 85 | 6, 1, 0, 0, 1, 0, 2, 1, 3, 1, 3, 2, 2, 2, 1, -1, 86 | 6, 1, 3, 0, 0, 0, 1, 1, 2, 1, 2, 2, 1, 2, -1, 0, 87 | 6, 1, 0, 0, 1, 1, 3, 1, 2, 2, 4, 3, 3, 3, 2, 4, 88 | 6, 1, 0, 2, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 3, 0, 89 | 6, 1, 2, 1, 0, 0, 2, 2, 0, 1, 2, 3, 1, 2, 2, 0, 90 | 6, 1, 2, 1, 0, 0, 1, 3, 0, 1, 2, 3, 1, 2, 2, 0, 91 | 5, 2, 2, 2, 0, 0, 1, 0, 1, 1, 0, 1, 2, 1, 1, 2, 92 | 5, 1, 0, 0, 2, 1, 0, 1, 2, 3, 1, 2, 1, 3, 93 | 5, 1, 1, 0, 0, 0, 1, 1, 1, 2, 2, 1, 1, -1, 94 | 5, 1, 1, 1, 1, 0, 0, 2, 1, 3, 1, 2, 2, 2, 95 | 5, 1, 1, 0, 0, 0, 0, 1, 1, 1, 2, 3, 2, 2, 96 | 5, 2, 0, 0, 1, 1, 1, 2, 0, 1, 2, 1, 2, 0, 3, 0, 97 | 5, 1, 0, 2, 1, 0, 2, 0, 2, 1, 1, 1, -1, 3, 98 | 5, 1, 1, 0, 1, 1, 0, 1, 2, 1, 3, 2, 2, -1, 99 | 5, 1, 1, 1, 0, 0, 2, 1, 0, 2, 3, 1, 0, 1, 100 | 5, 2, 1, 1, 0, 0, 2, 1, 1, 3, 1, 2, 0, 1, 3, 1, 101 | 5, 2, 1, 0, 0, 0, 0, 1, 2, 1, 1, 1, 1, 2, -1, 2, 102 | 5, 1, 1, 0, 1, 2, 0, 1, 3, 2, 2, 1, 2, -1, 103 | 5, 2, 0, 1, 1, 2, 2, 1, 3, 0, 0, 3, 1, 1, 0, 2, 104 | 5, 1, 2, 0, 0, 2, 1, 1, 1, 2, 2, 2, 0, 0, 105 | 5, 1, 0, 0, 1, 1, 1, 0, 1, 2, 0, 2, 0, 1, 106 | 4, 1, 1, 0, 0, 1, 1, 3, 1, 2, -1, 0, 107 | 4, 1, 1, 0, 0, 1, 1, 1, 1, 2, -1, 0, 108 | 4, 1, 1, 0, 1, 1, 0, 2, 2, 2, 0, 0, 109 | 4, 1, 2, 0, 0, 0, 0, 2, 1, 1, 2, 2, 110 | 4, 1, 0, 0, 1, 1, 3, 1, 2, 2, 3, 3, 111 | 4, 2, 2, 0, 0, 0, 2, 2, 1, 1, 0, -1, 1, -1, 112 | 4, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2, 2, 113 | 4, 1, 1, 0, 0, 1, 2, 0, 1, 2, -1, 0, 114 | 4, 1, 1, 0, 0, 0, 0, 2, 1, 1, -1, -1, 115 | 4, 1, 1, 0, 0, 1, 2, 2, 1, 2, -1, 0, 116 | 4, 1, 0, 0, 1, 1, 2, 1, 2, 2, 3, 3, 117 | 3, 1, 0, 1, 0, 0, 1, 0, 1, 1, 118 | 3, 1, 0, 0, 2, 0, 1, 1, 2, 2, 119 | 3, 4, 1, 0, 0, 1, 1, 2, 0, 2, 0, 0, 2, 0, 2, 2, 120 | 3, 1, 1, 2, 0, 0, 1, 1, 1, 3, 121 | 3, 1, 1, 0, 0, 0, 1, 1, 1, 2, 122 | 3, 1, 0, 0, 0, 2, 0, 1, 0, -1, 123 | 3, 1, 0, 0, 2, 1, 1, 1, 2, 2, 124 | 3, 1, 0, 0, 0, 1, 1, 2, 1, 1, 125 | 3, 2, 0, 0, 2, 2, 1, 1, 2, 1, 1, 2, 126 | 3, 1, 0, 1, 3, 0, 2, 0, 1, 1, 127 | 3, 1, 0, 0, 2, 1, 2, 2, 1, 1, 128 | 3, 4, 0, 0, 1, 1, 2, 2, 1, -1, -1, 1, 3, 1, 1, 3, 129 | 3, 1, 0, 0, 0, 2, 1, 2, 1, 0, 130 | 3, 2, 1, 0, 0, 3, 1, 2, 2, 3, 1, 1, 131 | 3, 2, 0, 0, 0, 3, 0, 2, 1, 3, -1, 3, 132 | 3, 1, 0, 0, 0, 3, 1, 2, 1, 1, 133 | 3, 1, 1, 0, 0, 2, 1, 2, 1, 1, 134 | 3, 1, 0, 0, 2, 1, 1, 2, 0, 2, 135 | 3, 1, 0, 0, 2, 2, 1, 2, 0, 1, 136 | 3, 1, 0, 0, 3, 3, 2, 2, 1, 1, 137 | 3, 1, 0, 0, 3, 2, 2, 2, 1, 1, 138 | 3, 1, 0, 0, 3, 1, 2, 2, 3, 3, 139 | 3, 6, 0, 0, 1, 0, 2, 0, 1, 1, 1, -1, 0, 2, 0, -2, 2, 2, 2, -2, 140 | 3, 3, 0, 0, 3, 2, 2, 1, 1, 0, 1, 1, 0, 1, 141 | 2, 3, 0, 0, 1, 1, 0, 2, 2, 0, 1, 2, 142 | 2, 8, 0, 0, 1, 0, -1, -1, 0, -1, 1, -1, 2, -1, -1, 1, 0, 1, 1, 1, 2, 1, 143 | 2, 2, 0, 0, 2, 2, 1, 3, 3, 1, 144 | 1, 8, 0, 0, -1, 0, 1, 0, 0, 1, 0, -1, 1, 1, -1, 1, 1, -1, -1, -1, 145 | 0, 0 146 | }; 147 | //------------------------------------------------------------------- 148 | Psquare Square(int x, int y) //indexed from zero 149 | { 150 | return boardb + x*height2+(y+1); 151 | } 152 | //------------------------------------------------------------------- 153 | struct PR2 { short h[2]; }; 154 | PR2 K[262144]; //evaluation for all combinations of 9 squares 155 | static int comb[10]; //current combination 156 | static PR2 *ind; //write position in array K 157 | static int n[4]; //number of empty fields, stones and borders 158 | //------------------------------------------------------------------- 159 | void gen2(int *pos) 160 | { 161 | int *pb, *pe; 162 | int n[4], a1, a2; 163 | int s; 164 | bool six[2]; 165 | 166 | if(pos==comb+9){ 167 | a1=a2=0; 168 | if(comb[4]==0){ //the middle square must be empty 169 | n[1]=::n[1]; n[2]=::n[2]; n[3]=::n[3]; 170 | six[0]=six[1]=false; 171 | pb=comb; 172 | pe=pb+4; 173 | while(pe!=comb+9){ 174 | if(!n[3]){ //must not be outside the board 175 | if(!n[2]){ 176 | //my chances 177 | s=0; 178 | if(!*pb && pe[1]<2 && pb!=comb+4){ 179 | s++; 180 | if(!*pe && pe!=comb+4) s++; 181 | } 182 | if(info_exact5==1 && n[1]==4 && 183 | (pecomb && pb[-1]==1)){ 184 | six[0]=true; 185 | } 186 | amin(a1, priority[n[1]][s]); 187 | } 188 | if(!n[1]){ 189 | //opponent's chances 190 | s=0; 191 | if(!*pb && !(pe[1]&1) && pb!=comb+4){ 192 | s++; 193 | if(!*pe && pe!=comb+4) s++; 194 | } 195 | if(info_exact5==1 && n[2]==4 && 196 | (pecomb && pb[-1]==2)){ 197 | six[1]=true; 198 | } 199 | amin(a2, priority[n[2]][s]); 200 | } 201 | } 202 | n[*++pe]++; 203 | n[*pb++]--; 204 | } 205 | } 206 | //store computed evaluation to the array 207 | ind->h[0]= short(six[0] ? 0 : a1); 208 | ind->h[1]= short(six[1] ? 0 : a2); 209 | ind++; 210 | } 211 | else{ 212 | //generate last five squares of combination 213 | for(int z=0; z<4; z++){ 214 | *pos=z; 215 | gen2(pos+1); 216 | } 217 | } 218 | } 219 | 220 | //generate first four squares of combination 221 | void gen1(int *pos) 222 | { 223 | if(pos==comb+5){ 224 | gen2(pos); 225 | } 226 | else{ 227 | for(int z=0; z<4; z++){ 228 | *pos=z; 229 | n[z]++; 230 | gen1(pos+1); 231 | n[z]--; 232 | } 233 | } 234 | } 235 | 236 | void gen() 237 | { 238 | ind=K; 239 | gen1(comb); 240 | } 241 | //------------------------------------------------------------------- 242 | void init() 243 | { 244 | int x, y, k; 245 | Psquare p; 246 | Tprior *pr; 247 | 248 | memset(goodMoves, 0, sizeof(goodMoves)); 249 | memset(winMove, 0, sizeof(winMove)); 250 | sum[0]= sum[1]= 0; 251 | 252 | //alocate the board 253 | delete[] board; 254 | height2=height+2; 255 | board= new Tsquare[(width+10)*(height2)]; 256 | boardb= board + 5*height2; 257 | boardk= boardb+ width*height2; 258 | // 5 4 3 259 | // 6 8 2 260 | // 7 0 1 261 | diroff[0]=sizeof(Tsquare); 262 | diroff[4]=-diroff[0]; 263 | diroff[1]=sizeof(Tsquare)*(1+height2); 264 | diroff[5]=-diroff[1]; 265 | diroff[2]=sizeof(Tsquare)* height2; 266 | diroff[6]=-diroff[2]; 267 | diroff[3]=sizeof(Tsquare)*(-1+height2); 268 | diroff[7]=-diroff[3]; 269 | diroff[8]=0; 270 | 271 | //initialize the board 272 | p=board; 273 | for(x=-5; x<=width+4; x++){ 274 | for(y=-1; y<=height; y++){ 275 | p->z= (x<0 || y<0 || x>=width || y>=height) ? 3 : 0; 276 | p->x= (short)x; 277 | p->y= (short)y; 278 | for(k=0; k<2; k++){ 279 | pr=&p->h[k]; 280 | pr->i=0; 281 | pr->pv=4; 282 | pr->ps[0]=pr->ps[1]=pr->ps[2]=pr->ps[3]=1; 283 | } 284 | p++; 285 | } 286 | } 287 | moves=0; 288 | } 289 | //------------------------------------------------------------------- 290 | //evaluate squares around p0 to distance 4 291 | void evaluate(Psquare p0) 292 | { 293 | int i, k, m, s, h; 294 | Tprior *pr; 295 | Psquare p, q, qk, *up, pe, pk1; 296 | int *u; 297 | int ind; 298 | unsigned pattern; 299 | static int last_exact5=-1; 300 | 301 | if(info_exact5!=last_exact5){ 302 | last_exact5=info_exact5; 303 | gen(); 304 | } 305 | //remove not empty square from list and set its evaluation to zero 306 | if(p0->z){ 307 | for(k=0; k<2; k++){ 308 | pr=&p0->h[k]; 309 | if(pr->pv){ 310 | if(pr->i){ 311 | if((*pr->pre= pr->nxt)!=0) pr->nxt->h[k].pre= pr->pre; 312 | pr->i=0; 313 | } 314 | sum[k]-= pr->pv; 315 | pr->pv= pr->ps[0]= pr->ps[1]= pr->ps[2]= pr->ps[3]= 0; 316 | } 317 | } 318 | } 319 | //cycle all directions 320 | for(i=0; i<4; i++){ 321 | s=diroff[i]; 322 | pk1=p0; 323 | nxtP(pk1, 5); 324 | pe=p0; 325 | p=p0; 326 | for(m=4; m>0; m--){ 327 | prvP(p, 1); 328 | if(p->z==3){ 329 | nxtP(pe, m); 330 | nxtP(p, 1); 331 | break; 332 | } 333 | } 334 | pattern=0; 335 | qk=pe; 336 | prvP(qk, 9); 337 | for(q=pe; q!=qk; prvP(q, 1)){ 338 | pattern*=4; 339 | pattern+=q->z; 340 | } 341 | while(p->z!=3){ 342 | if(!p->z){ 343 | for(k=0; k<2; k++){ //both players 344 | pr= &p->h[k]; 345 | //change evaluation in one direction 346 | u= &pr->ps[i]; 347 | h= K[pattern].h[k]; 348 | if(info_exact5 && h>=H4){ 349 | if(prvQ(p, 5)->z==k+1 && nxtQ(p, 1)->z==0 || 350 | nxtQ(p, 5)->z==k+1 && prvQ(p, 1)->z==0){ 351 | h=0; 352 | } 353 | } 354 | m=h-*u; 355 | if(m){ 356 | *u=h; 357 | sum[k]+=m; 358 | pr->pv+=m; 359 | //choose linked list 360 | ind=0; 361 | if(pr->pv >= H21){ 362 | ind++; 363 | if(pr->pv >= 2*H21){ 364 | ind++; 365 | if(pr->pv >= H4) ind++; 366 | } 367 | } 368 | //put square to another linked list 369 | if(ind!=pr->i){ 370 | //remove 371 | if(pr->i){ 372 | if((*pr->pre= pr->nxt)!=0) pr->nxt->h[k].pre= pr->pre; 373 | } 374 | //append 375 | if((pr->i=ind)!=0){ 376 | up= &goodMoves[ind][k]; 377 | pr->nxt= *up; 378 | if(*up) (*up)->h[k].pre= &pr->nxt; 379 | pr->pre= up; 380 | *up= p; 381 | } 382 | } 383 | } 384 | } 385 | } 386 | nxtP(p, 1); 387 | if(p==pk1) break; 388 | nxtP(pe, 1); 389 | pattern>>=2; 390 | pattern+= pe->z << 16; 391 | } 392 | } 393 | } 394 | //------------------------------------------------------------------- 395 | int getEval(int player1, Psquare p0) 396 | { 397 | int i, s, y, c, c1, c2, n, d1, d2; 398 | Psquare p; 399 | 400 | y=0; 401 | //count symbols on 8 squares around p0 402 | c1=c2=0; 403 | for(i=0; i<8; i++){ 404 | s=diroff[i]; 405 | p=p0; 406 | nxtP(p, 1); 407 | if(p->z==player1+1) c1++; 408 | if(p->z==2-player1) c2++; 409 | } 410 | c=c1+c2; 411 | if(c==0) y-=20; //too empty 412 | if(c>4) y-=4*(c-3); //too many 413 | 414 | //blocked directions 415 | d1=d2=0; 416 | for(i=0; i<4; i++){ 417 | if(p0->h[player1].ps[i]<=1) d1++; 418 | if(p0->h[1-player1].ps[i]<=1) d2++; 419 | } 420 | 421 | //detect if there is only one player here 422 | if(c2==0 && c1>0 && p0->h[player1].pv>=H12){ 423 | y+= (c1+1)*5; 424 | } 425 | if(d2==4){ 426 | n=0; 427 | for(i=0; i<4; i++){ 428 | if(p0->h[player1].ps[i]>=H12) n++; 429 | } 430 | y+=15; 431 | if(n>1) y+=n*64; 432 | } 433 | return y + p0->h[player1].pv; 434 | } 435 | 436 | 437 | int getEval(Psquare p) 438 | { 439 | int a, b; 440 | a=getEval(0, p); 441 | b=getEval(1, p); 442 | return a>b ? a+b/2 : a/2+b; 443 | } 444 | 445 | //evaluate all squares in array winMoves 446 | void evalWinMoves() 447 | { 448 | int Nwins; 449 | int *e; 450 | Psquare *t, p; 451 | 452 | carefulAttack=true; 453 | //add high priority squares 454 | for(p=goodMoves[2][1]; p; p=p->h[1].nxt){ 455 | addWinMove(p); 456 | } 457 | //evaluate 458 | Nwins= UwinMoves-winMoves1; 459 | assert(Nwins<=MwinMoves); 460 | for(t=UwinMoves-1, e=winEval+Nwins-1; t!=winMoves1-1; t--, e--){ 461 | *e= getEval(1, *t); 462 | if(*t==highestEval) *e+=DEFEND_HIGHEVAL; 463 | } 464 | //add my chances to make four 465 | for(p=goodMoves[1][0]; p; p=p->h[0].nxt){ 466 | if(p->h[0].pvinWinMoves==UwinMoves-1){ 469 | winEval[Nwins++]= p->h[0].pv>>3; 470 | } 471 | } 472 | } 473 | 474 | //------------------------------------------------------------------- 475 | //find square which has greatest evaluation 476 | //return 0 if evaluation is too low 477 | Psquare findMax() 478 | { 479 | Psquare p, t; 480 | int m, r; 481 | int i, k; 482 | 483 | m=-1; 484 | t=0; 485 | for(i=2; i>0 && !t; i--){ 486 | for(k=0; k<2; k++){ 487 | for(p=goodMoves[i][k]; p; p=p->h[k].nxt){ 488 | r= getEval(p); 489 | if(r>m){ 490 | m=r; 491 | t=p; 492 | } 493 | } 494 | } 495 | } 496 | return t; 497 | } 498 | 499 | 500 | //find out what total evaluation will be after AHEAD_DEPTH moves 501 | int lookAhead(int player1) 502 | { 503 | Psquare p; 504 | int y, i; 505 | 506 | if(goodMoves[3][player1]) return 700; 507 | int player2=1-player1; 508 | p=goodMoves[3][player2]; 509 | if(!p && dpthz || q->h[0].pv == q->h[1].pv) continue; 521 | 522 | int count[4]; 523 | count[0]=count[1]=count[2]=0; //empty, our, opponent 524 | 525 | //count of symbols on 5x5 square 526 | Psquare q2 = q - 2*height2 - 2; 527 | for(int i=0; i < 5; q2+=height2, i++) 528 | for(int j=0; j<5; j++) 529 | count[q2[j].z]++; 530 | 531 | //thank Farmer Lu for this formula 532 | y += (q->h[0].pv - q->h[1].pv) * (count[0] + (count[1] - count[2])/2 - 1); 533 | } 534 | y /= AHEAD_IRRELEVANCE1; 535 | } 536 | 537 | for(i=2; i>0; i--){ 538 | for(p=goodMoves[i][0]; p; p=p->h[0].nxt) y+=NUM_GOOD0; 539 | for(p=goodMoves[i][1]; p; p=p->h[1].nxt) y-=NUM_GOOD1; 540 | } 541 | if(player1) y=-y; 542 | return int(y/AHEAD_IRRELEVANCE2); 543 | } 544 | dpth++; 545 | p->z=player1+1; 546 | evaluate(p); 547 | y= -lookAhead(player2); 548 | p->z=0; 549 | evaluate(p); 550 | dpth--; 551 | return y; 552 | } 553 | 554 | //------------------------------------------------------------------- 555 | 556 | DWORD seed= GetTickCount(); 557 | 558 | unsigned rnd(unsigned n) 559 | { 560 | seed=seed*367413989+174680251; 561 | return (unsigned)(UInt32x32To64(n, seed)>>32); 562 | } 563 | 564 | void databaseMove() 565 | { 566 | signed char *s, *sn; 567 | Psquare p, k; 568 | int i, x, y, x1, y1, flip, len1, len2, left, top, right, bottom; 569 | 570 | //board rectangle 571 | for(p=boardb; p->z!=1 && p->z!=2; p++); 572 | left=p->x; 573 | for(k=boardk; k->z!=1 && k->z!=2; k--); 574 | right=k->x; 575 | top=bottom=k->y; 576 | for(; pz==1 || p->z==2){ 578 | amax(top, p->y); 579 | amin(bottom, p->y); 580 | } 581 | } 582 | //find current board in the database 583 | for(s=data;; s=sn){ 584 | len1=*s++; 585 | len2=*s++; 586 | sn= s + 2*(len1+len2); 587 | if(len1!=moves){ 588 | if(len1z != 2-(i&1)) break; 617 | } 618 | } 619 | } 620 | } 621 | 622 | void firstMove() 623 | { 624 | //the first move is in the middle of the board 625 | if(moves==0){ 626 | doMove(Square(width/2+rnd(5)-2, height/2+rnd(5)-2)); 627 | return; 628 | } 629 | if(moves==2){ 630 | Psquare p; 631 | for(p=boardb; p->z!=1; p++); 632 | doMove(nxtS(p, rnd(8))); 633 | } 634 | databaseMove(); 635 | //already four in a line -> don't think 636 | if(goodMoves[3][0] && (!info_continuous || !goodMoves[3][0]->h[0].nxt || !goodMoves[3][1])){ 637 | if(doMove(goodMoves[3][0])) return; //I win 638 | } 639 | doMove(goodMoves[3][1]); //I have to defend 640 | } 641 | 642 | 643 | //find square which has very good evaluation 644 | void getBestEval() 645 | { 646 | int i, r, m, d, a, b; 647 | Psquare p, bestMove; 648 | int Nresults=0; 649 | 650 | bestMove=0; 651 | if(moves>4){ 652 | m=-0x7ffffffe; 653 | for(p=boardb; pz && (p->h[0].pv>10 || p->h[1].pv>10)){ 655 | a=getEval(0, p); 656 | b=getEval(1, p); 657 | r= (a>b) ? int((a + b/2)*OFFENSIVE) : (a/2 + b); 658 | p->z=1; 659 | evaluate(p); 660 | r-= lookAhead(1); 661 | p->z=0; 662 | evaluate(p); 663 | if(r>m){ 664 | m=r; 665 | bestMove=p; 666 | Nresults=1; 667 | } 668 | else if(r>m-EVAL_RAND1){ 669 | Nresults++; 670 | if(!rnd(Nresults)) bestMove=p; 671 | } 672 | } 673 | } 674 | } 675 | if(!bestMove){ 676 | m=-0x7fffff; 677 | for(p=boardb; pz){ 679 | r=getEval(p); 680 | if(r>m) m=r; 681 | } 682 | } 683 | d= abs(m/12); 684 | amax(d, EVAL_RAND2); 685 | Nresults=0; 686 | for(p=boardb; pz){ 688 | if(getEval(p) >= m-d){ 689 | Nresults++; 690 | if(!rnd(Nresults)) bestMove=p; 691 | } 692 | } 693 | } 694 | } 695 | doMove(bestMove); 696 | highestEval=bestMove; 697 | 698 | if(lastMove){ 699 | p=lastMove; 700 | for(i=0;; i++){ 701 | if(i==8){ 702 | //opponent made an isolated move -> defend it 703 | doMove(nxtS(p, rnd(8))); 704 | break; 705 | } 706 | if(nxtS(p, i)->h[1].ps[i&3]!=H12) break; 707 | } 708 | } 709 | } 710 | 711 | //------------------------------------------------------------------- 712 | 713 | void computer1() 714 | { 715 | int y=0; 716 | const int player1=0, player2=1; 717 | 718 | if(loss4){ 719 | winMove[player2]=loss4; 720 | winMoveDepth[player2]=10; 721 | y=-1; 722 | } 723 | bestMove=0; 724 | //attack 725 | if(!attackDone && (!loss4 || winMove[player1])){ 726 | #ifdef DEBUG 727 | print(carefulAttack ? "attack2" : "attack"); 728 | #endif 729 | depthReached=false; 730 | //I have already found win 731 | if(winMove[player1]){ 732 | y= alfabeta(carefulAttack, 1, player1, 0, winMove[player1]); 733 | if(y<=0){ 734 | if(winMoveDepth[player1]<=depth) winMove[player1]= 0; 735 | } 736 | } 737 | if(!bestMove){ 738 | y= alfabeta(carefulAttack, 1, player1, 0); 739 | } 740 | if(y>0 && bestMove){ 741 | doMove(bestMove); 742 | winMove[player1]=bestMove; 743 | winMoveDepth[player1]=depth; 744 | #ifdef DEBUG 745 | if(!terminate) resulty=y; 746 | #endif 747 | if(!carefulAttack){ 748 | carefulAttack=true; 749 | } 750 | else{ 751 | terminate=3; //win 752 | } 753 | return; 754 | } 755 | if(!depthReached) attackDone=true; 756 | } 757 | //find out if opponent can win 758 | if(UwinMoves==winMoves1 && !testDone){ 759 | #ifdef DEBUG 760 | print("thinking"); 761 | #endif 762 | depthReached=false; 763 | y=0; 764 | if(winMove[player2]){ 765 | y= alfabeta(0, 1, player2, 1, winMove[player2]); 766 | if(y<=0){ 767 | if(winMoveDepth[player2]<=depth) winMove[player2]=0; 768 | UwinMoves=winMoves1; 769 | } 770 | } 771 | if(y<=0){ 772 | y= alfabeta(0, 1, player2, 1); 773 | if(y>0){ 774 | winMove[player2]=bestMove; 775 | winMoveDepth[player2]=depth; 776 | } 777 | else{ 778 | UwinMoves=winMoves1; 779 | } 780 | } 781 | if(y>0) evalWinMoves(); 782 | if(!depthReached) testDone=true; 783 | } 784 | 785 | //defend 786 | if(UwinMoves>winMoves1 && !defendDone && 787 | (!defendDone1 || carefulDefend)){ 788 | #ifdef DEBUG 789 | print(carefulDefend ? "defend2" : "defend"); 790 | #endif 791 | depthReached=false; 792 | bestMove=0; 793 | y=defend(); 794 | if(!bestMove){ 795 | y=alfabeta(1, 0, player1, 0); 796 | } 797 | #ifdef DEBUG 798 | if(y<=0 && !terminate) resulty=y; 799 | #endif 800 | if(!depthReached){ 801 | if(!carefulDefend) defendDone1=true; 802 | else defendDone=true; 803 | } 804 | if(y<0) carefulDefend=true; 805 | doMove(bestMove); 806 | } 807 | assert(dpth==0); 808 | } 809 | 810 | -------------------------------------------------------------------------------- /pbrain/pisktur.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2004-2006 Petr Lastovicka 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License. 6 | */ 7 | #include 8 | #pragma hdrstop 9 | #include 10 | #include 11 | #include "board.h" 12 | 13 | #define MATCH_SPARE 7 //how much is time spared for the rest of game 14 | #define TIMEOUT_PREVENT 3 //how much is alfabeta slower when the depth is increased 15 | 16 | const char *infotext="author=\"Petr Lastovicka\", version=\"7.6\", country=\"Czech Republic\", www=\"http://petr.lastovicka.sweb.cz\""; 17 | 18 | 19 | void brain_init() 20 | { 21 | if(width<5 || width>127 || height<5 || height>127){ 22 | pipeOut("ERROR size of the board"); 23 | return; 24 | } 25 | init(); 26 | pipeOut("OK"); 27 | } 28 | 29 | void brain_restart() 30 | { 31 | brain_init(); 32 | } 33 | 34 | int brain_takeback(int x, int y) 35 | { 36 | Psquare p=Square(x, y); 37 | if(p=boardk || !p->z) return 2; 38 | p->z=0; 39 | moves--; 40 | evaluate(p); 41 | lastMove=0; 42 | return 0; 43 | } 44 | 45 | static bool doMove0(Psquare p, int z) 46 | { 47 | if(p=boardk || p->z) return false; 48 | p->z= z; 49 | moves++; 50 | evaluate(p); 51 | lastMove=p; 52 | return true; 53 | } 54 | 55 | void brain_my(int x, int y) 56 | { 57 | if(!doMove0(Square(x, y), 1)){ 58 | pipeOut("ERROR my move [%d,%d]", x, y); 59 | } 60 | } 61 | 62 | void brain_opponents(int x, int y) 63 | { 64 | if(!doMove0(Square(x, y), 2)){ 65 | pipeOut("ERROR opponents's move [%d,%d]", x, y); 66 | } 67 | } 68 | 69 | void brain_block(int x, int y) 70 | { 71 | if(!doMove0(Square(x, y), 3)){ 72 | pipeOut("ERROR winning move [%d,%d]", x, y); 73 | } 74 | } 75 | 76 | bool doMove(Psquare p) 77 | { 78 | if(p=boardk || p->z) return false; 79 | if(!terminate || !resultMove) resultMove=p; 80 | return true; 81 | } 82 | 83 | void computer() 84 | { 85 | int i; 86 | DWORD t0, t1; 87 | Psquare p; 88 | 89 | resultMove=0; 90 | holdMove=0; 91 | highestEval=0; 92 | firstMove(); 93 | if(resultMove) return; 94 | 95 | for(p=boardb; pinWinMoves= winMoves1+MwinMoves; 97 | } 98 | UwinMoves=winMoves1; 99 | 100 | if(doMove(try4(0))){ 101 | #ifdef DEBUG 102 | print("win4"); 103 | #endif 104 | static bool w=false; 105 | if(!w && resultMove->h[0].pv=stopTime()) break; 131 | } 132 | 133 | if(terminate) depth-=2; 134 | pipeOut("DEBUG depth %d, nodes %d", depth, benchmark); 135 | #ifdef DEBUG 136 | if(resulty>0) print("win"); 137 | if(resulty<0) print("loss"); 138 | if(resulty==0) print("---"); 139 | printXY(60, 18, 130, "moves=%d", benchmark); 140 | #endif 141 | } 142 | 143 | DWORD stopTime() 144 | { 145 | return start_time + min(info_timeout_turn, info_time_left/MATCH_SPARE)-30; 146 | } 147 | 148 | void brain_turn() 149 | { 150 | computer(); 151 | do_mymove(resultMove->x, resultMove->y); 152 | } 153 | 154 | void brain_end() 155 | { 156 | } 157 | 158 | //---------------------------------------------------------------------- 159 | #ifdef DEBUG 160 | 161 | HWND wnd=FindWindow("Piskvork", 0); 162 | 163 | void vprint(int x, int y, int w, char *format, va_list va) 164 | { 165 | HDC dc= GetDC(wnd); 166 | RECT rc; 167 | rc.top=y; 168 | rc.bottom=y+16; 169 | rc.left= x - w/2; 170 | rc.right= rc.left + w; 171 | char buf[128]; 172 | int n = vsprintf(buf, format, va); 173 | SetTextAlign(dc, TA_CENTER); 174 | ExtTextOut(dc, x, y, ETO_OPAQUE, &rc, buf, n, 0); 175 | ReleaseDC(wnd, dc); 176 | } 177 | 178 | void printXY(int x, int y, int w, char *format, ...) 179 | { 180 | va_list va; 181 | va_start(va, format); 182 | vprint(x, y, w, format, va); 183 | va_end(va); 184 | } 185 | 186 | void print(char *format, ...) 187 | { 188 | RECT rc; 189 | GetClientRect(wnd, &rc); 190 | va_list va; 191 | va_start(va, format); 192 | vprint(rc.right*900/1000, 0, 80, format, va); 193 | va_end(va); 194 | } 195 | 196 | void paintSquare(Psquare p) 197 | { 198 | SendMessage(wnd, WM_APP+123, p->z, MAKELPARAM(p->x, p->y)); 199 | } 200 | 201 | void brain_eval(int x, int y) 202 | { 203 | Psquare p= Square(x, y); 204 | printXY(300, 0, 60, "%d,%d", p->h[0].pv, p->h[1].pv); 205 | printXY(300, 16, 60, "%d,%d", getEval(0, p), getEval(1, p)); 206 | printXY(300, 32, 60, "%d", getEval(p)); 207 | } 208 | 209 | 210 | #endif 211 | -------------------------------------------------------------------------------- /piskvork.h: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | (C) 2015 Tianyi Hao 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "lang.h" 19 | #include "taskbarprogress.h" 20 | 21 | #define myAI "pbrain-pela" 22 | #define fnHtmlTable "_table.html" 23 | #define fnResult "_result.txt" 24 | #define fnState "state.tur" 25 | #define fnStateTmp "turstate.tmp" 26 | #define fnMsg "messages.txt" 27 | #define fnOpenings "openings.txt" 28 | #define tmpOpenings "tmpOpening.txt" 29 | 30 | #define Mplayer 127 31 | #define NET_PLAYER 0 32 | 33 | typedef int Tsymbol; 34 | struct Tsquare; 35 | typedef Tsquare *Psquare; 36 | typedef char TfileName[256]; 37 | typedef char TdirName[224]; 38 | enum{ INFO_TIMEMOVE=1,INFO_TIMEGAME=2,INFO_MEMORY=4,INFO_RULE=8, 39 | INFO_GAMETYPE=16,INFO_TIMELEFT=32,INFO_DIR=64, INFO_ALL=0xffff }; 40 | 41 | struct Tsquare 42 | { 43 | Tsymbol z; //0=nothing, 1=X, 2=O, 3=outside 44 | Psquare nxt,pre;//linked list for undo, redo 45 | int x,y; //coordinates <1..width, 1..height> 46 | int time; //total thinking time 47 | Psquare winLineStart;//0 or beginning of a winning line 48 | int winLineDir; //direction offset of a winning line 49 | int foul; 50 | }; 51 | 52 | struct Txyp { 53 | int x,y; 54 | Psquare p; 55 | }; 56 | 57 | struct ThreadItem 58 | { 59 | ThreadItem *nxt,*prv; 60 | HANDLE h; 61 | DWORD id; 62 | ThreadItem(){ nxt=prv=this; } 63 | void init(){ nxt=prv=this; } 64 | ~ThreadItem(){ prv->nxt= nxt; nxt->prv= prv; } 65 | void append(ThreadItem *item); 66 | int isEmpty(){ return nxt==this; } 67 | }; 68 | 69 | struct Tplayer 70 | { 71 | int isComp; //0=human, 1=computer 72 | int timeMove; //time for a move (ms) 73 | int timeGame; //time for a game (s) 74 | int score; //number of wins 75 | int time; //total time (ms) 76 | int timeInit; //time of initialization, -1 during initialization, 0 after the first move 77 | int memory; //used memory (bytes) 78 | int turPlayerId; //number of player in tournament 79 | int Nmoves; //moves counter 80 | HANDLE process; //process handle 81 | DWORD processId; //process identifier 82 | HANDLE pipeToAI; //pipe handle 83 | HANDLE pipeFromAI;//pipe handle 84 | HANDLE dbgThread; //debugger thread (only pipe protocol) 85 | ThreadItem threads; //list of threads (only pipe protocol) 86 | Txyp *lastBoard; 87 | int DlastBoard; 88 | bool mustSendBoard; //whole board must be send to AI 89 | bool isTimeOut; //time out 90 | bool mustSendInfo; //INFO timeout_turn must be send to AI 91 | TfileName brain; //name of the EXE or ZIP file 92 | TfileName brain2; //name of the EXE file 93 | TdirName temp; //temporary folder 94 | 95 | int level(); 96 | void getName(char *buf, int n); 97 | char *getFilePart(); 98 | void rdBrain(FILE *f); 99 | int timeLeft(); 100 | void checkTimeOut(int currentTime); 101 | int move(); 102 | void getMem(); 103 | int createProcess(bool pipe, STARTUPINFO &si); 104 | void stopAI(); 105 | void startPipeAI(); 106 | bool notRunning(); 107 | void sendCommand(char *text,...); 108 | int sendInfo(int mask=INFO_ALL); 109 | void sendInfoCmd(char *key, int value); 110 | void sendInfoCmd(char *key, char *value); 111 | int storeBoard(); 112 | int readCommand(char *buf, int n); 113 | int brainChanged(); 114 | void wrMsg(char *s); 115 | void wrDebugLog(char *s); 116 | void openThreads(); 117 | 118 | FILE *infoDatFile; 119 | }; 120 | 121 | struct TturPlayer 122 | { 123 | int wins,losses,timeouts,errors,wins1,winsE,losses1; 124 | int time,memory,maxTurnTime; 125 | int Nmoves,Ngames; 126 | DWORD crc; 127 | int points; 128 | float ratio; 129 | }; 130 | 131 | struct TturCell 132 | { 133 | short start,notStart,error; 134 | int sum(){ return start+notStart+error; } 135 | }; 136 | 137 | struct Tclient { 138 | SOCKET socket; 139 | HANDLE thread; 140 | int player[2]; 141 | int repeatCount; 142 | int gameCount; 143 | int opening; 144 | u_long IP; 145 | void gameFinished(); 146 | }; 147 | 148 | struct PROCESS_MEMORY_COUNTERS { 149 | DWORD cb,PageFaultCount,PeakWorkingSetSize,WorkingSetSize, 150 | QuotaPeakPagedPoolUsage,QuotaPagedPoolUsage, 151 | QuotaPeakNonPagedPoolUsage,QuotaNonPagedPoolUsage, 152 | PagefileUsage,PeakPagefileUsage; 153 | }; 154 | typedef BOOL (__stdcall *TmemInfo)(HANDLE,PROCESS_MEMORY_COUNTERS*,DWORD); 155 | 156 | //----------------------------------------------------------------- 157 | extern int player,moves,width,height,tolerance,maxMemory,turNplayers,logDebug,logMessage,suspendAI,debugAI,port,turCurRepeat,autoBegin,turRepeat,turRecord,turDelay,priority,terminatee,turGamesCounter,turTieRepeat,turTieCounter,startMoves,errDelay,turOnlyLosses,turFormat,turGamesTotal,turOpening,invert,turNet,turRule,mx,my,height2,lastTurnTime[2],hardTimeOut,humanTimeOut,opening,logMoves,moveStart,coordStart,sameTime,turMatchRepeat,turLogMsg,infoEval,saveLock,debugPipe,ruleFive,continuous,undoRequest,netGameVersion,ignoreErrors,openingRandomShift1,openingRandomShiftT,affinity, Nopening, includeUndoMoves, soundNotification,cmdlineGameOutFileFormat; 158 | extern DWORD openingCRC; 159 | extern bool paused,finished,disableScore,isWin9X,isClient,isServer,isNetGame,isListening,turTimerAvail,levelChanged,cmdLineGame,autoBeginForce,tmpPsq; 160 | 161 | extern Psquare lastMove,board,boardb,boardk,hilited; 162 | extern DWORD lastTick; 163 | extern TturPlayer *turTable; 164 | extern TturCell *turCells; 165 | extern Tplayer players[2]; 166 | extern HANDLE thread,pipeThread,endGameEvent; 167 | extern char *title; 168 | extern TfileName fnstate,TahDat,PlochaDat,TimeOutsDat,MsgDat,InfoDat,cmdlineGameOutFile,cmdlineLogMsgOutFile,cmdlineLogPipeOutFile; 169 | extern TdirName fntur,tempDir,AIfolder,dataDir; 170 | extern char servername[128],turPlayerStr[50000],cmdGameEnd[512],cmdTurEnd[512]; 171 | extern CRITICAL_SECTION threadsLock,netLock,timerLock,infoLock; 172 | extern SYSTEMTIME turDateTime; 173 | extern HWND hWin,msgWnd,logDlg,resultDlg; 174 | extern SOCKET sock,sock_l; 175 | extern HMODULE psapi; 176 | extern TmemInfo getMemInfo; 177 | extern Tclient clients[Mplayer]; 178 | 179 | //----------------------------------------------------------------- 180 | 181 | int vmsg(char *caption, char *text, int btn, va_list v); 182 | int msg1(int btn, char *text, ...); 183 | void wrLog(char *text, ...); 184 | void vwrLog(char *text, va_list ap); 185 | void writeini(bool saveToolbar=true); 186 | char* parseCommandLine(); 187 | int close(FILE *f,char *fn); 188 | void show(HWND wnd); 189 | void paintSquare(Psquare p); 190 | void printLevel(); 191 | void printLevel1(); 192 | void printScore(); 193 | void printMoves(); 194 | void printTime(int pl); 195 | bool getWinLine(Psquare p, Psquare &p2); 196 | void printWinLine(Psquare p); 197 | void printFoul(Psquare p); 198 | void invalidate(); 199 | void hiliteLast(); 200 | void cancelHilite(); 201 | Psquare Square(int x,int y); 202 | void browseFolder(char *buf,HWND wnd,int item,char *txt); 203 | void drawTitle(); 204 | void setPriority(HANDLE process); 205 | unsigned rnd(unsigned n); 206 | TturCell *getCell(int loser,int winner); 207 | bool cmpExt(char *s,char *e); 208 | void delDir(char *path,bool d); 209 | int checkDir(HWND hDlg, int item); 210 | DWORD WINAPI threadLoop(LPVOID); 211 | DWORD WINAPI pipeThreadLoop(LPVOID); 212 | 213 | void turGetBrain(int i, char *out, int n, bool noPath); 214 | char *getTurDir(char *buf); 215 | void getMsgFn(char *fn); 216 | DWORD searchAI(const char *src, int n, char *dest, char **filePart); 217 | void wrMsgNewGame(int p1,int p2); 218 | void wrMessage(char *fmt,...); 219 | void executeCmd(char *cmd); 220 | int getNplayers(); 221 | //if filename is NULL, opening is read from filename define by fnOpenings, otherwise by the parameter 222 | void initOpeningTab(char* filename = NULL); 223 | void shutOpeningTab(); 224 | signed char* getOpening(int i); 225 | 226 | //parametres viz declaration of initOpeningTab and newGame 227 | void turStart(char* openingFileName = NULL); 228 | void turRestart(); 229 | void turNext(); 230 | bool turNext(Tclient *client); 231 | 232 | void turLocalNext(); 233 | void turResult(); 234 | void turGameFinished(); 235 | bool doMove(Psquare p); 236 | bool doMove1(Psquare p, int action=0); 237 | void init(); 238 | void resetScore(); 239 | 240 | //parameter forceAutoBegin force to use automatic opening even if global autoBegin is 0 241 | void newGame(int pl, bool openingEnabled, bool forceAutoBegin = false); 242 | void restartGame(); 243 | void resume(); 244 | void softPause(); 245 | void hardPause(); 246 | void killBrains(); 247 | int stopThinking(); 248 | void finishGame(int errCode); 249 | void turAddTime(); 250 | void saveRec(int errCode, bool includeUndoMoves); 251 | void saveRecTmp(int errCode); 252 | void wrGameResult(); 253 | void sendInfoEval(); 254 | void boardChanged(); 255 | bool notSuspended(); 256 | bool redo(); 257 | bool undo(); 258 | void setLevel(int l,int h); 259 | void switchPlayer(int h1, int h2); 260 | void savePsq(char *fn, int format, int errCode, bool includeUndoMoves); 261 | void openPsq(char *fn); 262 | DWORD getTickCount(); 263 | 264 | int initWSA(); 265 | int startListen(); 266 | int startConnection(); 267 | int clientStart(); 268 | void clientEnd(); 269 | void killClient(int i); 270 | void turAbort(); 271 | void stopListen(); 272 | void serverEnd(); 273 | int serverStart(); 274 | void clientFinished(); 275 | int calcCRC(const char *fn, DWORD &result); 276 | void wrState(); 277 | int rdState(); 278 | int rd(char *buf, int len); 279 | int rd1(); 280 | int rd2(); 281 | int rd4(); 282 | int wr(char *buf, int len); 283 | int wr1(SOCKET s, int i); 284 | int wr1(int i); 285 | 286 | int netGameStart(); 287 | void netGameEnd(); 288 | void newNetGame(LPARAM lP); 289 | void netGameMove(Psquare p); 290 | void netGameMsg(); 291 | void netGameUndo(); 292 | void netGameNew(); 293 | 294 | //----------------------------------------------------------------- 295 | 296 | #define nxtP(p,i) (p=(Psquare)(((char*)p)+(i*s))) 297 | #define prvP(p,i) (p=(Psquare)(((char*)p)-(i*s))) 298 | #define nxtS(p,s) ((Psquare)(((char*)p)+diroff[s])) 299 | 300 | template inline void amin(T &x,int m){ if(x inline void amax(T &x,int m){ if(x>m) x=m; } 302 | template inline void aminmax(T &x,int l,int h){ 303 | if(xh) x=h; 305 | } 306 | 307 | -------------------------------------------------------------------------------- /piskvork.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/piskvork.rc -------------------------------------------------------------------------------- /protocol.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2000-2015 Petr Lastovicka 3 | (C) 2015-2016 Tianyi Hao 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | #include "hdr.h" 19 | #pragma hdrstop 20 | #include 21 | #include 22 | #include "piskvork.h" 23 | 24 | int errDelay=20000; 25 | int debugPipe=0; 26 | static HANDLE startEvent, start2Event; 27 | CRITICAL_SECTION threadsLock, infoLock; 28 | 29 | const DWORD priorCnst[]={IDLE_PRIORITY_CLASS, 16384, 30 | NORMAL_PRIORITY_CLASS, 32768, HIGH_PRIORITY_CLASS}; 31 | 32 | //----------------------------------------------------------------- 33 | void getMsgFn(char *fn) 34 | { 35 | if(strlen(cmdlineLogMsgOutFile) > 0){ 36 | strcpy(fn, cmdlineLogMsgOutFile); 37 | return; 38 | } 39 | else if(isClient){ 40 | strcpy(fn, tempDir); 41 | } 42 | else{ 43 | getTurDir(fn); 44 | } 45 | strcat(fn, fnMsg); 46 | } 47 | 48 | void vwrMessage(char *fmt, va_list va) 49 | { 50 | FILE *f; 51 | TfileName fn; 52 | 53 | if(!isServer) vwrLog(fmt, va); 54 | if((!turNplayers || !turLogMsg) && strlen(cmdlineLogMsgOutFile) == 0) return; 55 | getMsgFn(fn); 56 | f=fopen(fn, "ab"); 57 | if(f){ 58 | vfprintf(f, fmt, va); 59 | fputc('\r', f); 60 | fputc('\n', f); 61 | fclose(f); 62 | } 63 | } 64 | 65 | void wrMessage(char *fmt, ...) 66 | { 67 | va_list va; 68 | va_start(va, fmt); 69 | vwrMessage(fmt, va); 70 | va_end(va); 71 | } 72 | 73 | void Tplayer::wrMsg(char *s) 74 | { 75 | if(players[0].isComp && players[1].isComp){ 76 | wrMessage("%2d) %s: %s", moves, getFilePart(), s); 77 | } 78 | else{ 79 | wrMessage("%s", s); 80 | } 81 | } 82 | 83 | void errMsg(char *text, ...) 84 | { 85 | int i1, i2; 86 | va_list va; 87 | 88 | va_start(va, text); 89 | if(turNplayers){ 90 | if(!disableScore){ 91 | disableScore=true; 92 | turTable[i1=players[player].turPlayerId].errors++; 93 | turTable[i2=players[1-player].turPlayerId].winsE++; 94 | getCell(i1, i2)->error++; 95 | win7TaskbarProgress.SetProgressState(hWin, TBPF_ERROR); 96 | turAddTime(); 97 | } 98 | vwrMessage(text, va); 99 | show(logDlg); 100 | turDelay+=errDelay; 101 | //Tomas Kubes: I didn' find error message code list, so i choose -2 to mean other code 102 | finishGame(-2); 103 | turDelay-=errDelay; 104 | } 105 | else if(cmdLineGame){ 106 | fprintf(stderr, text); 107 | finishGame(-2); 108 | } 109 | else{ 110 | softPause(); 111 | vmsg(title, text, MB_OK|MB_ICONERROR, va); 112 | } 113 | va_end(va); 114 | } 115 | 116 | bool Tplayer::notRunning() 117 | { 118 | DWORD e; 119 | return !process || !GetExitCodeProcess(process, &e) || e!=STILL_ACTIVE; 120 | } 121 | 122 | #define fort(l) for(ThreadItem *item=(l).nxt;\ 123 | item!=&(l); item=item->nxt) 124 | 125 | void ThreadItem::append(ThreadItem *item) 126 | { 127 | prv->nxt= item; 128 | item->prv= prv; 129 | prv= item; 130 | item->nxt= this; 131 | } 132 | 133 | void Tplayer::openThreads() 134 | { 135 | if(!process) return; 136 | static FARPROC pOpenThread; 137 | if(!pOpenThread){ 138 | pOpenThread= GetProcAddress(GetModuleHandle("kernel32.dll"), "OpenThread"); 139 | if(!pOpenThread) return; 140 | } 141 | THREADENTRY32 te; 142 | te.dwSize = sizeof(THREADENTRY32); 143 | HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 144 | if(h!=(HANDLE)-1){ 145 | if(Thread32First(h, &te)){ 146 | do{ 147 | if(te.th32OwnerProcessID==processId){ 148 | ThreadItem *t= new ThreadItem; 149 | t->h= ((HANDLE(WINAPI*)(DWORD, BOOL, DWORD))pOpenThread)(THREAD_SUSPEND_RESUME, 0, te.th32ThreadID); 150 | threads.append(t); 151 | } 152 | } while(Thread32Next(h, &te)); 153 | } 154 | CloseHandle(h); 155 | } 156 | } 157 | 158 | void setPriority(HANDLE process) 159 | { 160 | if(process){ 161 | aminmax(priority, 0, sizeA(priorCnst)); 162 | SetPriorityClass(process, priorCnst[priority]); 163 | } 164 | } 165 | 166 | int Tplayer::createProcess(bool pipe, STARTUPINFO &si) 167 | { 168 | //add quotes 169 | char *exe=brain2; 170 | char buf[sizeof(TfileName)+2]; 171 | if(exe[0]!='"'){ 172 | buf[0]='"'; 173 | size_t len = strlen(brain2); 174 | memcpy(buf+1, exe, len); 175 | buf[len+1]='"'; 176 | exe=buf; 177 | } 178 | //start process 179 | si.cb=sizeof(STARTUPINFO); 180 | si.wShowWindow = SW_HIDE; 181 | si.dwFlags |= STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK; 182 | PROCESS_INFORMATION pi; 183 | UINT m= SetErrorMode((ignoreErrors || isClient) ? SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX : 0); 184 | if(!CreateProcess(0, exe, 0, 0, pipe ? TRUE : FALSE, 185 | 0, 0, tempDir, &si, &pi)){ 186 | DWORD err= GetLastError(); 187 | if(err==ERROR_FILE_NOT_FOUND) errMsg(lng(739, "File not found: %s"), brain2); 188 | else errMsg(lng(806, "Can't create process (error %d)"), err); 189 | return 1; 190 | } 191 | SetErrorMode(m); 192 | CloseHandle(pi.hThread); 193 | process=pi.hProcess; 194 | processId=pi.dwProcessId; 195 | setPriority(process); 196 | //setting affinity (change to version 8.4 by Tomas Kubes) 197 | if(affinity != -1){ 198 | BOOL res = SetProcessAffinityMask(process, (DWORD_PTR)affinity); 199 | if(res == 0){ 200 | //Error setting affinity mask!! 201 | errMsg(lng(820, "Error setting affinity mask! (error %d)"), GetLastError()); 202 | return 1; 203 | } 204 | } 205 | return 0; 206 | } 207 | 208 | 209 | //create pipes and start AI process 210 | void Tplayer::startPipeAI() 211 | { 212 | HANDLE h, hChildStdOut, hChildStdIn, hChildStdErr; 213 | 214 | // Set up the security attributes struct 215 | SECURITY_ATTRIBUTES sa; 216 | sa.nLength= sizeof(SECURITY_ATTRIBUTES); 217 | sa.lpSecurityDescriptor = NULL; 218 | sa.bInheritHandle = TRUE; 219 | 220 | // Create the AI output pipe 221 | if(!CreatePipe(&h, &hChildStdOut, &sa, 0)) errMsg("CreatePipe failed"); 222 | 223 | if(!DuplicateHandle(GetCurrentProcess(), h, 224 | GetCurrentProcess(), &pipeFromAI, 225 | 0, FALSE, DUPLICATE_SAME_ACCESS)) errMsg("DuplicateHandle failed"); 226 | CloseHandle(h); 227 | 228 | // Create the AI input pipe 229 | if(!CreatePipe(&hChildStdIn, &h, &sa, width*height*10)) errMsg("CreatePipe failed"); 230 | 231 | if(!DuplicateHandle(GetCurrentProcess(), h, 232 | GetCurrentProcess(), &pipeToAI, 233 | 0, FALSE, DUPLICATE_SAME_ACCESS)) errMsg("DuplicateHandle failed"); 234 | CloseHandle(h); 235 | 236 | if(!DuplicateHandle(GetCurrentProcess(), hChildStdOut, 237 | GetCurrentProcess(), &hChildStdErr, 238 | 0, TRUE, DUPLICATE_SAME_ACCESS)) errMsg("DuplicateHandle failed"); 239 | 240 | STARTUPINFO si; 241 | memset(&si, 0, sizeof(si)); 242 | si.dwFlags = STARTF_USESTDHANDLES; 243 | si.hStdInput = hChildStdIn; 244 | si.hStdOutput = hChildStdOut; 245 | si.hStdError = hChildStdErr; 246 | createProcess(true, si); 247 | CloseHandle(hChildStdIn); 248 | CloseHandle(hChildStdOut); 249 | CloseHandle(hChildStdErr); 250 | wrDebugLog("______Process started______"); 251 | } 252 | 253 | DWORD WINAPI pipeThreadLoop(void *param) 254 | { 255 | DEBUG_EVENT e; 256 | ThreadItem *t; 257 | Tplayer *player= (Tplayer*)param; 258 | DWORD cont; 259 | bool done=false; 260 | 261 | //create brain's process 262 | player->startPipeAI(); 263 | ResetEvent(start2Event); 264 | SetEvent(startEvent); 265 | //wait until brain sends OK 266 | //(DebugActiveProcess must not be called immediately after CreateProcess) 267 | if(WaitForInputIdle(player->process, 5000)==WAIT_FAILED) Sleep(800); else Sleep(200); 268 | WaitForSingleObject(start2Event, INFINITE); 269 | if(player->notRunning()) return 1; 270 | 271 | if(!DebugActiveProcess(player->processId)) return 2; 272 | do{ 273 | if(!WaitForDebugEvent(&e, INFINITE)) return 3; 274 | cont=DBG_CONTINUE; 275 | EnterCriticalSection(&threadsLock); 276 | switch(e.dwDebugEventCode){ 277 | case EXCEPTION_DEBUG_EVENT: 278 | if(e.u.Exception.ExceptionRecord.ExceptionCode!=STATUS_BREAKPOINT){ 279 | cont=DBG_EXCEPTION_NOT_HANDLED; 280 | } 281 | break; 282 | case CREATE_PROCESS_DEBUG_EVENT: 283 | CloseHandle(e.u.CreateProcessInfo.hFile); 284 | if(isWin9X) CloseHandle(e.u.CreateProcessInfo.hProcess); 285 | t=new ThreadItem; 286 | t->h= e.u.CreateProcessInfo.hThread; 287 | t->id= e.dwThreadId; 288 | player->threads.append(t); 289 | break; 290 | case CREATE_THREAD_DEBUG_EVENT: 291 | t=new ThreadItem; 292 | t->h= e.u.CreateThread.hThread; 293 | t->id= e.dwThreadId; 294 | player->threads.append(t); 295 | break; 296 | case EXIT_THREAD_DEBUG_EVENT: 297 | { 298 | fort(player->threads){ 299 | if(item->id==e.dwThreadId){ 300 | if(isWin9X) CloseHandle(item->h); 301 | delete item; 302 | break; 303 | } 304 | } 305 | break; 306 | } 307 | case EXIT_PROCESS_DEBUG_EVENT: 308 | while(player->threads.nxt!=&player->threads){ 309 | ThreadItem *item= player->threads.nxt; 310 | if(isWin9X) CloseHandle(item->h); 311 | delete item; 312 | } 313 | done=true; 314 | break; 315 | case LOAD_DLL_DEBUG_EVENT: 316 | CloseHandle(e.u.LoadDll.hFile); 317 | break; 318 | } 319 | LeaveCriticalSection(&threadsLock); 320 | ContinueDebugEvent(e.dwProcessId, e.dwThreadId, cont); 321 | } while(!done); 322 | return 0; 323 | } 324 | 325 | bool cmpExt(char *s, char *e) 326 | { 327 | int len=(int)strlen(s)-4; 328 | return len>0 && s[len]=='.' && _stricmp(s+len+1, e)==0; 329 | } 330 | 331 | struct TchooseExe { 332 | char *exe; 333 | int n; 334 | char *zip; 335 | int eval; 336 | void find(const char *path); 337 | }; 338 | 339 | void TchooseExe::find(const char *path) 340 | { 341 | HANDLE h; 342 | int e; 343 | char *f, *s; 344 | WIN32_FIND_DATA fd; 345 | char oldDir[256]; 346 | char name[MAX_PATH]; 347 | 348 | GetCurrentDirectory(sizeof(oldDir), oldDir); 349 | SetCurrentDirectory(path); 350 | h = FindFirstFile("*", &fd); 351 | if(h!=INVALID_HANDLE_VALUE){ 352 | do{ 353 | if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ 354 | if(fd.cFileName[0]!='.') find(fd.cFileName); 355 | continue; 356 | } 357 | e=0; 358 | if(cmpExt(fd.cFileName, "exe")) e=1000; 359 | else if(cmpExt(fd.cFileName, "com")) e=900; 360 | strcpy(name, fd.cFileName); 361 | _strupr(name); 362 | if(!strcmp(name, "RENJU.BOOK")){ 363 | TfileName buf; 364 | sprintf(buf, "%srenju.book", tempDir); 365 | CopyFile(name, buf, FALSE); 366 | } 367 | s=strchr(name, 0)-4; 368 | if(s>name && *s=='.') *s=0; 369 | if(!strcmp(name, zip)) e+=200; 370 | else if(strstr(name, zip)) e+=50; 371 | if(e>eval){ 372 | eval=e; 373 | GetFullPathName(fd.cFileName, n, exe, &f); 374 | } 375 | } while(FindNextFile(h, &fd)); 376 | } 377 | FindClose(h); 378 | SetCurrentDirectory(oldDir); 379 | } 380 | 381 | DWORD searchAI(const char *src, int n, char *dest, char **filePart) 382 | { 383 | DWORD d; 384 | char *fp; 385 | TfileName fn; 386 | 387 | d=SearchPath(0, src, ".exe", n, dest, &fp); 388 | if(!d) d=SearchPath(0, src, ".zip", n, dest, &fp); 389 | if(!d && cutPath(src)==src && strlen(src)=sizeof(buf)-L-1) return 14; 411 | if(d==0) return 11; 412 | if(cmpExt(filePart, "zip")){ 413 | wrLog(lng(865, "Extracting %s"), filePart); 414 | //create temporary folder 415 | workDir=temp; 416 | CreateDirectory(workDir, 0); 417 | delDir(workDir, false); 418 | //run external unzip 419 | memcpy(buf, "unzip -qq -o \"", L); 420 | strcat(filePart, "\""); 421 | STARTUPINFO si; 422 | memset(&si, 0, sizeof(si)); 423 | si.cb= sizeof(si); 424 | si.dwFlags= STARTF_USESHOWWINDOW; 425 | si.wShowWindow= SW_HIDE; 426 | PROCESS_INFORMATION pi; 427 | if(CreateProcess(0, buf, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, workDir, &si, &pi)==0){ 428 | return 12; 429 | } 430 | CloseHandle(pi.hThread); 431 | WaitForSingleObject(pi.hProcess, 50000); 432 | CloseHandle(pi.hProcess); 433 | strchr(filePart, 0)[-1]=0; 434 | //find exe file in destination folder 435 | che.eval=-1; 436 | che.exe=brain2; 437 | che.n=sizeof(brain2); 438 | che.zip=filePart; 439 | strchr(che.zip, 0)[-4]=0; 440 | _strupr(filePart); 441 | che.find(workDir); 442 | if(che.eval<0) return 13; 443 | } 444 | else{ 445 | strcpy(brain2, buf+L); 446 | } 447 | return 0; 448 | } 449 | 450 | char *Tplayer::getFilePart() 451 | { 452 | return cutPath(brain); 453 | } 454 | 455 | //kill AI process and close pipes 456 | void Tplayer::stopAI() 457 | { 458 | if(pipeToAI){ 459 | sendCommand("END"); 460 | CloseHandle(pipeToAI); 461 | pipeToAI=0; 462 | } 463 | if(process){ 464 | if(WaitForSingleObject(process, pipeFromAI ? 700 : 20)!=WAIT_OBJECT_0){ 465 | TerminateProcess(process, 0); 466 | } 467 | CloseHandle(process); 468 | process=0; 469 | } 470 | if(pipeFromAI){ 471 | CloseHandle(pipeFromAI); 472 | pipeFromAI=0; 473 | } 474 | if(dbgThread){ 475 | WaitForSingleObject(dbgThread, 3000); 476 | CloseHandle(dbgThread); 477 | dbgThread=0; 478 | } 479 | mustSendBoard=true; 480 | DlastBoard=0; 481 | } 482 | 483 | void Tplayer::wrDebugLog(char *s) 484 | { 485 | TfileName fn; 486 | char *t; 487 | FILE *f; 488 | 489 | if(((debugPipe && !turNplayers) || strlen(cmdlineLogPipeOutFile) > 0)&& *s){ 490 | if(strlen(cmdlineLogPipeOutFile) > 0){ 491 | strcpy(fn, cmdlineLogPipeOutFile); 492 | strcat(fn, cutPath(brain2)); 493 | strcat(fn, ".log"); 494 | } 495 | else{ 496 | strcpy(fn, brain2); 497 | t=strchr(fn, 0); 498 | while(t>fn && *t!='.') t--; 499 | strcpy(t, ".log"); 500 | } 501 | f=fopen(fn, "at"); 502 | if(f){ 503 | fputs(s, f); 504 | fputc('\n', f); 505 | fclose(f); 506 | } 507 | } 508 | } 509 | 510 | //read one line from the pipe 511 | int Tplayer::readCommand(char *buf, int n) 512 | { 513 | char *p; 514 | 515 | do{ 516 | for(p=buf;;){ 517 | DWORD r; 518 | if(!ReadFile(pipeFromAI, p, 1, &r, 0) || !r){ 519 | *p=0; 520 | return 1; 521 | } 522 | if(*p=='\r' || *p=='\n') break; 523 | if(p 0) wrMsg(buf+8); 533 | p=buf; 534 | } 535 | } while(p==buf); 536 | return 0; 537 | } 538 | 539 | //write one line to the pipe 540 | void Tplayer::sendCommand(char *text, ...) 541 | { 542 | if(!pipeToAI) return; 543 | char buf[256]; 544 | va_list v; 545 | va_start(v, text); 546 | int i=vsprintf(buf, text, v); 547 | buf[i++]='\r'; 548 | buf[i++]='\n'; 549 | buf[i]=0; 550 | DWORD w; 551 | WriteFile(pipeToAI, buf, i, &w, 0); 552 | if(strncmp(buf, "INFO eval", 9)){ 553 | buf[i-2]=0; 554 | wrDebugLog(buf); 555 | } 556 | va_end(v); 557 | } 558 | 559 | void Tplayer::sendInfoCmd(char *key, int value) 560 | { 561 | if(infoDatFile){ 562 | fprintf(infoDatFile, "%s %d\n", key, value); 563 | } 564 | else{ 565 | sendCommand("INFO %s %d", key, value); 566 | } 567 | } 568 | 569 | void Tplayer::sendInfoCmd(char *key, char *value) 570 | { 571 | if(infoDatFile){ 572 | fprintf(infoDatFile, "%s %s\n", key, value); 573 | } 574 | else{ 575 | sendCommand("INFO %s %s", key, value); 576 | } 577 | } 578 | 579 | int Tplayer::sendInfo(int mask) 580 | { 581 | int result=0; 582 | 583 | EnterCriticalSection(&infoLock); 584 | infoDatFile=0; 585 | if(!pipeToAI){ 586 | if(this!=&players[player]){ result=9; goto lend; } 587 | infoDatFile= fopen(InfoDat, "wt"); 588 | if(!infoDatFile){ result=7; goto lend; } 589 | mask=INFO_ALL; 590 | } 591 | if(mask & INFO_MEMORY) sendInfoCmd("max_memory", maxMemory<<20); 592 | if(mask & INFO_TIMEGAME) sendInfoCmd("timeout_match", timeGame*1000); 593 | if(mask & INFO_TIMEMOVE){ 594 | sendInfoCmd("timeout_turn", timeMove); 595 | mustSendInfo=false; 596 | } 597 | if(mask & INFO_GAMETYPE){ 598 | int i= players[0].isComp && players[1].isComp; 599 | if(turNplayers) i= isClient ? 3 : 2; 600 | sendInfoCmd("game_type", i); 601 | } 602 | if((mask & INFO_RULE)/* && !turNplayers*/){ 603 | //I dont why there is !turNplayers in condition, 604 | //but that is the reason why rule 1 is not send in the tournament 605 | if(ruleFive < 2) { 606 | sendInfoCmd("rule", ruleFive|(continuous<<1)); 607 | } 608 | else { 609 | sendInfoCmd("rule", 4|(continuous<<1)); 610 | } 611 | } 612 | if(mask & INFO_TIMELEFT) sendInfoCmd("time_left", timeLeft()); 613 | if((mask & INFO_DIR) && dataDir[0] && !isClient){ 614 | sendInfoCmd("folder", dataDir); 615 | } 616 | 617 | if(!pipeToAI){ 618 | if(fclose(infoDatFile)) result=8; 619 | } 620 | lend: 621 | LeaveCriticalSection(&infoLock); 622 | return result; 623 | } 624 | 625 | //write the board and info to files (only for FILE protocol) 626 | int Tplayer::storeBoard() 627 | { 628 | FILE *f= fopen(PlochaDat, "wt"); 629 | if(!f) return 1; 630 | for(int y=0; ywinLineDir ? '#' : "-xo-"[p->z], f); 634 | } 635 | fputc('\n', f); 636 | } 637 | if(fclose(f)) return 2; 638 | 639 | f= fopen(TahDat, "wt"); 640 | if(!f) return 3; 641 | fprintf(f, "%c\n", player ? 'o' : 'x'); 642 | if(fclose(f)) return 4; 643 | 644 | timeInit=0; 645 | f= fopen(TimeOutsDat, "wt"); 646 | if(!f) return 5; 647 | fprintf(f, "%d\n%d\n", timeMove/1000, timeLeft()); 648 | if(fclose(f)) return 6; 649 | 650 | f= fopen(MsgDat, "w"); 651 | fclose(f); 652 | 653 | return sendInfo(); 654 | } 655 | 656 | //send the last move to AI, and wait for the AI move 657 | //runs in a worker thread 658 | int Tplayer::move() 659 | { 660 | char buf[8000]; 661 | int x, y, err, i; 662 | DWORD threadId; 663 | Psquare p; 664 | FILE *f; 665 | Txyp *t; 666 | char *s; 667 | bool restarted; 668 | 669 | timeInit=-1; 670 | if(!isComp) return 0; 671 | if(finished || terminatee){ 672 | softPause(); 673 | return 1; 674 | } 675 | if(process && notRunning()){ 676 | stopAI(); 677 | } 678 | if(!brain2[0]){ 679 | err=brainChanged(); 680 | if(err==11) errMsg(lng(739, "File not found: %s"), brain); 681 | if(err==12) errMsg(lng(811, "Can't run unzip")); 682 | if(err==13) errMsg(lng(812, "Cannot extract files from %s"), brain); 683 | if(err==14) errMsg("File path is too long"); 684 | if(err) return err; 685 | } 686 | if(!_strnicmp(cutPath(brain2), "pbrain-", 7)){ 687 | if(mustSendBoard && moves<=DlastBoard+1 && moves>1){ 688 | for(i=moves-2, p=lastMove->nxt; i>=0; i--, p=p->nxt){ 689 | t=&lastBoard[i]; 690 | if(t->x!=p->x || t->y!=p->y || t->p!=p->winLineStart) goto l1; //board has changed 691 | } 692 | for(i=DlastBoard-1; i>=moves-1; i--){ 693 | if(lastBoard[i].p) goto l1; //TAKEBACK cannot remove winning lines 694 | } 695 | for(i=DlastBoard-1; i>=moves-1; i--){ 696 | sendCommand("TAKEBACK %d,%d", lastBoard[i].x-1, lastBoard[i].y-1); 697 | readCommand(buf, sizeof(buf)); 698 | if(terminatee) return 9; //time out 699 | if(_stricmp(buf, "OK")) goto l1; //not supported 700 | } 701 | mustSendBoard=false; 702 | } 703 | if(mustSendBoard){ 704 | l1: 705 | if(!process && !pipeToAI && !dbgThread){ 706 | //create process and pipes 707 | if(!debugAI || !suspendAI){ 708 | startPipeAI(); 709 | } 710 | else{ 711 | ResetEvent(startEvent); 712 | dbgThread=CreateThread(0, 0, pipeThreadLoop, this, 0, &threadId); 713 | WaitForSingleObject(startEvent, INFINITE); 714 | } 715 | if(!process){ 716 | SetEvent(start2Event); 717 | stopAI(); 718 | return 2; 719 | } 720 | if(width==height) 721 | sendCommand("START %d", width); 722 | else 723 | sendCommand("RECTSTART %d,%d", width, height); 724 | restarted=false; 725 | } 726 | else{ 727 | sendCommand("RESTART"); 728 | restarted=true; 729 | } 730 | readCommand(buf, sizeof(buf)); 731 | SetEvent(start2Event); 732 | if(terminatee) return 9; 733 | if(_stricmp(buf, "OK")){ 734 | if(restarted){ stopAI(); goto l1; } 735 | if((width!=20 || height!=20) && !turNplayers && 736 | (!_strnicmp(buf, "UNKNOWN", 7) && width!=height || 737 | !_strnicmp(buf, "ERROR", 5) && strstr(buf, "20"))){ 738 | softPause(); 739 | PostMessage(hWin, WM_COMMAND, 993, 0); 740 | } 741 | else{ 742 | errMsg(lng(808, "%s did not answer OK to the START command\r\n%s"), 743 | getFilePart(), buf); 744 | stopAI(); 745 | } 746 | return 2; 747 | } 748 | mustSendBoard=false; 749 | timeInit= getTickCount()-lastTick; 750 | sendInfo(); 751 | if(moves==0){ 752 | sendCommand("BEGIN"); 753 | } 754 | else if(moves==1){ 755 | sendCommand("TURN %d,%d", lastMove->x-1, lastMove->y-1); 756 | } 757 | else{ 758 | EnterCriticalSection(&infoLock); 759 | sendCommand("BOARD"); 760 | for(p=lastMove; p->nxt; p=p->nxt); 761 | for(;;){ 762 | assert(p->z==1 || p->z==2); 763 | sendCommand("%d,%d,%d", p->x-1, p->y-1, p->winLineDir ? 3 : 764 | (this==&players[0] ? p->z : 3-p->z)); 765 | if(p==lastMove) break; 766 | p=p->pre; 767 | } 768 | sendCommand("DONE"); 769 | LeaveCriticalSection(&infoLock); 770 | } 771 | } 772 | else{ 773 | assert(moves>0); 774 | timeInit=0; 775 | if(mustSendInfo) sendInfo(INFO_TIMEMOVE); 776 | sendInfo(INFO_TIMELEFT); 777 | sendCommand("TURN %d,%d", lastMove->x-1, lastMove->y-1); 778 | } 779 | //wait for AI turn 780 | for(;;){ 781 | readCommand(buf, sizeof(buf)); 782 | if(terminatee) return 9; 783 | if(_strnicmp(buf, "suggest ", 8)){ 784 | if(sscanf(buf, "%d,%d", &x, &y)!=2){ 785 | if(!buf[0] && notRunning()){ 786 | errMsg(lng(818, "%s has exited unexpectedly !"), getFilePart()); 787 | } 788 | else{ 789 | errMsg(lng(804, "%s has not returned coordinates x,y\r\n%s"), 790 | getFilePart(), buf); 791 | } 792 | stopAI(); 793 | return 3; 794 | } 795 | break; 796 | } 797 | sendCommand("PLAY %s", buf+8); 798 | } 799 | getMem(); 800 | } 801 | else{ 802 | //write the board to file plocha.dat 803 | if(storeBoard()){ 804 | errMsg(lng(733, "The board cannot be written to %s"), PlochaDat); 805 | return 8; 806 | } 807 | //start process and wait until it is finished 808 | STARTUPINFO si; 809 | memset(&si, 0, sizeof(si)); 810 | if(createProcess(false, si)) return 4; 811 | WaitForSingleObject(process, INFINITE); 812 | getMem(); 813 | if(process){ 814 | CloseHandle(process); 815 | process=0; 816 | } 817 | if(terminatee) return 9; 818 | 819 | //read messages 820 | f= fopen(MsgDat, "rt"); 821 | if(f){ 822 | while(fgets(buf, sizeof(buf), f)){ 823 | s=strchr(buf, '\n'); 824 | if(s) *s=0; 825 | wrMsg(buf); 826 | } 827 | fclose(f); 828 | } 829 | //read result from file tah.dat 830 | f= fopen(TahDat, "r"); 831 | if(!f){ 832 | errMsg(lng(805, "%s has not created file %s"), getFilePart(), TahDat); 833 | return 5; 834 | } 835 | i=fscanf(f, "%d,%d", &x, &y); 836 | fclose(f); 837 | if(i!=2){ 838 | errMsg(lng(809, "%s has not returned coordinates x,y"), 839 | getFilePart()); 840 | return 6; 841 | } 842 | } 843 | err=0; 844 | EnterCriticalSection(&timerLock); 845 | if(finished){ 846 | err=15; //timeout 847 | } 848 | else if(memory>(maxMemory<<20) && turNplayers){ 849 | err=16; 850 | } 851 | else{ 852 | //draw a square, increment moves, switch players 853 | if(!doMove(Square(x, y))){ 854 | err=7; 855 | } 856 | } 857 | //remember the board 858 | delete[] lastBoard; 859 | if(moves==0 || lastMove->winLineStart || lastMove->foul || err){ 860 | DlastBoard=0; 861 | lastBoard=0; 862 | } 863 | else{ 864 | lastBoard= new Txyp[DlastBoard=moves]; 865 | for(i=moves-1, p=lastMove; i>=0; i--, p=p->nxt){ 866 | t=&lastBoard[i]; 867 | t->x= p->x; 868 | t->y= p->y; 869 | t->p= p->winLineStart; 870 | } 871 | } 872 | LeaveCriticalSection(&timerLock); 873 | if(err==16) errMsg(lng(813, "%s allocated %u kB of memory"), 874 | getFilePart(), memory>>10); 875 | if(err==7) errMsg(lng(807, "%s returned invalid move [%d,%d]"), 876 | getFilePart(), x, y); 877 | return err; 878 | } 879 | 880 | //worker thread main function 881 | DWORD WINAPI threadLoop(LPVOID) 882 | { 883 | startEvent= CreateEvent(0, TRUE, FALSE, 0); 884 | start2Event= CreateEvent(0, TRUE, FALSE, 0); 885 | //infinite loop 886 | for(;;){ 887 | if(paused || !players[player].isComp) SuspendThread(thread); 888 | //suspend opponent 889 | Tplayer *p= &players[1-player]; 890 | int d = suspendAI; 891 | bool dbg = (p->dbgThread!=0); 892 | if(d){ 893 | EnterCriticalSection(&threadsLock); 894 | if(!dbg) p->openThreads(); 895 | fort(p->threads) SuspendThread(item->h); 896 | LeaveCriticalSection(&threadsLock); 897 | } 898 | //move 899 | int errCode = players[player].move(); 900 | 901 | //save continuous results in tournament 902 | if(tmpPsq && turNplayers > 0) saveRecTmp(errCode); 903 | 904 | //resume opponent 905 | if(d){ 906 | EnterCriticalSection(&threadsLock); 907 | fort(p->threads) ResumeThread(item->h); 908 | if(!dbg){ 909 | while(!p->threads.isEmpty()){ 910 | ThreadItem *t= p->threads.nxt; 911 | CloseHandle(t->h); 912 | delete t; 913 | } 914 | } 915 | LeaveCriticalSection(&threadsLock); 916 | } 917 | } 918 | } 919 | -------------------------------------------------------------------------------- /renju/Class_line.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2012-2015 Tianyi Hao 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #include 18 | #include 19 | #include "game.h" 20 | #define COMB(X, Y) (((X)<<8)|((Y)-2)) 21 | #define COMC(X, Y, Z) COMB(COMB((X), (Y)), (Z)) 22 | #define COMD(X, Y, Z, W) COMB(COMC((X), (Y), (Z)), (W)) 23 | //#define COME(X, Y, Z, W, V) COMB(COMD((X), (Y), (Z), (W)), (V)) 24 | using namespace std; 25 | 26 | extern int nosix; 27 | extern int fflag; 28 | 29 | game::game() 30 | { 31 | int i,j; 32 | for(i=0;i. 16 | */ 17 | #include 18 | #include 19 | #include "game.h" 20 | using namespace std; 21 | #define GA(x) ((x)&0xff) 22 | #define GB(x) (((x)&0xff00)>>8) 23 | 24 | int line4v::foulr(int x,int y) 25 | { 26 | if(fflag==0) 27 | { 28 | return 0; 29 | } 30 | 31 | int sign=0; 32 | if(x1[x][y]==0) 33 | { 34 | sign=1; 35 | x1[x][y]=1; 36 | x2[y][x]=1; 37 | x3[x+y][y]=1; 38 | x4[S-1-y+x][S-1-y]=1; 39 | } 40 | if(x1[x][y]==-1) 41 | { 42 | return 0; 43 | } 44 | if(A5(x,y)) 45 | { 46 | x1[x][y]-=sign; 47 | x2[y][x]-=sign; 48 | x3[x+y][y]-=sign; 49 | x4[S-1-y+x][S-1-y]-=sign; 50 | 51 | return 0; 52 | } 53 | if(double4(x,y)) 54 | { 55 | x1[x][y]-=sign; 56 | x2[y][x]-=sign; 57 | x3[x+y][y]-=sign; 58 | x4[S-1-y+x][S-1-y]-=sign; 59 | return 2; 60 | } 61 | if(double3r(x,y)) 62 | { 63 | x1[x][y]-=sign; 64 | x2[y][x]-=sign; 65 | x3[x+y][y]-=sign; 66 | x4[S-1-y+x][S-1-y]-=sign; 67 | return 1; 68 | } 69 | if(overline(x,y)) 70 | { 71 | x1[x][y]-=sign; 72 | x2[y][x]-=sign; 73 | x3[x+y][y]-=sign; 74 | x4[S-1-y+x][S-1-y]-=sign; 75 | return 3; 76 | } 77 | x1[x][y]-=sign; 78 | x2[y][x]-=sign; 79 | x3[x+y][y]-=sign; 80 | x4[S-1-y+x][S-1-y]-=sign; 81 | 82 | return 0; 83 | } 84 | 85 | int line4v::B4p(int x,int y) 86 | { 87 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 88 | int p1=y,p2=x,p3=y,p4=S-1-y; 89 | int count=0; 90 | int count1,count2,count3,count4; 91 | count1=l1.B4p(p1); 92 | count2=l2.B4p(p2); 93 | count3=l3.B4p(p3); 94 | count4=l4.B4p(p4); 95 | if((count1|count2|count3|count4)>=(1<<16)) 96 | { 97 | if(count1>=(1<<16)) 98 | { 99 | return (1<<24)|((count1&255)*S+x); 100 | } 101 | else if(count2>=(1<<16)) 102 | { 103 | return (1<<24)|(y*S+(count2&255)); 104 | } 105 | else if(count3>=(1<<16)) 106 | { 107 | return (1<<24)|((count3&255)*(S-1)+x+y); 108 | } 109 | else 110 | { 111 | return (1<<24)|(((S-1)-(count4&255))*(S+1)+x-y); 112 | } 113 | } 114 | switch((!!(count1))+((!!(count2))<<1)+((!!(count3))<<2)+((!!(count4))<<3)) 115 | { 116 | case 0: return 0;break; 117 | case 1: 118 | return (1<<16)|((count1&255)*S+x); 119 | break; 120 | case 2: 121 | return (1<<16)|(y*S+(count2&255)); 122 | break; 123 | case 4: 124 | return (1<<16)|((count3&255)*(S-1)+x+y); 125 | break; 126 | case 8: 127 | return (1<<16)|(((S-1)-(count4&255))*(S+1)+x-y); 128 | break; 129 | case 3: 130 | case 5: 131 | case 7: 132 | case 9: 133 | case 11: 134 | case 13: 135 | case 15: 136 | return (1<<24)|((count1&255)*S+x); 137 | break; 138 | case 6: 139 | case 10: 140 | case 14: 141 | return (1<<24)|(y*S+(count2&255)); 142 | break; 143 | case 12: 144 | return (1<<24)|((count3&255)*(S-1)+x+y); 145 | break; 146 | } 147 | return -1; 148 | } 149 | 150 | int line4v::B4p(int c) 151 | { 152 | int i; 153 | int j; 154 | int count=0; 155 | 156 | for(i=0;i=(1<<24)) 164 | { 165 | return temp; 166 | } 167 | if(temp) 168 | { 169 | if(count&&count!=temp) 170 | { 171 | return (1<<24)|temp; 172 | } 173 | else 174 | { 175 | count=temp; 176 | } 177 | } 178 | } 179 | } 180 | } 181 | return count; 182 | } 183 | 184 | int line4v::A4(int x,int y) 185 | { 186 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 187 | int p1=y,p2=x,p3=y,p4=S-1-y; 188 | if(l1.A4(p1)) 189 | { 190 | return 1; 191 | } 192 | if(l2.A4(p2)) 193 | { 194 | return 1; 195 | } 196 | if(l3.A4(p3)) 197 | { 198 | return 1; 199 | } 200 | if(l4.A4(p4)) 201 | { 202 | return 1; 203 | } 204 | return 0; 205 | } 206 | 207 | line4v::line4v(game& board) 208 | { 209 | if(&board==NULL) 210 | { 211 | return; 212 | } 213 | int i,j; 214 | 215 | for(i=0;i=2) 283 | { 284 | return 1; 285 | } 286 | return 0; 287 | } 288 | 289 | int line4v::double4(int x,int y) 290 | { 291 | if(B4(x,y)>=2) 292 | { 293 | return 1; 294 | } 295 | return 0; 296 | } 297 | 298 | int line4v::overline(int x,int y) 299 | { 300 | if(A6(x,y)) 301 | { 302 | return 1; 303 | } 304 | return 0; 305 | } 306 | 307 | int line4v::A3r(int x,int y) 308 | { 309 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 310 | int p1=y,p2=x,p3=y,p4=S-1-y; 311 | int count=0; 312 | int ll1=l1.A3(p1); 313 | int ll2=l2.A3(p2); 314 | int ll3=l3.A3(p3); 315 | int ll4=l4.A3(p4); 316 | 317 | if(ll1) 318 | { 319 | if(ll1<65536) 320 | { 321 | int r=GA(ll1); 322 | // cout << r << '\n' ; 323 | if(x1[x][y]==1&&(foulr(x,r)||A5test(x,r))) 324 | { 325 | count--; 326 | } 327 | count++; 328 | } 329 | else 330 | { 331 | int r1=GA(ll1); 332 | int r2=GB(ll1); 333 | if(x1[x][y]==1&&(foulr(x,r1)||A5test(x,r1))&&(foulr(x,r2)||A5test(x,r2))) 334 | { 335 | count--; 336 | } 337 | count++; 338 | } 339 | } 340 | if(ll2) 341 | { 342 | if(ll2<65536) 343 | { 344 | int r=GA(ll2); 345 | // cout << r << '\n' ; 346 | if(x1[x][y]==1&&(foulr(r,y)||A5test(r,y))) 347 | { 348 | count--; 349 | } 350 | count++; 351 | } 352 | else 353 | { 354 | int r1=GA(ll2); 355 | int r2=GB(ll2); 356 | if(x1[x][y]==1&&(foulr(r1,y)||A5test(r1,y))&&(foulr(r2,y)||A5test(r2,y))) 357 | { 358 | count--; 359 | } 360 | count++; 361 | } 362 | } 363 | // cout << "count=" << count << '\n' ; 364 | if(ll3) 365 | { 366 | if(ll3<65536) 367 | { 368 | int r=GA(ll3); 369 | // cout << r << '\n' ; 370 | if(x1[x][y]==1&&(foulr(x+y-r,r)||A5test(x+y-r,r))) 371 | { 372 | count--; 373 | } 374 | count++; 375 | } 376 | else 377 | { 378 | int r1=GA(ll3); 379 | int r2=GB(ll3); 380 | if(x1[x][y]==1&&(foulr(x+y-r1,r1)||A5test(x+y-r1,r1))&&(foulr(x+y-r2,r2)||A5test(x+y-r2,r2))) 381 | { 382 | count--; 383 | } 384 | count++; 385 | } 386 | } 387 | if(ll4) 388 | { 389 | if(ll4<65536) 390 | { 391 | int r=GA(ll4); 392 | if(x1[x][y]==1&&(foulr(S-1+x-y-r,S-1-r)||A5test(S-1+x-y-r,S-1-r))) 393 | { 394 | count--; 395 | } 396 | count++; 397 | } 398 | else 399 | { 400 | int r1=GA(ll4); 401 | int r2=GB(ll4); 402 | if(x1[x][y]==1&&(foulr(S-1+x-y-r1,S-1-r1)||A5test(S-1+x-y-r1,S-1-r1))&&(foulr(S-1+x-y-r2,S-1-r2)||A5test(S-1+x-y-r2,S-1-r2))) 403 | { 404 | count--; 405 | } 406 | count++; 407 | } 408 | } 409 | return count; 410 | } 411 | 412 | int line4v::B4(int x,int y) 413 | { 414 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 415 | int p1=y,p2=x,p3=y,p4=S-1-y; 416 | int count=0; 417 | count+=l1.B4(p1); 418 | count+=l2.B4(p2); 419 | count+=l3.B4(p3); 420 | count+=l4.B4(p4); 421 | return count; 422 | } 423 | 424 | int line4v::A5test(int x,int y) 425 | { 426 | int sign=0; 427 | if(x1[x][y]==0) 428 | { 429 | sign=1; 430 | x1[x][y]=1; 431 | x2[y][x]=1; 432 | x3[x+y][y]=1; 433 | x4[S-1-y+x][S-1-y]=1; 434 | } 435 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 436 | int p1=y,p2=x,p3=y,p4=S-1-y; 437 | if(l1.A5(p1)) 438 | { 439 | x1[x][y]-=sign; 440 | x2[y][x]-=sign; 441 | x3[x+y][y]-=sign; 442 | x4[S-1-y+x][S-1-y]-=sign; 443 | return 1; 444 | } 445 | if(l2.A5(p2)) 446 | { 447 | x1[x][y]-=sign; 448 | x2[y][x]-=sign; 449 | x3[x+y][y]-=sign; 450 | x4[S-1-y+x][S-1-y]-=sign; 451 | return 1; 452 | } 453 | if(l3.A5(p3)) 454 | { 455 | x1[x][y]-=sign; 456 | x2[y][x]-=sign; 457 | x3[x+y][y]-=sign; 458 | x4[S-1-y+x][S-1-y]-=sign; 459 | return 1; 460 | } 461 | if(l4.A5(p4)) 462 | { 463 | x1[x][y]-=sign; 464 | x2[y][x]-=sign; 465 | x3[x+y][y]-=sign; 466 | x4[S-1-y+x][S-1-y]-=sign; 467 | return 1; 468 | } 469 | x1[x][y]-=sign; 470 | x2[y][x]-=sign; 471 | x3[x+y][y]-=sign; 472 | x4[S-1-y+x][S-1-y]-=sign; 473 | return 0; 474 | } 475 | 476 | int line4v::A6(int x,int y) 477 | { 478 | line l1(x1[x]),l2(x2[y]),l3(x3[x+y]),l4(x4[S-1-y+x]); 479 | int p1=y,p2=x,p3=y,p4=S-1-y; 480 | if(l1.A6(p1)) 481 | { 482 | return 1; 483 | } 484 | if(l2.A6(p2)) 485 | { 486 | return 1; 487 | } 488 | if(l3.A6(p3)) 489 | { 490 | return 1; 491 | } 492 | if(l4.A6(p4)) 493 | { 494 | return 1; 495 | } 496 | return 0; 497 | } -------------------------------------------------------------------------------- /renju/game.h: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2012-2015 Tianyi Hao 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | // Version 4.0 18 | 19 | #ifndef _CLASS 20 | #define _CLASS 21 | #include 22 | #include 23 | #include 24 | #include 25 | using namespace std; 26 | 27 | #define N 20 28 | #define P(X,Y) ((X)+(Y)*(S)) 29 | 30 | class line4v; 31 | extern int S; 32 | extern int fflag; 33 | 34 | class game 35 | { 36 | public: 37 | int board[N][N]; 38 | int move; 39 | game(); 40 | }; 41 | 42 | class line 43 | { 44 | public: 45 | int x[N+4]; 46 | line(){} 47 | line(int a[]); 48 | line(game& b,int p,int d); 49 | int A6(int p); 50 | int A5(int p); 51 | int A4(int p); 52 | int B4(int p); 53 | int B4p(int p); 54 | int A3(int p); 55 | int A3pb(int p); 56 | }; 57 | 58 | class line4v 59 | { 60 | 61 | private: 62 | public: 63 | int x1[N][N],x2[N][N],x3[2*N-1][N],x4[2*N-1][N]; 64 | line4v(game& board); 65 | int A6(int x,int y); 66 | int A5(int x,int y); 67 | int A5test(int x,int y); 68 | int A4(int x,int y); 69 | int B4(int x,int y); 70 | int B4p(int x,int y); 71 | int overline(int x,int y); 72 | int double4(int x,int y); 73 | int A3r(int x,int y); 74 | int double3r(int x,int y); 75 | int foulr(int x,int y); 76 | int B4p(int c); 77 | }; 78 | 79 | 80 | #endif -------------------------------------------------------------------------------- /renju/global.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | (C) 2012-2015 Tianyi Hao 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | #include 18 | using namespace std; 19 | #include "game.h" 20 | 21 | int fflag=0; 22 | int nosix=0; 23 | int S=20; 24 | int boardSize=20; 25 | 26 | int forbid(int board_[N][N], int pos,int size) 27 | { 28 | game board; 29 | board.move=0; 30 | boardSize=size; 31 | S=size; 32 | for(int i=0;i 3 | 4 | const char *infotext="name=\"Random\", author=\"Petr Lastovicka\", version=\"3.1\", country=\"Czech Republic\", www=\"http://petr.lastovicka.sweb.cz\""; 5 | 6 | #define MAX_BOARD 100 7 | int board[MAX_BOARD][MAX_BOARD]; 8 | static unsigned seed; 9 | 10 | 11 | void brain_init() 12 | { 13 | if(width<5 || width>MAX_BOARD || height<5 || height>MAX_BOARD){ 14 | pipeOut("ERROR size of the board"); 15 | return; 16 | } 17 | seed=start_time; 18 | pipeOut("OK"); 19 | } 20 | 21 | void brain_restart() 22 | { 23 | int x,y; 24 | for(x=0; x=0 && y>=0 && x=0 && y>=0 && x>32); 77 | } 78 | 79 | void brain_turn() 80 | { 81 | int x,y,i; 82 | 83 | i=-1; 84 | do{ 85 | x=rnd(width); 86 | y=rnd(height); 87 | i++; 88 | if(terminate) return; 89 | }while(!isFree(x,y)); 90 | 91 | if(i>1) pipeOut("DEBUG %d coordinates didn't hit an empty field",i); 92 | do_mymove(x,y); 93 | } 94 | 95 | void brain_end() 96 | { 97 | } 98 | 99 | #ifdef DEBUG_EVAL 100 | #include 101 | 102 | void brain_eval(int x,int y) 103 | { 104 | HDC dc; 105 | HWND wnd; 106 | RECT rc; 107 | char c; 108 | wnd=GetForegroundWindow(); 109 | dc= GetDC(wnd); 110 | GetClientRect(wnd,&rc); 111 | c=(char)(board[x][y]+'0'); 112 | TextOut(dc, rc.right-15, 3, &c, 1); 113 | ReleaseDC(wnd,dc); 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /skelet/pisqpipe.cpp: -------------------------------------------------------------------------------- 1 | /** functions that communicate with manager through pipes */ 2 | /** don't modify this file */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "pisqpipe.h" 11 | 12 | int width, height; /* the board size */ 13 | int info_timeout_turn=30000; /* time for one turn in milliseconds */ 14 | int info_timeout_match=1000000000; /* total time for a game */ 15 | int info_time_left=1000000000; /* left time for a game */ 16 | int info_max_memory=0; /* maximum memory in bytes, zero if unlimited */ 17 | int info_game_type=1; /* 0:human opponent, 1:AI opponent, 2:tournament, 3:network tournament */ 18 | int info_exact5=0; /* 0:five or more stones win, 1:exactly five stones win */ 19 | int info_continuous=0; /* 0:single game, 1:continuous */ 20 | int terminate; /* return from brain_turn when terminate>0 */ 21 | unsigned start_time; /* tick count at the beginning of turn */ 22 | char dataFolder[256]; /* folder for persistent files */ 23 | 24 | static char cmd[256]; 25 | static HANDLE event1, event2; 26 | 27 | 28 | /** write a line to STDOUT */ 29 | int pipeOut(char *fmt, ...) 30 | { 31 | int i; 32 | va_list va; 33 | va_start(va, fmt); 34 | i=vprintf(fmt, va); 35 | putchar('\n'); 36 | fflush(stdout); 37 | va_end(va); 38 | return i; 39 | } 40 | 41 | /** read a line from STDIN */ 42 | static void get_line() 43 | { 44 | int c, bytes; 45 | 46 | bytes=0; 47 | do{ 48 | c=getchar(); 49 | if(c==EOF) exit(0); 50 | if(bytes=width || *y>=height){ 62 | return 0; 63 | } 64 | return 1; 65 | } 66 | 67 | /** parse coordinates x,y and player number z */ 68 | static void parse_3int_chk(const char *param, int *x, int *y, int *z) 69 | { 70 | if(sscanf(param, "%d,%d,%d", x, y, z)!=3 || *x<0 || *y<0 || 71 | *x>=width || *y>=height) *z=0; 72 | } 73 | 74 | /** return pointer to word after cmd if input starts with cmd, otherwise return NULL */ 75 | static const char *get_cmd_param(const char *cmd, const char *input) 76 | { 77 | int n1, n2; 78 | n1=strlen(cmd); 79 | n2=strlen(input); 80 | if(n1>n2 || _strnicmp(cmd, input, n1)) return NULL; /* it is not cmd */ 81 | input+=strlen(cmd); 82 | while(isspace(input[0])) input++; 83 | return input; 84 | } 85 | 86 | /** send suggest */ 87 | void suggest(int x, int y) 88 | { 89 | pipeOut("SUGGEST %d,%d", x, y); 90 | } 91 | 92 | /** write move to the pipe and update internal data structures */ 93 | void do_mymove(int x, int y) 94 | { 95 | brain_my(x, y); 96 | pipeOut("%d,%d", x, y); 97 | } 98 | 99 | /** main function for the working thread */ 100 | static DWORD WINAPI threadLoop(LPVOID) 101 | { 102 | for(;;){ 103 | WaitForSingleObject(event1, INFINITE); 104 | brain_turn(); 105 | SetEvent(event2); 106 | } 107 | } 108 | 109 | /** start thinking */ 110 | static void turn() 111 | { 112 | terminate=0; 113 | ResetEvent(event2); 114 | SetEvent(event1); 115 | } 116 | 117 | /** stop thinking */ 118 | static void stop() 119 | { 120 | terminate=1; 121 | WaitForSingleObject(event2, INFINITE); 122 | } 123 | 124 | static void start() 125 | { 126 | start_time=GetTickCount(); 127 | stop(); 128 | if(!width){ 129 | width=height=20; 130 | brain_init(); 131 | } 132 | } 133 | 134 | /** do command cmd */ 135 | static void do_command() 136 | { 137 | const char *param; 138 | const char *info; 139 | char *t; 140 | int x, y, who, e; 141 | 142 | if((param=get_cmd_param("info", cmd))!=0) { 143 | if((info=get_cmd_param("max_memory", param))!=0) info_max_memory=atoi(info); 144 | if((info=get_cmd_param("timeout_match", param))!=0) info_timeout_match=atoi(info); 145 | if((info=get_cmd_param("timeout_turn", param))!=0) info_timeout_turn=atoi(info); 146 | if((info=get_cmd_param("time_left", param))!=0) info_time_left=atoi(info); 147 | if((info=get_cmd_param("game_type", param))!=0) info_game_type=atoi(info); 148 | if((info=get_cmd_param("rule", param))!=0){ e=atoi(info); info_exact5=e&1; info_continuous=(e>>1)&1; } 149 | if((info=get_cmd_param("folder", param))!=0) strncpy(dataFolder, info, sizeof(dataFolder)-1); 150 | #ifdef DEBUG_EVAL 151 | if((info=get_cmd_param("evaluate", param))!=0){ if(parse_coord(info, &x, &y)) brain_eval(x, y); } 152 | #endif 153 | /* unknown info is ignored */ 154 | } 155 | else if((param=get_cmd_param("start", cmd))!=0) { 156 | if(sscanf(param, "%d", &width)!=1 || width<5){ 157 | width=0; 158 | pipeOut("ERROR bad START parameter"); 159 | } 160 | else{ 161 | height=width; 162 | start(); 163 | brain_init(); 164 | } 165 | } 166 | else if((param=get_cmd_param("rectstart", cmd))!=0) { 167 | if(sscanf(param, "%d ,%d", &width, &height)!=2 || width<5 || height<5){ 168 | width=height=0; 169 | pipeOut("ERROR bad RECTSTART parameters"); 170 | } 171 | else{ 172 | start(); 173 | brain_init(); 174 | } 175 | } 176 | else if((param=get_cmd_param("restart", cmd))!=0) { 177 | start(); 178 | brain_restart(); 179 | } 180 | else if((param=get_cmd_param("turn", cmd))!=0) { 181 | start(); 182 | if(!parse_coord(param, &x, &y)){ 183 | pipeOut("ERROR bad coordinates"); 184 | } 185 | else{ 186 | brain_opponents(x, y); 187 | turn(); 188 | } 189 | } 190 | else if((param=get_cmd_param("play", cmd))!=0) { 191 | start(); 192 | if(!parse_coord(param, &x, &y)){ 193 | pipeOut("ERROR bad coordinates"); 194 | } 195 | else{ 196 | do_mymove(x, y); 197 | } 198 | } 199 | else if((param=get_cmd_param("begin", cmd))!=0) { 200 | start(); 201 | turn(); 202 | } 203 | else if((param=get_cmd_param("about", cmd))!=0) { 204 | #ifdef ABOUT_FUNC 205 | brain_about(); 206 | #else 207 | pipeOut("%s", infotext); 208 | #endif 209 | } 210 | else if((param=get_cmd_param("end", cmd))!=0) { 211 | stop(); 212 | brain_end(); 213 | exit(0); 214 | } 215 | else if((param=get_cmd_param("board", cmd))!=0) { 216 | start(); 217 | for(;;){ /* fill the whole board */ 218 | get_line(); 219 | parse_3int_chk(cmd, &x, &y, &who); 220 | if(who==1) brain_my(x, y); 221 | else if(who==2) brain_opponents(x, y); 222 | else if(who==3) brain_block(x, y); 223 | else{ 224 | if(_stricmp(cmd, "done")) pipeOut("ERROR x,y,who or DONE expected after BOARD"); 225 | break; 226 | } 227 | } 228 | turn(); 229 | } 230 | else if((param=get_cmd_param("takeback", cmd))!=0) { 231 | start(); 232 | t="ERROR bad coordinates"; 233 | if(parse_coord(param, &x, &y)){ 234 | e= brain_takeback(x, y); 235 | if(e==0) t="OK"; 236 | else if(e==1) t="UNKNOWN"; 237 | } 238 | pipeOut(t); 239 | } 240 | else{ 241 | pipeOut("UNKNOWN command"); 242 | } 243 | } 244 | 245 | 246 | /** main function for AI console application */ 247 | int main() 248 | { 249 | DWORD mode; 250 | if(GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode)) 251 | puts("MESSAGE Gomoku AI should not be started directly. Please install gomoku manager (http://sourceforge.net/projects/piskvork). Then enter path to this exe file in players settings."); 252 | 253 | #ifdef DEBUG 254 | SetErrorMode(0); 255 | #endif 256 | DWORD tid; 257 | event1=CreateEvent(0, FALSE, FALSE, 0); 258 | CreateThread(0, 0, threadLoop, 0, 0, &tid); 259 | event2=CreateEvent(0, TRUE, TRUE, 0); 260 | for(;;){ 261 | get_line(); 262 | do_command(); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /skelet/pisqpipe.h: -------------------------------------------------------------------------------- 1 | /** header with functions and variables for pipe AI */ 2 | 3 | /* information about a game - you should use these variables */ 4 | extern int width,height; /* the board size */ 5 | extern int info_timeout_turn; /* time for one turn in milliseconds */ 6 | extern int info_timeout_match; /* total time for a game */ 7 | extern int info_time_left; /* remaining time for a game */ 8 | extern int info_max_memory; /* maximum memory in bytes, zero if unlimited */ 9 | extern int info_game_type; /* 0:human opponent, 1:AI opponent, 2:tournament, 3:network tournament */ 10 | extern int info_exact5; /* 0:five or more stones win, 1:exactly five stones win */ 11 | extern int info_continuous; /* 0:single game, 1:continuous */ 12 | extern int terminate; /* return from brain_turn when terminate>0 */ 13 | extern unsigned start_time; /* tick count at the beginning of turn */ 14 | extern char dataFolder[256]; /* folder for persistent files */ 15 | 16 | /* you have to implement these functions */ 17 | void brain_init(); /* create the board and call pipeOut("OK"); */ 18 | void brain_restart(); /* delete old board, create new board, call pipeOut("OK"); */ 19 | void brain_turn(); /* choose your move and call do_mymove(x,y); 20 | 0<=xMAX_BOARD)or(height<5)or(height>MAX_BOARD) then begin 14 | pipeOut('ERROR size of the board'); 15 | exit; 16 | end; 17 | seed:=start_time; 18 | pipeOut('OK'); 19 | end; 20 | 21 | procedure brain_restart(); 22 | var x,y:integer; 23 | begin 24 | for x:=0 to width-1 do begin 25 | for y:=0 to height-1 do begin 26 | board[x][y]:=0; 27 | end; 28 | end; 29 | pipeOut('OK'); 30 | end; 31 | 32 | function isFree(x,y:integer):boolean; 33 | begin 34 | result:=(x>=0)and(y>=0)and(x=0)and(y>=0)and(x0) then begin 67 | board[x][y]:=0; 68 | result:=0; 69 | end else result:=2; 70 | end; 71 | 72 | function rnd(n:cardinal):cardinal; 73 | begin 74 | {$Q-} 75 | seed:=word(314159*seed+2718281); 76 | result:=(seed * n) shr 16; 77 | end; 78 | 79 | procedure brain_turn(); 80 | var x,y,i:integer; 81 | begin 82 | i:=-1; 83 | repeat 84 | x:=rnd(width); 85 | y:=rnd(height); 86 | i:=i+1; 87 | if terminate>0 then exit; 88 | until isFree(x,y); 89 | 90 | if i>1 then pipeOut('DEBUG %d coordinates didn''t hit an empty field',[i]); 91 | do_mymove(x,y); 92 | end; 93 | 94 | procedure brain_end(); 95 | begin 96 | end; 97 | 98 | {$IFDEF DEBUG_EVAL} 99 | procedure brain_eval(x,y:integer); 100 | var dc:HDC; 101 | wnd:HWND; 102 | rc:TRECT; 103 | c:string; 104 | begin 105 | wnd:=GetForegroundWindow(); 106 | dc:= GetDC(wnd); 107 | GetClientRect(wnd,rc); 108 | str(board[x][y],c); 109 | TextOut(dc, rc.right-15, 3, PChar(c), 1); 110 | ReleaseDC(wnd,dc); 111 | end; 112 | {$ENDIF} 113 | 114 | initialization 115 | infotext:='name="Random", author="Petr Lastovicka", version="3.1", country="Czech Republic", www="http://petr.lastovicka.sweb.cz"' 116 | end. 117 | -------------------------------------------------------------------------------- /skelet_Delphi/header.pas: -------------------------------------------------------------------------------- 1 | interface 2 | var infotext:string; { AI identification (copyright, version) } 3 | 4 | { you have to implement these functions } 5 | procedure brain_init(); { create the board and call pipeOut('OK'); } 6 | procedure brain_restart(); { delete old board, create new board, call pipeOut('OK'); } 7 | procedure brain_turn(); { choose your move and call do_mymove(x,y); 8 | 0<=x0 } 20 | start_time:longword; { tick count at the beginning of turn } 21 | dataFolder:string; { folder for persistent files } 22 | 23 | { these functions are implemented in this file } 24 | procedure pipeOut(s:string);overload; 25 | procedure pipeOut(fmt:string; args:array of const);overload; 26 | procedure do_mymove(x,y:integer); 27 | procedure suggest(x,y:integer); 28 | 29 | implementation 30 | uses windows,sysutils; 31 | var cmd:string; 32 | tid:DWORD; 33 | event1,event2:THANDLE; 34 | 35 | {* write a line to the pipe } 36 | procedure pipeOut(s:string);overload; 37 | begin 38 | writeln(s); 39 | Flush(output); 40 | end; 41 | 42 | procedure pipeOut(fmt:string; args:array of const);overload; 43 | begin 44 | pipeOut(Format(fmt,args)); 45 | end; 46 | 47 | {* parse two integers } 48 | function parse_xy(param:string; var x,y:integer): boolean; 49 | var i,ex,ey:integer; 50 | begin 51 | i:=pos(',',param); 52 | val(copy(param,1,i-1),x,ex); 53 | val(copy(param,i+1,255),y,ey); 54 | if (i=0)or(ex<>0)or(ey<>0)or(x<0)or(y<0) then result:=false 55 | else result:=true; 56 | end; 57 | 58 | {* parse coordinates x,y } 59 | function parse_coord(param:string; var x,y:integer): boolean; 60 | begin 61 | result:=parse_xy(param,x,y); 62 | if (x>=width)or(y>=height) then result:=false 63 | end; 64 | 65 | {* parse coordinates x,y and player number z } 66 | procedure parse_3int_chk(param:string; var x,y,z:integer); 67 | var i,ex:integer; 68 | eyz:boolean; 69 | begin 70 | i:=pos(',',param); 71 | val(copy(param,1,i-1),x,ex); 72 | eyz:=parse_xy(copy(param,i+1,255),y,z); 73 | if (i=0)or(ex<>0)or not eyz or(x<0)or(y<0)or(x>=width)or(y>=height) then z:=0; 74 | end; 75 | 76 | {* get word after cmd if input starts with cmd, otherwise return false } 77 | function get_cmd_param(cmd,input:string; var param:string):boolean; 78 | var n1,n2:integer; 79 | begin 80 | n1:=length(cmd); 81 | n2:=length(input); 82 | if (n1>n2)or(StrLIComp(PChar(cmd),PChar(input),n1)<>0) then begin 83 | { it is not cmd } 84 | result:=false; 85 | exit; 86 | end; 87 | result:=true; 88 | repeat 89 | inc(n1); 90 | if n1>length(input) then begin {###F20081208} 91 | param:=''; 92 | exit; 93 | end; 94 | until input[n1]<>' '; 95 | param:=copy(input,n1,255) 96 | end; 97 | 98 | {* send suggest } 99 | procedure suggest(x,y:integer); 100 | begin 101 | pipeOut('SUGGEST %d,%d',[x,y]); 102 | end; 103 | 104 | {* write move to the pipe and update internal data structures } 105 | procedure do_mymove(x,y:integer); 106 | begin 107 | brain_my(x,y); 108 | pipeOut('%d,%d',[x,y]); 109 | end; 110 | 111 | {* main function for the working thread } 112 | function threadLoop(param:Pointer):DWORD;stdcall; 113 | begin 114 | while true do begin 115 | WaitForSingleObject(event1,INFINITE); 116 | brain_turn(); 117 | SetEvent(event2); 118 | end; 119 | end; 120 | 121 | {* start thinking } 122 | procedure turn(); 123 | begin 124 | terminate:=0; 125 | ResetEvent(event2); 126 | SetEvent(event1); 127 | end; 128 | 129 | {* stop thinking } 130 | procedure stop(); 131 | begin 132 | terminate:=1; 133 | WaitForSingleObject(event2,INFINITE); 134 | end; 135 | 136 | procedure start(); 137 | begin 138 | start_time:=GetTickCount(); 139 | stop(); 140 | if width=0 then begin 141 | width:=20; 142 | height:=20; 143 | brain_init(); 144 | end; 145 | end; 146 | 147 | {* do command cmd } 148 | procedure do_command(); 149 | var 150 | param,info,t:string; 151 | x,y,who,e:integer; 152 | begin 153 | if get_cmd_param('info',cmd,param) then begin 154 | if get_cmd_param('max_memory',param,info) then info_max_memory:=StrToInt(info); 155 | if get_cmd_param('timeout_match',param,info) then info_timeout_match:=StrToInt(info); 156 | if get_cmd_param('timeout_turn',param,info) then info_timeout_turn:=StrToInt(info); 157 | if get_cmd_param('time_left',param,info) then info_time_left:=StrToInt(info); 158 | if get_cmd_param('game_type',param,info) then info_game_type:=StrToInt(info); 159 | if get_cmd_param('rule',param,info) then begin e:=StrToInt(info); info_exact5:=e and 1; info_continuous:=(e shr 1)and 1; end; 160 | if get_cmd_param('folder',param,info) then dataFolder:=info; 161 | {$IFDEF DEBUG_EVAL} 162 | if get_cmd_param('evaluate',param,info) then begin 163 | if parse_coord(info,x,y) then brain_eval(x,y); 164 | end; 165 | {$ENDIF} 166 | { unknown info is ignored } 167 | end 168 | else if get_cmd_param('start',cmd,param) then begin 169 | width:= StrToInt(param); 170 | height:=width; 171 | start(); 172 | brain_init(); 173 | end 174 | else if get_cmd_param('rectstart',cmd,param) then begin 175 | if not parse_xy(param,width,height) then begin 176 | pipeOut('ERROR bad RECTSTART parameters'); 177 | end else begin 178 | start(); 179 | brain_init(); 180 | end; 181 | end 182 | else if get_cmd_param('restart',cmd,param) then begin 183 | start(); 184 | brain_restart(); 185 | end 186 | else if get_cmd_param('turn',cmd,param) then begin 187 | start(); 188 | if not parse_coord(param,x,y) then begin 189 | pipeOut('ERROR bad coordinates'); 190 | end else begin 191 | brain_opponents(x,y); 192 | turn(); 193 | end; 194 | end 195 | else if get_cmd_param('play',cmd,param) then begin 196 | start(); 197 | if not parse_coord(param,x,y) then begin 198 | pipeOut('ERROR bad coordinates'); 199 | end else begin 200 | do_mymove(x,y); 201 | end; 202 | end 203 | else if get_cmd_param('begin',cmd,param) then begin 204 | start(); 205 | turn(); 206 | end 207 | else if get_cmd_param('about',cmd,param) then begin 208 | pipeOut('%s',[infotext]); 209 | end 210 | else if get_cmd_param('end',cmd,param) then begin 211 | stop(); 212 | brain_end(); 213 | halt; 214 | end 215 | else if get_cmd_param('board',cmd,param) then begin 216 | start(); 217 | while true do begin { fill the whole board } 218 | readln(cmd); 219 | parse_3int_chk(cmd,x,y,who); 220 | if who=1 then brain_my(x,y) 221 | else if who=2 then brain_opponents(x,y) 222 | else if who=3 then brain_block(x,y) 223 | else begin 224 | if StrIComp(PChar(cmd),'done')<>0 then pipeOut('ERROR x,y,who or DONE expected after BOARD'); 225 | break; 226 | end; 227 | end; 228 | turn(); 229 | end 230 | else if get_cmd_param('takeback',cmd,param) then begin 231 | start(); 232 | t:='ERROR bad coordinates'; 233 | if parse_coord(param,x,y) then begin 234 | e:= brain_takeback(x,y); 235 | if e=0 then t:='OK' 236 | else if e=1 then t:='UNKNOWN'; 237 | end; 238 | pipeOut(t); 239 | end 240 | else begin 241 | pipeOut('UNKNOWN command'); 242 | end; 243 | end; 244 | 245 | 246 | {* main function for AI console application } 247 | initialization 248 | begin 249 | event1:=CreateEvent(nil,FALSE,FALSE,nil); 250 | CreateThread(nil,0,@threadLoop,nil,0,tid); 251 | event2:=CreateEvent(nil,TRUE,TRUE,nil); 252 | 253 | while true do begin 254 | readln(cmd); 255 | do_command(); 256 | end; 257 | end; 258 | end. 259 | 260 | -------------------------------------------------------------------------------- /skelet_Delphi/skelet.dpr: -------------------------------------------------------------------------------- 1 | program skelet; 2 | uses pisqpipe in 'pisqpipe.pas', 3 | example in 'example.pas'; 4 | {$APPTYPE CONSOLE} 5 | begin 6 | end. 7 | -------------------------------------------------------------------------------- /skins/pisq.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/skins/pisq.bmp -------------------------------------------------------------------------------- /taskbarprogress.cpp: -------------------------------------------------------------------------------- 1 | // http://stackoverflow.com/questions/15001638/windows-7-taskbar-state-with-minimal-code 2 | 3 | #include "taskbarprogress.h" 4 | 5 | Win7TaskbarProgress::Win7TaskbarProgress() 6 | { 7 | m_pITaskBarList3 = NULL; 8 | m_bFailed = false; 9 | } 10 | 11 | Win7TaskbarProgress::~Win7TaskbarProgress() 12 | { 13 | if (m_pITaskBarList3) 14 | { 15 | m_pITaskBarList3->Release(); 16 | CoUninitialize(); 17 | } 18 | } 19 | 20 | void Win7TaskbarProgress::SetProgressState( HWND hwnd, TBPFLAG flag ) 21 | { 22 | if (Init()) 23 | m_pITaskBarList3->SetProgressState(hwnd, flag); 24 | } 25 | 26 | void Win7TaskbarProgress::SetProgressValue( HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal ) 27 | { 28 | if (Init()) 29 | m_pITaskBarList3->SetProgressValue(hwnd, ullCompleted, ullTotal); 30 | } 31 | 32 | bool Win7TaskbarProgress::Init() 33 | { 34 | if (m_pITaskBarList3) 35 | return true; 36 | 37 | if (m_bFailed) 38 | return false; 39 | 40 | // Initialize COM for this thread... 41 | CoInitialize(NULL); 42 | 43 | CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_pITaskBarList3); 44 | 45 | if (m_pITaskBarList3) 46 | return true; 47 | 48 | m_bFailed = true; 49 | CoUninitialize(); 50 | return false; 51 | } 52 | -------------------------------------------------------------------------------- /taskbarprogress.h: -------------------------------------------------------------------------------- 1 | // http://stackoverflow.com/questions/15001638/windows-7-taskbar-state-with-minimal-code 2 | 3 | #ifndef __TASKBAR_PROGRESS 4 | #define __TASKBAR_PROGRESS 5 | #include 6 | #include 7 | #pragma comment(lib, "Shell32.lib") 8 | #pragma comment(lib, "Ole32.lib") 9 | 10 | class Win7TaskbarProgress 11 | { 12 | public: 13 | Win7TaskbarProgress(); 14 | virtual ~Win7TaskbarProgress(); 15 | 16 | void SetProgressState(HWND hwnd, TBPFLAG flag); 17 | void SetProgressValue(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal); 18 | 19 | private: 20 | bool Init(); 21 | ITaskbarList3* m_pITaskBarList3; 22 | bool m_bFailed; 23 | }; 24 | 25 | extern Win7TaskbarProgress win7TaskbarProgress; 26 | 27 | #endif -------------------------------------------------------------------------------- /toolbar.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wind23/piskvork_renju/f76a43afb67861883c86f8bd22b1a4957c27f068/toolbar.bmp --------------------------------------------------------------------------------