#include #include #include #include #define TRUE 1 #define FALSE 0 typedef short int bool; typedef struct { bool origin[2]; bool target[2]; bool castle[4]; } move; struct nodetype { char board[8][8]; bool turn; move lastMove; struct nodetype *next; }; struct nodesize { char board[8][8]; bool turn; move lastMove; int *next; }; typedef struct nodetype *NODEPTR; //Node operation functions NODEPTR getNode(void); void freeNode(NODEPTR p); //Function called by main program, initializes variables void initialize(char board[][8], move *lastmove); //Functions called by main program, print board or move void printBoard(char board[][8]); void printMove(move m); //Function called by main program, reads user input move getMove(char board[][8], move lastmove, char name[]); //Function called by main program, finds best next move move nextMove(char brd[][8], move lastmove, int looklevel, char player); //Functions build game tree for use by function nextMove NODEPTR buildTree(char brd[][8], move lastmove, int looklevel, char player, NODEPTR *best, int *value); NODEPTR generate(NODEPTR position, char player, int *mate, int *moves); NODEPTR tacticalgen(NODEPTR p, char player, int *morecaptures); void makeNode(char brd[][8], NODEPTR q, move newmove, bool firstnode); //Functions evaluate game tree, assisting function nextMove void miniMax(NODEPTR pnd, int plevel, int depth, int uvalue, char player, NODEPTR *pbest, int *pvalue); int evaluate(char brd[][8], char player, move lastmove); void tacticaleval(NODEPTR pnd, int plevel, int depth, int uvalue, char player, int *pvalue); int peiceValue(char peice); int positionalValue(int i, int j, char brd[][8]); int tacticalValue(char brd[][8], move lastmove); bool attackedByPawn(int i, int j, char brd[][8]); bool attackedByBishop(int i, int j, char brd[][8], move lastmove); bool attackedByKnight(int i, int j, char brd[][8], move lastmove); bool attackedByRook(int i, int j, char brd[][8], move lastmove); //Function to test legality of a move, assists generate and is called by main program bool isLegal(move m, char brd[][8], move lastmove); //Helper Functions for isLegal bool isLegalP(move m, char brd[][8], move lastmove); bool isLegalp(move m, char brd[][8], move lastmove); bool isLegalKNight(move m); bool isLegalBishop(move m, char brd[][8]); bool isLegalRook(move m, char brd[][8]); bool isLegalQueen(move m, char brd[][8]); bool isLegalK(move m, char brd[][8]); bool isLegalk(move m, char brd[][8]); bool whiteInCheck(char brd[][8], move lastmove); bool blackInCheck(char brd[][8], move lastmove); bool whiteIsPinned(int alpha, int numeric, char brd[][8], move lastmove); bool blackIsPinned(int alpha, int numeric, char brd[][8], move lastmove); bool isClearDiagonal(move m, char brd[][8]); bool isClearFile(move m, char brd[][8]); bool isClearRank(move m, char brd[][8]); //Function to find checkmate and stalemate int isMate(char brd[][8], move lastmove); //Function to take a board position and a move and makes a new board position by applying the move void executeMove(char position[][8], move *newmove, char newposition[][8]); //Minor helper functions that help to maintain abstraction move lastMove(NODEPTR p); move makeMove(int oa, int on, int ta, int tn, move lastmove); move convertInput(char input[], move lastmove); move copyMove(move m); char originAlpha(move newmove); char originNumeric(move newmove); char targetAlpha(move newmove); char targetNumeric(move newmove); bool whiteCanCastleLeft(move m); bool whiteCanCastleRight(move m); bool blackCanCastleLeft(move m); bool blackCanCastleRight(move m); NODEPTR getNode(void) { NODEPTR newnode; newnode =(NODEPTR) malloc(sizeof(struct nodesize)); return newnode; } void freeNode(NODEPTR p) { free(p); } void initialize(char board[][8], move *lastmove) { int i; board[0][7]=board[7][7]='r'; board[1][7]=board[6][7]='n'; board[2][7]=board[5][7]='b'; board[3][7]='q'; board[4][7]='k'; for(i=0;i<8;i++) board[i][6]='p'; for(i=0;i<8;i++) board[i][5]='-'; for(i=0;i<8;i++) board[i][4]='-'; for(i=0;i<8;i++) board[i][3]='-'; for(i=0;i<8;i++) board[i][2]='-'; for(i=0;i<8;i++) board[i][1]='P'; board[0][0]=board[7][0]='R'; board[1][0]=board[6][0]='N'; board[2][0]=board[5][0]='B'; board[3][0]='Q'; board[4][0]='K'; //lastmove's target implies that it is white's turn to move lastmove->target[0]=4; lastmove->target[1]=7; for(i=0;i<4;i++) lastmove->castle[i]=1; } void printBoard(char board[][8]) { int i, j; for(i=7;i>-1;i--){ printf("\n%i ", i+1); for(j=0;j<8;j++) printf(" %c", board[j][i]); } printf("\n\n A B C D E F G H\n"); } void printMove(move m) { int oa, on, ta, tn; char origin, target; oa = m.origin[0]; on = m.origin[1] + 1; ta = m.target[0]; tn = m.target[1] + 1; switch(oa) { case 7: origin = 'h'; break; case 6: origin = 'g'; break; case 5: origin = 'f'; break; case 4: origin = 'e'; break; case 3: origin = 'd'; break; case 2: origin = 'c'; break; case 1: origin = 'b'; break; case 0: origin = 'a'; break; default: printf("Error: cannot print invalid move"); } switch(ta) { case 7: target = 'h'; break; case 6: target = 'g'; break; case 5: target = 'f'; break; case 4: target = 'e'; break; case 3: target = 'd'; break; case 2: target = 'c'; break; case 1: target = 'b'; break; case 0: target = 'a'; break; default: printf("Error: cannot print invalid move"); } printf("%c%d%c%d\n", origin, on, target, tn); } move getMove(char board[][8], move lastmove, char name[]) { int originalpha, originnumeric, targetalpha, targetnumeric; char originchar, targetchar, nowhere; move newmove; printf("\n\nPlease enter your move, %s.\n", name); printf("Please enter origin square (ex. e2):"); scanf("%c%i", &originchar, &originnumeric);scanf("%c", &nowhere); printf("Please enter target square (ex. e4):"); scanf("%c%i", &targetchar, &targetnumeric);scanf("%c", &nowhere); originnumeric-=1; targetnumeric-=1; switch(originchar) { case'A': case'a': originalpha=0; break; case'B': case'b': originalpha=1; break; case'C': case'c': originalpha=2; break; case'D': case'd': originalpha=3; break; case'E': case'e': originalpha=4; break; case'F': case'f': originalpha=5; break; case'G': case'g': originalpha=6; break; case'H': case'h': originalpha=7; break; default: originalpha=99; } switch(targetchar) { case'A': case'a': targetalpha=0; break; case'B': case'b': targetalpha=1; break; case'C': case'c': targetalpha=2; break; case'D': case'd': targetalpha=3; break; case'E': case'e': targetalpha=4; break; case'F': case'f': targetalpha=5; break; case'G': case'g': targetalpha=6; break; case'H': case'h': targetalpha=7; break; default: targetalpha=99; } if(0 <= originalpha <= 7) if(0 <= originnumeric <= 7) if(0 <= targetalpha <= 7) if(0 <= targetnumeric <= 7) if(!(board[originalpha][originnumeric]=='-')) { newmove=makeMove(originalpha, originnumeric, targetalpha, targetnumeric, lastmove); if(isLegal(newmove, board, lastmove)) return newmove; } printf("\nI'm sorry, but that move is not valid"); printBoard(board); if(whiteInCheck(board, lastmove)) printf("\nCheck!"); if(blackInCheck(board, lastmove)) printf("\nCheck!"); return getMove(board, lastmove, name); } move nextMove(char brd[][8], move lastmove, int looklevel, char player) { move newmove; NODEPTR ptree, best; int value; //float valueprintable; ptree = buildTree(brd, lastmove, looklevel, player, &best, &value); //printf("Found best branch!\n"); //valueprintable = (float)value; //valueprintable /= 1000; //printf("\nComputer has a tactical score of %.2f compared to the player", valueprintable); newmove = lastMove(best); return newmove; } NODEPTR buildTree(char brd[][8], move lastmove, int looklevel, char player, NODEPTR *best, int *value) { NODEPTR ptree; int i, j; ptree=getNode(); //printf("\nThinking..."); for(i=0;i<8;i++) for(j=0;j<8;j++) ptree->board[i][j]=brd[i][j]; ptree->turn=1; ptree->lastMove=lastmove; //printf("\nReady to expand..."); ptree->next=NULL; miniMax(ptree, 0, looklevel, 100000, player, best, value); //printf("\nTree build success!\n"); return(ptree); } NODEPTR generate(NODEPTR p, char player, int *mate, int *moves) { int i, j, k, l; move newmove; NODEPTR q = getNode(); bool firstnode = TRUE; *mate=0; *moves=0; if(p->turn == -1) { if(player == 'W') player = 'B'; else player = 'W'; } for(i=0;i<8;i++) for(j=0;j<8;j++) if(p->board[i][j] != '-') if( (player == 'W' && isupper(p->board[i][j])) || (player == 'B' && islower(p->board[i][j])) ) for(k=0;k<8;k++) for(l=0;l<8;l++) { newmove = makeMove(i, j, k, l, lastMove(p)); if(isLegal(newmove, p->board, lastMove(p))) { makeNode(p->board, q, newmove, firstnode); (*moves)++; firstnode = FALSE; } } if(firstnode) { freeNode(q); if(!whiteInCheck(p->board, lastMove(p)) && !blackInCheck(p->board, lastMove(p))) *mate=1; else *mate=2; } return q; } void makeNode(char brd[][8], NODEPTR q, move newmove, bool firstnode) { if(firstnode==1){ q->lastMove=newmove; executeMove(brd, &newmove, q->board); q->next=NULL; return;} if(q->next==NULL){ NODEPTR newnode; newnode=getNode(); executeMove(brd, &newmove, newnode->board); newnode->lastMove=newmove; q->next=newnode; newnode->next=NULL; return;} makeNode(brd, q->next, newmove, firstnode); } void executeMove(char position[][8], move *newmove, char newposition[][8]) { char temp, enpassanttemp; int i, j; if((originAlpha(*newmove)==0&&originNumeric(*newmove)==0) || (targetAlpha(*newmove)==0&&targetNumeric(*newmove)==0)) newmove->castle[0]=0; if((originAlpha(*newmove)==7&&originNumeric(*newmove)==0) || (targetAlpha(*newmove)==7&&targetNumeric(*newmove)==0)) newmove->castle[1]=0; if((originAlpha(*newmove)==0&&originNumeric(*newmove)==7) || (targetAlpha(*newmove)==0&&targetNumeric(*newmove)==7)) newmove->castle[2]=0; if((originAlpha(*newmove)==7&&originNumeric(*newmove)==7) || (targetAlpha(*newmove)==7&&targetNumeric(*newmove)==7)) newmove->castle[3]=0; temp = position[originAlpha(*newmove)][originNumeric(*newmove)]; enpassanttemp = position[targetAlpha(*newmove)][targetNumeric(*newmove)]; for(i=0;i<8;i++) for(j=0;j<8;j++) newposition[i][j]=position[i][j]; if(temp=='P'&&targetNumeric(*newmove)==7) temp='Q'; if(temp=='p'&&targetNumeric(*newmove)==0) temp='q'; newposition[originAlpha(*newmove)][originNumeric(*newmove)]='-'; newposition[targetAlpha(*newmove)][targetNumeric(*newmove)]=temp; //Special conditions for castling moves if(temp=='K') if(originAlpha(*newmove)==4&&originNumeric(*newmove)==0){ if(targetAlpha(*newmove)==2) { newposition[3][0]='R'; newposition[0][0]='-'; } if(targetAlpha(*newmove)==6) { newposition[5][0]='R'; newposition[7][0]='-'; } newmove->castle[0]=0; newmove->castle[1]=0; } if(temp=='k') if(originAlpha(*newmove)==4&&originNumeric(*newmove)==7){ if(targetAlpha(*newmove)==2) { newposition[3][7]='r'; newposition[0][7]='-'; } if(targetAlpha(*newmove)==6) { newposition[5][7]='r'; newposition[7][7]='-'; } newmove->castle[2]=0; newmove->castle[3]=0; } //Special conditions for en passant if(temp=='P') if(originAlpha(*newmove) != targetAlpha(*newmove)) if(enpassanttemp=='-') newposition[targetAlpha(*newmove)][4]='-'; if(temp=='p') if(originAlpha(*newmove) != targetAlpha(*newmove)) if(enpassanttemp=='-') newposition[targetAlpha(*newmove)][3]='-'; } void miniMax(NODEPTR pnd, int plevel, int depth, int uvalue, char player, NODEPTR *pbest, int *pvalue) { /*** Leaf, unless lastmove was a capture ***/ if(plevel==depth) { tacticaleval(pnd, 0, 1, 100000, player, pvalue); /*val = evaluate(pnd->board, player, lastMove(pnd)); if (val > *pvalue) *pvalue = val;*/ return; } /*** Root of tree ***/ if(plevel==0){ NODEPTR p; int val, mate, moves; p=generate(pnd, player, &mate, &moves); /*if(moves < 10) depth = 3;*/ p->turn=-1; miniMax(p, plevel+1, depth, 100000, player, pbest, pvalue); *pbest=p; p=p->next; while(p != NULL) { p->turn=-1; miniMax(p, plevel+1, depth, *pvalue, player, pbest, &val); if(val == *pvalue) if(rand()%2) // Randomly pick one of the two equivalent moves *pbest = p; if(val>*pvalue) { *pvalue=val; *pbest=p; } p=p->next; } return; } /*** Branches of tree ***/ else { NODEPTR p, q; int val, mate, moves; p=generate(pnd, player, &mate, &moves); if(mate == 1) { *pvalue = 0; return; } if(mate == 2) { if(player=='W') { if(whiteInCheck(pnd->board, lastMove(pnd))) *pvalue = -99000; else *pvalue = 99000; } else { if(blackInCheck(pnd->board, lastMove(pnd))) *pvalue = -99000; else *pvalue = 99000; } return; } if(pnd->turn==1) p->turn=-1; else p->turn=1; miniMax(p, plevel+1, depth, 100000, player, pbest, pvalue); q=p; p=p->next; freeNode(q); while(p != NULL) { if(pnd->turn==1) p->turn=-1; else p->turn=1; miniMax(p, plevel+1, depth, *pvalue, player, pbest, &val); if(pnd->turn==1) { if(val>*pvalue) { *pvalue=val; } if(uvalue != 100000) if(uvalue<*pvalue) { while(p != NULL) { q=p; p=p->next; freeNode(q); } return; } } if(pnd->turn==-1) { if(val<*pvalue) { *pvalue=val; } if(uvalue != 100000) if(uvalue>*pvalue) { while(p != NULL) { q=p; p=p->next; freeNode(q); } return; } } q=p; p=p->next; freeNode(q); } } } void tacticaleval(NODEPTR pnd, int plevel, int depth, int uvalue, char player, int *pvalue) { NODEPTR p, q; int val, morecaptures; p=tacticalgen(pnd, player, &morecaptures); if(morecaptures == TRUE && plevel < depth) { if(pnd->turn==1) p->turn=-1; else p->turn=1; tacticaleval(p, plevel+1, depth, 100000, player, pvalue); q=p; p=p->next; freeNode(q); while(p != NULL) { if(pnd->turn==1) p->turn=-1; else p->turn=1; tacticaleval(p, plevel+1, depth, *pvalue, player, &val); if(pnd->turn==1) { if(val>*pvalue) *pvalue=val; if(uvalue != 100000) if(uvalue<*pvalue) { while(p != NULL) { q=p; p=p->next; freeNode(q); } return; } } if(pnd->turn==-1) { if(val<*pvalue) *pvalue=val; if(uvalue != 100000) if(uvalue>*pvalue) { while(p != NULL) { q=p; p=p->next; freeNode(q); } return; } } q=p; p=p->next; freeNode(q); } val = evaluate(pnd->board, player, lastMove(pnd)); if(pnd->turn == 1) if(val > *pvalue) *pvalue = val; if(pnd->turn == -1) if(val < *pvalue) *pvalue = val; } else *pvalue = evaluate(pnd->board, player, lastMove(pnd)); } NODEPTR tacticalgen(NODEPTR p, char player, int *morecaptures) { int i, j, k, l; move newmove; NODEPTR q = getNode(); bool firstnode = TRUE; *morecaptures= TRUE; if(p->turn == -1) { if(player == 'W') player = 'B'; else player = 'W'; } for(i=0;i<8;i++) for(j=0;j<8;j++) if(p->board[i][j] != '-') if( (player == 'W' && isupper(p->board[i][j])) || (player == 'B' && islower(p->board[i][j])) ) for(k=0;k<8;k++) for(l=0;l<8;l++) if( (player == 'W' && islower(p->board[k][l])) || (player == 'B' && isupper(p->board[k][l])) ) { newmove = makeMove(i, j, k, l, lastMove(p)); if(isLegal(newmove, p->board, lastMove(p))) { makeNode(p->board, q, newmove, firstnode); firstnode = FALSE; } } if(firstnode) { freeNode(q); *morecaptures = FALSE; } return q; } int evaluate(char brd[][8], char player, move lastmove) { int i, j, mate=0, score=0; mate = isMate(brd, lastmove); if(mate==2) { if(blackInCheck(brd, lastmove)) score += 99000; if(whiteInCheck(brd, lastmove)) score += -99000; } else if(mate==1) return 0; if(score == 0) for(i=0;i<8;i++) for(j=0;j<8;j++) { score += peiceValue(brd[i][j]); score += positionalValue(i, j, brd); } //score += tacticalValue(brd, lastmove); if(player=='B') score = -score; return score; } int peiceValue(char peice) { switch(peice) { case'K': return 99000; case'k': return -99000; case'Q': return 9000; case'q': return -9000; case'R': return 5000; case'r': return -5000; case'B': return 3000; case'b': return -3000; case'N': return 3000; case'n': return -3000; case'P': return 1000; case'p': return -1000; case'-': default: return 0; } } int positionalValue(int j, int i, char brd[][8]) { int bishopPlacement[8][8] = { { -100, -100, -100, -100, -100, -100, -100, -100 }, { -100, 25, 0, 0, 0, 0, 25, -100 }, { -100, 0, 50, 50, 50, 50, 0, -100 }, { -100, 0, 50, 100, 100, 50, 0, -100 }, { -100, 0, 50, 100, 100, 50, 0, -100 }, { -100, 0, 50, 50, 50, 50, 0, -100 }, { -100, 25, 0, 0, 0, 0, 25, -100 }, { -100, -100, -200, -100, -100, -200, -100, -100 } }; int knightPlacement[8][8] = { { -100, -100, -100, -100, -100, -100, -100, -100 }, { -100, 0, 0, 0, 0, 0, 0, -100 }, { -100, 0, 50, 50, 50, 50, 0, -100 }, { -100, 0, 50, 100, 100, 50, 0, -100 }, { -100, 0, 50, 100, 100, 50, 0, -100 }, { -100, 0, 50, 50, 50, 50, 0, -100 }, { -100, 0, 0, 0, 0, 0, 0, -100 }, { -100, -200, -100, -100, -100, -100, -200, -100 } }; int pawnPlacement[8][8] = { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 200, 200, 200, 200, 200, 200, 200, 200 }, { 40, 80, 120, 160, 160, 120, 80, 40 }, { 30, 60, 90, 120, 120, 90, 60, 30 }, { 20, 20, 60, 100, 100, 10, 20, 10 }, { 10, 20, 0, -10, -10, 0, 20, 0 }, { 0, 0, 0, -200, -200, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }; int kingPlacement[8][8] = { { -80, -80, -80, -80, -80, -80, -80, -80 }, { -80, -80, -80, -80, -80, -80, -80, -80 }, { -80, -80, -80, -80, -80, -80, -80, -80 }, { -80, -80, -80, -80, -80, -80, -80, -80 }, { -80, -80, -80, -80, -80, -80, -80, -80 }, { -80, -80, -80, -80, -80, -80, -80, -80 }, { -40, -40, -40, -40, -40, -40, -40, -40 }, { 0, 40, 200, -40, 0, -40, 200, 40 } }; int flipI[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; switch(brd[j][i]) { case'K': return kingPlacement[ flipI[i] ][j]; case'k': return -kingPlacement[i][j]; case'Q': return 0; case'q': return 0; case'R': return 0; case'r': return 0; case'B': return bishopPlacement[ flipI[i] ][j]; case'b': return -bishopPlacement[i][j]; case'N': return knightPlacement[ flipI[i] ][j]; case'n': return -knightPlacement[i][j]; case'P': return pawnPlacement[ flipI[i] ][j]; case'p': return -pawnPlacement[i][j]; case'-': default: return 0; } } int tacticalValue(char brd[][8], move lastmove) { int i, j, value, multiplier; value = multiplier = 0; for(i=0;i<8;i++) for(j=0;j<8;j++) switch(brd[i][j]) { case'K': if(whiteInCheck(brd, lastmove)) { value += -300; multiplier--; } break; case'k': if(blackInCheck(brd, lastmove)) { value += 300; multiplier++; } break; case'Q': if(attackedByPawn(i, j, brd)) { value += -200; multiplier--; } if(attackedByBishop(i, j, brd, lastmove)) { value += -150; multiplier--; } if(attackedByKnight(i, j, brd, lastmove)) { value += -150; multiplier--; } if(attackedByRook(i, j, brd, lastmove)) { value += -100; multiplier--; } break; case'q': if(attackedByPawn(i, j, brd)) { value += 200; multiplier++; } if(attackedByBishop(i, j, brd, lastmove)) { value += 150; multiplier++; } if(attackedByKnight(i, j, brd, lastmove)) { value += 150; multiplier++; } if(attackedByRook(i, j, brd, lastmove)) { value += 100; multiplier++; } break; case'R': if(attackedByPawn(i, j, brd)) { value += -100; multiplier--; } if(attackedByBishop(i, j, brd, lastmove)) { value += -50; multiplier--; } if(attackedByKnight(i, j, brd, lastmove)) { value += -50; multiplier--; } break; case'r': if(attackedByPawn(i, j, brd)) { value += 100; multiplier++; } if(attackedByBishop(i, j, brd, lastmove)) { value += 50; multiplier++; } if(attackedByKnight(i, j, brd, lastmove)) { value += 50; multiplier++; } break; case'B': if(attackedByPawn(i, j, brd)) { value += -50; multiplier--; } break; case'b': if(attackedByPawn(i, j, brd)) { value += 50; multiplier++; } break; case'N': if(attackedByPawn(i, j, brd)) { value += -50; multiplier--; } break; case'n': if(attackedByPawn(i, j, brd)) { value += 50; multiplier++; } break; default:; } if(multiplier < 0) multiplier *= -1; switch(multiplier) { case'0': return value; break; case'1': return value; break; case'2': return value * 3; break; case'3': return value * 6; break; case'4': return value * 10; default: ; } if(multiplier > 4) return value * 12; else return value; } bool attackedByPawn(int i, int j, char brd[][8]) { if(isupper(brd[i][j])) { if(brd[i+1][j+1] == 'p') return TRUE; if(brd[i-1][j+1] == 'p') return TRUE; return FALSE; } else { if(brd[i+1][j-1] == 'P') return TRUE; if(brd[i-1][j-1] == 'P') return TRUE; return FALSE; } } bool attackedByBishop(int i, int j, char brd[][8], move lastmove) { int k, l; if(isupper(brd[i][j])) { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='b') if(isLegalBishop(makeMove(i, j, k, l, lastmove), brd)) return TRUE; return FALSE; } else { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='B') if(isLegalBishop(makeMove(i, j, k, l, lastmove), brd)) return TRUE; return FALSE; } } bool attackedByKnight(int i, int j, char brd[][8], move lastmove) { int k, l; if(isupper(brd[i][j])) { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='n') if(isLegalKNight(makeMove(i, j, k, l, lastmove))) return TRUE; return FALSE; } else { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='N') if(isLegalKNight(makeMove(i, j, k, l, lastmove))) return TRUE; return FALSE; } } bool attackedByRook(int i, int j, char brd[][8], move lastmove) { int k, l; if(isupper(brd[i][j])) { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='r') if(isLegalRook(makeMove(i, j, k, l, lastmove), brd)) return TRUE; return FALSE; } else { for(k=0; k<8; k++) for(l=0; l<8; l++) if(brd[k][l]=='R') if(isLegalRook(makeMove(i, j, k, l, lastmove), brd)) return TRUE; return FALSE; } } // Here is where the fun begins!! bool isLegal(move m, char brd[][8], move lastmove) { char player = 'W'; char nextposition[8][8]; move nextmove = makeMove(originAlpha(m), originNumeric(m), targetAlpha(m), targetNumeric(m), lastmove); if(0 > originAlpha(m)) return FALSE; if(originAlpha(m) > 7) return FALSE; if(0 > originNumeric(m)) return FALSE; if(originNumeric(m) > 7) return FALSE; if(0 > targetAlpha(m)) return FALSE; if(targetAlpha(m) > 7) return FALSE; if(0 > targetNumeric(m)) return FALSE; if(targetNumeric(m) > 7) return FALSE; if(isupper(brd[targetAlpha(lastmove)][targetNumeric(lastmove)])) player = 'B'; // We now know that the move involves two legit board squares. // Additionally we have determined whose turn it is to move. if(brd[originAlpha(m)][originNumeric(m)]=='-'){ //printf(" -'s are being passed to isLegal"); return FALSE;} // The origin is not an empty square. if(player=='W') { if(isupper(brd[targetAlpha(m)][targetNumeric(m)])) return FALSE; if(islower(brd[originAlpha(m)][originNumeric(m)])) return FALSE; } if(player=='B') { if(islower(brd[targetAlpha(m)][targetNumeric(m)])) return FALSE; if(isupper(brd[originAlpha(m)][originNumeric(m)])) return FALSE; } // The move does not try to take a peice of the same army or move a peice of the other army switch(brd[originAlpha(m)][originNumeric(m)]) { case'P': if(!isLegalP(m, brd, lastmove)) return FALSE; break; case'p': if(!isLegalp(m, brd, lastmove)) return FALSE; break; case'N': if(!isLegalKNight(m)) return FALSE; break; case'n': if(!isLegalKNight(m)) return FALSE; break; case'B': if(!isLegalBishop(m, brd)) return FALSE; break; case'b': if(!isLegalBishop(m, brd)) return FALSE; break; case'R': if(!isLegalRook(m, brd)) return FALSE; break; case'r': if(!isLegalRook(m, brd)) return FALSE; break; case'Q': if(!isLegalQueen(m, brd)) return FALSE; break; case'q': if(!isLegalQueen(m, brd)) return FALSE; break; case'K': if(!isLegalK(m, brd)) return FALSE; break; case'k': if(!isLegalk(m, brd)) return FALSE; break; default: printf("\nError: Invalid Peice Type... %c\n", brd[originAlpha(m)][originNumeric(m)]); } // We now know that the move is to a valid square given peice type. executeMove(brd, &nextmove, nextposition); if(player=='W') if(whiteInCheck(nextposition, nextmove)) return FALSE; if(player=='B') if(blackInCheck(nextposition, nextmove)) return FALSE; // We now know that the move is not a move into check. return TRUE; } bool isLegalP(move m, char brd[][8], move lastmove) { if(originAlpha(m)==targetAlpha(m)) if(targetNumeric(m)==(originNumeric(m)+1)) if(brd[targetAlpha(m)][targetNumeric(m)]=='-') return TRUE; if(targetAlpha(m)==(originAlpha(m)+1) || targetAlpha(m)==(originAlpha(m)-1)) if(targetNumeric(m)==(originNumeric(m)+1)) { if(islower(brd[targetAlpha(m)][targetNumeric(m)])) { return TRUE; } else if(brd[targetAlpha(lastmove)][targetNumeric(lastmove)]=='p') if(targetNumeric(lastmove)==4) if(originNumeric(lastmove)==6) if(targetNumeric(m)==5) if(targetAlpha(m)==targetAlpha(lastmove)) return TRUE; } if(originNumeric(m)==1) if(targetNumeric(m)==3) if(originAlpha(m)==targetAlpha(m)) if(brd[targetAlpha(m)][targetNumeric(m)]=='-') if(brd[targetAlpha(m)][targetNumeric(m)-1]=='-') return TRUE; return FALSE; } bool isLegalp(move m, char brd[][8], move lastmove) { if(originAlpha(m)==targetAlpha(m)) if(targetNumeric(m)==(originNumeric(m)-1)) if(brd[targetAlpha(m)][targetNumeric(m)]=='-') return TRUE; if((targetAlpha(m)==(originAlpha(m)+1) || targetAlpha(m)==(originAlpha(m)-1))) if(targetNumeric(m)==(originNumeric(m)-1)) { if(isupper(brd[targetAlpha(m)][targetNumeric(m)])) { return TRUE; } else if(brd[targetAlpha(lastmove)][targetNumeric(lastmove)]=='P') if(targetNumeric(lastmove)==3) if(originNumeric(lastmove)==1) if(targetNumeric(m)==2) if(targetAlpha(m)==targetAlpha(lastmove)) return TRUE; } if(originNumeric(m)==6) if(targetNumeric(m)==4) if(originAlpha(m)==targetAlpha(m)) if(brd[targetAlpha(m)][targetNumeric(m)]=='-') if(brd[targetAlpha(m)][targetNumeric(m)+1]=='-') return TRUE; return FALSE; } bool isLegalKNight(move m) { if(targetAlpha(m)==(originAlpha(m)+2)) if((targetNumeric(m)==(originNumeric(m)+1) || targetNumeric(m)==(originNumeric(m)-1)) ) return TRUE; if(targetAlpha(m)==(originAlpha(m)+1)) if((targetNumeric(m)==(originNumeric(m)+2) || targetNumeric(m)==(originNumeric(m)-2)) ) return TRUE; if(targetAlpha(m)==(originAlpha(m)-1)) if((targetNumeric(m)==(originNumeric(m)+2) || targetNumeric(m)==(originNumeric(m)-2)) ) return TRUE; if(targetAlpha(m)==(originAlpha(m)-2)) if((targetNumeric(m)==(originNumeric(m)+1) || targetNumeric(m)==(originNumeric(m)-1)) ) return TRUE; return FALSE; } bool isLegalBishop(move m, char brd[][8]) { if((originAlpha(m)-targetAlpha(m)==originNumeric(m)-targetNumeric(m) || originAlpha(m)-targetAlpha(m)==targetNumeric(m)-originNumeric(m) )) if(isClearDiagonal(m, brd) ) return TRUE; return FALSE; } bool isLegalRook(move m, char brd[][8]) { if(originAlpha(m)==targetAlpha(m)) if(isClearFile(m, brd) ) return TRUE; if(originNumeric(m)==targetNumeric(m)) if(isClearRank(m, brd) ) return TRUE; return FALSE; } bool isLegalQueen(move m, char brd[][8]) { if(isLegalRook(m, brd)) return TRUE; if(isLegalBishop(m, brd)) return TRUE; return FALSE; } bool isLegalK(move m, char brd[][8]) { if(targetAlpha(m)==(originAlpha(m)+1) || targetAlpha(m)==(originAlpha(m)-1) || originAlpha(m)==targetAlpha(m) ) if(targetNumeric(m)==originNumeric(m) || targetNumeric(m)==(originNumeric(m)+1) || targetNumeric(m)==(originNumeric(m)-1) ) return TRUE; if(targetAlpha(m)==2) if(targetNumeric(m)==0) if(whiteCanCastleLeft(m)) if(brd[1][0]=='-') if(isClearRank(m, brd)) if(!whiteIsPinned(3, 0, brd, m)) if(!whiteIsPinned(2, 0, brd, m)) if(!whiteInCheck(brd, m)) return TRUE; if(targetAlpha(m)==6) if(targetNumeric(m)==0) if(whiteCanCastleRight(m)) if(isClearRank(m, brd)) if(!whiteIsPinned(5, 0, brd, m)) if(!whiteIsPinned(6, 0, brd, m)) if(!whiteInCheck(brd, m)) return TRUE; return FALSE; } bool isLegalk(move m, char brd[][8]) { if(targetAlpha(m)==(originAlpha(m)+1) || targetAlpha(m)==(originAlpha(m)-1) || originAlpha(m)==targetAlpha(m) ) if(targetNumeric(m)==originNumeric(m) || targetNumeric(m)==(originNumeric(m)+1) || targetNumeric(m)==(originNumeric(m)-1) ) return TRUE; if(targetAlpha(m)==2) if(targetNumeric(m)==7) if(blackCanCastleLeft(m)) if(brd[1][7]=='-') if(isClearRank(m, brd)) if(!blackIsPinned(3, 7, brd, m)) if(!blackIsPinned(2, 7, brd, m)) if(!blackInCheck(brd, m)) return TRUE; if(targetAlpha(m)==6) if(targetNumeric(m)==7) if(blackCanCastleRight(m)) if(isClearRank(m, brd)) if(!blackIsPinned(5, 7, brd, m)) if(!blackIsPinned(6, 7, brd, m)) if(!blackInCheck(brd, m)) return TRUE; return FALSE; } bool whiteInCheck(char brd[][8], move lastmove) { int i, j, alpha, numeric; bool kingfound = 0; move checkingmove; for(i=0;i<8 && kingfound==0;i++) for(j=0;j<8 && kingfound==0;j++) if(brd[i][j]=='K') { alpha=i; numeric=j; kingfound=TRUE; } for(i=0;i<8;i++) for(j=0;j<8;j++) if(islower(brd[i][j])){ checkingmove = makeMove(i, j, alpha, numeric, lastmove); switch(brd[i][j]) { case'k': if(isLegalk(checkingmove, brd)) return TRUE; break; case'q': if(isLegalQueen(checkingmove, brd)) return TRUE; break; case'r': if(isLegalRook(checkingmove, brd)) return TRUE; break; case'b': if(isLegalBishop(checkingmove, brd)) return TRUE; break; case'n': if(isLegalKNight(checkingmove)) return TRUE; break; case'p': if(isLegalp(checkingmove, brd, lastmove)) return TRUE; default: break; } } return FALSE; } bool blackInCheck(char brd[][8], move lastmove) { int i, j, alpha, numeric; bool kingfound = 0; move checkingmove; for(i=0;i<8 && kingfound==0;i++) for(j=8;j>0 && kingfound==0;--j) if(brd[i][j]=='k') { alpha=i; numeric=j; kingfound=TRUE; } for(i=0;i<8;i++) for(j=0;j<8;j++) if(isupper(brd[i][j])){ checkingmove = makeMove(i, j, alpha, numeric, lastmove); switch(brd[i][j]) { case'K': if(isLegalK(checkingmove, brd)) return TRUE; break; case'Q': if(isLegalQueen(checkingmove, brd)) return TRUE; break; case'R': if(isLegalRook(checkingmove, brd)) return TRUE; break; case'B': if(isLegalBishop(checkingmove, brd)) return TRUE; break; case'N': if(isLegalKNight(checkingmove)) return TRUE; break; case'P': if(isLegalP(checkingmove, brd, lastmove)) return TRUE; default: break; } } return FALSE; } bool whiteIsPinned(int alpha, int numeric, char brd[][8], move lastmove) { int i, j; move pinningmove; for(i=0;i<8;i++) for(j=0;j<8;j++) if(islower(brd[i][j])){ pinningmove = makeMove(i, j, alpha, numeric, lastmove); switch(brd[i][j]) { case'q': if(isLegalQueen(pinningmove, brd)) return TRUE; break; case'r': if(isLegalRook(pinningmove, brd)) return TRUE; break; case'b': if(isLegalBishop(pinningmove, brd)) return TRUE; break; case'n': if(isLegalKNight(pinningmove)) return TRUE; break; case'p': if(isLegalp(pinningmove, brd, lastmove)) return TRUE; default: break; } } return FALSE; } bool blackIsPinned(int alpha, int numeric, char brd[][8], move lastmove) { int i, j; move pinningmove; for(i=0;i<8;i++) for(j=0;j<8;j++) if(isupper(brd[i][j])){ pinningmove = makeMove(i, j, alpha, numeric, lastmove); switch(brd[i][j]) { case'Q': if(isLegalQueen(pinningmove, brd)) return TRUE; break; case'R': if(isLegalRook(pinningmove, brd)) return TRUE; break; case'B': if(isLegalBishop(pinningmove, brd)) return TRUE; break; case'N': if(isLegalKNight(pinningmove)) return TRUE; break; case'P': if(isLegalP(pinningmove, brd, lastmove)) return TRUE; default: break; } } return FALSE; } bool isClearDiagonal(move m, char brd[][8]) { int i, j, istart, ifinish; if(originAlpha(m) > targetAlpha(m) && originNumeric(m) > targetNumeric(m)) { istart=targetAlpha(m)+1; ifinish=originAlpha(m); j=targetNumeric(m)+1; for(i=istart;i targetAlpha(m) && originNumeric(m) < targetNumeric(m)) { istart=originAlpha(m)-1; ifinish=targetAlpha(m); j=originNumeric(m)+1; for(i=istart;i>ifinish;i--) { if(!(brd[i][j]=='-')) return FALSE; j++; } return TRUE; } if(originAlpha(m) < targetAlpha(m) && originNumeric(m) > targetNumeric(m)) { istart=targetAlpha(m)-1; ifinish=originAlpha(m); j=targetNumeric(m)+1; for(i=istart;i>ifinish;i--) { if(!(brd[i][j]=='-')) return FALSE; j++; } return TRUE; } else { istart=originAlpha(m)+1; ifinish=targetAlpha(m); j=originNumeric(m)+1; for(i=istart;i targetNumeric(m)) { start=targetNumeric(m)+1; finish=originNumeric(m); } else { start=originNumeric(m)+1; finish=targetNumeric(m); } for(i=start;i targetAlpha(m)) { start=targetAlpha(m)+1; finish=originAlpha(m); } else { start=originAlpha(m)+1; finish=targetAlpha(m); } for(i=start;ilastMove; return newmove; } move makeMove(int oa, int on, int ta, int tn, move lastmove) { move newmove; int i; newmove.origin[0]=oa; newmove.origin[1]=on; newmove.target[0]=ta; newmove.target[1]=tn; for(i=0;i<4;i++) newmove.castle[i]=lastmove.castle[i]; return newmove; } move convertInput(char input[], move lastmove) { int oa, on, ta, tn; oa = (int)input[0]; oa -= 97; on = (int)input[1]; on -= 49; ta = (int)input[2]; ta -= 97; tn = (int)input[3]; tn -= 49; return makeMove(oa, on, ta, tn, lastmove); } char originAlpha(move newmove) { return newmove.origin[0]; } char originNumeric(move newmove) { return newmove.origin[1]; } char targetAlpha(move newmove) { return newmove.target[0]; } char targetNumeric(move newmove) { return newmove.target[1]; } bool whiteCanCastleLeft(move m) { return m.castle[0]; } bool whiteCanCastleRight(move m) { return m.castle[1]; } bool blackCanCastleLeft(move m) { return m.castle[2]; } bool blackCanCastleRight(move m) { return m.castle[3]; } void main ( void ) { bool gameNotOver=1; bool WINBOARD=0; char board[8][8]; move lastmove, newmove; int mate=0; int depth=2; char player='B'; char computerplayer = 'B'; char humanplayer = 'W'; char nowhere; char input[30]; // Buffering I/O interferes with Xboard/Winboard communication setbuf(stdout, NULL); srand(time(NULL)); printf("Hello, please enter your name: "); scanf("%s", input);scanf("%c", &nowhere); printf("\n"); if(strcmp(input, "xboard") == 0) WINBOARD=1; if(!WINBOARD) { initialize(board, &lastmove); printf("Hi, %s! What side would you like to control?\nPlease enter W for white or B for black: ", input); scanf("%c", &humanplayer);scanf("%c", &nowhere); if(humanplayer == 'W') computerplayer = 'B'; else { computerplayer = 'W'; humanplayer = 'B'; } while(gameNotOver) { printBoard(board); if(whiteInCheck(board, lastmove)) printf("\nCheck!"); if(blackInCheck(board, lastmove)) printf("\nCheck!"); if(player=='B') player = 'W'; else player = 'B'; if(player==computerplayer) newmove = nextMove(board, lastmove, depth, player); if(player==humanplayer) newmove = getMove(board, lastmove, input); printf("\n\nYep, that's legal!\nMove made: "); printMove(newmove); executeMove(board, &newmove, board); lastmove=newmove; mate = isMate(board, lastmove); if(mate==2) { if(player=='W') printf("\n****White checkmated Black!!****\n"); else printf("\n****Black checkmated White!!****\n"); printBoard(board); gameNotOver=FALSE; printf("Press enter to exit"); scanf("%c", &nowhere); } if(mate==1) { printf("\n****The game is drawn due to stalemate!!****\n"); printBoard(board); gameNotOver=FALSE; printf("Press enter to exit"); scanf("%c", &nowhere); } } } else { // Winboard interface bool commandfound; //setbuf(stdin, NULL); /*if(UNIX) { signal(SIGTERM, SIG_IGN); signal(SIGINT, SIG_IGN); }*/ initialize(board, &lastmove); player = 'W'; while(TRUE) { //_read(0,&input); if(player == computerplayer) { newmove = nextMove(board, lastmove, depth, player); executeMove(board, &newmove, board); lastmove = newmove; printf("move "); printMove(newmove); mate = isMate(board, lastmove); if(mate== 2) { if(computerplayer=='W') printf("1-0 {White mates}\n"); else printf("0-1 {Black mates}\n"); gameNotOver=FALSE; } if(mate== 1) { printf("1/2-1/2 {Stalemate}\n"); gameNotOver=FALSE; } if(player == 'W') player = 'B'; else player = 'W'; } scanf("%s", input);scanf("%c", &nowhere); commandfound = FALSE; if(strcmp(input, "new") == 0) { initialize(board, &lastmove); commandfound = TRUE; } if(strcmp(input, "quit") == 0) { exit(0); } if(strcmp(input, "white") == 0) { computerplayer = 'W'; humanplayer = 'B'; commandfound = TRUE; } if(strcmp(input, "black") == 0) { computerplayer = 'B'; humanplayer = 'W'; commandfound = TRUE; } // List of unsupported but recognized commands if(strcmp(input, "level 40 5 0") == 0) { printf("yaya"); initialize(board, &lastmove); commandfound = TRUE; } if(strcmp(input, "post") == 0) commandfound = TRUE; if(strcmp(input, "hard") == 0) commandfound = TRUE; if(strncmp(input, "time", 4) == 0) commandfound = TRUE; if(!commandfound) { if(player == humanplayer) { newmove = convertInput(input, lastmove); //if(!isLegal(newmove, board, lastmove)); if(isLegal(newmove, board, lastmove)) { executeMove(board, &newmove, board); lastmove = newmove; mate = isMate(board, lastmove); if(mate== 2) { if(computerplayer=='B') printf("1-0 {White mates}\n"); else printf("0-1 {Black mates}\n"); gameNotOver=FALSE; } if(mate== 1) { printf("1/2-1/2 {Stalemate}\n"); gameNotOver=FALSE; } if(player == 'B') player = 'W'; else player = 'B'; } } } } } }