seeking critique/feedback/criticism chess program

I've been working on chess for about a month now. I know it shouldn't take that long but I've started from scratch and rewritten it at least a dozen times when i didn't like one thing or another. Anyway its done now!

I know i could have done it better using techniques that i dont know about, and i wouldn't dismiss comments suggesting such techniques but thats not really what im looking for. Also i know there are bugs, im not really looking for help debugging either. Mostly im looking for feedback on how i could have used the techniques that i did use more effectively.

Unfortunately i had to change some things in order to make it fit in < 8100 characters. A couple of the logic gates like in the function legalMove() for example became incomprehensible so i know and i apologize.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#include <iostream>
#include <string>

std::string trn="W", input;
int in[4];

class CPiece
{
public:

bool alive, moved;
int y,x,id;
std::string clr,typ;

} *deadPce, emt={0,0,0,0,0," "," "}, pce[32]={
{1,0,0,4,0,"B","K"},{1,0,7,4,1,"W","K"},{1,0,0,3,2,"B","Q"},
{1,0,7,3,3,"W","Q"},{1,0,0,0,4,"B","R"},{1,0,0,7,5,"B","R"},
{1,0,7,0,6,"W","R"},{1,0,7,7,7,"W","R"},{1,0,0,1,8,"B","B"},
{1,0,0,6,9,"B","B"},{1,0,7,1,10,"W","B"},{1,0,7,6,11,"W","B"},
{1,0,0,2,12,"B","N"},{1,0,0,5,13,"B","N"},{1,0,7,2,14,"W","N"},
{1,0,7,5,15,"W","N"},{1,0,1,0,16,"B","P"},{1,0,1,1,17,"B","P"},
{1,0,1,2,18,"B","P"},{1,0,1,3,19,"B","P"},{1,0,1,4,20,"B","P"},
{1,0,1,5,21,"B","P"},{1,0,1,6,22,"B","P"},{1,0,1,7,23,"B","P"},
{1,0,6,0,24,"W","P"},{1,0,6,1,25,"W","P"},{1,0,6,2,26,"W","P"},
{1,0,6,3,27,"W","P"},{1,0,6,4,28,"W","P"},{1,0,6,5,29,"W","P"},
{1,0,6,6,30,"W","P"},{1,0,6,7,31,"W","P"}};

