• (3 Pages)
  • +
  • 1
  • 2
  • 3

Chess Board and Moving Pieces in C++ How to make a simple chess program Rate Topic: ***** 2 Votes

#31 Deepglue555  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 6
  • View blog
  • Posts: 117
  • Joined: 13-April 09

Posted 06 August 2014 - 09:54 PM

Keep in mind you will have to either return the contents of the 4 parallel arrays (that contain the move coordinates) or format the info into a string. In my actual code, this function went on to test each move individually to see if it left the friendly king in check, and if it did discard those moves (it's illegal to perform a move that leaves the player moving himself in check), and keep the rest then process each move as 4 characters each appended all together as one string, then returning that string to exit the function.

If the final string contains 1 move or more the game is still in progress, if however the movelist contains no legal moves then we check to see if our king is in check, if there are no legal moves and our king is in check, then player to move is checkmated, if the player to move is NOT in check and there are no legal moves then the game is drawn by stalemate.

checkmated:

whitecheck is true;

allmoves.length() == 0;

stalemate:

whitecheck is false;

allmoves.length() == 0;

Game is still in progress:

whitecheck is either true or false

allmoves.length() != 0;

assuming allmoves is the movelist received from function whitemoves();

and check is true when white is in check and false when white is not in check.

The blackmoves function is a mirror of the whitemoves function, I only had to change less than symbols with greater than symbols (and vice versa), the case statements to find the negative value pieces, and the check function for white changed for the check function for black. (and a couple other things like castling squares and promotions (queen) and under promotions (rook, bishop knight)).

(full code not yet published in this thread or site).

This post has been edited by Deepglue555: 06 August 2014 - 10:09 PM

Was This Post Helpful? 0
  • +
  • -

#32 Deepglue555  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 6
  • View blog
  • Posts: 117
  • Joined: 13-April 09

Posted 07 August 2014 - 03:02 PM

I have published the source code to my chess program site, you can find the source there under downloads, or in the previous post, the url is http://www.echochess.pw/

Here is the whole whitemoves function, it generates a string of 4 characters for each legal move in the position and returns with that.

string whitemoves(int epa, int epb){	//epa is integer for en passant square file, epb is en passant square rank, together they make a coordinate
	string allmoves;
	int fromSQa[218];
	int fromSQb[218];
	int toSQa[218];
	int toSQb[218];
	
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	int e = 0;
	int f = 0;
	int z = 0;
	string promotions;
	int i2;

	promotions = "qrbn";

	for (a = 0; a < 8; a++){
		for (b = 0; b < 8; b++){
			switch (board[a][b]) {
			
				case queen:
					{
						for (e = -1; e <= 1; e++) {
						for (f = -1; f <= 1; f++) {
							c = a + e;
							d = b + f;
							if (!(f == 0 && e == 0)) {
								do {
									if (bounds(c, d)) {
										
										if (board[c][d] == 0) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;
											z = z + 1;
										}
										if (board[c][d] < 0) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;

											z = z + 1;
											break; 
										}
										if (board[c][d] > 0) break; 
										c = c + e;
										d = d + f;
									}
								}
								while (!(bounds(c, d) == false));
							
							}
							
						}
					}

				
				case rook:
					for (e = -1; e <= 1; e++) {
						for (f = -1; f <= 1; f++) {
							c = a + e;
							d = b + f;
							if (abs(e)+abs(f) == 1) {
								do {
									if (bounds(c, d)) {
										
										if (board[c][d] == 0) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;
											z = z + 1;
										}
										if (board[c][d] < 0) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;

											z = z + 1;
											break; 
										}
										if (board[c][d] > 0) break; 
										c = c + e;
										d = d + f;
									}
								}
								while (!(bounds(c, d) == false));
							
							}
							
						}
					}
					break;
					case bishop:
					for (e = -1; e <= 1; e++) {
						for (f = -1; f <= 1; f++) {
							c = a + e;
							d = b + f;
							if (abs(e)+abs(f) == 2) {
								do {
									if (bounds(c, d)) {
										
										if (board[c][d] == 0) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;
											z = z + 1;
										}
									if (board[c][d] < 0) {
										fromSQa[z] = a;
										fromSQb[z] = b;
										toSQa[z] = c;
										toSQb[z] = d;

										z = z + 1;
										break; 
									}
									if (board[c][d] > 0) break; 

								}
							c = c + e;
							d = d + f;
							}
							while (!(bounds(c, d) == false));
						}
					}
				}
				break;
				case knight:
					for(e=-2; e<=2; e+=1){
						for(f=-2; f<=2; f+=1){
							c = a + e;
							d = b + f;
							if(abs(e) + abs(f) == 3){
								if(bounds(c,d)){
									if(board[c][d]<=0){
										fromSQa[z]=a;
										fromSQb[z]=b;
										toSQa[z]=c;
										toSQb[z]=d;
										z+=1;
									}
								}
							}
						}
					}
					break;
					case pawn:
						//white pawn attack left and forward
						c = a + 1;
						d = b - 1;
						if (bounds(c, d)) {		//bounds checks if the square is on the board, if not go to next move direction for pawn.
							
							if (board[c][d] < 0 || (epa == c && epb == d)) { //if diagonal square attacked contains a piece valued less than zero then capture is possible, or square is the en passant square from previous move.
								fromSQa[z] = a;
								fromSQb[z] = b;
								toSQa[z] = c;
								toSQb[z] = d;
								z = z + 1;
							}
						}
						//white pawn attack right and forward
						c = a + 1;
						d = b + 1;
						if (bounds(c, d)) {
							
							if (board[c][d] < 0 || (epa == c && epb == d)) {
								fromSQa[z] = a;
								fromSQb[z] = b;
								toSQa[z] = c;
								toSQb[z] = d;
								z = z + 1;
							}
						}
						//check if one square forward is unoccupied and add it to the movelist
							if (a == 1) {
								c = 2;
								d = b;
								if (bounds(c, d)) {
									
									if (board[c][d] == 0) {
										fromSQa[z] = a;
										fromSQb[z] = b;
										toSQa[z] = c;
										toSQb[z] = d;
										z = z + 1;
										c = 3;
										d = b;
										//another square forward if the pawn is on it's starting rank
										if (bounds(c, d)) {
											
											if (board[c][d] == 0) {
												fromSQa[z] = a;
												fromSQb[z] = b;
												toSQa[z] = c;
												toSQb[z] = d;
												z = z + 1;
											}
										}
									}
								}
							}
						else {	//pawn is not on starting rank
							c = a + 1;
							d = b;
							if (bounds(c, d)) {
								if (board[c][d] == 0) {
									fromSQa[z] = a;
									fromSQb[z] = b;
									toSQa[z] = c;
									toSQb[z] = d;
									z = z + 1;
								}
							}
						}

					break;
					case king:
						for (e = -1; e <= 1; e++) {
							for (f = -1; f <= 1; f++) {
								if (!(e == 0 && f == 0)) {
									c = a + e;
									d = b + f;

									if (bounds(c, d)) {		//checks if coordinates exist on the board
													  
										if (board[c][d] <= 0 && checkwhite(c, d, a, B)/>.empty()) {
											fromSQa[z] = a;
											fromSQb[z] = b;
											toSQa[z] = c;
											toSQb[z] = d;
											z = z + 1;
										}
									}
								}
							}
						}
					//castleKingSide
						if (wkside && a == 0 && b == 4 && board[0][7] == rook && board[0][6] == 0 && board[0][5] == 0) {
							if (checkwhite(0, 4, 0, 4).empty() && checkwhite(0, 5, 0, 4).empty() && checkwhite(0, 6, 0, 4).empty()) {
								fromSQa[z] = 0;
								fromSQb[z] = 4;
								toSQa[z] = 0;
								toSQb[z] = 6;
								z = z + 1;
							}
						}

						//castleQueenSide
						if (wqside == true && a == 0 && b == 4 && board[0][0] == rook && board[0][1] == 0 && board[0][2] == 0 && board[0][3] == 0) {
							if (checkwhite(0, 4, 0, 4).empty() && checkwhite(0, 3, 0, 4).empty() && checkwhite(0, 2, 0, 4).empty()) {
								fromSQa[z] = 0;
								fromSQb[z] = 4;
								toSQa[z] = 0;
								toSQb[z] = 2;
								z = z + 1;
							}
						}
				} // close switch

			}


		}
	}
	//now all moves are checked to see if they leave the white king in check and if they do they are discarded from the list
	int i;
	int captured;
	int wksqa, wksqb;
	string addmove;

	for(a = 0; a <= 7; a++){
		for(b = 0; b <= 7; b++){
			if(board[a][b] == king){
				wksqa = a;
				wksqb = b;
				goto kingfound;
			}		
		}
	}
