/******* ** ** Adapted for Parsec v. 1.0 on 09-12-97 by Monnica Terwilliger ** Parallelized by Lokesh Bajaj 1-22-98 ** *******/ /*----------------------------------------------------------------- AUTHOR : Ramesh Panwar (UCLA CS Dept.) DATE : Feb 25, 1992 ------------------------------------------------------------------*/ char *GAME_INFO[12] ={ "One the game starts, the user can specify 4 types of inputs: ", " B <1-8> ", " W <1-8> ", " P ", " Q ", "B <1-8> is accepted as a legal command if the user is playing ", "black and the move to the specified location is a legal move. \n", "W <1-8> is accepted as a legal command if the user is playing ", "white and the move to the specified location is a legal move. \n", "P is accepted as a legal command if the user does not have a ", "legal move and has to pass his turn to move. ", "Q is a legal command to terminate game and prints out the score. \n"}; #include #include #define BLACK 'B' #define WHITE 'W' #define EMPTY '+' #define POSINF 999999 #define NEGINF -999999 #define NORTH 0 #define NW 7 #define WIN 10000 #define MAX 0 #define MIN 1 #define MOBILITY 200 #define CORNER 1000 #define A 50 #define B 10 #define C -10 #define X -200 #define EDGE 10 #define CENTRAL 2 #define MAXPLY 5 #define max(x,y) ((x) > (y) ? (x) : (y)) #define min(x,y) ((x) < (y) ? (x) : (y)) #define OpColor(x) ((x) == WHITE ? BLACK : WHITE ) struct dir { int dr, dc; }; struct SQUARE { int r, c; }; struct dir directions[] = { {-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,1}, {1,-1}, {1,0}, {1,1} }; message moveval {int value; int row; int col;}; message bmove {int status; int row; int col;}; /* InitBoard initializes the board. */ void InitBoard(board) char board[][8]; { int r, c; for (r = 0; r < 8; r++) for ( c = 0; c < 8; c++) board[r][c] = EMPTY; board[4][3] = board[3][4] = BLACK; board[3][3] = board[4][4] = WHITE; } /* PrintBoard prints the board */ void PrintBoard(board) char board[][8]; { int r, c; printf(" "); for (c = 0; c < 8; c++) printf("%c ", c+'a'); printf("\n"); for (r = 0; r < 8; r++) { printf("%d ", r+1); for (c = 0; c < 8; c++) printf("%c ", board[r][c]); printf("\n"); } printf("\n"); } /* IsLegal checks whether a move by the specified color to the specified location (, ) is possible. If the move is possible, it returns 1 else it returns 0. */ int IsLegal(row, col, color, board) int row, col; char color; char board[][8]; { int r, c, drow, dcol, i, inbetween; if (board[row][col] != EMPTY) return(0); for (i = NORTH; i <= NW; i++){ r = row; c = col; drow = directions[i].dr; dcol = directions[i].dc; inbetween = 0; while (1) { r += drow; c += dcol; if ((r < 0) || (r > 7) || (c < 0) || (c > 7) || (board[r][c] == EMPTY)) break; if (board[r][c] == color) { if (!inbetween) break; else return(1); } else inbetween++; } } return(0); } /* MovePos checks whether any move of the specified color are possible. If a move is possible, it returns 1 else it returns 0. */ int MovePos(color, board) char color; char board[][8]; { int row, col; for (row = 0; row < 8; row++) for (col = 0; col < 8; col++) if (IsLegal(row, col, color, board)) return(1); return(0); } /* Flip flips all the pieces in the direction specified by starting at the location specified by (, ) to the color specified by . */ void Flip(row, col, dir, color, board, plylist, ply, numberflipped) int row, col; struct dir *dir; char color; char board[][8]; char plylist[][60][2]; int ply; int numberflipped[]; { int r, c, inbetween, drow, dcol; drow = dir->dr; dcol = dir->dc; r = row; c = col; inbetween = 0; while (1) { r += drow; c += dcol; if ((r < 0) || (r > 7) || (c < 0) || (c > 7) || (board[r][c] == EMPTY)) return; if (board[r][c] == color) break; else inbetween++; } r = row; c = col; for ( ; inbetween > 0; inbetween--) { r += drow; c += dcol; board[r][c] = color; plylist[ply][numberflipped[ply]][0] = r; plylist[ply][numberflipped[ply]++][1] = c; } } /* Playpiece plays a piece of the color specified by at the location specified by (row>, ). */ void PlayPiece(row, col, color, board, plylist, ply, numberflipped) int row, col; char color; char board[][8]; char plylist[][60][2]; int ply; int numberflipped[]; { int i; numberflipped[ply] = 0; for (i = NORTH; i <= NW; i++) Flip(row, col, &directions[i], color, board, plylist, ply, numberflipped); board[row][col] = color; } /* UndoMove undoes the changes that were made to the board during the AlphaBeta search at location (, ). The global data structure called plylist maintains the information about the pieces that were flipped when this move was originally made. */ void UndoMove(row, col, board, plylist, ply, numberflipped) int row, col; char board[][8]; char plylist[MAXPLY][60][2]; int ply; int numberflipped[MAXPLY]; { int i, n, r, c; char color; if (board[row][col] == BLACK) color = WHITE; else color = BLACK; n = numberflipped[ply]; for (i = 0; i < n; i++ ) { r = plylist[ply][i][0]; c = plylist[ply][i][1]; board[r][c] = color; } board[row][col] = EMPTY; numberflipped[ply] = 0; } /* EvalPos does the static evaluation of a position during the AlphaBeta search. The static evaluation follows a weighted square strategy along with a mobility heuristic. The function returns a value which is a measure of the goodness of the position as determined by the static evaluation heuristic. */ int EvalPos(board) char board[][8]; { int row, col, nb, nw, blegal, wlegal, result; blegal = 0; wlegal = 0; nb = 0; nw = 0; for (row = 0; row < 8; row++) for (col = 0; col < 8; col++) { if (board[row][col] == BLACK) nb++; else if (board[row][col] == WHITE) nw++; if (IsLegal(row, col, BLACK, board)) blegal++; if (IsLegal(row, col, WHITE, board)) wlegal++; } if (!blegal && !wlegal) { if (nb > nw) return(WIN + nb - nw); else if (nw > nb) return(-WIN + nb - nw); else return(0); } result = MOBILITY * (blegal - wlegal) / (blegal + wlegal); for (row = 1; row < 7; row++) for (col = 1; col < 7; col++) if (board[row][col] == BLACK) result -= CENTRAL; else if (board[row][col] == WHITE) result += CENTRAL; if (board[0][0] == BLACK) result += CORNER; else if (board[0][0] == WHITE) result -= CORNER; if (board[0][7] == BLACK) result += CORNER; else if (board[0][7] == WHITE) result -= CORNER; if (board[7][0] == BLACK) result += CORNER; else if (board[7][0] == WHITE) result -= CORNER; if (board[7][7] == BLACK) result += CORNER; else if (board[7][7] == WHITE) result -= CORNER; if (board[0][0] == EMPTY) { if (board[1][1] == WHITE) result -= X; else if (board[1][1] == BLACK) result += X; if (board[1][0] == WHITE) result -= C; else if (board[1][0] == BLACK) result += C; if (board[0][1] == WHITE) result -= C; else if (board[0][1] == BLACK) result += C; if (board[0][2] == WHITE) result -= A; else if (board[0][2] == BLACK) result += A; if (board[2][0] == WHITE) result -= A; else if (board[2][0] == BLACK) result += A; if (board[0][3] == WHITE) result -= B; else if (board[0][3] == BLACK) result += B; if (board[3][0] == WHITE) result -= B; else if (board[3][0] == BLACK) result += B; } else { if (board[1][1] == WHITE) result -= EDGE; else if (board[1][1] == BLACK) result += EDGE; if (board[0][1] == WHITE) result -= EDGE; else if (board[0][1] == BLACK) result += EDGE; if (board[1][0] == WHITE) result -= EDGE; else if (board[1][0] == BLACK) result += EDGE; if (board[0][2] == WHITE) result -= EDGE; else if (board[0][2] == BLACK) result += EDGE; if (board[2][0] == WHITE) result -= EDGE; else if (board[2][0] == BLACK) result += EDGE; if (board[0][3] == WHITE) result -= EDGE; else if (board[0][3] == BLACK) result += EDGE; if (board[3][0] == WHITE) result -= EDGE; else if (board[3][0] == BLACK) result += EDGE; } if (board[7][7] == EMPTY) { if (board[6][6] == WHITE) result -= X; else if (board[6][6] == BLACK) result += X; if (board[6][7] == WHITE) result -= C; else if (board[6][7] == BLACK) result += C; if (board[7][6] == WHITE) result -= C; else if (board[7][6] == BLACK) result += C; if (board[7][5] == WHITE) result -= A; else if (board[7][5] == BLACK) result += A; if (board[5][7] == WHITE) result -= A; else if (board[5][7] == BLACK) result += A; if (board[7][4] == WHITE) result -= B; else if (board[7][4] == BLACK) result += B; if (board[4][7] == WHITE) result -= B; else if (board[4][7] == BLACK) result += B; } else { if (board[6][6] == WHITE) result -= EDGE; else if (board[6][6] == BLACK) result += EDGE; if (board[7][6] == WHITE) result -= EDGE; else if (board[7][6] == BLACK) result += EDGE; if (board[6][7] == WHITE) result -= EDGE; else if (board[6][7] == BLACK) result += EDGE; if (board[7][5] == WHITE) result -= EDGE; else if (board[7][5] == BLACK) result += EDGE; if (board[5][7] == WHITE) result -= EDGE; else if (board[5][7] == BLACK) result += EDGE; if (board[7][4] == WHITE) result -= EDGE; else if (board[7][4] == BLACK) result += EDGE; if (board[4][7] == WHITE) result -= EDGE; else if (board[4][7] == BLACK) result += EDGE; } if (board[0][7] == EMPTY) { if (board[1][7] == WHITE) result -= X; else if (board[1][6] == BLACK) result += X; if (board[1][7] == WHITE) result -= C; else if (board[1][7] == BLACK) result += C; if (board[0][6] == WHITE) result -= C; else if (board[0][6] == BLACK) result += C; if (board[0][5] == WHITE) result -= A; else if (board[0][5] == BLACK) result += A; if (board[2][7] == WHITE) result -= A; else if (board[2][7] == BLACK) result += A; if (board[0][4] == WHITE) result -= B; else if (board[0][4] == BLACK) result += B; if (board[3][7] == WHITE) result -= B; else if (board[3][7] == BLACK) result += B; } else { if (board[1][6] == WHITE) result -= EDGE; else if (board[1][1] == BLACK) result += EDGE; if (board[0][6] == WHITE) result -= EDGE; else if (board[0][6] == BLACK) result += EDGE; if (board[1][7] == WHITE) result -= EDGE; else if (board[1][7] == BLACK) result += EDGE; if (board[0][5] == WHITE) result -= EDGE; else if (board[0][5] == BLACK) result += EDGE; if (board[2][7] == WHITE) result -= EDGE; else if (board[2][7] == BLACK) result += EDGE; if (board[0][4] == WHITE) result -= EDGE; else if (board[0][4] == BLACK) result += EDGE; if (board[3][7] == WHITE) result -= EDGE; else if (board[3][7] == BLACK) result += EDGE; } if (board[7][0] == EMPTY) { if (board[6][1] == WHITE) result -= X; else if (board[6][1] == BLACK) result += X; if (board[6][0] == WHITE) result -= C; else if (board[6][0] == BLACK) result += C; if (board[7][1] == WHITE) result -= C; else if (board[7][1] == BLACK) result += C; if (board[7][2] == WHITE) result -= A; else if (board[7][2] == BLACK) result += A; if (board[5][0] == WHITE) result -= A; else if (board[5][0] == BLACK) result += A; if (board[7][3] == WHITE) result -= B; else if (board[7][3] == BLACK) result += B; if (board[4][0] == WHITE) result -= B; else if (board[4][0] == BLACK) result += B; } else { if (board[6][1] == WHITE) result -= EDGE; else if (board[6][1] == BLACK) result += EDGE; if (board[7][1] == WHITE) result -= EDGE; else if (board[7][1] == BLACK) result += EDGE; if (board[6][0] == WHITE) result -= EDGE; else if (board[6][0] == BLACK) result += EDGE; if (board[7][2] == WHITE) result -= EDGE; else if (board[7][2] == BLACK) result += EDGE; if (board[5][0] == WHITE) result -= EDGE; else if (board[5][0] == BLACK) result += EDGE; if (board[7][3] == WHITE) result -= EDGE; else if (board[7][3] == BLACK) result += EDGE; if (board[4][0] == WHITE) result -= EDGE; else if (board[4][0] == BLACK) result += EDGE; } return(result); } /* AlphaBeta as its name suggests does an Alpha-Beta search of the game tree. */ int AlphaBeta(alpha, beta, player1, board, ply, plylist, numberflipped) int alpha, beta, player1; char board[][8]; int ply; int plylist[][60][2]; int numberflipped[]; { struct SQUARE legalmoves[60]; int numlegal, player2, row, col, posval, result, i; char color1, color2; numlegal = 0; ply++; if (player1 == MAX) { posval = alpha; player2 = MIN; color1 = BLACK; color2 = WHITE; } else { posval = beta; player2 = MAX; color1 = WHITE; color2 = BLACK; } for (row = 0; row < 8; row++) for (col = 0; col < 8; col++) if (IsLegal(row, col, color1, board)) { legalmoves[numlegal].r = row; legalmoves[numlegal++].c = col; } if (!numlegal) if ((ply >= MAXPLY-1) || !MovePos(color2, board)) posval = EvalPos(board); else posval = AlphaBeta(alpha, beta, player2, board, ply, plylist, numberflipped); for (i = 0; i < numlegal; i++) { row = legalmoves[i].r; col = legalmoves[i].c; PlayPiece(row, col, color1, board, plylist, ply, numberflipped); if (ply >= MAXPLY-1) result = EvalPos(board); else if (player1 == MAX) result = AlphaBeta(max(alpha,posval), beta, player2, board, ply, plylist, numberflipped); else result = AlphaBeta(alpha, min(beta,posval), player2, board, ply, plylist, numberflipped); UndoMove(row, col, board, plylist, ply, numberflipped); if (player1 == MAX) { if (result > posval) { posval = result; if (posval >= beta) break; /* alpha cut off */ } } else { if (result < posval) { posval = result; if (posval <= alpha) break; /* beta cut off */ } } } return(posval); } /* GameOver prints the final scores and exits. */ void GameOver(board) char board[][8]; { int row, col, nb, nw; nb = 0; nw = 0; for (row = 0; row < 8; row++) for (col = 0; col < 8; col++) { if (board[row][col] == BLACK) nb++; else if (board[row][col] == WHITE) nw++; } printf("Black: %d White: %d \n", nb, nw); pc_exit(1); } /* MoveValue evalutes the value of a move. The calling process is MakeMove which passes on the color and player who makes the move. The row and col parameters specify the location of the move. The present board configuration is passed to MoveValue. MoveValue evaluates the move by making the move and evaluating the resulting board configuration by spawning an Alpha-Beta entity. MoveValue returns a message called moveval to the MakeMove entity that called it. The moveval message has 3 fields: the first field called value specifies the value of the move and the next two fields specify the row and col of the move. */ entity MoveValue (int row, int col, char color, int player, char board[8][8], ename cid) { int i, j, result; char plylist[MAXPLY][60][2]; int numberflipped[MAXPLY]; PlayPiece (row, col, color, board, plylist, 0, numberflipped); result = AlphaBeta (NEGINF, POSINF, player, board, 0, plylist, numberflipped); send moveval{result, row, col} to cid; } /* MakeMove make a move of the specified color (which is the color of the program). Making the move requires a search of the game tree. First it checks if a legal move is possible at all. If a legal move is not possible, it returns 0 in the status field of the message bmove. The message bmove also returns the row and col of the best move. */ entity MakeMove (char color, char board[8][8], ename cid) { struct SQUARE legalmoves[60]; struct SQUARE move; int posval, result, player2, numlegal, row, col, i, j; ename move_ent; numlegal = 0; if (color == BLACK) { posval = NEGINF; player2 = MIN; } else { posval = POSINF; player2 = MAX; } for (row = 0; row < 8; row++) for (col = 0; col < 8; col++) if (IsLegal(row, col, color, board)) { legalmoves[numlegal].r = row; legalmoves[numlegal++].c = col; } if (!numlegal) { send bmove {0, -1, -1} to cid; return; } else { printf("Thinking ....\n"); if (color == BLACK) { for (i = 0; i < numlegal; i++) { row = legalmoves[i].r; col = legalmoves[i].c; move_ent = new MoveValue (row, col, color, player2, board::64*sizeof(char), self) at i + 1; } for (i = 0; i < numlegal; i++) { receive (moveval var_moveval) { result = var_moveval.value; row = var_moveval.row; col = var_moveval.col; } if (posval < result) { posval = result; move.r = row; move.c = col; } } } else { for (i = 0; i < numlegal; i++) { row = legalmoves[i].r; col = legalmoves[i].c; move_ent = new MoveValue (row, col, color, player2, board::64*sizeof(char), self) at i + 1; } for (i = 0; i < numlegal; i++) { receive (moveval var_moveval) { result = var_moveval.value; row = var_moveval.row; col = var_moveval.col; } if (posval > result) { posval = result; move.r = row; move.c = col; } } } } send bmove {1, move.r, move.c} to cid; printf("I play: %c %c %c \n", color, 'a'+move.c, '1'+move.r); } print_info() { int i; char s[128]; for(i=0; i < 12; i++) printf("%s\n",GAME_INFO[i]); printf("\n..... to continue....\n"); gets(s); printf("\n"); } entity driver () { int i, j, row, col, ply, movepos; char mycolor, hiscolor, command[2], x[2], y[2], buffer[80]; char plylist[MAXPLY][60][2]; int numberflipped[MAXPLY]; char board[8][8]; printf("Playing at PLY level %d \n\n", MAXPLY); print_info(); InitBoard(board); PrintBoard(board); printf("Do you want to play white or black (W/B)?: \n"); scanf("%1s", &hiscolor); printf("\n"); if(hiscolor=='W' || hiscolor=='w') { hiscolor = WHITE; printf("You are playing WHITE\n"); } else { hiscolor = BLACK; printf("You are playing BLACK\n"); } mycolor = OpColor(hiscolor); if (mycolor == BLACK) { ename move_ent; move_ent = new MakeMove (mycolor, board::64*sizeof(char), self) at 0; receive(bmove var_bmove) { PlayPiece (var_bmove.row, var_bmove.col, mycolor, board, plylist, 0, numberflipped); } PrintBoard (board); } printf("Your turn to move: \n"); gets(buffer); /* to work around scanf bug */ for (;;) { gets(buffer); sscanf(buffer, "%1s", command); switch (command[0]) { case '?': case 'H': case 'h': print_info(); PrintBoard(board); printf("Your turn to move: \n"); break; case 'q': case 'Q': GameOver(board); break; case 'p': case 'P': if (MovePos (hiscolor, board)) printf("You have a legal move. Input your move: \n"); else { ename move_ent; move_ent = new MakeMove (mycolor, board::64*sizeof(char), self) at 0; receive (bmove my_bmove) { if (my_bmove.status) { PlayPiece (my_bmove.row, my_bmove.col, mycolor, board, plylist, 0, numberflipped); PrintBoard(board); printf("Your turn to move: \n"); } else { printf("Game is over. \n"); GameOver(board); } } } break; case 'w': case 'W': if (sscanf(buffer, "%1s%1s%1s", command, x, y) == 3) { row = y[0] - '1'; col = x[0] - 'a'; if ((hiscolor == WHITE) && IsLegal(row, col, hiscolor, board)) { ename move_ent; PlayPiece (row, col, hiscolor, board, plylist, 0, numberflipped); PrintBoard(board); move_ent = new MakeMove (mycolor, board::64*sizeof(char), self) at 0; receive (bmove my_bmove) { if (my_bmove.status) { PlayPiece (my_bmove.row, my_bmove.col, mycolor, board, plylist, 0, numberflipped); PrintBoard(board); printf("Your turn to move: \n"); } else { if (MovePos(hiscolor, board)) printf("I can't move. Your turn to move: \n"); else GameOver(board); } } } else printf("Illegal move. Input your move: \n"); } else printf("Illegal move. Input your move: \n"); break; case 'b': case 'B': if (sscanf(buffer, "%1s%1s%1s", command, x, y) == 3) { row = y[0] - '1'; col = x[0] - 'a'; if ((hiscolor == BLACK) && IsLegal(row, col, hiscolor, board)) { ename move_ent; PlayPiece (row, col, hiscolor, board, plylist, 0, numberflipped); PrintBoard(board); move_ent = new MakeMove (mycolor, board::64*sizeof(char), self) at 0; receive (bmove my_bmove) { if (my_bmove.status) { PlayPiece (my_bmove.row, my_bmove.col, mycolor, board, plylist, 0, numberflipped); PrintBoard(board); printf("Your turn to move: \n"); } else { if (MovePos(hiscolor, board)) printf("I can't move. Your turn to move: \n"); else GameOver(board); } } } else printf("Illegal move. Input your move: \n"); } else printf("Illegal move. Input your move: \n"); break; default: printf("Illegal command. Your turn to move: \n"); break; } } }