• (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: 7
  • View blog
  • Posts: 118
  • 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: 7
  • View blog
  • Posts: 118
  • 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: 7
  • View blog
  • Posts: 118
  • 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
  • +
  • -

#34 sajking  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 22-May 15

Posted 22 May 2015 - 05:41 AM

View PostDeepglue555, on 16 September 2009 - 04:40 AM, said:

here this version will compile under DEV C++ 4.9.9.2

#include<iostream>
#include<string>


// in this example pieces aer described as integer values 
// we will make them constants, so that if at any time we want to change their values we can do so here
// but will still need to recompile

const int pawn = 100;
const int bishop = 305;
const int knight = 300;
const int rook = 500;
const int queen = 900;
const int king = 2000;

// an alternative would be to use string constants or another data type

//now we need a board to put the pieces on and move around on
//the board data type should match the pieces data type
// the board in regular chess is always 8x8, but for speedy legal move generator
//other programs use larger than 8x8 where an 8x8 real board exists in a larger array ie 12x14
// but for simplicity of understanding we will use the simple 8x8

int board[8][8];

// board [rank] [file];
// where rank = 0 - 7 (1 to 8 on a real chess board) and file = 0 - 7 (a - h)

const int startup[8][8] = { rook, knight, bishop, queen, king, bishop, knight, rook, pawn, pawn,pawn,pawn,pawn,pawn,pawn, pawn, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -pawn, -rook, -knight, -bishop, -queen, -king, -bishop, -knight, -rook};

// the startup constant contains the standard starting position of all chess games (not variants)
//each side has 8 pieces and 8 pawns / all pawns are on the colours respective ranks
// for black pieces we use -piecetype. (negative)

void setup (void) {
int i, j;
	for (i = 0; i < 8; i++){
		  for (j = 0; j < 8; j++){
			board[i][j] = startup[i][j]; //setup starting position
	  }
		}

}

//the two for loops run through all the iteratins of the 8x8 array and copy the starting position to the real board.

// next we need a function that will display the board some way either graphics or text
// in this case we will print to the screen a text version of the boards contents

//it is standard in FEN notations and other text of a chess board to express each piece by it's first letter
// except the knight which uses 'N'

// the black pieces are lower case while the white pieces are upper case
// otherwise it is impossible to distinguish black pieces from white pieces

void printb (void){
using namespace std; // this must be here in order to begin using strings.
int a, b;
string piece;
for (a = 7; a > -1; a--){  // we must iterate the ranks down from 7 to 0 otherwise the board will be upside down
cout << endl;
 for (b = 0; b < 8; b++){
 switch (board[a][b]){
 case 0:
 piece = "-";
 break;
 case pawn:
 piece = "P";
 break;
 case knight:
 piece = "N";
 break;
 case bishop:
 piece = "B";
 break;
 case rook:
 piece = "R";
 break;
 case queen:
 piece = "Q";
 break;
 case king:
 piece = "K";
 break;
 case -pawn:
 piece = "p";
 break;
 case -knight:
 piece = "n";
 break;
 case -bishop:
 piece = "b";
 break;
 case -rook:
 piece = "r";
 break;
 case -queen:
 piece = "q";
 break;
 case -king:
 piece = "k";
 break;
 }
  cout << " " << piece << " ";
 }
}

 cout << endl << endl;
}


// every program in win32 console must have a main


int main (void) {

using namespace std;

//we need to tell the user about the program  ..  and how to use it

cout << "welcome to simplechess 1.0!" << endl << "created by Deepglue555" << endl << endl;
cout << "please enter your moves in 4 letter algebraic" << endl << "ie e2e4 in lower case only" << endl;
cout << "commands: exit = quit, abort = quit, print = displays the board," << endl << "new = new game" << endl << endl;

string passd; // this will be the string that contains info from the user
setup(); //we must set up the initial position

while (1){ // a while loop that always loops; except when a break; statement occurs

	getline (cin, passd );  //ask the user to input what he wants the app to do
		 if (passd.substr(0, 4) == "exit" || passd.substr(0, 5) == "abort" || passd.substr(0, 4) == "quit")   { //test //for quit or exit statements
		  break;
		 }
		 if (passd.substr(0, 5) == "print")   { // display the board
		  printb();
		 }
		 if (passd.substr(0, 3) == "new")   { // ask for a new game
		  setup();
		 }
		 if (passd.substr(0, 1) >= "a" && passd.substr(0, 1) <= "h" && passd.substr(1, 1) >= "1" && passd.substr(1, 1) <= "8" && passd.substr(2, 1) >= "a" && passd.substr(2, 1) <= "h" && passd.substr(3, 1) >= "1" && passd.substr(3, 1) <= "8")   { // this statement makes sure both squares are on the chess board when executing //a move
		  // execute move
		  // then display new board position

		  int a, b, c, d;


		  a = passd[0] - 'a';
		  b = passd[1] - '1';
		  c = passd[2] - 'a';
		  d = passd[3] - '1';

//executes the move if its on the board!
		  board[d][c] = board[b][a];
		  board[b][a] = 0;

		  printb(); //prints out to the screen the updated position after moving the pieces
		 }
		}
}



I think ill build part 2 over code from part 1.

Was This Post Helpful? 0
  • +
  • -

#35 sajking  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 22-May 15

Posted 22 May 2015 - 05:47 AM

const int pawn = 100;
const int bishop = 305;
const int knight = 300;
const int rook = 500;
const int queen = 900;
const int king = 2000;

can anybody tell me why we alloted 100,305,100 vlues to these ???can we change these values and what will be the effect if we change these values...thnX..
Was This Post Helpful? 0
  • +
  • -

#36 andrewsw  Icon User is online

  • I'm not here to twist your niblets
  • member icon

Reputation: 4665
  • View blog
  • Posts: 17,291
  • Joined: 12-December 12

Posted 22 May 2015 - 06:09 AM

The traditional, relative values of chess pieces are 1, 3, 5, and 9. These are relative values so they are unaffected when multiplied by 100, which may make other arithmetic easier to work with: keeping everything as integer values.

The bishop is often considered to be of more value than the knight (depending on the position) so I assume the author has increased its value slightly from 300 to 305.

The king is priceless, so I assume that 2000 was chosen as an arbitrarily high value.

I suppose modifying the values shouldn't be an issue, but the author would have to confirm this (or you could study the code).

This comment in the code:
// we will make them constants, so that if at any time we want to change their values we can do so here

suggests that the author anticipated that these values could be changed.

This post has been edited by andrewsw: 22 May 2015 - 06:07 AM

Was This Post Helpful? 1
  • +
  • -

#37 Deepglue555  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 7
  • View blog
  • Posts: 118
  • Joined: 13-April 09

Posted 22 May 2015 - 08:34 AM

THANKYOU :)
Was This Post Helpful? 0
  • +
  • -

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