kingfound:
	


	bool epcapture;
	epcapture = false;
	
	i = 0;
	for(i = 0; i < z; i++){
		a = fromSQa[i];
		b = fromSQb[i];
		c = toSQa[i];
		d = toSQb[i];

		//perform the move
		captured = board[c][d];
		board[c][d] = board[a][b];
		board[a][b] = 0;

		if(board[c][d] == pawn && (b != d) && (captured == 0) && bounds((c - 1), d)){
			board[c-1][d] = 0;
			epcapture = true;
		}

		//if the king is the piece moving wksqa and wksqb won't contain the coordinates of the king! c and d will
		if(board[c][d] == king){
			if(checkwhite(c, d, 64, 0).empty()){
				//add move to list, otherwise discard move (do nothing)
				addmove = chfile(B)/> + chrank(a) + chfile(d) + chrank(c);		//convert coordinates to ascii
				allmoves = allmoves + addmove;		//add to the movelist
			}
		}
		else{		//if the king is not the piece moving then the king is in the coordinates wksqa and wksqb, and we check that square for check, if it is check it is not added to the movelist (allmoves)
			if(checkwhite(wksqa, wksqb, 64, 0).empty()){
				//add move to list, otherwise discard move (do nothing)
				if(!(board[c][d] == pawn && (c == 7))){		// if the move is not a pawn progressed to the 8th rank, then add move to the list, otherwise, pawn promotions and underpromotions must be added to the move list (each)
					addmove = chfile(B)/> + chrank(a) + chfile(d) + chrank(c);		//convert coordinates to ascii
					allmoves = allmoves + addmove;		//add to the movelist
				}
				else{
					for(i2 = 0; i2 < 4; i2++){
						addmove = chfile(B)/> + chrank(a) + chfile(d) + promotions.substr(i2,1);		//promotion is 4 characters the file the pawn starts on followed by the rank and file moving to (if capturing will be different) followed by either q for promote to queen, r for rook, n for knight and b for bishop.
						allmoves = allmoves + addmove;		//add to the movelist
					}
				}
			}
		}


		//undo the move
		board[a][b] = board[c][d];
		board[c][d] = captured;

		if (epcapture == true){
			board[c-1][d] = -pawn;
			epcapture = false;

		}

	}
	return allmoves;
}



