Game.c - OpenLearning
// 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)

Comments

Chat