// Our Game.c with all of the Game functions and the game struct #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include "Game.h" #define NUM_TILES 19 #define NUM_VERTEXES 54 #define NUM_ARCS 72 #define MAX_NUM_GO8 8 #define NUM_TRADING_STATIONS 5 #define NUM_STUDENTS 6 #define NUM_PLAYERS 4 #define MAX_XPOS_VERTEX 12 #define MAX_YPOS_VERTEX 11 #define VERTEX_CONTENTS 7 #define NO_VERTEX -1 #define NUM_VERT_ARC 2 #define NUM_VERT_TILE 6 #define DEFAULT_DISCIPLINES {STUDENT_BQN, STUDENT_MMONEY, STUDENT_MJ, \ STUDENT_MMONEY, STUDENT_MJ, STUDENT_BPS, \ STUDENT_MTV, STUDENT_MTV, STUDENT_BPS, \ STUDENT_MTV, STUDENT_BQN, STUDENT_MJ, \ STUDENT_BQN, STUDENT_THD, STUDENT_MJ, \ STUDENT_MMONEY, STUDENT_MTV, STUDENT_BQN, \ STUDENT_BPS} #define DEFAULT_DICE {9, 10, 8, 12, 6, 5, 3, 11, 3, 11, 4, 6, 4, 7, 9, \ 2, 8, 10, 5} #define VERTEXES {{5, 10, CAMPUS_A}, {6, 10, VACANT_VERTEX}, \ {3, 9, VACANT_VERTEX}, {4, 9, VACANT_VERTEX}, \ {7, 9, VACANT_VERTEX}, {8, 9, VACANT_VERTEX}, \ {1, 8, VACANT_VERTEX}, {2, 8, VACANT_VERTEX}, \ {5, 8, VACANT_VERTEX}, {6, 8, VACANT_VERTEX}, \ {9, 8, VACANT_VERTEX}, {10, 8, CAMPUS_C}, \ {0, 7, CAMPUS_B}, {3, 7, VACANT_VERTEX}, \ {4, 7, VACANT_VERTEX}, {7, 7, VACANT_VERTEX}, \ {8, 7, VACANT_VERTEX}, {11, 7, VACANT_VERTEX}, \ {1, 6, VACANT_VERTEX}, {2, 6, VACANT_VERTEX}, \ {5, 6, VACANT_VERTEX}, {6, 6, VACANT_VERTEX}, \ {9, 6, VACANT_VERTEX}, {10, 6, VACANT_VERTEX}, \ {0, 5, VACANT_VERTEX}, {3, 5, VACANT_VERTEX}, \ {4, 5, VACANT_VERTEX}, {7, 5, VACANT_VERTEX}, \ {8, 5, VACANT_VERTEX}, {11, 5, VACANT_VERTEX}, \ {1, 4, VACANT_VERTEX}, {2, 4, VACANT_VERTEX}, \ {5, 4, VACANT_VERTEX}, {6, 4, VACANT_VERTEX}, \ {9, 4, VACANT_VERTEX}, {10, 4, VACANT_VERTEX}, \ {0, 3, VACANT_VERTEX}, {3, 3, VACANT_VERTEX}, \ {4, 3, VACANT_VERTEX}, {7, 3, VACANT_VERTEX}, \ {8, 3, VACANT_VERTEX}, {11, 3, CAMPUS_B}, \ {1, 2, CAMPUS_C}, {2, 2, VACANT_VERTEX}, \ {5, 2, VACANT_VERTEX}, {6, 2, VACANT_VERTEX}, \ {9, 2, VACANT_VERTEX}, {10, 2, VACANT_VERTEX}, \ {3, 1, VACANT_VERTEX}, {4, 1, VACANT_VERTEX}, \ {7, 1, VACANT_VERTEX}, {8, 1, VACANT_VERTEX}, \ {5, 0, VACANT_VERTEX}, {6, 0, CAMPUS_A}} #define ARCS_INDEXES {{0, 1}, {0, 3}, \ {4, 1}, {4, 5}, {4, 9}, \ {10, 5}, {10, 11}, {10, 16}, \ {17, 11}, {17, 23}, \ {2, 3}, {2, 7}, \ {8, 9}, {8, 3}, {8, 14}, \ {15, 9}, {15, 16}, {15, 21}, \ {22, 16}, {22, 23}, {22, 28}, \ {29, 23}, {29, 35}, \ {6, 7}, {6, 12}, \ {13, 7}, {13, 14}, {13, 19}, \ {20, 14}, {20, 21}, {20, 26}, \ {27, 21}, {27, 28}, {27, 33}, \ {34, 28}, {34, 35}, {34, 40}, \ {41, 35}, {41, 47}, \ {18, 12}, {18, 19}, {18, 24}, \ {25, 19}, {25, 26}, {25, 31}, \ {32, 26}, {32, 33}, {32, 38}, \ {39, 33}, {39, 40}, {39, 45}, \ {46, 40}, {46, 47}, {46, 51}, \ {30, 24}, {30, 31}, {30, 36}, \ {37, 31}, {37, 38}, {37, 43}, \ {44, 38}, {44, 45}, {44, 49}, \ {50, 45}, {50, 51}, {50, 53}, \ {42, 36}, {42, 43}, \ {48, 43}, {48, 49}, \ {52, 49}, {52, 53}} #define TILES_INDEXES {{6, 7, 12, 13, 18, 19}, \ {18, 19, 24, 25, 30, 31}, {30, 31, 36, 37, 42, 43}, \ {2, 3, 7, 8, 13, 14}, {13, 14, 19, 20, 25, 26}, \ {25, 26, 31, 32, 37, 38}, {37, 38, 43, 44, 48, 49}, \ {0, 1, 3, 4, 8, 9}, {8, 9, 14, 15, 20, 21}, \ {20, 21, 26, 27, 32, 33}, {32, 33, 38, 39, 44, 45}, \ {44, 45, 49, 50, 52, 53}, {4, 5, 9, 10, 15, 16}, \ {15, 16, 21, 22, 27, 28}, {27, 28, 33, 34, 39, 40}, \ {39, 40, 45, 46, 50, 51}, {10, 11, 16, 17, 22, 23}, \ {22, 23, 28, 29, 34, 35}, {34, 35, 40, 41, 46, 47}} #define TRADE_STATION_IND {{2, 3, STUDENT_MTV}, \ {4, 5, STUDENT_MMONEY}, \ {29, 35, STUDENT_BQN}, \ {46, 51, STUDENT_MJ}, \ {43, 48, STUDENT_BPS}} \ typedef struct _coord { int x; int y; } coord; typedef struct _direction { coord L; coord R; coord B; } direction; typedef struct _vertex { int xPos; int yPos; int contents; } vertex; //see photo (Vertex_Coord) in dropbox typedef struct _arc { vertex *start; vertex *end; int arcType; } arc; // look at two verticies to work out arc typedef struct _tile { vertex *corners[NUM_VERT_TILE]; int tileNum; int disciplineType; } tile; typedef struct _player { int KPI; int numOfCampuses; int numGO8; int numARCGrants; int numOfPatents; int numOfPapers; int students[NUM_STUDENTS]; } player; typedef struct _game { // gameboard defaults int disciplines[NUM_TILES]; int dice[NUM_TILES]; // gameboard vertex boardVertexes[NUM_VERTEXES]; arc boardARCs[NUM_ARCS]; tile boardTiles[NUM_TILES]; int turnNumber; // number of turns player players[NUM_PLAYERS]; // useful stuff int mostPubPlayer; int mostARCsPlayer; } game; // our prototypes static int vertexIndex (Game g, vertex v); static direction changeDirection (direction change, char lastMove); static vertex *pathToVertex (Game g, path p); static arc *pathToArc (Game g, path p); //static void printGame (Game g); //static char whatToPrint (Game g, double x, double y); Game newGame (int discipline[], int dice[]) { // malloc memory in the heap for game struct with ptr Game Game g = malloc (sizeof (struct _game)); assert (g != NULL); // check that the memory was correctly malloced and got the ptr // set the disciplines array int count = 0; while (count < NUM_TILES) { g->disciplines[count] = discipline[count]; count++; } // set the dice array count = 0; while (count < NUM_TILES) { g->dice[count] = dice[count]; count++; } // set the vertexes array from the #define above vertex boardVertexes[NUM_VERTEXES] = VERTEXES; count = 0; while (count < NUM_VERTEXES) { g->boardVertexes[count] = boardVertexes[count]; count++; } // using the defined indexes to the vertexes set up the array of // ptrs for each arc int boardARCsIndex[NUM_ARCS][NUM_VERT_ARC] = ARCS_INDEXES; count = 0; while (count < NUM_ARCS) { int startIndex = boardARCsIndex[count][0]; int endIndex = boardARCsIndex[count][1]; vertex *start = &g->boardVertexes[startIndex]; vertex *end = &g->boardVertexes[endIndex]; arc a = {start, end, VACANT_ARC}; g->boardARCs[count] = a; count++; } // do the above for the tiles int boardTilesIndex[NUM_TILES][NUM_VERT_TILE] = TILES_INDEXES; count = 0; while (count < NUM_TILES) { int ind1 = boardTilesIndex[count][0]; int ind2 = boardTilesIndex[count][1]; int ind3 = boardTilesIndex[count][2]; int ind4 = boardTilesIndex[count][3]; int ind5 = boardTilesIndex[count][4]; int ind6 = boardTilesIndex[count][5]; //printf ("%d, %d, %d, %d, %d, %d\n", ind1, ind2, ind3, ind4, // ind5, ind6); tile t = {{&g->boardVertexes[ind1], &g->boardVertexes[ind2], &g->boardVertexes[ind3], &g->boardVertexes[ind4], &g->boardVertexes[ind5], &g->boardVertexes[ind6]}, g->dice[count], g->disciplines[count]}; g->boardTiles[count] = t; count++; } // setup game variables g->turnNumber = -1; g->mostPubPlayer = NO_ONE; g->mostARCsPlayer = NO_ONE; // setup players - note the player name will be the index of the // player in the players array contained in Game. // number of each student the player has - index corresponds to type /* typedef struct _player { int KPI; int numOfCampuses; int numGO8; int numARCGrants; int numOfPatents; int numOfPapers; int students[NUM_STUDENTS]; } player; */ player setup = {20, 2, 0, 0, 0, 0, {0, 3, 3, 1, 1, 1}}; count = 0; while (count < NUM_PLAYERS) { g->players[count] = setup; count++; } return g; } // free all the memory malloced for the game void disposeGame (Game g) { free (g); } // make the specified action for the current player and update the // game state accordingly. // The function may assume that the action requested is legal. // START_SPINOFF is not a legal action here void makeAction (Game g, action a){ int uni = getWhoseTurn (g); int actionCode = a.actionCode; if (actionCode == BUILD_CAMPUS) { //BPS, BQN, BJ, MTV) // Reduce BPS, BQN, BJ, MTV by One g->players[uni].students[STUDENT_BPS]--; g->players[uni].students[STUDENT_BQN]--; g->players[uni].students[STUDENT_MJ]--; g->players[uni].students[STUDENT_MTV]--; // Change vertex contents to player vertex *newCampus = pathToVertex (g, a.destination); newCampus->contents = uni; // Increase campus number by one g->players[uni].numOfCampuses++; //KPI g->players[uni].KPI += 10; } else if (actionCode == BUILD_GO8) { //(2MJ, 3MMON) // reduce , MJ by 2, MMON by 3 g->players[uni].students[STUDENT_MJ] -= 2; g->players[uni].students[STUDENT_MMONEY] -= 3; // Add 3 to content of vertex vertex *newGO8 = pathToVertex (g, a.destination); newGO8->contents = uni + 3; // Increase GO8 by one g->players[uni].numGO8++; // Decrease campus by one g->players[uni].numOfCampuses--; // KPI g->players[uni].KPI += 10; } else if (actionCode == OBTAIN_ARC) { //(BPS, BQN) // Reduce BPS and BQN by 1 g->players[uni].students[STUDENT_BPS]--; g->players[uni].students[STUDENT_BQN]--; // Change arc content to player arc *newARC = pathToArc (g, a.destination); newARC->arcType = uni; // Increase arc by one g->players[uni].numARCGrants++; //KPI g->players[uni].KPI += 2; //Update Arcs(firstly take 10 KPI points from leader) int mostArcs = g->mostARCsPlayer; g->players[mostArcs].KPI -= 10; // Work out new leader mostArcs = getMostARCs (g); // (is it Game g or just g?) g->mostARCsPlayer = mostArcs; // Add 10 KPI points to new leader g->players[mostArcs].KPI += 10; } else if (actionCode == OBTAIN_PUBLICATION) { //(MJ, MTV, MMON) // Reduce MJ, MTV, MMON by 1 g->players[uni].students[STUDENT_MJ]--; g->players[uni].students[STUDENT_MTV]--; g->players[uni].students[STUDENT_MMONEY]--; // Increase Publicaiton by 1 g->players[uni].numOfPapers++; //Update Publication(firstly take 10 KPI points from leader) int mostPub = g->mostPubPlayer; g->players[mostPub].KPI -= 10; // Work out new leader mostPub = getMostPublications(g); g->mostPubPlayer = mostPub; // Add 10 KPI points to new leader g->players[mostPub].KPI += 10; } else if (actionCode == OBTAIN_IP_PATENT) {//(MJ, MTV, MMON) // Reduce MJ, MTV, MMON by 1 g->players[uni].students[STUDENT_MJ]--; g->players[uni].students[STUDENT_MTV]--; g->players[uni].students[STUDENT_MMONEY]--; // Increase IP by 1 g->players[uni].numOfPatents++; //KPI g->players[uni].KPI += 10; } else if (actionCode == RETRAIN_STUDENTS) { // WHATEVA int exchange = 0; exchange = getExchangeRate (g, uni, a.disciplineFrom, a.disciplineTo); // DisciplineFrom - exchange g->players[uni].students[a.disciplineFrom] -= exchange; // DisciplineTo +1 g->players[uni].students[a.disciplineTo]++; } } // advance the game to the next turn, // assuming that the dice has just been rolled and produced diceScore // the game starts in turn -1 (we call this state "Terra Nullis") and // moves to turn 0 as soon as the first dice is thrown. void throwDice (Game g, int diceScore) { g->turnNumber++; // add one to number of turns // gives students resources from tiles with dice == diceScore int count = 0; while (count < NUM_TILES) { tile currentTile = g->boardTiles[count]; int tileStudent = currentTile.disciplineType; int tileDice = currentTile.tileNum; int c = 0; while (c < NUM_VERT_TILE) { vertex *v = currentTile.corners[c]; int vertContent = v->contents; if (tileDice == diceScore) { if (vertContent >= 4) { vertContent -= 3; } g->players[vertContent].students[tileStudent]++; } c++; } count++; } // retrains to ThD if 7 is rolled if (diceScore == 7) { int counter = 1; while (counter <= NUM_UNIS) { int addToTHD = g->players[counter].students[STUDENT_MTV] + g->players[counter].students[STUDENT_MMONEY]; g->players[counter].students[STUDENT_MTV] = 0; g->players[counter].students[STUDENT_MMONEY] = 0; g->players[counter].students[STUDENT_THD] += addToTHD; counter++; } } } /* **** Functions which GET data about the game aka GETTERS **** */ // what type of students are produced by the specified region? // regionID is the index of the region in the newGame arrays (above) // see discipline codes above int getDiscipline (Game g, int regionID) { return g->disciplines[regionID];; } // what dice value produces students in the specified region? // 2..12 int getDiceValue (Game g, int regionID) { return g->dice[regionID]; } // which university currently has the prestige award for the most ARCs? // this is NO_ONE until the first arc is purchased after the game // has started. int getMostARCs (Game g) { int leader = g->mostARCsPlayer; int uniAARC = g->players[UNI_A].numARCGrants; int uniBARC = g->players[UNI_B].numARCGrants; int uniCARC = g->players[UNI_C].numARCGrants; if ((uniAARC > uniBARC) && (uniAARC > uniCARC)) { leader = UNI_A; } if ((uniBARC > uniAARC) && (uniBARC > uniCARC)) { leader = UNI_B; } if ((uniCARC > uniAARC) && (uniCARC > uniBARC)) { leader = UNI_C; } g->mostARCsPlayer = leader; return leader; } // which university currently has the prestige award for the most pubs? // this is NO_ONE until the first publication is made. int getMostPublications (Game g) { int leadPub; //Person with the most publications int publiA = 0; // Each uni's tally int publiB = 0; int publiC = 0; leadPub = g->mostPubPlayer; // Requesting all the values from getPublications function publiA = getPublications (g, UNI_A); publiB = getPublications (g, UNI_B); publiC = getPublications (g, UNI_C); // Determining who has the most if ((publiA > publiB) && (publiA > publiC)) { leadPub = UNI_A; } else if ((publiB > publiC) && (publiB > publiA)) { leadPub = UNI_B; } else if ((publiC > publiA) && (publiC > publiB)) { leadPub = UNI_C; } g->mostPubPlayer = leadPub; return leadPub; } // return the current turn number of the game -1,0,1, .. int getTurnNumber (Game g) { return g->turnNumber; } // return the player id of the player whose turn it is // the result of this function is NO_ONE during Terra Nullis int getWhoseTurn (Game g) { int turnNumber = g->turnNumber; int whoseTurn; if (turnNumber == -1) { whoseTurn = NO_ONE; } else { whoseTurn = turnNumber % NUM_UNIS + 1; } return whoseTurn; } // return the contents of the given vertex (ie campus code or // VACANT_VERTEX) int getCampus (Game g, path p) { vertex *v = pathToVertex (g, p); return v->contents; } // the contents of the given edge (ie ARC code or vacent ARC) int getARC (Game g, path pathToEdge) { arc *arcPtr = pathToArc (g, pathToEdge); return arcPtr->arcType; } // returns TRUE if it is legal for the current // player to make the specified action, FALSE otherwise. // // "legal" means everything is legal: // * that the action code is a valid action code which is legal to // be made at this time // * that any path is well formed and legal ie consisting only of // the legal direction characters and of a legal length, // and which does not leave the island into the sea at any stage. // * that disciplines mentioned in any retraining actions are valid // discipline numbers, and that the university has sufficient // students of the correct type to perform the retraining // // eg when placing a campus consider such things as: // * is the path a well formed legal path // * does it lead to a vacent vertex? // * under the rules of the game are they allowed to place a // campus at that vertex? (eg is it adjacent to one of their ARCs?) // * does the player have the 4 specific students required to pay for // that campus? // It is not legal to make any action during Terra Nullis ie // before the game has started. // It is not legal for a player to make the moves OBTAIN_PUBLICATION // or OBTAIN_IP_PATENT (they can make the move START_SPINOFF) // you can assume that any pths passed in are NULL terminated strings. int isLegalAction (Game g, action a) { // Ignore anything not relevant //PASS 0 -- Should be by itself (ignore everthting else) //BUILD_CAMPUS 1 -- "empty vertex on board", arc connected, "enough supplies", no campus on adjacent vertex //BUILD_GO8 2 -- campus there , less then 8 GO8( use getgo8 and add all together) , enough supplies //OBTAIN_ARC 3 -- no arc there, arc connected, "enough supplies" //START_SPINOFF 4 -- enough supplies(this goes to a magical place to get changed to a ob pub or ob ip before makeaction) //OBTAIN_PUBLICATION 5 -- Not allowed //OBTAIN_IP_PATENT 6 -- Not allowed //RETRAIN_STUDENTS 7 -- "legal to and from", enough resources (retraining centres), "cant be THD's" int uni = getWhoseTurn (g); int turn = getTurnNumber (g); int legal = TRUE; int actionCode = a.actionCode; // resources for player int BPS = getStudents (g, uni, STUDENT_BPS); int BQN = getStudents (g, uni, STUDENT_BQN); int MJ = getStudents (g, uni, STUDENT_MJ); int MTV = getStudents (g, uni, STUDENT_MTV); int MMONEY = getStudents (g, uni, STUDENT_MMONEY); int GO8A = getGO8s (g, UNI_A); int GO8B = getGO8s (g, UNI_B); int GO8C = getGO8s (g, UNI_C); int numGO8 = GO8A + GO8B + GO8C; // Checking legalActionCode if ((actionCode < PASS) || (actionCode > RETRAIN_STUDENTS) || (actionCode == OBTAIN_PUBLICATION) || (actionCode == OBTAIN_IP_PATENT)) { legal = FALSE; } // Checking legalDestination // Test each step that it is on the board (set as (0,0) if FALSE) vertex *end = pathToVertex (g, a.destination); if (end == NULL) { legal = FALSE; } else if (actionCode == BUILD_CAMPUS) { int noNeighbours = TRUE; int arcNeighbour = FALSE; int count = 0; while (count < NUM_ARCS) { arc a = g->boardARCs[count]; vertex *s = a.start; vertex *e = a.end; // int arcContents = g->boardARCs[count].arcType; if (s == end || e == end) { if ((s->contents != VACANT_VERTEX) && (e->contents != VACANT_VERTEX)) { noNeighbours = FALSE; } } if (a.arcType == uni) { arcNeighbour = TRUE; } count++; } if ((noNeighbours == FALSE) || (arcNeighbour == FALSE)) { legal = FALSE; } } else if (actionCode == OBTAIN_ARC) { int arcNeighbour = FALSE; arc *newARC = pathToArc (g, a.destination); int count = 0; while (count < NUM_ARCS) { arc a = g->boardARCs[count]; if ((a.start == newARC->start) || (a.start == newARC->end) || (a.end == newARC->start) || (a.end == newARC->end)) { if (a.arcType == uni) { arcNeighbour = TRUE; count = NUM_ARCS; } } count++; } if (arcNeighbour == FALSE) { legal = FALSE; } } else if (actionCode == BUILD_GO8) { // Checking they own the vertex if (end->contents != uni) { legal = FALSE; } } else if (actionCode == OBTAIN_ARC){ // Arc Test (BPS, BQN) // Checking if they have enough resources if ((BPS < 1) || (BQN < 1)) { legal = FALSE; } } else if (actionCode == BUILD_CAMPUS){ // Campus Test(BPS, BQN, BJ, MTV) if ((BPS < 1) || (BQN < 1) || (MJ < 1) || (MTV < 1)){ legal = FALSE; } } else if (actionCode == BUILD_GO8) { // GO8 Test(2MJ, 3MMON) if ((numGO8 >= 8) || (MJ < 2) || (MMONEY < 3)){ legal = FALSE; // Test less then 8 GO8 campuses } } else if (actionCode == START_SPINOFF){ // Spin Off Test (MJ, MTV, MMON) if ((MJ < 1) || (MTV < 1) || (MMONEY < 1)){ legal = FALSE; } } else if (actionCode == RETRAIN_STUDENTS) { // Check the exchange rate int exchange = getExchangeRate (g, uni, a.disciplineFrom, a.disciplineTo); if (a.disciplineFrom < exchange) { legal = FALSE; } // Checking legalDisciplineFrom (1->5) if ((a.disciplineFrom < STUDENT_BPS) || (a.disciplineFrom > STUDENT_MMONEY)){ legal = FALSE; } // Checking legalDisciplineTo (0->5) if ((a.disciplineTo < STUDENT_THD) || (a.disciplineTo > STUDENT_MMONEY)){ legal = FALSE; } } // Check if Pass if (actionCode == PASS) { // If its a pass other values dont matter legal = TRUE; } if (turn < 0) { legal = FALSE; } return legal; } // --- get data about a specified player --- // return the number of KPI points the specified player currently has int getKPIpoints (Game g, int player) { return g->players[player].KPI; } // return the number of ARC grants the specified player currently has int getARCs (Game g, int player) { return g->players[player].numARCGrants; } // return the number of GO8 campuses the specified player currently has int getGO8s (Game g, int player) { return g->players[player].numGO8; } // return the number of normal Campuses the specified player currently has int getCampuses (Game g, int player) { return g->players[player].numOfCampuses; } // return the number of IP Patents the specified player currently has int getIPs (Game g, int player) { return g->players[player].numOfPatents; } // return the number of Publications the specified player currently has int getPublications (Game g, int player) { return g->players[player].numOfPapers; } // return the number of students of the specified discipline type // the specified player currently has int getStudents (Game g, int player, int discipline) { return g->players[player].students[discipline]; } // return how many students of discipline type disciplineFrom // the specified player would need to retrain in order to get one // student of discipline type disciplineTo. This will depend // on what retraining centers, if any, they have a campus at. int getExchangeRate (Game g, int player, int disciplineFrom, int disciplineTo) { //** int exchange = 3; //Check if person has campus on trade station //Check discipline from = that trade station //The numbers used are the respective indexes for the tradeStation //vertexes. if (disciplineFrom == STUDENT_BPS) { if ((g->boardVertexes[43].contents == player) || (g->boardVertexes[48].contents == player) || (g->boardVertexes[43].contents == player + 3) || (g->boardVertexes[48].contents == player + 3)) { exchange--; } } else if (disciplineFrom == STUDENT_BQN) { if ((g->boardVertexes[29].contents == player) || (g->boardVertexes[35].contents == player) || (g->boardVertexes[29].contents == player + 3) || (g->boardVertexes[35].contents == player + 3)) { exchange--; } } else if (disciplineFrom == STUDENT_MJ) { if ((g->boardVertexes[46].contents == player) || (g->boardVertexes[51].contents == player) || (g->boardVertexes[46].contents == player + 3) || (g->boardVertexes[51].contents == player + 3)) { exchange--; } } else if (disciplineFrom == STUDENT_MTV) { if ((g->boardVertexes[2].contents == player) || (g->boardVertexes[3].contents == player) || (g->boardVertexes[2].contents == player + 3) || (g->boardVertexes[3].contents == player + 3)) { exchange--; } } else if (disciplineFrom == STUDENT_MMONEY) { if ((g->boardVertexes[4].contents == player) || (g->boardVertexes[5].contents == player) || (g->boardVertexes[4].contents == player + 3) || (g->boardVertexes[5].contents == player + 3)) { exchange--; } } // Just incase weird things happen if (exchange <= 0) { exchange = 1; } return exchange; } // OUR new functions - prototypes not in header // This function takes in a vertex and searches the boardVertexes array // for it. Once found it returns a pointer to that vertex (the vertex // from boardVertexes). If no match is found it will return an invalid // index i.e. -1 (aka NO_VERTEX). static int vertexIndex (Game g, vertex v) { int count = 0; int vertexIndex = NO_VERTEX; while (count < NUM_VERTEXES) { // take the vertex at index count to compare to v vertex test = g->boardVertexes[count]; // compare the vertexes - if the same save the index if (v.xPos == test.xPos && v.yPos == test.yPos) { vertexIndex = count; // this ends the while loop - job done! count = NUM_VERTEXES; } count++; } return vertexIndex; } static direction changeDirection (direction change, char lastMove) { coord buffer = change.L; if (lastMove == 'B') { change.L.x *= -1; change.L.y *= -1; change.R.x *= -1; change.R.y *= -1; change.B.x *= -1; change.B.y *= -1; } else if (lastMove == 'R') { change.L.x = -change.B.x; change.L.y = -change.B.y; change.B.x = -change.R.x; change.B.y = -change.R.y; change.R.x = -buffer.x; change.R.y = -buffer.y; } else if (lastMove == 'L') { change.L.x = -change.R.x; change.L.y = -change.R.y; change.R.x = -change.B.x; change.R.y = -change.B.y; change.B.x = -buffer.x; change.B.y = -buffer.y; } return change; } // pathToVertex takes in a string of type path composed of L, B and R. // It then converts that into a vertex through a series of calculations. // This resultant vertex is compared with the vertexes on the board. // If this vertex is found in the boardVertexes then the pointer to that // vertex is returned. // // Note: if at any point the vertex calculated is not on the board then // a null pointer is returned (hence the path was not valid). static vertex *pathToVertex (Game g, path p) { int validPath = TRUE; // Takes the start vertex coord 5, 0 and index 0 in boardVertexes vertex v = g->boardVertexes[0]; // This is the change in x and y that must occur to go... // Left Right Back // x y x y x y direction change = {{1, 0}, {-1, -1}, {-1, 1}}; int count = 0; while (count < strlen (p)) { // current place in the string path char currentChar = p[count]; // printf used for debugging to show each step and direction // change along a path. /* printf ("(%d, %d)\n", v.xPos, v.yPos); printf ("L: %d %d, R: : %d %d, B: %d %d\n", change.L.x, change.L.y, change.R.x, change.R.y, change.B.x, change.B.y); printf ("%c\n", currentChar); */ // sees what direction the path is going, applies the correct // operation and the changes the orientation by changing the // L R and B operations. if (currentChar == 'B') { v.xPos += change.B.x; v.yPos += change.B.y; change = changeDirection (change, 'B'); } else if (currentChar == 'L') { v.xPos += change.L.x; v.yPos += change.L.y; change = changeDirection (change, 'L'); } else if (currentChar == 'R') { v.xPos += change.R.x; v.yPos += change.R.y; change = changeDirection (change, 'R'); } else { // char is not a valid part of a path validPath = FALSE; } // checks that the vertex lies on the board by finding its index // in boardVertexes. If it cannot be found NO_VERTEX == -1 is // returned instead. if (vertexIndex (g, v) == NO_VERTEX) { validPath = FALSE; printf ("%d %d\n", v.xPos, v.yPos); } count++; } vertex *vPtr = &g->boardVertexes[vertexIndex (g, v)]; // if any vertex along the path was not on the board then return // null -> this allows pathToVertex to test for valid paths. if (!validPath) { vPtr = NULL; } return vPtr; } static arc *pathToArc (Game g, path p) { arc *arcPtr = NULL; path original = {*p}; path toEndPoint; path toStartPoint; strcpy (toEndPoint, original); original[strlen (original) - 1] = '\0'; strcpy (toStartPoint, original); vertex *start = pathToVertex (g, toStartPoint); vertex *end = pathToVertex (g, toEndPoint); int count = 0; while (count < NUM_ARCS) { arc test = g->boardARCs[count]; if ((test.start == start && test.end == end) || (test.end == start && test.start == end)) { arcPtr = &g->boardARCs[count]; count = NUM_ARCS; } count++; } return arcPtr; } /* static void printGame (Game g) { double x = 0; double y = MAX_YPOS_VERTEX - 1; while (y >= 0) { x = 0; while (x <= MAX_XPOS_VERTEX) { char toPrint = whatToPrint (g, x, y); if (toPrint == 'T') { // looking through the tiles and taking the x and y pos as the // average of the first (top left) and last (bottom right) vertex int arrCount = 0; while (arrCount < NUM_TILES) { tile t = g->boardTiles[arrCount]; double tileXPos = (t.corners[0]->xPos + t.corners[1]->xPos)/2.0; double tileYPos = (t.corners[0]->yPos + t.corners[4]->yPos)/2.0; if (x == tileXPos && y == tileYPos) { printf ("%d", t.disciplineType); } arrCount++; } } else { printf ("%c", toPrint); } x += 0.5; } printf ("\n"); y -= 0.5; } } // This function compares the x y value with all of the arcs/vertexes. // If a position match is found then return what value to print static char whatToPrint (Game g, double x, double y) { char toPrint = ' '; // look for a vertex that matches the x and y pos and according to // what the vertex contents are print a different char int arrCount = 0; while (arrCount < NUM_VERTEXES) { vertex vert = g->boardVertexes[arrCount]; if (y == vert.yPos && x == vert.xPos) { if (vert.contents == VACANT_VERTEX) { toPrint = 'o'; } else if (vert.contents < 4) { if (vert.contents == UNI_A) { toPrint = 'A'; } else if (vert.contents == UNI_B) { toPrint = 'B'; } else if (vert.contents == UNI_C) { toPrint = 'C'; } } else if (vert.contents > 4) { toPrint = '8'; } //printf("%d", vert.contents); //toPrint = "O"; arrCount = NUM_VERTEXES; } arrCount++; } // looking through the arcs - taking the position as the average of // the start and end x and y pos. arrCount = 0; while (arrCount < NUM_ARCS) { arc a = g->boardARCs[arrCount]; vertex strt = *a.start; vertex ending = *a.end; double arcXPos = (ending.xPos + strt.xPos) / 2.0; double arcYPos = (ending.yPos + strt.yPos) / 2.0; if (x == arcXPos && y == arcYPos) { if (a.arcType == VACANT_ARC) { toPrint = ' '; } else if (a.arcType == UNI_A) { toPrint = 'a'; } else if (a.arcType == UNI_B) { toPrint = 'b'; } else if (a.arcType == UNI_C) { toPrint = 'c'; } arrCount = NUM_ARCS; } arrCount++; } // looking through the tiles and taking the x and y pos as the // average of the first (top left) and last (bottom right) vertex arrCount = 0; while (arrCount < NUM_TILES) { tile t = g->boardTiles[arrCount]; double tileXPos = (t.corners[0]->xPos + t.corners[1]->xPos)/2.0; double tileYPos = (t.corners[0]->yPos + t.corners[4]->yPos)/2.0; if (x == tileXPos && y == tileYPos) { toPrint = 'T'; arrCount = NUM_TILES; } arrCount++; } return toPrint; } */
Download file: Game.c
(35.2 KB)