//MAKEFILE # To use this Makefile, just type make. That's it. CC = gcc LDLIBS = -L /usr/X11R6/lib -lGL -lGLU -lglut -lXmu -lX11 -lXi -lm INCLUDE = -I /usr/X11R6/include -I /usr/X11R6/include/GL executable: $(CC) -g $(INCLUDE) -o $I checkers $I checkers.c $(LDLIBS) -Wall ------------------------------------------------------------------------- //checkers.h /*used to denote checker color or player turn*/ #define BLACK 1 #define RED 2 /*used to define background*/ #define BLACK_BG 0 #define WHITE_BG 1 /*used to define states of squares*/ #define NO_CHECKER 0 #define NOT_SELECTED 0 #define YES_SELECTED 1 #define NOT_KING 0 #define YES_KING 1 /*menu definitions*/ #define MENU_DEMO_GAME 1 #define MENU_NEW_GAME 2 #define MENU_QUIT 3 #define MENU_CURRENT_SCORE 4 #define MENU_PLAYER1_RESIGN 5 #define MENU_PLAYER2_RESIGN 6 #define MENU_DECLARE_DRAW 7 /*movement states*/ #define JUST_JUMPED 1 #define DIDNT_JUMP 0 #define NO_JUMP 0 #define MUST_JUMP 1 /*definitions for function validMove()*/ #define NO_MOVE 0 #define REGULAR_MOVE 1 #define JUMP_MOVE 2 /*definitions for jump possibilities*/ #define YES 1 #define NO 0 /*valid move check flag*/ #define CHECK_MJ 1 #define DONT_CHECK_MJ 0 /*additional game states*/ #define SPLASH_SCREEN 0 /*additional win/loss state*/ #define GAME_DRAW 3 /*playerColor definitions*/ #define NORMAL 1 #define BACKWARDS 2 struct square { int color;//either BLACK_BG or WHITE_BG int checker;//0 for none, 1 for black, 2 for red int selected;//0 if not selected, 1 if selected int minX, maxX;//the min and max X values int minY, maxY;//the min and max Y values int king;//am I a king or not? }; /*type definitions*/ typedef GLfloat xyPoint[2]; typedef int xyPointInt[2]; typedef GLdouble xyzPoint[3]; typedef GLfloat color3f[3]; typedef GLfloat color4f[4]; ------------------------------------------------------------------------- //checkers.c /*************************************************************** * This program allows two people to play checkers interactively **************************************************************/ #include #include #include #include #include #include #include "checkers.h" /*globals*/ xyPointInt whoJustJumped; struct square bd_array[8][8]; int whosTurn, justJumped, mustJump; int boardSquares[64]; /*64 squares on the board. Some of these will hold no lists*/ int boardRedCheckers[64]; int boardBlackCheckers[64]; int boardSelected[64]; int boardKingSymbol[64]; int gameState;//controls what we're doing in the game int displayScore, lostGame, validMoveYN; int playerColor; /*function definition*/ void setWindowVals(xyPoint windowSize, xyPoint windowLoc, char * windowName); void initSystem(color4f color, color3f drawColor, xyPoint startDisplay, xyPoint endDisplay, float ptSize); void defineMenu(); void keyboardReader(unsigned char key, int x, int y); void mouseReader(int button, int state, int x, int y); void menu_function(); int validMove(xyPointInt from, xyPointInt to, int checkJump); void moveChecker(xyPointInt from, xyPointInt to); void textWriter (char * text, int posX, int posY); int anyMovesLeft(); void switchSides(); void kingMe(xyPointInt to); int canThisCheckerMove(xyPointInt checker); int canThisCheckerJump(xyPointInt checker); int getScore(int color); void defineLists(); void initBoard(); void demoGame(); void moveCheckerXY(int x1, int y1, int x2, int y2); /*void defineLists() * This function defines the gl lists and stores the reference values * in 64 int arrays. Each array is offset so that no array has any * duplicate numbers*/ void defineLists(){ GLUquadricObj * checker; int counter = 1; int xCtr, yCtr; struct square * sq; for (yCtr = 0; yCtr < 8; yCtr++){ for(xCtr = 0; xCtr < 8; xCtr++){ sq = &bd_array[yCtr][xCtr]; boardSquares[counter - 1] = counter; glNewList(counter, GL_COMPILE); if (sq->color == BLACK_BG){ glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.0, 0.0, 0.0); glBegin(GL_POLYGON); glVertex2f(sq->minX, sq->minY); glVertex2f(sq->minX, sq->maxY); glVertex2f(sq->maxX, sq->maxY); glVertex2f(sq->maxX, sq->minY); glEnd(); glPopAttrib(); } else{ glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.6, 0.6, 0.6); glBegin(GL_POLYGON); glVertex2f(sq->minX, sq->minY); glVertex2f(sq->minX, sq->maxY); glVertex2f(sq->maxX, sq->maxY); glVertex2f(sq->maxX, sq->minY); glEnd(); glPopAttrib(); } glEndList(); /*populate all squares with red checkers*/ boardRedCheckers[counter - 1] = counter + 64; if (sq->color == BLACK_BG){ glPushAttrib(GL_ALL_ATTRIB_BITS); glNewList(counter + 64, GL_COMPILE); glColor3f(1.0,0.0,0.0); checker = gluNewQuadric(); gluQuadricDrawStyle(checker, GLU_FILL); glLoadIdentity(); glTranslatef(sq->minX + 5, sq->minY + 5, 0.0); gluDisk(checker, 0.0, 4.0, 40, 40); glTranslatef(-(sq->minX + 5), -(sq->minY + 5), 0.0); glPopAttrib(); glEndList(); } /*populate all squares with black checkers*/ boardBlackCheckers[counter - 1] = counter + 128; glNewList(counter + 128, GL_COMPILE); if (sq->color == BLACK_BG){ glPushAttrib(GL_ALL_ATTRIB_BITS); glNewList(counter + 64, GL_COMPILE); glColor3f(0.4,0.4,0.4); checker = gluNewQuadric(); gluQuadricDrawStyle(checker, GLU_FILL); glLoadIdentity(); glTranslatef(sq->minX + 5, sq->minY + 5, 0.0); gluDisk(checker, 0.0, 4.0, 40, 40); glTranslatef(-(sq->minX + 5), -(sq->minY + 5), 0.0); glPopAttrib(); glEndList(); } glEndList(); /*populate all squares with the "selected" highlight*/ boardSelected[counter - 1] = counter + 192; glNewList(counter + 192, GL_COMPILE); if (sq->color == BLACK_BG){ glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.0, 0.0, 1.0); glBegin(GL_POLYGON); glVertex2f(sq->minX, sq->minY); glVertex2f(sq->minX, sq->minY + 1); glVertex2f(sq->maxX, sq->minY + 1); glVertex2f(sq->maxX, sq->minY); glEnd(); glBegin(GL_POLYGON); glVertex2f(sq->minX, sq->maxY); glVertex2f(sq->minX, sq->maxY - 1); glVertex2f(sq->maxX, sq->maxY - 1); glVertex2f(sq->maxX, sq->maxY); glEnd(); glBegin(GL_POLYGON); glVertex2f(sq->minX, sq->minY); glVertex2f(sq->minX + 1, sq->minY); glVertex2f(sq->minX + 1, sq->maxY); glVertex2f(sq->minX, sq->maxY); glEnd(); glBegin(GL_POLYGON); glVertex2f(sq->maxX, sq->minY); glVertex2f(sq->maxX - 1, sq->minY); glVertex2f(sq->maxX - 1, sq->maxY); glVertex2f(sq->maxX, sq->maxY); glEnd(); glPopAttrib(); } glEndList(); /*populate all squares with king symbols*/ boardKingSymbol[counter - 1] = counter + 256; if (sq->color == BLACK_BG){ glNewList(counter + 256, GL_COMPILE); glPushAttrib(GL_ALL_ATTRIB_BITS); glColor3f(0.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(sq->minX + 4, sq->minY + 2); glVertex2f(sq->minX + 6, sq->minY + 2); glVertex2f(sq->minX + 6, sq->minY + 4); glVertex2f(sq->minX + 8, sq->minY + 4); glVertex2f(sq->minX + 8, sq->minY + 6); glVertex2f(sq->minX + 6, sq->minY + 6); glVertex2f(sq->minX + 6, sq->minY + 8); glVertex2f(sq->minX + 4, sq->minY + 8); glVertex2f(sq->minX + 4, sq->minY + 6); glVertex2f(sq->minX + 2, sq->minY + 6); glVertex2f(sq->minX + 2, sq->minY + 4); glVertex2f(sq->minX + 4, sq->minY + 4); glEnd(); glPopAttrib(); glEndList(); } counter++; } } } /*void switchSides() * This function attempts to switch sides and set all appropriate values. * If there is a reason to not switch (i.e. there is a possible double * jump), sides will not be switched*/ void switchSides(){ int movesLeft = 0; /*check if we just jumped, and if there are any more jumps*/ if((justJumped == JUST_JUMPED) && (canThisCheckerJump(whoJustJumped) == YES)){ mustJump = MUST_JUMP; } /*if we didn't just jump, or if there are no jumps left*/ else{ justJumped = DIDNT_JUMP; /*switch turns*/ if (whosTurn == RED){ whosTurn = BLACK; /*check for moves*/ movesLeft = anyMovesLeft(); /*if there is a jump, set mustJump*/ if(movesLeft == JUMP_MOVE){ mustJump = MUST_JUMP; } /*if there is no jump, set that*/ else if (movesLeft == REGULAR_MOVE){ mustJump = NO_JUMP; } /*if there are no moves, black loses*/ else{ lostGame = BLACK; } } else if (whosTurn == BLACK){ whosTurn = RED; /*check for moves*/ movesLeft = anyMovesLeft(); /*if there is a jump, set mustJump*/ if(movesLeft == JUMP_MOVE){ mustJump = MUST_JUMP; } /*if there is no jump, set that*/ else if (movesLeft == REGULAR_MOVE){ mustJump = NO_JUMP; } /*if there are no moves, red loses*/ else{ lostGame = RED; } } } } /*int anyMovesLeft() * This function goes through each checker of the current player's color and checks * if there are any moves left for that player.*/ int anyMovesLeft(){ xyPointInt from; int xCounter, yCounter; int move = 0; if (whosTurn == RED){ /*go through all spaces looking for a red checker*/ for (yCounter = 0; yCounter < 8; yCounter++){ for(xCounter = 0; xCounter < 8; xCounter++){ if(bd_array[yCounter][xCounter].checker == RED){ /*see if the red checker can move*/ from[0] = xCounter; from[1] = yCounter; /*if we find a jump, return immediately*/ if (canThisCheckerJump(from) == YES){ return JUMP_MOVE; } if(canThisCheckerMove(from) == YES){ /*store the non-jump, but keep checking * in case there is a jump*/ move = REGULAR_MOVE; } } } } } if (whosTurn == BLACK){ /*go through all spaces looking for a black checker*/ for (yCounter = 0; yCounter < 8; yCounter++){ for(xCounter = 0; xCounter < 8; xCounter++){ if(bd_array[yCounter][xCounter].checker == BLACK){ /*see if the black checker can move*/ from[0] = xCounter; from[1] = yCounter; /*if we find a jump, return immediately*/ if(canThisCheckerJump(from) == YES){ return JUMP_MOVE; } if(canThisCheckerMove(from) == YES){ /*store the non-jump, but keep checking * in case there is a jump*/ move = REGULAR_MOVE; } } } } } return move; } /*int validMove(xyPointInt from, xyPointInt to, int checkJump) * given a from and to point, this function will tell you if the move is valid * return 0 is an invalid move. 1 is valid. 2 is valid and a jump * if checkJump = CHECK_MJ then only return valid if the checker can jump*/ int validMove(xyPointInt from, xyPointInt to, int checkJump){ struct square *fromPtr; struct square *toPtr; struct square *midPtr; fromPtr = &bd_array[from[1]][from[0]]; toPtr = &bd_array[to[1]][to[0]]; if (whosTurn == RED){ /** SIMPLE MOVE **/ if(checkJump == DONT_CHECK_MJ){ /*test to see if the movement in the X direction is valid*/ if(abs(from[0] - to[0]) == 1){ /*test to see if the movement in the Y direction is valid*/ if(((to[1] - from[1] == 1) || ((fromPtr->king == YES_KING) && (from[1] - to[1] == 1)))){ /*check if we're stepping on another checker*/ if(toPtr->checker == NO_CHECKER){ return REGULAR_MOVE;//we have a valid move } } } } /** JUMP MOVE **/ /*test to see if the movement in the X direction is valid*/ if(abs(from[0] - to[0]) == 2){ /*test to see if the movement in the Y direction is valid*/ if(((to[1] - from[1] == 2) || ((fromPtr->king == YES_KING) && (from[1] - to[1] == 2)))){ /*check to see if we're on top of another checker*/ if(toPtr->checker == NO_CHECKER){ /*make sure we're jumping something*/ midPtr = &bd_array[(to[1] + from[1])/2][(to[0] + from[0])/2]; if((midPtr->checker != NO_CHECKER) && (midPtr->checker != fromPtr->checker)){ return JUMP_MOVE;//we have a valid move } } } } } if (whosTurn == BLACK){ /** SIMPLE MOVE **/ if(checkJump == DONT_CHECK_MJ){ /*test to see if the movement in the X direction is valid*/ if(abs(from[0] - to[0]) == 1){ /*test to see if the movement in the Y direction is valid*/ if(((from[1] - to[1] == 1) || ((fromPtr->king == YES_KING) && (to[1] - from[1] == 1)))){ /*check if we're stepping on another checker*/ if(toPtr->checker == NO_CHECKER){ return REGULAR_MOVE;//we have a valid move } } } } /** JUMP MOVE **/ /*test to see if the movement in the X direction is valid*/ if(abs(from[0] - to[0]) == 2){ /*test to see if the movement in the Y direction is valid*/ if(((from[1] - to[1] == 2) || ((fromPtr->king == YES_KING) && (to[1] - from[1] == 2)))){ /*check to see if we're on top of another checker*/ if(toPtr->checker == NO_CHECKER){ /*make sure we're jumping something*/ midPtr = &bd_array[(to[1] + from[1])/2][(to[0] + from[0])/2]; if((midPtr->checker != NO_CHECKER) && (midPtr->checker != fromPtr->checker)){ return JUMP_MOVE;//we have a valid move } } } } } return NO_MOVE;//otherwise we have an invalid move } /*int main(int argc, char **argv) * This function initializes the board, glut, the window, the GL system * the menu, the gl lists, and then calls the glutMainLoop*/ int main(int argc, char **argv){ xyPoint startDisplay = {0.0,0.0};//location to start the display at xyPoint endDisplay = {500.0,500.0};//location to finish the display at color4f winBGColor = {0.6, 0.6, 0.6, 1.0};//window background color color3f drawColor = {1.0, 1.0, 1.0};//color we are drawing in xyPoint windowSize = {500, 500};//size of the window xyPoint windowLoc = {0, 0};//location on screen of the window float ptsize = 0.5;//the point size char * windowName = "Checkers";//name of the window /*initialize the squares*/ initBoard(); /*initiate interaction with the local window system*/ glutInit(&argc, argv); /*initialize the window variables*/ setWindowVals(windowSize, windowLoc, windowName); /*initialize the system*/ initSystem(winBGColor, drawColor, startDisplay, endDisplay, ptsize); defineMenu(); defineLists(); playerColor = BACKWARDS; glutMainLoop(); } /*void display() * This is the display function. It handles all drawing to the screen*/ void display(){ int counter = 0; int xCtr, yCtr; char buffer[32]; glClear(GL_COLOR_BUFFER_BIT); /*if we're in a regular or demo game*/ if(gameState == MENU_NEW_GAME || gameState == MENU_DEMO_GAME){ for (yCtr = 0; yCtr < 8; yCtr++){ for(xCtr = 0; xCtr < 8; xCtr++){ /*go through all squares and see what needs to be drawn*/ glCallList(boardSquares[counter]);/*draw all squares*/ /*if the square has a red checker, draw it*/ if(bd_array[yCtr][xCtr].checker == RED){ glCallList(boardRedCheckers[counter]); } /*if the square has a black checker, draw it*/ if(bd_array[yCtr][xCtr].checker == BLACK){ glCallList(boardBlackCheckers[counter]); } /*if the square is selected, draw it*/ if(bd_array[yCtr][xCtr].selected == YES_SELECTED){ glCallList(boardSelected[counter]); } /*if the piece is a king, show it*/ if(bd_array[yCtr][xCtr].king == YES_KING){ glCallList(boardKingSymbol[counter]); } counter++; } } /*output messages to the screen when appropriate*/ glColor3f(0.0,0.0,0.0); if(whosTurn == BLACK){ textWriter("Black's Turn\n", -45, -45); } if(whosTurn == RED){ textWriter("Red's Turn\n", -45, -45); } if(gameState == MENU_DEMO_GAME){ textWriter("Demo Game. Please wait.\n", 10, -45); } if(lostGame == BLACK){ textWriter("Game Over. Black Loses.\n", -15, 45); } if(lostGame == RED){ textWriter("Game Over. Red Loses.\n", -15, 45); } if(lostGame == GAME_DRAW){ textWriter("Game Over. Tie Game.\n", -15, 45); } if(displayScore == YES){ sprintf(buffer, "The score is Red %d, Black %d\n", getScore(RED), getScore(BLACK)); textWriter(buffer, -10, -45); } if(validMoveYN == NO && mustJump == NO_JUMP){ textWriter("Invalid Move. Please Try Again.\n", -20, 45); } if(validMoveYN == NO && mustJump == MUST_JUMP){ textWriter("Invalid Move. You Must Jump.\n", -20, 45); } if(playerColor == NORMAL){ textWriter("Player 1 is Red. Player 2 is Black.\n", -45, -48); } if(playerColor == BACKWARDS){ textWriter("Player 2 is Red. Player 1 is Black.\n", -45, -48); } } else if (gameState == SPLASH_SCREEN){ glColor3f(0.0,0.0,0.0); textWriter("CHECKERS\n", -5, 45); textWriter("Right click to start\n", -15, 40); for (yCtr = 0; yCtr < 8; yCtr++){ for(xCtr = 0; xCtr < 8; xCtr++){ /*only print the right bottom section of the board*/ if(xCtr >= yCtr){ /*go through all squares and see what needs to be drawn*/ glCallList(boardSquares[counter]);/*draw all squares*/ /*if the square has a red checker, draw it*/ if(bd_array[yCtr][xCtr].checker == RED){ glCallList(boardRedCheckers[counter]); } /*if the square has a black checker, draw it*/ if(bd_array[yCtr][xCtr].checker == BLACK){ glCallList(boardBlackCheckers[counter]); } /*if the square is selected, draw it*/ if(bd_array[yCtr][xCtr].selected == YES_SELECTED){ glCallList(boardSelected[counter]); } /*if the piece is a king, show it*/ if(bd_array[yCtr][xCtr].king == YES_KING){ glCallList(boardKingSymbol[counter]); } } counter++; } } } /*swap the buffers*/ glutSwapBuffers(); } /*Function textWriter (char * text) * This function writes a null terminated character string to the screen * starting at position X, Y*/ void textWriter (char * text, int posX, int posY){ int counter = 0; /*set the position for the text*/ glRasterPos2i(posX, posY); while ((char)text[counter] != '\n') { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, text[counter]); counter++; } } /* initSystem(color4f winColor, color3f drawColor, xyPoint startDisp, xyPoint endDisp, float ptSize) * This function initializes all of display variables*/ void initSystem(color4f winColor, color3f drawColor, xyPoint startDisp, xyPoint endDisp, float ptSize){ /*set the background color*/ glClearColor(winColor[0], winColor[1], winColor[2], winColor[3]); /*clear the window*/ glClear(GL_COLOR_BUFFER_BIT); /*set the drawing color*/ glColor3f(drawColor[0], drawColor[1], drawColor[2]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /*set the portion of the world to display*/ gluOrtho2D(-50.0, 50.0, -50.0, 50.0); glMatrixMode(GL_MODELVIEW); /*set the point size*/ glPointSize(ptSize); /*set the callback functions*/ glutDisplayFunc(display); glutKeyboardFunc(keyboardReader); glutMouseFunc(mouseReader); } /*setWindowVals(xyPoint size, xyPoint pos, char * name) * Set the variables for the window*/ void setWindowVals(xyPoint size, xyPoint pos, char * name){ /*set number and type of buffers*/ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); /*set the window size*/ glutInitWindowSize(size[0], size[1]); /*position the window*/ glutInitWindowPosition(pos[0], pos[1]); /*actually create the window*/ glutCreateWindow(name); } /*void keyboardReader(unsigned char key, int x, int y) * this function handles all keyboard interaction*/ void keyboardReader(unsigned char key, int x, int y){ if ((key == 'Q') || (key == 'q')){ exit(1); } } /*void mouseReader(int button, int state, int x, int y) * This function handles all mouse interaction*/ void mouseReader(int button, int state, int x, int y){ static int selected = NO; static int xAxis = 0; static int yAxis = 0; struct square *ptr; int isItValid = 0; div_t divTemp; xyPointInt from; xyPointInt to; if ((state == GLUT_DOWN) && (button == GLUT_LEFT_BUTTON)){ /*the only time we need the mouse is during an active game*/ if(gameState == MENU_NEW_GAME && lostGame == 0){ /*if we're in the playing area*/ if ((x < 450) && (x > 50) && (y < 450) && (y > 50)){ /*if there isn't already a checker selected*/ if (selected == NO){ /*calculate the array location using the X Y coordinateds*/ divTemp = div(x, 50);//divide x by 10 xAxis = (divTemp.quot - 1); divTemp = div(y, 50);//divide y by 10 yAxis = (8 - divTemp.quot); /*set the pointer using this location*/ ptr = &bd_array[yAxis][xAxis]; /*if the check and the current player are the same*/ if(whosTurn == ptr->checker){ /*select the checker*/ ptr->selected = YES_SELECTED; selected = YES; display(); } } else{/*if there was already a selected checker*/ /*set the location of selected checker*/ from[0] = xAxis; from[1] = yAxis; /*calculate array location of new checker location*/ divTemp = div(x, 50);//divide x by 10 xAxis = (divTemp.quot - 1); divTemp = div(y, 50);//divide y by 10 yAxis = (8 - divTemp.quot); /*store this new location*/ to[0] = xAxis; to[1] = yAxis; /*if there was a possible jump, we must make it*/ if(mustJump == MUST_JUMP){ /*returns valid if we're trying to jump*/ isItValid = validMove(from, to, CHECK_MJ); } else{ /*returns valid if we're making any valid move*/ isItValid = validMove(from, to, DONT_CHECK_MJ); } /*if it's a valid move, move checker*/ if(isItValid != NO_MOVE){ validMoveYN = YES; moveChecker(from, to); }else{ /*if it's an invalid move, deselect the square*/ ptr = &bd_array[from[1]][from[0]]; ptr->selected = NOT_SELECTED; validMoveYN = NO; } display(); selected = NO; } } } } } /*Function defineMenu() * This function defines the main menu for the program and attaches * values to each of the choices*/ void defineMenu(){ int sub; sub = glutCreateMenu(menu_function); glutAddMenuEntry("Toggle Current Score", MENU_CURRENT_SCORE); glutAddMenuEntry("Player 1 Resign", MENU_PLAYER1_RESIGN); glutAddMenuEntry("Player 2 Resign", MENU_PLAYER2_RESIGN); glutAddMenuEntry("Declare Draw", MENU_DECLARE_DRAW); glutAttachMenu(GLUT_RIGHT_BUTTON); glutCreateMenu(menu_function); glutAddMenuEntry("Play Demo Game", MENU_DEMO_GAME); glutAddMenuEntry("Play New Game", MENU_NEW_GAME); glutAddSubMenu("Current Game Status", sub); glutAddMenuEntry("Quit", MENU_QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); } /*Function menu_function(int ID) * This is the callback function for the menu. It handles all menu * interaction*/ void menu_function(int ID){ switch(ID){ case MENU_QUIT: { /*exit the game*/ exit(1); } case MENU_NEW_GAME:{ /*game is in demo mode*/ if(playerColor == NORMAL){ playerColor = BACKWARDS; } else{ playerColor = NORMAL; } initBoard(); gameState = MENU_NEW_GAME; break; } case MENU_DEMO_GAME:{ /*start a new game*/ initBoard(); gameState = MENU_DEMO_GAME; demoGame(); break; } case MENU_PLAYER1_RESIGN: { /*red player resigns the game*/ lostGame = RED; display(); break; } case MENU_PLAYER2_RESIGN: { /*black player resigns the game*/ lostGame = BLACK; display(); break; } case MENU_CURRENT_SCORE: { /*toggle the score display*/ if(displayScore == YES){ displayScore = NO; } else{ displayScore = YES; } display(); break; } case MENU_DECLARE_DRAW: { /*players agree to tie*/ lostGame = GAME_DRAW; display(); break; } } } /*void moveChecker(xyPointInt from, xyPointInt to) * This function moves the checker from one point to another. * If the move is a jump, it also removes the jumped checker.*/ void moveChecker(xyPointInt from, xyPointInt to){ struct square *fromPtr; struct square *toPtr; struct square *midPtr; int jumpType; /*initialize the pointers to squares*/ fromPtr = &bd_array[from[1]][from[0]]; toPtr = &bd_array[to[1]][to[0]]; /*turn off the selection*/ fromPtr->selected = NOT_SELECTED; /*figure out the type of move we're dealing with*/ if(abs(from[0] - to[0]) == 2){ jumpType = JUMP_MOVE; } else{ jumpType = REGULAR_MOVE; } switch (jumpType){ case REGULAR_MOVE:{ justJumped = DIDNT_JUMP; /*regular move. shift around the checkers*/ toPtr->checker = fromPtr->checker; toPtr->king = fromPtr->king; fromPtr->checker = NO_CHECKER; fromPtr->king = NOT_KING; kingMe(to); switchSides(); break; } case JUMP_MOVE:{ justJumped = JUST_JUMPED; /*location of checker that just jumped*/ whoJustJumped[0] = to[0]; whoJustJumped[1] = to[1]; /*jump move. shift checkers, remove the jumped one*/ toPtr->checker = fromPtr->checker; toPtr->king = fromPtr->king; fromPtr->checker = NO_CHECKER; fromPtr->king = NOT_KING; midPtr = &bd_array[(to[1] + from[1])/2][(to[0] + from[0])/2]; midPtr->checker = NO_CHECKER; midPtr->checker = NOT_KING; /*switch turns if there aren't any more jumps*/ kingMe(to); switchSides(); break; } } } /*void kingMe(xyPointInt to) * If the checker is in the appropriate place, it gets kinged*/ void kingMe(xyPointInt to){ struct square *toPtr = &bd_array[to[1]][to[0]]; if((to[1] == 7) && (toPtr->checker == RED)){ toPtr->king = YES_KING; } else if((to[1] == 0) && (toPtr->checker == BLACK)){ toPtr->king = YES_KING; } } /*int canThisCheckerMove(xyPointInt checker) * This function takes an array location of a square. It then checks * if the checker on that square has the ability to move.*/ int canThisCheckerMove(xyPointInt checker){ struct square *ptr = &bd_array[checker[1]][checker[0]]; xyPointInt from, to; int xAxis = checker[0]; int yAxis = checker[1]; /*set the location the checker is currently at*/ from[0] = xAxis; from[1] = yAxis; if(ptr->checker == RED){ /*check all the backwards king moves first*/ if(ptr->king == YES_KING){ /*check the backwards left move*/ if((xAxis != 0) && (yAxis != 0)){ to[0] = from[0] - 1; to[1] = from[1] - 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the backwards right move*/ if((xAxis != 7) && (yAxis != 0)){ to[0] = from[0] + 1; to[1] = from[1] - 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } /*check the left move*/ if((xAxis != 0) && (yAxis != 7)){ to[0] = from[0] - 1; to[1] = from[1] + 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the right move*/ if((xAxis != 7) && (yAxis != 7)){ to[0] = from[0] + 1; to[1] = from[1] + 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } if(ptr->checker == BLACK){ /*check all the backwards king moves first*/ if(ptr->king == YES_KING){ /*check the backwards left move*/ if((xAxis != 0) && (yAxis != 7)){ to[0] = from[0] - 1; to[1] = from[1] + 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the backwards right move*/ if((xAxis != 7) && (yAxis != 7)){ to[0] = from[0] + 1; to[1] = from[1] + 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } /*check the left move*/ if((xAxis != 0) && (yAxis != 0)){ to[0] = from[0] - 1; to[1] = from[1] - 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the right move*/ if((xAxis != 7) && (yAxis != 0)){ to[0] = from[0] + 1; to[1] = from[1] - 1; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } return NO; } /*int canThisCheckerJump(xyPointInt checker) * This function takes an array location of a square. It then checks * if the checker on that square has the ability to jump.*/ int canThisCheckerJump(xyPointInt checker){ struct square *ptr = &bd_array[checker[1]][checker[0]]; xyPointInt from, to; /*fill in the x and y location of the checker*/ int xAxis = checker[0]; int yAxis = checker[1]; /*set the location the checker is currently at*/ from[0] = xAxis; from[1] = yAxis; /*check the black checker*/ if(ptr->checker == BLACK){ /*if it's a king, check backwards moves*/ if(ptr->king == YES_KING){ /*check the backwards left jump*/ if((xAxis > 1) && (yAxis < 6)){ to[0] = from[0] - 2; to[1] = from[1] + 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the backwards right jump*/ if((xAxis < 6) && (yAxis < 6)){ to[0] = from[0] + 2; to[1] = from[1] + 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } /*check the left jump*/ if((xAxis > 1) && (yAxis > 1)){ to[0] = from[0] - 2; to[1] = from[1] - 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the right jump*/ if((xAxis < 6) && (yAxis > 1)){ to[0] = from[0] + 2; to[1] = from[1] - 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } /*check the red checker*/ if(ptr->checker == RED){ /*if it's a king, check backwards moves*/ if(ptr->king == YES_KING){ /*check the backwards left jump*/ if((xAxis > 1) && (yAxis > 1)){ to[0] = from[0] - 2; to[1] = from[1] - 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the backwards right jump*/ if((xAxis < 6) && (yAxis > 1)){ to[0] = from[0] + 2; to[1] = from[1] - 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } /*check the left jump*/ if((xAxis > 1) && (yAxis < 6)){ to[0] = from[0] - 2; to[1] = from[1] + 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } /*check the right jump*/ if((xAxis < 6) && (yAxis < 6)){ to[0] = from[0] + 2; to[1] = from[1] + 2; if(validMove(from, to, DONT_CHECK_MJ) != NO_MOVE){ return YES; } } } return NO; } /*void initBoard() * This function initializes the 64 squares. Each square that is * supposed to have a checker is given one. Each square is also * given it's drawing coordinates*/ void initBoard(){ int xCounter, yCounter; struct square *ptr; /*run through the entire array of squares*/ for (yCounter = 0; yCounter < 8; yCounter++){ for(xCounter = 0; xCounter < 8; xCounter++){ /*set the pointer to the correct square*/ ptr = &bd_array[yCounter][xCounter]; /*if we're on a square that should be black*/ if(((fmod(xCounter, 2) == 0) && (fmod(yCounter, 2) == 0)) || ((fmod(xCounter, 2) != 0) && (fmod(yCounter, 2) != 0))){ /*initalize basic information*/ ptr->color = BLACK_BG; ptr->king = NOT_KING; /*set the square's location*/ ptr->minX = -40 + 10 * xCounter; ptr->maxX = -40 + 10 * (xCounter + 1); ptr->minY = -40 + 10 * yCounter; ptr->maxY = -40 + 10 * (yCounter + 1); /*set the appropriate checker color*/ if (yCounter < 3){ ptr->checker = RED; } else if(yCounter > 4) { ptr->checker = BLACK; } else{ ptr->checker = NO_CHECKER; } } else{ /*if not a black square*/ ptr->color = WHITE_BG; } } } /*initialize the system*/ gameState = SPLASH_SCREEN; whosTurn = RED; justJumped = DIDNT_JUMP; mustJump = NO_JUMP; lostGame = 0; displayScore = NO; validMoveYN = YES; } /*void moveCheckerXY(int x1, int y1, int x2, int y2) * This function converts two sets of XY coordinates into * two xyPointInts. It then pauses one second, moves * the checker using the xyPointInts, and calls the display*/ void moveCheckerXY(int x1, int y1, int x2, int y2){ xyPointInt from, to; from[0] = x1; from[1] = y1; to[0] = x2; to[1] = y2; sleep(1); moveChecker(from, to); display(); } /*void demoGame() * This function runs through a sample game by making individual * checker movements*/ void demoGame(){ moveCheckerXY(2, 2, 3, 3); moveCheckerXY(3, 5, 2, 4); moveCheckerXY(4, 2, 5, 3); moveCheckerXY(2, 4, 4, 2); moveCheckerXY(5, 1, 3, 3); moveCheckerXY(5, 5, 4, 4); moveCheckerXY(5, 3, 3, 5); moveCheckerXY(2, 6, 4, 4); moveCheckerXY(4, 4, 2, 2); moveCheckerXY(1, 1, 3, 3); moveCheckerXY(1, 5, 2, 4); moveCheckerXY(3, 3, 1, 5); moveCheckerXY(0, 6, 2, 4); moveCheckerXY(2, 0, 1, 1); moveCheckerXY(1, 7, 2, 6); moveCheckerXY(3, 1, 4, 2); moveCheckerXY(4, 6, 5, 5); moveCheckerXY(6, 2, 5, 3); moveCheckerXY(5, 5, 6, 4); moveCheckerXY(5, 3, 4, 4); moveCheckerXY(6, 4, 7, 3); moveCheckerXY(6, 0, 5, 1); moveCheckerXY(2, 6, 3, 5); moveCheckerXY(4, 4, 2, 6); moveCheckerXY(3, 7, 1, 5); moveCheckerXY(4, 2, 5, 3); moveCheckerXY(6, 6, 5, 5); moveCheckerXY(5, 1, 6, 2); moveCheckerXY(7, 3, 5, 1); moveCheckerXY(4, 0, 6, 2); moveCheckerXY(5, 5, 6, 4); moveCheckerXY(6, 2, 7, 3); moveCheckerXY(6, 4, 4, 2); moveCheckerXY(1, 1, 2, 2); moveCheckerXY(4, 2, 3, 1); moveCheckerXY(7, 1, 6, 2); moveCheckerXY(3, 1, 2, 0); moveCheckerXY(0, 0, 1, 1); moveCheckerXY(2, 0, 3, 1); moveCheckerXY(6, 2, 5, 3); moveCheckerXY(3, 1, 1, 3); moveCheckerXY(5, 3, 4, 4); moveCheckerXY(5, 7, 4, 6); moveCheckerXY(1, 1, 2, 2); moveCheckerXY(1, 3, 3, 1); moveCheckerXY(4, 4, 5, 5); moveCheckerXY(4, 6, 6, 4); moveCheckerXY(7, 3, 5, 5); moveCheckerXY(2, 4, 1, 3); moveCheckerXY(0, 2, 2, 4); moveCheckerXY(2, 4, 0, 6); moveCheckerXY(3, 1, 4, 2); moveCheckerXY(5, 5, 4, 6); moveCheckerXY(4, 2, 5, 3); moveCheckerXY(4, 6, 3, 7); moveCheckerXY(7, 7, 6, 6); moveCheckerXY(3, 7, 4, 6); moveCheckerXY(5, 3, 4, 4); moveCheckerXY(4, 6, 5, 5); moveCheckerXY(4, 4, 3, 5); moveCheckerXY(5, 5, 7, 7); moveCheckerXY(7, 5, 6, 4); moveCheckerXY(0, 6, 1, 7); moveCheckerXY(3, 5, 4, 6); moveCheckerXY(1, 7, 2, 6); moveCheckerXY(6, 4, 5, 3); moveCheckerXY(7, 7, 6, 6); moveCheckerXY(5, 3, 6, 2); moveCheckerXY(2, 6, 3, 7); moveCheckerXY(4, 6, 5, 5); moveCheckerXY(6, 6, 4, 4); moveCheckerXY(6, 2, 5, 1); moveCheckerXY(4, 4, 5, 3); moveCheckerXY(5, 1, 6, 0); moveCheckerXY(5, 3, 4, 2); moveCheckerXY(6, 0, 7, 1); moveCheckerXY(4, 2, 5, 1); moveCheckerXY(7, 1, 6, 2); moveCheckerXY(5, 1, 7, 3); } /*int getScore(int color) * This function returns the player's score. Score is calculated * by taking 12 (max number of checkers) and subtracting 1 for * each checker the opponent still has*/ int getScore(int color){ int score = 12; int xCounter, yCounter; struct square *ptr; /*run through the entire array of squares*/ for (yCounter = 0; yCounter < 8; yCounter++){ for(xCounter = 0; xCounter < 8; xCounter++){ ptr = &bd_array[yCounter][xCounter]; if(color == RED){ if(ptr->checker == BLACK){ score--; } } if(color == BLACK){ if(ptr->checker == RED){ score--; } } } } return score; }