Here is the latter half that discards the illegal moves and processes the legal moves into a long string of moves, 4 characters each.

//now all moves are checked to see if they leave the white king in check and if they do they are discarded from the list
	int i;
	int captured;
	int wksqa, wksqb;
	string addmove;

	for(a = 0; a <= 7; a++){
		for(b = 0; b <= 7; b++){
			if(board[a][b] == king){
				wksqa = a;
				wksqb = b;
				goto kingfound;
			}		
		}
	}
kingfound:
	


	bool epcapture;
	epcapture = false;
	
	i = 0;
	for(i = 0; i < z; i++){
		a = fromSQa[i];
		b = fromSQb[i];
		c = toSQa[i];
		d = toSQb[i];

		//perform the move
		captured = board[c][d];
		board[c][d] = board[a][b];
		board[a][b] = 0;

		if(board[c][d] == pawn && (b != d) && (captured == 0) && bounds((c - 1), d)){
			board[c-1][d] = 0;
			epcapture = true;
		}

		//if the king is the piece moving wksqa and wksqb won't contain the coordinates of the king! c and d will
		if(board[c][d] == king){
			if(checkwhite(c, d, 64, 0).empty()){
				//add move to list, otherwise discard move (do nothing)
				addmove = chfile(B)/> + chrank(a) + chfile(d) + chrank(c);		//convert coordinates to ascii
				allmoves = allmoves + addmove;		//add to the movelist
			}
		}
		else{		//if the king is not the piece moving then the king is in the coordinates wksqa and wksqb, and we check that square for check, if it is check it is not added to the movelist (allmoves)
			if(checkwhite(wksqa, wksqb, 64, 0).empty()){
				//add move to list, otherwise discard move (do nothing)
				if(!(board[c][d] == pawn && (c == 7))){		// if the move is not a pawn progressed to the 8th rank, then add move to the list, otherwise, pawn promotions and underpromotions must be added to the move list (each)
					addmove = chfile(B)/> + chrank(a) + chfile(d) + chrank(c);		//convert coordinates to ascii
					allmoves = allmoves + addmove;		//add to the movelist
				}
				else{
					for(i2 = 0; i2 < 4; i2++){
						addmove = chfile(B)/> + chrank(a) + chfile(d) + promotions.substr(i2,1);		//promotion is 4 characters the file the pawn starts on followed by the rank and file moving to (if capturing will be different) followed by either q for promote to queen, r for rook, n for knight and b for bishop.
						allmoves = allmoves + addmove;		//add to the movelist
					}
				}
			}
		}


		//undo the move
		board[a][b] = board[c][d];
		board[c][d] = captured;

		if (epcapture == true){
			board[c-1][d] = -pawn;
			epcapture = false;

		}

	}
	return allmoves;