class CNode
{
public:

void udPtr() {
	for (int i=0; i<32; ++i) {
		if (y==pce[i].y && x==pce[i].x && pce[i].alive) {
			ptr=&pce[i];
			return;
		}
	}
	ptr=&emt;
}

int thretBy(CPiece p) {
	if (p.typ=="K" || p.typ=="Q" || p.typ=="B") {
		for (int i=1; p.alive; ++i) {
			if (p.y-y!=p.x-x || y>=p.y || p.y-i<0 || p.x-i<0) {
				break;
			}
			if (p.y-i==y && p.x-i==x) {
				return 1;
			}
			if (p.typ=="K" || node[p.x-i][p.y-i].ptr->alive) {
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (y-p.x!=p.y-x || y>=p.y || p.y-i<0 || p.x+i>7) {
				break;
			}
			if (p.y-i==y && p.x+i==x) {
				return 3;
			}
			if (p.typ=="K" || node[p.y-i][p.x+i].ptr->alive) {
				std::cout << "foo";
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (y-p.x!=p.y-x || y<=p.y || p.y+i>7 || p.x-i<0) {
				break;
			}
			if (p.y+i==y && p.x-i==x) {
				return 6;
			}
			if (p.typ=="K" || node[p.y+i][p.x-i].ptr->alive) {
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (p.y-y!=p.x-x || y<=p.y || p.y+i>7 || p.x+i>7) {
				break;
			}
			if (p.y+i==y && p.x+i==x) {
				return 8;
			}
			if (p.typ=="K" || node[p.y+i][p.x+i].ptr->alive) {
				break;
			}
		}
	}
	if (p.typ=="K" || p.typ=="Q" || p.typ=="R") {
		for (int i=1; p.alive; ++i) {
			if (x!=p.x || y>=p.y || p.y-i<0) {
				break;
			}
			if (p.y-i==y) {
				return 2;
			}
			if (p.typ=="K" || node[p.y-i][p.x].ptr->alive) {
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (y!=p.y || x>=p.x || p.x-i<0) {
				break;
			}
			if (p.x-i==x) {
				return 4;
			}
			if (p.typ=="K" || node[p.y][p.x-i].ptr->alive) {
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (y!=p.y || x<=p.x || p.x+i>7) {
				break;
			}
			if (p.x+i==x) {
				return 5;
			}
			if (p.typ=="K" || node[p.y][p.x+i].ptr->alive) {
				break;
			}
		}
		for (int i=1; p.alive; ++i) {
			if (x!=p.x || y<=p.y || p.y+i>7) {
				break;
			}
			if (p.y+i==y) {
				return 7;
			}
			if (p.typ=="K" || node[p.y+i][p.x].ptr->alive) {
				break;
			}
		}
	}
	if (p.typ=="N" && ((y==p.y-2 && x==p.x-1)||(y==p.y-2 && x==p.x-1)|| 
	(y==p.y-1 && x==p.x-2)||(y==p.y-1 && x==p.x+2)||(y==p.y+1 && x==p.x-2)||
	(y==p.y+1 && x==p.x+2)||(y==p.y-2 && x==p.x-1)||(y==p.y+2 && x==p.x+1))) {
		return 9;
	}
	if (p.typ=="P"&&((p.clr=="W"&&(y==p.y-1&&(x==p.x-1||x==p.x+1)))||
	(p.clr=="B"&&(y==p.y+1&&(x==p.x-1||x==p.x+1))))) {
		return true;
	}
	return 0;
}

bool thretnd() {
	for (int i=0; i<32; ++i) {
		if (thretBy(pce[i]) && pce[i].clr!=trn) {
			return true;
		}
	}
	return false;
}

bool reinforced() {
	for (int i=2; i<32; ++i) {
		if (thretBy(pce[i]) && pce[i].clr==trn) {
			return true;
		}
	}
	return false;
}

bool bloxChek() {
	int Y,X;
	if (pce[0].clr==trn) {
		Y=pce[0].y; X=pce[0].x;
	} else { 
		Y=pce[1].y; X=pce[1].x;
	}
	for (int i=0; i<32 && !(y==Y && x==X); ++i) {
		if (pce[i].clr!=trn && node[Y][X].thretBy(pce[i])) {
			if (y==pce[i].y && x==pce[i].x) {
				return true;
			}
			if (pce[i].typ=="N" || pce[i].typ=="P") {
				return false;
			}
			if (node[y][x].thretBy(pce[i])==node[Y][X].thretBy(pce[i])) {
				return true;
			}
		}
	}
	return false;
}

int y,x;
CPiece *ptr;

} node[8][8];

class CChess 
{
public:

CChess() {
	for (int y=0; y<8; ++y) {
		for (int x=0; x<8; ++x) {
			node[y][x].y=y;
			node[y][x].x=x;
		}
	}
}

void udPtrs() {
	for (int y=0; y<8; ++y) {
		for (int x=0; x<8; ++x) {
			node[y][x].udPtr();
		}
	}
}

void prtBrd() {
	std::cout << std::endl << "      0  1  2  3  4  5  6  7" << std::endl; 
	for (int y=0; y<8; ++y) {
		std::cout << std::endl << "  " << y << "  ";
		for (int x=0; x<8; ++x) {
			std::cout << node[y][x].ptr->clr << node[y][x].ptr->typ << " ";
		}
		std::cout << std::endl;
	}
	if (trn=="W") {
		std::cout << std::endl << "Whites turn: ";
	} else {
		std::cout << std::endl << "Blacks turn: ";
	}
}

bool bndsChx(int Y,int X) {
	if ((Y>0&&((!node[Y-1][X].thretnd())||(X>0&&(!node[Y-1][X-1].thretnd()))||
	(X<7&&(!node[Y-1][X+1].thretnd()))))||(Y<7&&((!node[Y+1][X].thretnd())||
	(X>0&&(!node[Y+1][X-1].thretnd()))||(X<7&&(!node[Y+1][X+1].thretnd()))))||
	(X>0&&(!node[Y][X-1].thretnd()))||(X<7&&(!node[Y][X+1].thretnd()))) {
		return false;
	}
	return true;
}

bool checkmate() {
	int Y,X;
	if (trn=="B") {
		Y=pce[0].y; X=pce[0].x;
	} else {
		Y=pce[1].y; X=pce[1].x;
	}
	if (!node[Y][X].thretnd()||!bndsChx(Y,X)) {
		return false;
	}
	int c=0;
	for (int i=0; i<32; ++i) {
		if (node[Y][X].thretBy(pce[i]) && pce[i].clr!=trn) {
			++c;
		}
	}
	if (c>1) {
		return true;
	}
	for (int y=0; y<8; ++y) {
		for (int x=0; x<8; ++x) {
			if (node[y][x].reinforced() && node[y][x].bloxChek()) {
				return false;
			}
		}
	}
	return true;
}

bool stalemate() {
	int Y,X;
	if (trn=="B") {
		Y=pce[0].y; X=pce[0].x;
	} else {
		Y=pce[1].y; X=pce[1].x;
	}
	if (node[Y][X].thretnd()||!bndsChx(Y,X)) {
		return false;
	}
	for (int y=0; y<8; ++y) {
		for (int x=0; x<8; ++x) {
			if (node[y][x].reinforced()) {
				return false;
			}
		}
	}
	return true;
}

bool legalMove() {
	if (node[in[0]][in[1]].ptr->clr!=trn || node[in[2]][in[3]].ptr->clr==trn) {
		return false;
	}
	if ((node[in[0]][in[1]].ptr->typ=="P"&&((node[in[2]][in[3]].ptr->alive&&
	node[in[2]][in[3]].thretBy(pce[node[in[0]][in[1]].ptr->id]))||
	(node[in[0]][in[1]].ptr->clr=="W"&&(in[0]==in[2]+1||(in[0]==in[2]+2&&
	!node[in[0]][in[1]].ptr->moved)))||(node[in[0]][in[1]].ptr->clr=="B"&&
	(in[0]==in[2]-1||(in[0]==in[2]-2&&!node[in[0]][in[1]].ptr->moved)))))||
	(node[in[2]][in[3]].thretBy(pce[node[in[0]][in[1]].ptr->id]))) {
		return true;
	}
	return false;
}

void run() {
	std::cout << "Pass input as y of piece -> x of piece -> y of space -> x";
	std::cout << " of space (yxyx)" << std::endl;
	while (1) {
		udPtrs();
		if (checkmate()) {
			if (trn=="W") {
				std::cout << std::endl << "Checkmate! Black is victorious.";
			} else {
				std::cout << std::endl << "Checkmate! White is victorious.";
			}
			break;
		}
		if (stalemate()) {
			std::cout << std::endl << "Stalemate, the game is a draw.";
			break;
		}
		prtBrd();
		std::cin >> input;
		in[0]=int(input[0])-48;
		in[1]=int(input[1])-48;
		in[2]=int(input[2])-48;
		in[3]=int(input[3])-48;
		if (legalMove()) {
			node[in[0]][in[1]].ptr->y=in[2];
			node[in[0]][in[1]].ptr->x=in[3];
			node[in[0]][in[1]].ptr->moved=true;
			bool fatality=false;
			if (node[in[2]][in[3]].ptr->alive) {
				deadPce=&pce[node[in[2]][in[3]].ptr->id];
				node[in[2]][in[3]].ptr->alive=false;
				fatality=true;
			}
			udPtrs();
			if ((node[pce[0].y][pce[0].x].thretnd() && 
			node[pce[0].y][pce[0].x].ptr->clr==trn) || 
			(node[pce[1].y][pce[1].x].thretnd() && 
			node[pce[1].y][pce[1].x].ptr->clr==trn)) {
				node[in[0]][in[1]].ptr->moved=false;
				node[in[2]][in[3]].ptr->y=in[0];
				node[in[2]][in[3]].ptr->x=in[1];
				if (fatality) {
					deadPce->alive=true;
				}
			} else {
				if (trn=="W") {
					trn="B";
				} else {
					trn="W";
				}
			}	
		}
	}
	std::cin.ignore();
}

} chess;

int main() {
	chess.run();
}
Last edited on
bump
bump
You aren't going to get too many replies because your code is close to unreadable. First, the indentation sucks. It is impossible to tell at a glance where a class definition ends. It is impossible to tell at a glance what functions are a member of what class. Aside from that, some of your function names are cryptic to the point of being useless for understanding the code. What does udPtrs() do and how does it's name reflect that?

The abbreviated spelling as if you're coding on a cell phone doesn't help. Overall, this is just a pain to read.
hey thanks for the response!

if the program is unreadable that certainly doesnt preclude it from criticism, just like you did someone could have said "hey my criticism is that this program too difficult to read".

I'm surprised you couldn't tell what udPtrs() means. i thought it was obvious but i guess its like one of those things like where if you are doing an i spy book and you know where something is its very easy for you to find it again. it stands for update pointers btw.

that was a conscious choice not to indent everything inside of a class. i thought it would make it easier to read by not having some of the denser logic so far indented. anyway ill reconsider that strategy.

as far as it being imposable to tell what functions are members of what classes. what should i have done differently to make this more obvious?
i don' understand, what this code use for? movement mapping?

1
2
3
4
5
6
7
8
9
10
11
12
pce[32]={
{1,0,0,4,0,"B","K"},{1,0,7,4,1,"W","K"},{1,0,0,3,2,"B","Q"},
{1,0,7,3,3,"W","Q"},{1,0,0,0,4,"B","R"},{1,0,0,7,5,"B","R"},
{1,0,7,0,6,"W","R"},{1,0,7,7,7,"W","R"},{1,0,0,1,8,"B","B"},
{1,0,0,6,9,"B","B"},{1,0,7,1,10,"W","B"},{1,0,7,6,11,"W","B"},
{1,0,0,2,12,"B","N"},{1,0,0,5,13,"B","N"},{1,0,7,2,14,"W","N"},
{1,0,7,5,15,"W","N"},{1,0,1,0,16,"B","P"},{1,0,1,1,17,"B","P"},
{1,0,1,2,18,"B","P"},{1,0,1,3,19,"B","P"},{1,0,1,4,20,"B","P"},
{1,0,1,5,21,"B","P"},{1,0,1,6,22,"B","P"},{1,0,1,7,23,"B","P"},
{1,0,6,0,24,"W","P"},{1,0,6,1,25,"W","P"},{1,0,6,2,26,"W","P"},
{1,0,6,3,27,"W","P"},{1,0,6,4,28,"W","P"},{1,0,6,5,29,"W","P"},
{1,0,6,6,30,"W","P"},{1,0,6,7,31,"W","P"}};
thats just giving all of the pieces their initial values. their attributes if you will.

so for example with the first one it says that its alive, it hasn't been moved, its y coord, x coord, id which allows me to refer to it, then its color and lastly what type of piece it is.

do you think it would have been better if i put all of this in the constructor of my chess class? i thought about doing it that way.
Last edited on
i don't think you have to, i think it depends on the need
Instead of giving us your code, why don't you give us your documentation? It's far more human-readable. Unless, of course, all you did was code.

I would first create a Piece class with enumerable fields of type Type and Color.

I would then create a Board class with a bi-dimensional field array of type Piece, a turn field of type Color, and a move method receiving two parameters, start and end, of type Position.

That's roughly it.

The move method would be gigantic, however, as it implements all of the game's logic. I'm sure there's a better way to abstract this game.

Nevertheless, if I follow this approach, I could easily add new pieces, colors, and even more players without having to parse through my code, replacing all instances of magic numbers and characters that have no meaning to anyone else but me (see chipp's reply).

Moreover, if I'm feeling ambitious, I could later create a neural network that instantiates ten thousand boards and asynchronously plays against itself overnight, effectively getting monstrously good at chess (or so I hope)!
Last edited on
Sorry idk what sort of documentation you are expecting. All i did was code. thanks for the reply though! I'm going to try to code it this way and see how it works.

as far as a good way to abstract this games logic. i picked chess because of how difficult and random and just plain crazy the rules are. i wanted a challenge, consequently there isnt a whole lot of recurrence of patterns in the rules and so not a whole lot of abstracting to be done. i was able to build the movements for queens and rooks and bishops out of common elements but thats about as far as you can take it. of course i could be wrong, im the furthest thing from a programming expert XD.
Last edited on
Topic archived. No new replies allowed.