//Prints out adjacency information for all //pairs of vertices for all connection types //Can be used for debugging void showIsAdjacent(Graph g){ int i,j; printf("Sea connections\n"); for(i=0; i < NUM_MAP_LOCATIONS; i++){ for(j=0; j < NUM_MAP_LOCATIONS; j++){ printf("%d ",isAdjacent(g,i,j,SEA)); } printf("\n"); } printf("LAND connections\n"); for(i=0; i < NUM_MAP_LOCATIONS; i++){ for(j=0; j < NUM_MAP_LOCATIONS; j++){ printf("%d ",isAdjacent(g,i,j,LAND)); } printf("\n"); } printf("ANY connections\n"); for(i=0; i < NUM_MAP_LOCATIONS; i++){ for(j=0; j < NUM_MAP_LOCATIONS; j++){ printf("%d ",isAdjacent(g,i,j,ANY)); } printf("\n"); } }
bool InnerRegion::isValid(){ // Is planar bool valid = isPlanar(); // All vertices (internal and boundary) must be dominated by the two endpoints for (int i = 0; i < getSize(); i++) { if (i == endpoint1 || i == endpoint2) { continue; } valid &= isAdjacent(i, endpoint1) || isAdjacent(i, endpoint2); } return valid; }
void FindShortest(int startPoint, int parentCost) { /* Tour through all the children, shorten their cost if possible */ int i; /* loop index */ node children[NUMA]; /* List of adjacent nodes */ int childIndex; /* Index to the child's number */ children[0].module = (startPoint / 8); children[0].sensorNum = (((startPoint % 8) * 2) + 1); isAdjacent(children[0], children); if (parentCost > NUMSEGMENTS) { return; } for (i = 0; i < NUMA; i++) { if (children[i].sensorNum != NIL) { childIndex = (children[i].module * 8); childIndex += ((children[i].sensorNum - 1) / 2); if ((trafficMap[childIndex].cost - 1) > parentCost) { trafficMap[childIndex].cost = (parentCost + 1); trafficMap[childIndex].parent = startPoint; FindShortest(childIndex, trafficMap[childIndex].cost); } } } }
void Graph::addEdge(int v, int u, int weight, bool createIfNotFound, bool forceCreate, int id) { //get the smaller int first, second; getInOrder(v, u, first, second); //check if v and u dont exist if (first >= adjacencyList.size() || second >= adjacencyList.size()) { //should we create them? if (!createIfNotFound) throw std::runtime_error("Graph::addEdge(int v, int u, int weight, bool createIfNotFound," "bool forceCreate, int id) -> vertex not found in graph"); //try to add addVertex(first, forceCreate); addVertex(second, forceCreate); } if (isAdjacent(first, second)) { throw std::runtime_error("Graph::addEdge(int v, int u, int weight, bool createIfNotFound," "bool forceCreate, int id) -> vertex already exist in graph"); } //add adjacencyList[first].emplace_back(first,second, weight, id); adjacencyList[second].emplace_back(first, second, weight, id); }
int solution(Graph graph, Jval start, Jval stop, Dllist stackVisit, Jval (*cloneFunc)(Jval), int (*compare)(Jval, Jval), void (*reportFunc)(Jval)) { Dllist stackRes; Dllist node; Jval nowNode, temp; int counter = 0; stackRes = new_dllist(); node = dll_first(stackVisit); nowNode = cloneFunc(node->val); dll_delete_node(node); dll_prepend(stackRes, nowNode); while(!dll_empty(stackVisit)) { if(isAdjacent(graph, nowNode, start, compare)) { dll_prepend(stackRes, start); counter++; break; } do { node = dll_first(stackVisit); temp = cloneFunc(node->val); dll_delete_node(node); if(isAdjacent(graph, nowNode, temp, compare)) { dll_prepend(stackRes, temp); nowNode = temp; counter++; break; } } while(!dll_empty(stackVisit)); } printf("Solution: The shortest path between two node: \n"); while(!dll_empty(stackRes)) { node = dll_first(stackRes); reportFunc(node->val); dll_delete_node(node); } free_dllist(stackVisit); return counter; }
void Graph::DFS(int u) { markVertex(u); cout << u << " "; for (int i = 0; i < NODE_COUNT; i++) if (isAdjacent(u,i) && !isMarked(i)) DFS(i); }
bool ScheduleCellSelection::merge( const ScheduleCellSelection & other ) { if( isAdjacent( other ) ) { mCellStart = qMin( mCellStart, other.mCellStart ); mCellEnd = qMax( mCellEnd, other.mCellEnd ); return true; } return false; }
// IMPLEMENT THIS FOR TASK 3 Edge getNextFlight(Graph g, int *dfsOrdered, int *nDiffCountries, Vertex currCountry){ int next = dfsOrdered[(*nDiffCountries)]; if (!isAdjacent(g, currCountry, next)) { // backtrack if not adjacent return mkEdge(currCountry, st[currCountry]); } // otherwise, go (*nDiffCountries)++; return mkEdge(currCountry, next); }
/** * Loads a graph from the given file. The file's first line must be the number * of vertices in the graph and each consecutive line must be a list of numbers * separated by spaces. The first number is the next vertex and the following * numbers are its neighbors. * @param fileName * @return */ Graph* loadGraph(const char* fileName) { FILE* file = fopen(fileName, "r"); char buffer[512]; // Get the number of vertices fgets(buffer, sizeof buffer, file); int numVertices = (int) strtol(buffer, NULL, 10); Graph* graph = malloc(sizeof(Graph)); graph->numVertices = numVertices; graph->numEdges = 0; // Initialize vertices graph->vertexSet = malloc(sizeof(Vertex) * numVertices); for (int i = 0; i < numVertices; ++i) { Vertex* vertex = &graph->vertexSet[i]; vertex->isVisited = 0; vertex->label = i; vertex->neighbors = NULL; vertex->numNeighbors = 0; } // Create edges while (fgets(buffer, sizeof buffer, file) != NULL) { char* begin = buffer; char* end = NULL; // Get vertex int i = (int) strtol(begin, &end, 10); Vertex* vertex = &graph->vertexSet[i]; begin = end; // Create edges for (int i = (int) strtol(begin, &end, 10); end != begin; i = (int) strtol(begin, &end, 10)) { Vertex* neighbor = &graph->vertexSet[i]; if (!isAdjacent(vertex, neighbor)) { createEdge(vertex, neighbor); ++(graph->numEdges); } begin = end; } } fclose(file); return graph; }
bool GameMap::newMeleeAttack(Actor* attacker, Actor* target){ if (attacker != nullptr && target != nullptr){ Coordinate *attack_pos = &attacker->pos; Coordinate *target_pos = &target->pos; bool adj = isAdjacent(attack_pos, target_pos); if (adj){ q.push(new MeleeAttack(attacker, target)); return true; } } return false; }
bool LoadMonitor::handlesAdjacentRegion(ServerID server_id) { BoundingBoxList otherBoundingBoxList = mCoordinateSegmentation->serverRegion(server_id); BoundingBoxList myBoundingBoxList = mCoordinateSegmentation->serverRegion(mContext->id()); for (std::vector<BoundingBox3f>::iterator other_it=otherBoundingBoxList.begin(); other_it != otherBoundingBoxList.end(); other_it++) { for (std::vector<BoundingBox3f>::iterator my_it=myBoundingBoxList.begin(); my_it != myBoundingBoxList.end(); my_it++) { if (isAdjacent(*other_it, *my_it)) return true; } } return false; }
//BREAD FIRST SEARCH void Graph::BFS() { unmarkAll(); int u = 0; queue<int> q; markVertex(u); q.push(u); while (!q.empty()) { u = q.front(); q.pop(); for (int i = 0; i < NODE_COUNT; i++) if (isAdjacent(u,i) && !isMarked(i)) { q.push(i); markVertex(i); } cout << u << " "; } }
void MainWindow::updateBoardPlayer1(int x, int y, int xCoordinate, int yCoordinate){ if(isAdjacent(player1->getXCoordinate(), player1->getYCoordinate(), xCoordinate, yCoordinate) == 1 ){ //updates board board[player1->getXCoordinate()][player1->getYCoordinate()]=0; board[xCoordinate][yCoordinate]=1; //update Player1 new coordinates player1->setXCoordinate(xCoordinate); player1->setYCoordinate(yCoordinate); //x and y values that are passed in are used as the coordinates to move the piece too ui->player_1->move(x, y); moved=1; } else{ ui->label->setText("Invalid square."); } }
void MainWindow::updateBoardPlayer2(int x, int y, int xCoordinate, int yCoordinate){ if(isAdjacent(player2->getXCoordinate(), player2->getYCoordinate(), xCoordinate, yCoordinate) ==1 ){ //updates board board[player2->getXCoordinate()][player2->getYCoordinate()]=0; board[xCoordinate][yCoordinate]=1; //update Player2 new coordinates player2->setXCoordinate(xCoordinate); player2->setYCoordinate(yCoordinate); ui->player_2->move(x, y); moved=1; } else{ ui->label->setText("Invalid square."); } }
void createGraph4(Graph* g) { Vertex* firstVert; Vertex* secondVert; int i; srand(9875); g->numVertices = 26; setupVertices(g); g->numEdges = 100; for(i = 0; i < g->numEdges; ++i) { firstVert = &g->vertexSet[rand() % g->numVertices]; secondVert = firstVert; while(firstVert == secondVert || isAdjacent(firstVert, secondVert)) secondVert = &g->vertexSet[rand() % g->numVertices]; setupEdge(g, firstVert, secondVert); } }
nat getCommonNode(const BranchPlain &oneBranch, const BranchPlain &otherBranch) { // assert(isAdjacent(oneBranch, otherBranch)); if(not isAdjacent(oneBranch, otherBranch)) { std::cout << SHOW(oneBranch) << SHOW(otherBranch) << std::endl; assert(0); } if(oneBranch.getPrimNode() == otherBranch.getPrimNode() || oneBranch.getPrimNode() == otherBranch.getSecNode()) return oneBranch.getPrimNode(); else if(oneBranch.getSecNode() == otherBranch.getPrimNode() || oneBranch.getSecNode() == otherBranch.getSecNode()) return oneBranch.getSecNode(); else // return oneBranch.getSecNode(); { assert(0); return oneBranch.getPrimNode(); } }
/***** Function re-definitions *****/ int ServantAssassin::attack(vector<Servant *> defenders, bool counter) { if (actionMPCosts[ascension][0] > currMP) return 1; // Not enough MP to attack else { subMP(actionMPCosts[ascension][0]); for (unsigned int i = 0; i < defenders.size(); i++) { int dam = 0; // Check if you hit the targets vector<int> opEvade = defenders[i]->getEvade(); bool hit = false; // Calculate accuracy int accuracy = capZero(getHitRate() - opEvade[0]); int r = getRandNum(); if (accuracy >= r) hit = true; // Skill: Presence Detection skips all other evasion checks! // If you hit, calculate crit chance if (hit) { int attackMult = 1; int critChance = capZero(getCriticalRate() - defenders[i]->getCriticalEvade()); r = getRandNum(); if (critChance >= r) attackMult *= 3; // Calculate the chance of Lethality r = getRandNum(); if (getSkl() / 8 > r) { dam = defenders[i]->getMaxHP() * attackMult; log->addToEventLog(getFullName() + " activated Lethality against " + defenders[i]->getFullName() + "!" + to_string(dam) + " damage dealt!"); defenders[i]->subHP(dam, D_STR); } else { // Deal the damage dam = capZero(getStr() - defenders[i]->getDef()) * attackMult; log->addToEventLog(getFullName() + " dealt " + to_string(dam) + " damage to " + defenders[i]->getFullName() + "."); defenders[i]->subHP(dam, D_STR); } // Add the weapon-specific debuff to the target Debuff *deb = new Debuff(classDebuff->getDebuffName(), classDebuff->getDebuffDescrip(), defenders[i]->getTeam(), classDebuff->getDebuffStats(), classDebuff->getDebuffAmounts(), classDebuff->getTurnsRemaining()); defenders[i]->addDebuff(deb); } else { log->addToEventLog(getFullName() + " missed " + defenders[i]->getFullName() + "!"); } // Check to see if the defender is dead. If they are, do not call // the counterattack. Additionally, if they are an Avenger and they // die, activate Final Revenge. // If they are not dead but they are a Berserker, check to see if // Mad Counter activates. if(defenders[i]->getCurrHP() > 0) { // Check if the defender is a Berserker. If they are, and they // are adjacent to this unit, check to see if Mad Counter // activates. if (defenders[i]->getClass() == Berserker && isAdjacent(defenders[i])) { r = getRandNum(); if (defenders[i]->getLuk() >= r) { // Mad Counter activated! The attacking servant takes // damage equal to the damage they dealt. log->addToEventLog(defenders[i]->getFullName() + "' Mad Counter activated, dealing " + to_string(dam) + " damage back to " + getFullName() + "."); subHP(dam, C_STR); } } // Call "attack" on the defending servant for their // counterattack, if you are in their range and you are the // initiating servant. if (defenders[i]->isInRange(this) && counter) { vector<Servant *> you; you.push_back(this); defenders[i]->attack(you, false); } } else { if (defenders[i]->getClass() == Avenger) { // Activate Final Revenge Debuff *finRev = defenders[i]->finalRevenge(); addDebuff(finRev); if (defenders[i]->getAscensionLvl() == 2) { subHP(.1 * getMaxHP(), OMNI); subMP(.1 * getMaxMP()); if (getCurrHP() == 0) { setHP(1); } } } } } } return 0; }
int ServantBerserkerFlail::attack(vector<Servant *> defenders, bool counter) { if (actionMPCosts[ascension][0] > currMP) return 1; // Not enough MP to attack else { subMP(actionMPCosts[ascension][0]); bool npActive = false; // Check if Lashing Out activates // "Hitting all adjacent opponents" only applies to the first two // ascension levels, as Maelstrom of Death trumps Lashing Out int r = getRandNum(); // Cratered Debuff vector<Stat> tS; tS.push_back(SPD); tS.push_back(DEF); vector<int> tA; tA.push_back(-5); tA.push_back(2); // Get the Team of the opposing team /*Team otherTeam = All; vector<vector<Servant*>> pField = field->getServantLocations(); for (unsigned int i = 0; i < pField.size(); i++) { for(unsigned int j = 0; j < pField[i].size(); j++) { if(pField[i][j] != NULL && pField[i][j]->getTeam() != getTeam()) { otherTeam = pField[i][j]->getTeam(); } } }*/ Debuff* br = new Debuff("Cratered", "The ground has been cratered.", All, tS, tA, -1); vector<Coordinate> crateredRange; if (ascension <= 1 && r < getLuk()) { // Add all adjacent servants to the defenders vector (as long as // they aren't already in it) vector<Servant*> adj = field->getAllInRange(this, getLowToHighRange(1,1)); for (unsigned int i = 0; i < adj.size(); i++) { bool isIn = false; for (unsigned int j = 0; j < defenders.size() && !isIn; j++) { if (adj[i] == defenders[j]) isIn = true; } if (!isIn) defenders.push_back(adj[i]); } crateredRange = getAbsoluteRange(1,1,this); } else if (ascension == 2 && r < getLuk() * 1.5) { crateredRange = getAbsoluteRange(1,2,this); } // Apply the cratered debuff to the appropriate spaces field->addDebuffToRange(br, crateredRange); for (unsigned int i = 0; i < defenders.size(); i++) { int dam = 0; // Check if you hit the targets vector<int> opEvade = defenders[i]->getEvade(); bool hit = false; // Calculate accuracy int accuracy = capZero(getHitRate() - opEvade[0]); r = getRandNum(); if (accuracy >= r) hit = true; // Maelstrom of Death doubles accuracy and prevents other evasion // skills from activating if (ascension == 2) accuracy *= 2; if (opEvade.size() > 1 && hit && ascension <= 1) { for (unsigned int j = 1; j < opEvade.size() && hit; j++) { r = getRandNum(); if (opEvade[j] >= r) hit = false; } } // If you hit, calculate crit chance if (hit) { int attackMult = 1; int critChance = capZero(getCriticalRate() - defenders[i]->getCriticalEvade()); // Spin To Win triples crit chance if (ascension >= 1) critChance *= 3; // Maelstrom of Death also doubles crit chance if (ascension == 2) critChance *= 2; r = getRandNum(); if (critChance >= r) attackMult *= 3; // Deal the damage dam = capZero(getStr() - defenders[i]->getDef()) * attackMult; log->addToEventLog(getFullName() + " dealt " + to_string(dam) + " damage to " + defenders[i]->getFullName() + "."); defenders[i]->subHP(dam, D_STR); } else { log->addToEventLog(getFullName() + " missed " + defenders[i]->getFullName() + "!"); } // Check to see if the defender is dead. If they are, do not call // the counterattack. Additionally, if they are an Avenger and they // die, activate Final Revenge. // If they are not dead but they are a Berserker, check to see if // Mad Counter activates. if(defenders[i]->getCurrHP() > 0) { // Check if the defender is a Berserker. If they are, and they // are adjacent to this unit, check to see if Mad Counter // activates. if (defenders[i]->getClass() == Berserker && isAdjacent(defenders[i])) { r = getRandNum(); if (defenders[i]->getLuk() >= r) { // Mad Counter activated! The attacking servant takes // damage equal to the damage they dealt. log->addToEventLog(defenders[i]->getFullName() + "'s Mad Counter activated, dealing " + to_string(dam) + " damage back to " + getFullName() + "."); subHP(dam, C_STR); } } // Call "attack" on the defending servant for their // counterattack, if you are in their range and you are the // initiating servant. // However if the servant is at their final ascension, or if // Lashing out activates, targets cannot counter if (!npActive && counter && defenders[i]->isInRange(this)) { vector<Servant *> you; you.push_back(this); defenders[i]->attack(you, false); } } else { if (defenders[i]->getClass() == Avenger) { // Activate Final Revenge Debuff *finRev = defenders[i]->finalRevenge(); addDebuff(finRev); if (defenders[i]->getAscensionLvl() == 2) { subHP(.1 * getMaxHP(), OMNI); subMP(.1 * getMaxMP()); if (getCurrHP() == 0) { setHP(1); } } } } } } return 0; }
int main (int argc, char * argv[]) { printf("Blackbox tests...\n"); printf("Test 1: newGraph..."); //empty graph Graph g1a = mkTestGraph(0); destroyGraph(g1a); //single graph Graph g1b = mkTestGraph(1); destroyGraph(g1b); printf("Passed!\n"); printf("Test 1a: mkEdge..."); //zero cost edge Edge e1a = mkEdge(0, 1, 0); assert(e1a.v == 0); assert(e1a.w == 1); assert(e1a.weight == 0); Edge e1ar = mkEdge(1, 0, 0); assert(e1ar.v == 1); assert(e1ar.w == 0); assert(e1ar.weight == 0); //edge Edge e1b = mkEdge(1, 5, 10); assert(e1b.v == 1); assert(e1b.w == 5); assert(e1b.weight == 10); Edge e1br = mkEdge(5, 1, 10); assert(e1br.v == 5); assert(e1br.w == 1); assert(e1br.weight == 10); printf("Passed!\n"); printf("Test 2: insertE..."); //double graph Graph g2 = mkTestGraph(2); Edge e2 = mkEdge(0, 1, 12); insertE(g2, e2); assert(numE(g2) == 1); destroyGraph(g2); printf("Passed!\n"); printf("Test 3: isAdjacent..."); //double graph Graph g3a = mkTestGraph(2); Edge e3a = {0, 1, 12}; insertE(g3a, e3a); assert(numV(g3a) == 2); assert(numE(g3a) == 1); assert(isAdjacent(g3a, 0, 1) == 1); assert(isAdjacent(g3a, 1, 0) == 1); destroyGraph(g3a); //graph Graph g3b = mkTestGraph(3); assert(isAdjacent(g3b, 0, 1) == 1); assert(isAdjacent(g3b, 0, 2) == 1); assert(isAdjacent(g3b, 0, 3) == 1); assert(isAdjacent(g3b, 0, 4) == 1); assert(isAdjacent(g3b, 1, 2) == 1); assert(isAdjacent(g3b, 2, 3) == 1); assert(isAdjacent(g3b, 3, 4) == 1); destroyGraph(g3b); printf("Passed!\n"); printf("Test 4: adjacentVertices..."); Graph g4a = mkTestGraph(2); Edge e4a = {0, 1, 12}; insertE(g4a, e4a); Vertex adj4a[2]; //allocate space for max number of vertices assert(adjacentVertices(g4a, 0, adj4a) == 1); assert(adj4a[0] >= 0); assert(adjacentVertices(g4a, 1, adj4a) == 1); assert(adj4a[0] >= 0); destroyGraph(g4a); printf("Passed!\n"); printf("Test 5: incidentEdges..."); Graph g5 = mkTestGraph(2); Edge e5 = {0, 1, 12}; insertE(g5, e5); Edge edges5[1]; //allocate space for max num of edges assert(incidentEdges(g5, 0, edges5) == 1); int v5 = edges5[0].v; int w5 = edges5[0].w; assert( (v5 == 0 && w5 == 1) || (v5 == 1 && w5 == 0) ); assert(edges5[0].weight == 12); assert(incidentEdges(g5, 1, edges5) == 1); v5 = edges5[0].v; w5 = edges5[0].w; assert( (v5 == 0 && w5 == 1) || (v5 == 1 && w5 == 0) ); assert(edges5[0].weight == 12); destroyGraph(g5); printf("Passed!\n"); printf("Test 6: edges..."); Graph g6 = mkTestGraph(2); Edge e6 = {0, 1, 12}; insertE(g6, e6); Edge es6[1]; //allocate space for max num of edges assert(edges(es6, 1, g6) == 1); int v6 = es6[0].v; int w6 = es6[0].w; assert( (v6 == 0 && w6 == 1) || (v6 == 1 && w6 == 0) ); assert(es6[0].weight == 12); destroyGraph(g6); printf("Passed!\n"); printf("All Test Passed! You are a Beast!\n"); return EXIT_SUCCESS; }
int ServantBerserkerClub::attack(vector<Servant *> defenders, bool counter) { if (actionMPCosts[ascension][0] > currMP) return 1; // Not enough MP to attack else { subMP(actionMPCosts[ascension][0]); for (unsigned int i = 0; i < defenders.size(); i++) { // Add the target to the list of previous targets (if they are not // already on it) if (!previouslyTargeted(defenders[i])) previousTargets.push_back(defenders[i]); int dam = 0; // Check if you hit the targets vector<int> opEvade = defenders[i]->getEvade(); bool hit = false; // Calculate accuracy int accuracy = capZero(getHitRate() - opEvade[0]); int r = getRandNum(); if (accuracy >= r) hit = true; if (opEvade.size() > 1 && hit) { for (unsigned int j = 1; j < opEvade.size() && hit; j++) { r = getRandNum(); if (opEvade[j] >= r) hit = false; } } // If you hit, calculate crit chance if (hit) { int attackMult = 1; int critChance = capZero(getCriticalRate() - defenders[i]->getCriticalEvade()); r = getRandNum(); if (critChance >= r) attackMult *= 3; // If you're at the Final Ascension and have already faced this // target, deal thrice as much damage and decrease DEF by 10 // (Barbarian's Wrath) if(ascension == 2 && previouslyTargeted(defenders[i])) { attackMult *= 3; vector<Stat> tS; tS.push_back(DEF); vector<int> tA; tA.push_back(-10); Debuff* bw = new Debuff("Barbarian's Wrath", "You tried to fight a Club Berserker twice, and paid the price.", defenders[i]->getTeam(), tS, tA, -1); defenders[i]->addDebuff(bw); log->addToEventLog(defenders[i]->getFullName() + " felt " + getFullName() + "'s Wrath!"); } // Deal the damage dam = capZero(getStr() - defenders[i]->getDef()) * attackMult; log->addToEventLog(getFullName() + " dealt " + to_string(dam) + " damage to " + defenders[i]->getFullName() + "."); defenders[i]->subHP(dam, D_STR); // Apply the Crushing Blow debuff vector<Stat> tStats; tStats.push_back(DEF); vector<int> tAmounts; tAmounts.push_back(-2); Debuff* bOut = new Debuff("Crushing Blow", "You took a blow from a Club Berserker, permanetly denting your armor.", defenders[i]->getTeam(), tStats, tAmounts, -1); defenders[i]->addDebuff(bOut); // Check to see if Barbarian's Might activates r = getRandNum(); if (r <= getLuk() * 2) { vector<Stat> tS; tS.push_back(DEF); vector<int> tA; tA.push_back(-5); Debuff* bm = new Debuff("Barbarian's Might", "You took an incredible blow from a Club Berserker, permanetly denting your armor.", defenders[i]->getTeam(), tS, tA, -1); defenders[i]->addDebuff(bm); log->addToEventLog(defenders[i]->getFullName() + " felt " + getFullName() + "'s Might!"); } } else { log->addToEventLog(getFullName() + " missed " + defenders[i]->getFullName() + "!"); } // Check to see if the defender is dead. If they are, do not call // the counterattack. Additionally, if they are an Avenger and they // die, activate Final Revenge. // If they are not dead but they are a Berserker, check to see if // Mad Counter activates. if(defenders[i]->getCurrHP() > 0) { // Check if the defender is a Berserker. If they are, and they // are adjacent to this unit, check to see if Mad Counter // activates. if (defenders[i]->getClass() == Berserker && isAdjacent(defenders[i])) { r = getRandNum(); if (defenders[i]->getLuk() >= r) { // Mad Counter activated! The attacking servant takes // damage equal to the damage they dealt. log->addToEventLog(defenders[i]->getFullName() + "'s Mad Counter activated, dealing " + to_string(dam) + " damage back to " + getFullName() + "."); subHP(dam, C_STR); } } // Call "attack" on the defending servant for their // counterattack, if you are in their range and you are the // initiating servant. if (defenders[i]->isInRange(this) && counter) { vector<Servant *> you; you.push_back(this); defenders[i]->attack(you, false); } } else { if (defenders[i]->getClass() == Avenger) { // Activate Final Revenge Debuff *finRev = defenders[i]->finalRevenge(); addDebuff(finRev); if (defenders[i]->getAscensionLvl() == 2) { subHP(.1 * getMaxHP(), OMNI); subMP(.1 * getMaxMP()); if (getCurrHP() == 0) { setHP(1); } } } } } } return 0; }
/* We begin at whatever our start position is -- From there (in order) we will check the north, west, east, and south "cells". Additionally each time we are checking these surrounding cells we are building paths from the starting cell that includes these cells. So assuming that ALL four cells where open, and NONE of these cells were the destination, we'd have four distinct paths that lead out from our start cell. So we've starting building four distinct paths from our start cell... What now? Well for each path we start to build we'll add it to a local variable "master_list". This is a queue of stacks. If you are unfamiliar with what a queue or stack is, this is where you stop reading this tutorial and brush up on those concepts, otherwise chances are good that you will become hopelessly lost. The "master_list", as aforementioned, is a queue of stacks -- We're using STL so we don't have to worry about the implementation of the queue or the stack, all we have to do is use it. Each stack in our queue will be a stack of "cells" that lead away from our start cell. The first time through the loop (assuming all the north, west, east and south cells are open) we'd have FOUR distinct stacks of cells leading out of the start cell. It would look something like this: QUEUE[0] = { STACK["North Cell"] ["Start Cell"] } // Top of queue QUEUE[1] = { STACK["West Cell"] ["Start Cell"] } QUEUE[2] = { STACK["East Cell"] ["Start Cell"] } QUEUE[3] = { STACK["South Cell"] ["Start Cell"] } // Bottom of queue The next time through the loop we'll pop off the TOP stack of our queue (the stack containing the start cell and the "north adjacent cell") -- Then we'd check to see if we can move to ANY of the adjacent cells to the "north adjacent cell" Lets assume we can move to the north, west, and east cell (we obviously can't move to the south cell because that's the start cell and we've all ready visited it) Then what we'd have is 3 NEW paths that are added to the master list. It would then look something like this: // N == the cell NORTH of the starting cell QUEUE[0] = { STACK["West Cell"] ["Start Cell"] } // Top of queue QUEUE[1] = { STACK["East Cell"] ["Start Cell"] } QUEUE[2] = { STACK["South Cell"] ["Start Cell"] } QUEUE[3] = { STACK["North of N"] [N] ["Start Cell"] } QUEUE[4] = { STACK["West of N"] [N] ["Start Cell"] } QUEUE[5] = { STACK["East of N"] [N] ["Start Cell"] } // Bottom of queue Basically the pattern continues in this fashion until the destination is reached or the "master_list" becomes empty signifying there is NO path from the start cell to the destination cell. This is all really wordy and high level. So if your eyes glazed over when you were reading it, don't worry so did mine :) -- Hopefully it will make some more sense when you read the implementation */ bool CGrid::pathFind() { /* So what's up with the COORD? Our grid is made up of a double array of CCell's. We'll use the COORD (which contains an x and y) for storing the row/column indices into our double array so we know what cell we are on. There is an explanation of row/column vs (x,y) at the bottom of grid.h in case you find yourself asking the question "What is he doing???" */ queue< stack<COORD> > master_list; // Our master list of stacks of cells that // are all valid different paths from the start cell stack<COORD> single_path; // This will hold ONE valid path from the start cell int startX, startY; getStartPos(startX,startY); // Get our starting position grid_array[startY][startX].setVisited(true); // Set the starting position to visited COORD cell = {startX,startY}; // Create a COORD representing our starting postion single_path.push(cell); // Our first path obviously begins with the starting position master_list.push(single_path); // This will also be the first stack of potential // paths on our master list // We loop while the "master_list" is not empty -- If it becomes empty then NO // path exists from the start cell to the destination cell while(master_list.empty() == false) { single_path = master_list.front(); // Get the TOP stack of path cells master_list.pop(); // ALWAYS remove the TOP of queue -- Any potential paths // will be re-added at the back of the queue once we've // went through checking for open adjacent cells cell = single_path.top(); // Get the current cell we're checking // for our current stack of path cells // Loop through all possible adjacent CCell's for(int dest_y = cell.Y - 1; dest_y <= cell.Y + 1; dest_y++) { for(int dest_x = cell.X - 1; dest_x <= cell.X + 1; dest_x++) { // We are only concerned with north, west, east, and south adjacent cells, // so skip all cells we don't care about if(!isAdjacent(cell.X,cell.Y,dest_x,dest_y)) continue; // If the CCell is open (ie it hasn't been visited and it's not a wall) if(isOpen(dest_x,dest_y)) { COORD temp_cell = {dest_x, dest_y}; // If the cell is the destination cell -- We're done!!!!!!!!! if(grid_array[dest_y][dest_x].getCellVal() == DEST) { dest_found = true; // We've found the destination // Add the destination to the stack of "path_nodes" path_nodes.push(temp_cell); // Then, while the "single_path" (which is the SHORTEST PATH) // isn't empty, add all the CCell's (the COORD holding the row/column // indexes into our double array of CCell's) in "single_path" to the // "path_nodes" -- This works out slick, so are path_nodes will // be in the correct order (ie start pos at top, end pos at bottom) while(single_path.empty() == false) { path_nodes.push(single_path.top()); single_path.pop(); } return true; // We have found the promised land! } // If we get here, then the current "open" cell is not the // destination cell // So... First set the now open cell to visited grid_array[dest_y][dest_x].setVisited(true); // Then add it to our current path single_path.push(temp_cell); // Then add the new current path to the master list master_list.push(single_path); // Last but not least, remove the "cell" we just added to our current // path. Remember we want to create all the new potential paths // leading away from our current "end cell" in our "current path" // So we pop off the cell we just added so next time through the loop // we'll check our previous state again single_path.pop(); } // end of if(isOpen(dest_x,dest_y)) } // end of for(int dest_x = cell.X - 1; dest_x <= cell.X + 1; dest_x++) } // end of for(int dest_y = cell.Y - 1; dest_y <= cell.Y + 1; dest_y++) } // end of while(master_list.empty() == false) return false; // No path existed } // end of void CGrid::pathFind()
bool PhysicsInterface::convertImageAlphaTo2DPolygons(const Image& image, Vector<Vector<Vec2>>& outPolygons, bool flipHorizontally, bool flipVertically) { // Check image is valid if (!image.isValid2DImage()) { LOG_ERROR << "The passed image is not a valid 2D image: " << image; return false; } auto bitmap = Bitmap(image.getWidth(), image.getHeight()); // Setup bitmap contents auto width = int(image.getWidth()); for (auto i = 0U; i < bitmap.data.size(); i++) bitmap.set(i % width, i / width, image.getPixelColor(i % width, i / width).a > 0.5f); // Find all the edge pixels auto edgePixels = Vector<PolygonVertex>(); for (auto y = 0; y < bitmap.height; y++) { for (auto x = 0; x < bitmap.width; x++) { if (bitmap.get(x, y) && (!bitmap.get(x - 1, y - 1) || !bitmap.get(x - 1, y) || !bitmap.get(x - 1, y + 1) || !bitmap.get(x, y - 1) || !bitmap.get(x, y + 1) || !bitmap.get(x + 1, y - 1) || !bitmap.get(x + 1, y) || !bitmap.get(x + 1, y + 1))) edgePixels.emplace(x, y); } } while (!edgePixels.empty()) { // Start the next polygon at an unused edge pixel auto polygon = Vector<PolygonVertex>(1, edgePixels.popBack()); // Each pixel that is put onto polygon can be backtracked if it leads to a dead end, this fixes problems with // pointy angles that can cause the edge walking to get stuck. auto hasBacktracked = false; while (true) { // Continue building this polygon by finding the next adjacent edge pixel auto adjacentPixel = 0U; for (; adjacentPixel < edgePixels.size(); adjacentPixel++) { if (bitmap.isAdjacent(polygon.back(), edgePixels[adjacentPixel])) break; } // If there was no adjacent edge pixel then this polygon is malformed, so skip it and keep trying to build // more if (adjacentPixel == edgePixels.size()) { if (!hasBacktracked) { polygon.popBack(); hasBacktracked = true; if (polygon.empty()) break; continue; } else break; } // Add the adjacent edge pixel to this polygon polygon.append(edgePixels[adjacentPixel]); edgePixels.erase(adjacentPixel); hasBacktracked = false; // Check whether this polygon is now complete, at least 4 points are required for a valid polygon if (polygon.size() < 4 || !bitmap.isAdjacent(polygon[0], polygon.back())) continue; // Now that a complete polygon has been constructed it needs to be simplified down as much as possible while // retaining key features such as large straight edges and right angles // Simplify perfectly horizontal and vertical edges as much as possible for (auto i = 0; i < int(polygon.size()); i++) { const auto& a = polygon[i]; const auto& b = polygon[(i + 1) % polygon.size()]; const auto& c = polygon[(i + 2) % polygon.size()]; if ((a.x == b.x && a.x == c.x) || (a.y == b.y && a.y == c.y)) polygon.erase((i-- + 1) % polygon.size()); } // Identify horizontal and vertical edges that are on the outside edge of the bitmap and mark their vertices // as important for (auto i = 0U; i < polygon.size(); i++) { auto& a = polygon[i]; auto& b = polygon[(i + 1) % polygon.size()]; if ((a.x == 0 || a.x == int(image.getWidth() - 1) || a.y == 0 || a.y == int(image.getHeight() - 1)) && a.isAxialEdge(b)) { a.keep = true; b.keep = true; } } // Identify axial right angles and flag the relevant vertices as important for (auto i = 0U; i < polygon.size(); i++) { const auto& a = polygon[i]; const auto& c = polygon[(i + 2) % polygon.size()]; auto& b = polygon[(i + 1) % polygon.size()]; if (a.isAxialEdge(b) && b.isAxialEdge(c) && (a - b).isRightAngle(c - b)) b.keep = true; } // The ends of straight edges that are not part of a right angle shape are pulled inwards by inserting new // vertices one pixel apart, this allows the ends of straight edges to undergo subsequent simplification. // The 'body' of the straight edge is then flagged as important to avoid any further simplification, which // will preserve the straight edge in the final result. const auto straightEdgePullBackSize = straightEdgeLength / 3; for (auto i = 0U; i < polygon.size(); i++) { auto a = polygon[i]; auto b = polygon[(i + 1) % polygon.size()]; if (a.isAxialEdge(b)) { auto xSign = Math::getSign(b.x - a.x); auto ySign = Math::getSign(b.y - a.y); if (!a.keep) { for (auto j = 0U; j < straightEdgePullBackSize; j++) polygon.insert(i++, PolygonVertex(a.x + xSign * (j + 1), a.y + (j + 1) * ySign)); polygon[i].keep = true; } if (!b.keep) { for (auto j = 0U; j < straightEdgePullBackSize; j++) { polygon.insert(i++, PolygonVertex(b.x - (straightEdgePullBackSize - j) * xSign, b.y - (straightEdgePullBackSize - j) * ySign)); } polygon[i - straightEdgePullBackSize + 1].keep = true; } } } // This is the main simplification loop, it works by trying to do progressively larger and larger // simplifcations on the polygon auto simplificationThreshold = 1.5f; while (polygon.size() > 3) { for (auto i = 0U; i < polygon.size(); i++) { const auto& a = polygon[i]; const auto& b = polygon[(i + 1) % polygon.size()]; const auto& c = polygon[(i + 2) % polygon.size()]; // If b is important then don't try to get rid of it if (b.keep) continue; // Get rid of point b if the line a-c is connected by an edge in the bitmap if (a.distance(c) < simplificationThreshold && bitmap.arePixelsConnectedByEdge(a, c)) polygon.erase((i + 1) % polygon.size()); } simplificationThreshold += 1.0f; if (simplificationThreshold >= std::max(image.getWidth(), image.getHeight())) break; } if (polygon.size() < 3) break; outPolygons.enlarge(1); auto& outPolygon = outPolygons.back(); // Scale to the range 0-1 for (const auto& vertex : polygon) outPolygon.append(vertex.toVec2() / Vec2(float(image.getWidth() - 1), float(image.getHeight() - 1))); // Apply horizontal and vertical flips if requested if (flipHorizontally) { for (auto& vertex : outPolygon) vertex.setXY(1.0f - vertex.x, vertex.y); } if (flipVertically) { for (auto& vertex : outPolygon) vertex.setXY(vertex.x, 1.0f - vertex.y); } // Order vertices clockwise auto center = outPolygon.getAverage(); if ((Vec3(outPolygon[0]) - center).cross(Vec3(outPolygon[1]) - center).z > 0.0f) outPolygon.reverse(); break; } } return !outPolygons.empty(); }
//This function returns an array of LocationID that represent all locations that are connected //to the given LocationID. //road, rail and sea are connections should only be considered if the road, rail, sea parameters //are TRUE. //The size of the array should be stored in the variable pointed to by numLocations //The array can be in any order but must contain unique entries //Your function must take into account the round and player id for rail travel //Your function must take into account that dracula can't move to the hospital or travel by rail //but need not take into account draculas trail //The destination 'from' should be included. LocationID * connectedLocations(HunterView currentView, int * numLocations, LocationID from, PlayerID player, Round round, int road, int rail, int sea) { //this should come from graph file. //this function alters the value pointed to be the pointer numLocations assert(road == FALSE || road == TRUE); assert(rail == FALSE || rail == TRUE); assert(sea == FALSE || sea == TRUE); //conditions that need to be considered LocationID to_search = NUM_MAP_LOCATIONS; int moves_allowed = round % 4; if (!moves_allowed) rail = FALSE; if (player == PLAYER_DRACULA) rail = FALSE; if (!sea) to_search = ZURICH + 1; //Zurich is the last city Graph g = newGraph(); //our graph to check int i; *numLocations = 0; LocationID *connected;//[NUM_MAP_LOCATIONS]; connected = malloc(sizeof(LocationID)*NUM_MAP_LOCATIONS); int locationsFound[NUM_MAP_LOCATIONS]; //using this later for (i = 0; i < NUM_MAP_LOCATIONS; i++) { connected[i] = -1; locationsFound[i] = FALSE; } i = 0; int found; while (i < to_search) { found = FALSE; if (road) { //don't need to check for duplicates here, all connections will be uninitialized if (isAdjacent(g,from, i, ROAD)) { connected[*numLocations] = i; (*numLocations)++; found = TRUE; } } if ((sea)&&(!found)) { if (isAdjacent(g,from, i, SEA)) { connected[*numLocations] = i; (*numLocations)++; found = TRUE; } } if (found) locationsFound[i] = TRUE; i++; } if (rail) { //now we consider being able to move further by train //only do the check for the further cities if the condition of mod 4 is met //check places within two moves LocationID connected_by_rail[NUM_MAP_LOCATIONS]; for (i = 0; i < NUM_MAP_LOCATIONS; i++) connected_by_rail[i] = FALSE; canReachInN(g, from, RAIL, moves_allowed, connected_by_rail); int j = 0; while (j < NUM_MAP_LOCATIONS) { if (!locationsFound[j]) { if (connected_by_rail[j]) { connected[*numLocations] = j; (*numLocations)++; locationsFound[j] = TRUE; } } j++; } } if (!locationsFound[from]) { connected[*numLocations] = from; (*numLocations)++; } return connected; }
// Re-define attack to account for the Vengeance skill int ServantAvenger::attack(vector<Servant *> defenders, bool counter) { if (actionMPCosts[ascension][0] > currMP) return 1; // Not enough MP to attack else { subMP(actionMPCosts[ascension][0]); for (unsigned int i = 0; i < defenders.size(); i++) { int dam = 0; // Check if you hit the targets vector<int> opEvade = defenders[i]->getEvade(); bool hit = false; // Calculate accuracy int accuracy = capZero(getHitRate() - opEvade[0]); int r = getRandNum(); if (accuracy >= r) hit = true; if (opEvade.size() > 1 && hit) { for (unsigned int j = 1; j < opEvade.size() && hit; j++) { r = getRandNum(); if (opEvade[j] >= r) hit = false; } } // If you hit, calculate crit chance // Also check if Skill: Vengeance activates if (hit) { int attackMult = 1; int critChance = capZero(getCriticalRate() - defenders[i]->getCriticalEvade()); r = getRandNum(); if (critChance >= r) attackMult *= 3; // Check for Vengeance int addVengeance = 0; r = getRandNum(); if (getSkl() * 2 >= r) { addVengeance = (getMaxHP() - getCurrHP()) * 2; log->addToEventLog(getFullName() + " activated Vengeance!"); } // Deal the damage dam = (capZero(getStr() - defenders[i]->getDef()) + addVengeance) * attackMult; log->addToEventLog(getFullName() + " dealt " + to_string(dam) + " damage to " + defenders[i]->getFullName() + "."); defenders[i]->subHP(dam, D_STR); } else { log->addToEventLog(getFullName() + " missed " + defenders[i]->getFullName() + "!"); } // Check to see if the defender is dead. If they are, do not call // the counterattack. Additionally, if they are an Avenger and they // die, activate Final Revenge. // If they are not dead but they are a Berserker, check to see if // Mad Counter activates. if(defenders[i]->getCurrHP() > 0) { // Check if the defender is a Berserker. If they are, and they // are adjacent to this unit, check to see if Mad Counter // activates. if (defenders[i]->getClass() == Berserker && isAdjacent(defenders[i])) { r = getRandNum(); if (defenders[i]->getLuk() >= r) { // Mad Counter activated! The attacking servant takes // damage equal to the damage they dealt. log->addToEventLog(defenders[i]->getFullName() + "' Mad Counter activated, dealing " + to_string(dam) + " damage back to " + getFullName() + "."); subHP(dam, C_STR); } } // Call "attack" on the defending servant for their // counterattack, if you are in their range and you are the // initiating servant. if (defenders[i]->isInRange(this) && counter) { vector<Servant *> you; you.push_back(this); defenders[i]->attack(you, false); } } else { if (defenders[i]->getClass() == Avenger) { // Activate Final Revenge Debuff *finRev = defenders[i]->finalRevenge(); addDebuff(finRev); if (defenders[i]->getAscensionLvl() == 2) { subHP(.1 * getMaxHP(), OMNI); subMP(.1 * getMaxMP()); if (getCurrHP() == 0) { setHP(1); } } } } } } return 0; }