// 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)