├── .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
--------------------------------------------------------------------------------