Ejemplo n.º 1
0
//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");
    }

}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
      }
    }
  }
}
Ejemplo n.º 4
0
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);

}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 8
0
// 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);
}
Ejemplo n.º 9
0
/**
 * 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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
//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 << " ";
    }
}
Ejemplo n.º 13
0
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.");
    }
}
Ejemplo n.º 14
0
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.");
    }

}
Ejemplo n.º 15
0
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);
	}
}
Ejemplo n.º 16
0
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();
    }
} 
Ejemplo n.º 17
0
/***** 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;
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
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;
}
Ejemplo n.º 20
0
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;
}
Ejemplo n.º 21
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()
Ejemplo n.º 22
0
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();
}
Ejemplo n.º 23
0
//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;
}
Ejemplo n.º 24
0
// 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;
}