The code above tests the entire move list, every move by performing the move, testing to see if player to moves king is in check, discarding it if it does leave the king in check, adding it to the string list allmoves if it doesn't and is a valid chess move, then undoing the move.

I will tell you right now it isn't very efficient!

But we can change that. 97% of the time, it won't be testing moves even in the ballpark of being an invalid move. (97% is an estimate).

We can make it more efficient by not testing all the moves, just the ones that attempt to move a piece or pawn out of an absolute pin.

If the king isn't in check to begin with, all we have to do is find all the absolute pins, that is a piece or pawn is pinned to the king by an enemy rook, queen or bishop. Knights and pawns don't pin anything!

So knowing already which square the king is on, we will use a function that returns all the square that piece are in an absolute pin on, from there, we don't need to do the test move part for pieces and pawns NOT in an absolute pin. That should save alot of cpu cycles. The only moves that will need to be tested are moving anything in an absolute pin, or moving the king, but the king is already covered in the first half of the function.

If however the king is in check to start with we could still test all moves or just moves that land on a square on the diagonal or rank or file of the check, or a king move, and discard the rest. For now I will leave this at the simpler option.

If the king is in double check we need not generate any other piece moves than the king, if you know chess the rule is in double check, the king must move, because no one piece can move anywhere to stop check from two directions!

Hopefully in my next post I will cover what happens in the latter half of the whitemoves function.

However for simplicity sake I have left the function as is, and it will be easier to understand for that tutorial.
Was This Post Helpful? 0
  • +
  • -

#33 Deepglue555  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 6
  • View blog
  • Posts: 117
  • Joined: 13-April 09

Posted 12 August 2014 - 11:35 AM

Randomizing the move list.

As a kid I would sometimes play solitaire. And I found a way to shuffle the deck because it was hard for me to do the method where you split the deck and have the cards interlace.

So I would start with the full deck and put down 5 different cards, then I would take a card off the top and put it randomly on one of the five card piles, rinse and repeat until the piles have all the cards, and when done put pile 1 on pile 2 then that pile of cards on pile 3, then add that to pile 4 and 5. What you end up with is a fairly shuffled deck. Repeat as necessary.

In chess, you may want the move list randomized for whatever reason.

We can do the same thing in chess. In our program, the move is assembled as a 4 character string then appended to allmoves (string).

However instead of appending it to allmoves we could have made 5 strings, ie string1, string2, string3, string4 and string5, (it doesn't have to be 5, it could be 10, or 6, or 3). Then after the move is assembled we use rand() to generate a number between 0-4, if the random number is 0 we put it on string1, if it's 1 then append the move string to string 2 and so on. When we are finished we take string1 + string2 + string3 + string4 + string 5 and put the total into allmoves and return allmoves and exit the function, now at least the moves are in a completely different order.
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3