0% found this document useful (0 votes)
2 views49 pages

Ho Chi Minh City Programming Assignment

The document contains initial code for programming assignments related to a simulation of military units and battles, specifically for students at Ho Chi Minh City University of Technology. It includes header and implementation files defining classes for units, armies, terrain elements, and various functionalities for a campaign simulation. The code is structured to enforce the use of specific libraries and includes sample test cases demonstrating the functionality of the defined classes.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views49 pages

Ho Chi Minh City Programming Assignment

The document contains initial code for programming assignments related to a simulation of military units and battles, specifically for students at Ho Chi Minh City University of Technology. It includes header and implementation files defining classes for units, armies, terrain elements, and various functionalities for a campaign simulation. The code is structured to enforce the use of specific libraries and includes sample test cases demonstrating the functionality of the defined classes.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

MAIN.

H:

/*

* Ho Chi Minh City University of Technology

* Faculty of Computer Science and Engineering

* Initial code for Assignment 1

* Programming Fundamentals Spring 2025

* Date: 02.2025

*/

#ifndef _MAIN_2_H_

#define _MAIN_2_H_

#include <iostream>

#include <iomanip>

#include <cmath>

#include <cstring>

#include <climits>

#include <cassert>

#include <string>

#include <fstream>

#include <sstream>

#include <vector>

using namespace std;

//The library here is concretely set, students are not allowed to include any other libraries.
#endif //_MAIN_2_H_

[Link]:

/*

* Ho Chi Minh City University of Technology

* Faculty of Computer Science and Engineering

* Initial code for Assignment 2

* Programming Fundamentals Spring 2025

* Date: 02.02.2025

*/

//The library here is concretely set, students are not allowed to include any other libraries.

#include "hcmcampaign.h"

using namespace std;

void g_satc_01() {

cout << "----- Sample Testcase 01 -----" << endl;

Configuration* config = new Configuration("[Link]");

cout << config->str() << endl;

delete config;

void g_satc_02() {

cout << "----- Sample Testcase 02 -----" << endl;

Vehicle tankOfLiber(5, 2, Position(1, 2), TANK);


Vehicle truckOfLiber(3, 1, Position(2, 2), TRUCK);

Infantry sniperOfLiber(5, 2, Position(1, 1), SNIPER);

Vehicle tankOfAr(5, 2, Position(3, 2), TANK);

Vehicle truckOfAr(3, 1, Position(3, 1), TRUCK);

Infantry sniperOfAr(5, 2, Position(3, 3), SNIPER);

Unit** unitArrayOfLiber = new Unit*[3];

unitArrayOfLiber[0] = &tankOfLiber;

unitArrayOfLiber[1] = &truckOfLiber;

unitArrayOfLiber[2] = &sniperOfLiber;

Unit** unitArrayOfAr = new Unit*[3];

unitArrayOfAr[0] = &tankOfAr;

unitArrayOfAr[1] = &truckOfAr;

unitArrayOfAr[2] = &sniperOfAr;

LiberationArmy* liberationArmy = new LiberationArmy(unitArrayOfLiber, 3, "LiberationArmy",


0);

cout << liberationArmy->str() << endl;

ARVN* arvn = new ARVN(unitArrayOfAr, 3, "ARVN", 0);

cout << arvn->str() << endl;

Army* enemyLiber = arvn;

liberationArmy->fight(enemyLiber, false);

Army* enemyAr = liberationArmy;


arvn->fight(enemyAr, false);

cout << "* After the fight" << endl;

cout << liberationArmy->str() << endl;

cout << arvn->str() << endl;

delete liberationArmy;

delete arvn;

delete[] unitArrayOfLiber;

delete[] unitArrayOfAr;

int main(int argc, const char * argv[]) {

g_satc_01();

g_satc_02();

return 0;

HCMCAMPAIGN.H:

/*

* Ho Chi Minh City University of Technology

* Faculty of Computer Science and Engineering

* Initial code for Assignment 2

* Programming Fundamentals Spring 2025

* Date: 02.02.2025

*/
// The library here is concretely set, students are not allowed to include any other libraries.

#ifndef _H_HCM_CAMPAIGN_H_

#define _H_HCM_CAMPAIGN_H_

#include "main.h"

////////////////////////////////////////////////////////////////////////

/// STUDENT'S ANSWER BEGINS HERE

/// Complete the following functions

/// DO NOT modify any parameters in the functions.

////////////////////////////////////////////////////////////////////////

// Forward declaration

class Unit;

class UnitList;

class Army;

class TerrainElement;

class Vehicle;

class Infantry;

class LiberationArmy;

class ARVN;

class Position;
class Road;

class Mountain;

class River;

class Urban;

class Fortification;

class SpecialZone;

class BattleField;

class HCMCampaign;

class Configuration;

enum VehicleType

TRUCK,

MORTAR,

ANTIAIRCRAFT,

ARMOREDCAR,

APC,

ARTILLERY,

TANK

};

enum InfantryType

SNIPER,

ANTIAIRCRAFTSQUAD,
MORTARSQUAD,

ENGINEER,

SPECIALFORCES,

REGULARINFANTRY

};

namespace Helper {

void arrayInput(std::vector<Position*>& input_vector, std::string input);

std::string str_format(const std::string& input);

std::string vehicleTypeToString(VehicleType type);

std::string infantryTypeToString(InfantryType type);

bool isPerfectSquareNumber(int num);

int personalNumber(int num, int year = 0);

bool isSpecialNumber(int num, int base);

int fibonacci(int num);

int to_nearest_fibonacci(int num);

int distance(::Position, ::Position);

void clearUnits(Unit**& unitArray, int size);

void clearVector(std::vector<Position*>& arr);

std::string pos_vec_to_str(const std::vector<Position*>& vec);

void generateSubsets(const vector<Unit*>& units, vector<vector<Unit*>>& subsets);

class Position

{
private:

int r, c;

public:

Position(int r = 0, int c = 0);

Position(const string& str_pos); // Example: str_pos = "(1,15)"

int getRow() const;

int getCol() const;

void setRow(int r);

void setCol(int c);

string str() const; // Example: returns "(1,15)"

friend double distance(Position a, Position b);

};

class Unit

protected:

int quantity, weight;

Position pos;

int attackScore;

public:

Unit(int quantity, int weight, Position pos);

virtual ~Unit();

virtual int getAttackScore() = 0;


Position getCurrentPosition() const;

int getQuantity();

int getWeight();

void setQuantity(double num);

void setWeight(double num);

virtual string str() const = 0;

int getScore() const;

void setScore(double);

};

class Vehicle : public Unit

private:

VehicleType vehicleType;

public:

Vehicle(int quantity, int weight, Position pos, VehicleType vehicleType);

VehicleType getType();

int getAttackScore() override;

string str() const override;

};

class Infantry : public Unit

private:

InfantryType infantryType;

public:

Infantry(int quantity, int weight, Position pos, InfantryType infantryType);

int getAttackScore() override;


InfantryType getType();

string str() const override;

};

class UnitList {

private:

int capacity{};

bool p_insert(Unit* unit);

public:

struct UnitInstance {

Unit* unit{ nullptr };

UnitInstance* next{ nullptr };

UnitInstance(Unit* d, UnitInstance* n) : unit(d), next(n) {}

};

UnitInstance* head{ nullptr };

UnitInstance* tail{ nullptr };

UnitList(Unit** unitArray, int size);

bool insert(Unit* unit);

bool remove(UnitInstance* unit_instance);

UnitInstance* findInstance(VehicleType vehicleType);

UnitInstance* findInstance(InfantryType infantryType);

bool isContain(VehicleType vehicleType);

bool isContain(InfantryType infantryType);


int findS();

std::string str();

template <typename Func>

void loop(Func func);

friend class Army;

};

class Army {

protected:

int LF{};

int EXP{};

string name{};

UnitList* unitList{};

BattleField* battleField{};

public:

Army(Unit** unitArray, int size, string name, BattleField* battleField);

virtual void fight(Army* enemy, bool defense = false) = 0;

virtual std::string str() const = 0;

void calculateCombatIndex();

int getLF();

int getEXP();

void setLF(int num);


void setEXP(int num);

template<typename T> void loop(T func);

void updateUnits();

friend class LiberationArmy;

friend class ARVN;

};

class LiberationArmy : public Army {

public:

LiberationArmy(Unit** unitArray, int size, std::string name, BattleField* battleField);

void fight(Army* enemy, bool defense = false) override;

bool findMinInfantryComboGreaterThan(int target, vector<Unit*>& result);

bool findMinVehicleComboGreaterThan(int target, vector<Unit*>& result);

std::string str() const override;

};

class ARVN : public Army {

public:

ARVN(Unit** unitArray, int size, std::string name, BattleField* battleField);

void fight(Army* enemy, bool defense = false) override;

std::string str() const override;

};

class TerrainElement {
protected:

Position position{};

public:

TerrainElement(Position position) : position(position) {}

virtual void getEffect(Army* army) = 0;

};

class Road : public TerrainElement {

public:

Road(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class ForestedMountain : public TerrainElement {

public:

ForestedMountain(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class DeepRiver : public TerrainElement {

public:

DeepRiver(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class UrbanArea : public TerrainElement {


public:

UrbanArea(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class Fortification : public TerrainElement {

public:

Fortification(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class DemilitarizedZone : public TerrainElement {

public:

DemilitarizedZone(Position pos) : TerrainElement(pos) {}

void getEffect(Army* army) override;

};

class BattleField {

private:

int n_rows{};

int n_cols{};

TerrainElement*** terrain{};

public:
BattleField(int n_rows, int n_cols, std::vector<Position*> arrayForest,
std::vector<Position*> arrayRiver,

std::vector<Position*> arrayFortification, std::vector<Position*> arrayUrban,

std::vector<Position*> arraySpecialZone);

~BattleField();

std::string str() const;

void getEffect(Army* army);

};

class Configuration {

private:

int num_rows, num_cols;

std::vector<Position*> arrayForest, arrayRiver, arrayFortification, arrayUrban,


arraySpecialZone;

Unit** liberationUnits, ** ARVNUnits;

int lib_size, arvn_size;

int eventCode;

public:

Configuration(const std::string& filepath);

~Configuration();

std::string str();

friend class HCMCampaign;

};

class HCMCampaign {

private:
Configuration* config{};

BattleField* battleField{};

LiberationArmy* liberationArmy{};

ARVN* arvn{};

bool libOffense{};

int eventCode{};

public:

HCMCampaign(const std::string& filepath);

void run();

std::string printResult();

};

#endif

[Link]:

#include "hcmcampaign.h"

////////////////////////////////////////////////////////////////////////

/// STUDENT'S ANSWER BEGINS HERE

////////////////////////////////////////////////////////////////////////

namespace Helper {

void arrayInput(std::vector<Position*>& input_vector, std::string input) {

std::stringstream input_stream(input);

std::string content;

input_stream.ignore(); // Ignore preceding '['


while (std::getline(input_stream, content, ')')) {

content += ')';

input_vector.push_back(new Position(content));

input_stream.ignore(); // Ignore following comma

std::string str_format(const std::string& input) {

std::string result{};

for (char c : input) {

if (c != ' ') result += std::toupper(c);

return result;

std::string vehicleTypeToString(VehicleType type) {

switch (type) {

case TRUCK: return "TRUCK";

case MORTAR: return "MORTAR";

case ANTIAIRCRAFT: return "ANTIAIRCRAFT";

case ARMOREDCAR: return "ARMOREDCAR";

case APC: return "APC";

case ARTILLERY: return "ARTILLERY";

case TANK: return "TANK";

default: return "UNKNOWN";

}
}

std::string infantryTypeToString(InfantryType type) {

switch (type) {

case SNIPER: return "SNIPER";

case ANTIAIRCRAFTSQUAD: return "ANTIAIRCRAFTSQUAD";

case MORTARSQUAD: return "MORTARSQUAD";

case ENGINEER: return "ENGINEER";

case SPECIALFORCES: return "SPECIALFORCES";

case REGULARINFANTRY: return "REGULARINFANTRY";

default: return "UNKNOWN";

bool isPerfectSquareNumber(int num) {

if (num < 0) return false;

for (int i = 0; i * i <= num; i++) {

if (i * i == num) return true;

return false;

int personalNumber(int num, int year) {

int sum{ 0 };

for (; num > 0; num /= 10) {

sum += num % 10;


}

for (; year > 0; year /= 10) {

sum += year % 10;

return (sum < 10 ? sum : personalNumber(sum));

bool isSpecialNumber(int num, int base) {

if (num == 0) return false;

int power{ 1 };

while (power <= num) {

power *= base;

for (; power > 0; power /= base) {

if (num >= power) num -= power;

return num == 0;

int fibonacci(int num) {

static std::vector<int> fibonacci_list{ 0, 1 };

while (fibonacci_list.size() <= num) {

fibonacci_list.push_back(fibonacci_list.back() +
fibonacci_list[fibonacci_list.size() - 2]);

return fibonacci_list[num];
}

int to_nearest_fibonacci(int num) {

int index{ 0 };

while (fibonacci(index) < num) index++;

return fibonacci(index);

int distance(Position a, Position b) {

return ceil(std::sqrt(std::pow([Link]() - [Link](), 2) +

std::pow([Link]() - [Link](), 2)));

void clearUnits(Unit**& unitArray, int size) {

if (unitArray) {

for (int i = 0; i < size; i++) {

delete unitArray[i];

delete[] unitArray;

unitArray = nullptr;

void clearVector(std::vector<Position*>& arr) {

for (Position* pos : arr) {

delete pos;
}

[Link]();

string pos_vec_to_str(const std::vector<Position*>& vec) {

if ([Link]()) return "[]"; // Handle empty case

std::string result = "[";

for (size_t i = 0; i < [Link](); i++) {

result += vec[i]->str();

if (i < [Link]() - 1) result += ","; // Avoid trailing comma

result += "]";

return result;

void generateSubsets(const vector<Unit*>& units, vector<vector<Unit*>>& subsets) {

int n = [Link]();

int total = 1 << n;

for (int mask = 1; mask < total; ++mask) {

vector<Unit*> subset;

for (int i = 0; i < n; ++i) {

if (mask & (1 << i)) subset.push_back(units[i]);

subsets.push_back(subset);

}
int sumAttackScore(const vector<Unit*>& units) {

int sum = 0;

for (const Unit* unit : units) {

sum += unit->getScore();

return sum;

Position::Position(int r, int c) : r(r), c(c) {}

Position::Position(const std::string& str_pos) {

std::stringstream input(str_pos);

char sep{};

input >> sep >> r >> sep >> c;

int Position::getRow() const { return r; }

int Position::getCol() const { return c; }

void Position::setRow(int r) { this->r = r; }

void Position::setCol(int c) { this->c = c; }

std::string Position::str() const {


return '(' + std::to_string(r) + ',' + std::to_string(c) + ')';

double distance(Position a, Position b) {

return std::sqrt(std::pow(a.r - b.r, 2) + std::pow(a.c - b.c, 2));

Unit::Unit(int quantity, int weight, Position pos)

: quantity(quantity), weight(weight), pos(pos) {

Unit::~Unit() {}

Position Unit::getCurrentPosition() const { return pos; }

int Unit::getQuantity() { return quantity; }

int Unit::getWeight() { return weight; }

void Unit::setQuantity(double num) { quantity = std::ceil(num); }

void Unit::setWeight(double num) { weight = std::ceil(num); }

int Unit::getScore() const { return attackScore; }

void Unit::setScore(double num) { attackScore = std::ceil(num); }

Vehicle::Vehicle(int quantity, int weight, const Position pos, VehicleType vehicleType)

: Unit(quantity, weight, Position(pos)), vehicleType(vehicleType) {

attackScore = getAttackScore();
}

VehicleType Vehicle::getType() {

return vehicleType;

int Vehicle::getAttackScore() {

double result{ (vehicleType * 304 + quantity * weight) / 30.0 };

return std::ceil(result);

string Vehicle::str() const {

return "Vehicle[vehicleType=" + Helper::vehicleTypeToString(vehicleType) +

",quantity=" + std::to_string(quantity) + ",weight=" +

std::to_string(weight) + ",position=" + [Link]() + "]";

Infantry::Infantry(int quantity, int weight, const Position pos, InfantryType infantryType)

: Unit(quantity, weight, Position(pos)), infantryType(infantryType) {

attackScore = getAttackScore();

InfantryType Infantry::getType() { return infantryType; }


int Infantry::getAttackScore() {

double result{ static_cast<double>(infantryType * 56 + quantity * weight) };

int personal_num = Helper::personalNumber(result, 1975);

if (infantryType == SPECIALFORCES && Helper::isPerfectSquareNumber(weight)) result


+= 75;

if (personal_num > 7) quantity = std::ceil(quantity * 1.2);

else if (personal_num < 3) quantity = std::ceil(quantity * 0.9);

result = infantryType * 56 + quantity * weight;

return std::ceil(result);

std::string Infantry::str() const {

return "Infantry[infantryType=" + Helper::infantryTypeToString(infantryType) +

",quantity=" + std::to_string(quantity) + ",weight=" +

std::to_string(weight) + ",position=" + [Link]() + "]";

UnitList::UnitList(Unit** unitArray, int size) {

for (int i = 0; i < size; i++) {

insert(const_cast<Unit*>(unitArray[i]));

int S{ findS() };

capacity = (Helper::isSpecialNumber(S, 3) || Helper::isSpecialNumber(S, 5) ||


Helper::isSpecialNumber(S, 7)) ? 12 : 8;

}
bool UnitList::p_insert(Unit* unit) {

if (!unit || !capacity) return false;

if (!head) {

head = new UnitInstance( unit, nullptr );

tail = head;

return true;

if (Vehicle* vehicle = dynamic_cast<Vehicle*>(unit)) {

if (isContain(vehicle->getType())) {

findInstance(vehicle->getType())->unit->setQuantity(findInstance(vehicle-
>getType())->unit->getQuantity() + vehicle->getQuantity());

return true;

tail->next = new UnitInstance( unit, nullptr );

tail = tail->next;

return true;

else if (Infantry* infantry = dynamic_cast<Infantry*>(unit)) {

if (isContain(infantry->getType())) {

findInstance(infantry->getType())->unit-
>setQuantity(findInstance(infantry->getType())->unit->getQuantity() + infantry->getQuantity());

return true;

head = new UnitInstance( unit, head );

return true;
}

return false;

bool UnitList::insert(Unit* unit) {

if (p_insert(unit)) {

capacity--;

return true;

return false;

bool UnitList::remove(UnitInstance* unit_instance) {

if (!unit_instance) return false;

unit_instance->next = nullptr;

if (unit_instance == head) {

head = head->next;

return true;

bool result{ false };

loop([&result, unit_instance, this](UnitInstance* current) {

if (current->next == unit_instance) {

current->next = unit_instance->next;

if (unit_instance == tail) tail = current;


result = true;

});

return result;

UnitList::UnitInstance* UnitList::findInstance(VehicleType vehicleType) {

UnitInstance* result{ nullptr };

loop([&result, vehicleType](UnitInstance* unit_instance) {

if (unit_instance->unit->str()[0] == 'V') {

if (dynamic_cast<Vehicle*>(unit_instance->unit)->getType() ==
vehicleType)

result = unit_instance;

});

return result;

UnitList::UnitInstance* UnitList::findInstance(InfantryType infantryType) {

UnitInstance* result{ nullptr };

loop([&result, infantryType](UnitInstance* unit_instance) {

if (unit_instance->unit->str()[0] == 'I') {

if (dynamic_cast<Infantry*>(unit_instance->unit)->getType() ==
infantryType)

result = unit_instance;

});
return result;

bool UnitList::isContain(VehicleType vehicleType) { return findInstance(vehicleType); }

bool UnitList::isContain(InfantryType infantryType) { return findInstance(infantryType); }

int UnitList::findS() {

int sum{ 0 };

loop([&sum](UnitInstance* unit_instance) { sum += unit_instance->unit->getScore(); });

return sum;

std::string UnitList::str() {

cout << 'u';

int vehicle_count{ 0 };

int infantry_count{ 0 };

std::string sub_output{};

loop([&vehicle_count, &infantry_count, &sub_output](UnitInstance* unit_instance) {

switch (unit_instance->unit->str()[0]) {

case 'V': vehicle_count++; break;

case 'I': infantry_count++; break;

sub_output += unit_instance->unit->str();

if (unit_instance->next) sub_output += ',';

});
return "UnitList[count_vehicle=" + std::to_string(vehicle_count) + ";count_infantry="

+ std::to_string(infantry_count) + ';' + sub_output + ']';

template <typename Func>

void UnitList::loop(Func func) {

UnitInstance* unit_instance{ head };

while (unit_instance) {

func(unit_instance);

unit_instance = unit_instance->next;

Army::Army(Unit** unitArray, int size, std::string name, BattleField* battleField)

: unitList(new UnitList(unitArray, size)), name(std::move(name)), battleField(battleField) {

calculateCombatIndex();

void Army::calculateCombatIndex() {

int vehicle_sum{ 0 };

int infantry_sum{ 0 };

unitList->loop([&vehicle_sum, &infantry_sum](UnitList::UnitInstance* unit_instance) {


switch (unit_instance->unit->str()[0]) {

case 'V': vehicle_sum += unit_instance->unit->getScore(); break;

case 'I': infantry_sum += unit_instance->unit->getScore(); break;

});

setLF(vehicle_sum);

setEXP(infantry_sum);

int Army::getLF() { return LF; }

int Army::getEXP() { return EXP; }

void Army::setLF(int num) { LF = std::min(std::max(num, 0), 1000); }

void Army::setEXP(int num) { EXP = std::min(std::max(num, 0), 500); }

template<typename T>

void Army::loop(T func) { unitList->loop(func); }

void Army::updateUnits() {

loop([this](UnitList::UnitInstance* unit_ins) {

if (unit_ins->unit->getScore() <= 5) unitList->remove(unit_ins);

});

calculateCombatIndex();

}
LiberationArmy::LiberationArmy(Unit** unitArray, int size, std::string name, BattleField*
battleField)

: Army(unitArray, size, std::move(name), battleField) {

void LiberationArmy::fight(Army* enemy, bool defense) {

if (!defense) {

setLF(getLF() * 1.5);

setEXP(getEXP() * 1.5);

vector<Unit*> infantryCombo, vehicleCombo;

bool infSuccess = findMinInfantryComboGreaterThan(enemy->EXP,


infantryCombo);

bool vehSuccess = findMinVehicleComboGreaterThan(enemy->LF,


vehicleCombo);

if ((!infSuccess && EXP <= enemy->getLF()) || (!vehSuccess && EXP <= enemy-
>getEXP())) {

loop([this](UnitList::UnitInstance* unit_instance) {

unit_instance->unit->setWeight(unit_instance->unit->getWeight()
* 0.9);

});

else {

for (Unit* unit : infantryCombo) {

unitList->remove(unitList-
>findInstance(dynamic_cast<Infantry*>(unit)->getType()));
}

for (Unit* unit : vehicleCombo) {

unitList->remove(unitList-
>findInstance(dynamic_cast<Vehicle*>(unit)->getType()));

while (unitList->insert(enemy->unitList->head->unit)) {

enemy->unitList->remove(enemy->unitList->head);

else {

setLF(getLF() * 1.3);

setEXP(getEXP() * 1.3);

while (!(LF > enemy->getLF() || EXP > enemy->getEXP())) {

unitList->loop([](UnitList::UnitInstance* unit_instance) {

unit_instance->unit-
>setQuantity(Helper::to_nearest_fibonacci(unit_instance->unit->getQuantity()));

});

calculateCombatIndex();

if ((LF > enemy->getLF()) != (EXP > enemy->getEXP())) {

unitList->loop([](UnitList::UnitInstance* unit_instance) {

unit_instance->unit->setQuantity(unit_instance->unit-
>getQuantity() * 0.9);

});

else {
while (unitList->insert(enemy->unitList->head->unit)) {

enemy->unitList->remove(enemy->unitList->head);

calculateCombatIndex();

bool LiberationArmy::findMinInfantryComboGreaterThan(int target, vector<Unit*>& result){

using namespace Helper;

vector<Unit*> allInfantry;

loop([&allInfantry](UnitList::UnitInstance* u) {

if (dynamic_cast<Infantry*>(u->unit)) {

allInfantry.push_back(u->unit);

});

vector<vector<Unit*>> subsets;

generateSubsets(allInfantry, subsets);

int minSum = INT_MAX;

for (auto& subset : subsets) {

int sum = sumAttackScore(subset);

if (sum > target && sum < minSum) {

minSum = sum;

result = subset;
}

if ([Link]()) {

result = allInfantry;

return false;

return true;

bool LiberationArmy::findMinVehicleComboGreaterThan(int target, vector<Unit*>& result) {

using namespace Helper;

vector<Unit*> allVehicles;

loop([&allVehicles](UnitList::UnitInstance* u) {

if (dynamic_cast<Vehicle*>(u->unit)) {

allVehicles.push_back(u->unit);

});

vector<vector<Unit*>> subsets;

generateSubsets(allVehicles, subsets);

int minSum = INT_MAX;

for (auto& subset : subsets) {

int sum = sumAttackScore(subset);

if (sum > target && sum < minSum) {


minSum = sum;

result = subset;

if ([Link]()) {

result = allVehicles;

return false;

return true;

std::string LiberationArmy::str() const {

cout << 'l';

return "LiberationArmy[name=" + name + ",LF=" + std::to_string(LF) +

",EXP=" + std::to_string(EXP) + ",unitList=" + unitList->str() +

",battleField=" + battleField->str() + "]";

ARVN::ARVN(Unit** unitArray, int size, std::string name, BattleField* battleField)

: Army(unitArray, size, std::move(name), battleField) {

void ARVN::fight(Army* enemy, bool defense) {

if (!defense) {
unitList->loop([this](UnitList::UnitInstance* unit_instance) {

if (unit_instance->unit->getQuantity() == 1) unitList-
>remove(unit_instance);

else unit_instance->unit->setQuantity(unit_instance->unit->getQuantity()
* 0.8);

});

calculateCombatIndex();

else {

if (dynamic_cast<LiberationArmy*>(enemy) && enemy->getLF() > getLF()) {

unitList->loop([this](UnitList::UnitInstance* unit_instance) {

unitList->remove(unit_instance);

});

std::string ARVN::str() const {

cout << 'a';

return "ARVN[name=" + name + ",LF=" + std::to_string(LF) +

",EXP=" + std::to_string(EXP) + ",unitList=" + unitList->str() +

",battleField=" + battleField->str() + "]";

void Road::getEffect(Army* army) {


return;

void ForestedMountain::getEffect(Army* army) {

int areaEffect{}; double EXPmod{}; double LFmod{};

if (dynamic_cast<LiberationArmy*>(army)) {

areaEffect = 2; EXPmod = 0.3; LFmod = 0.1;

else if (dynamic_cast<ARVN*>(army)) {

areaEffect = 4; EXPmod = 0.2; LFmod = 0.05;

else return;

army->loop([this, army, areaEffect, EXPmod, LFmod](UnitList::UnitInstance*


unit_instance) {

if (Helper::distance(position, unit_instance->unit->getCurrentPosition()) <=


areaEffect) {

if (unit_instance->unit->str()[0] == 'I')

army->setEXP(army->getEXP() + EXPmod * unit_instance->unit-


>getScore());

else if (unit_instance->unit->str()[0] == 'V')

army->setLF(army->getLF() - LFmod * unit_instance->unit-


>getScore());

});

}
void DeepRiver::getEffect(Army* army) {

army->loop([this](UnitList::UnitInstance* unit_instance) {

if (Helper::distance(position, unit_instance->unit->getCurrentPosition()) <= 2) {

if (unit_instance->unit->str()[0] == 'I')

unit_instance->unit->setScore(unit_instance->unit->getScore() *
0.9);

});

void UrbanArea::getEffect(Army* army) {

bool liberationArmy{ dynamic_cast<LiberationArmy*>(army) != nullptr};

army->loop([this, army, liberationArmy](UnitList::UnitInstance* unit_instance) {

int as{ unit_instance->unit->getScore() };

double pos_distance{ static_cast<double>(Helper::distance(position,


unit_instance->unit->getCurrentPosition())) };

double attackScoreIncrease{ (liberationArmy ? 2 : 3 / 2) * as / pos_distance };

int areaEffect{ liberationArmy ? 5 : 3 };

if (Infantry* infantry = dynamic_cast<Infantry*>(unit_instance->unit)) {

if (pos_distance <= areaEffect && (infantry->getType() ==


REGULARINFANTRY ||

(liberationArmy ? infantry->getType() == SPECIALFORCES : false)))

infantry->setScore(infantry->getScore() + attackScoreIncrease);

return;

if (!liberationArmy) return;
Vehicle* vehicle{ dynamic_cast<Vehicle*>(unit_instance->unit) };

if (vehicle->getType() == ARTILLERY && pos_distance <= 2)

vehicle->setScore(vehicle->getScore() * 0.5);

});

void Fortification::getEffect(Army* army) {

bool liberationArmy{ dynamic_cast<LiberationArmy*>(army) != nullptr };

army->loop([this, liberationArmy](UnitList::UnitInstance* unit_instance) {

if (Helper::distance(position, unit_instance->unit->getCurrentPosition()) <= 2) {

unit_instance->unit->setScore(unit_instance->unit->getScore() *
(liberationArmy ? 0.8 : 1.2));

});

void DemilitarizedZone::getEffect(Army* army) {

army->loop([this](UnitList::UnitInstance* unit_instance) {

if (Helper::distance(position, unit_instance->unit->getCurrentPosition()) <= 1) {

unit_instance->unit->setScore(0);

});

BattleField::BattleField(int n_rows, int n_cols, std::vector<Position*> arrayForest,


std::vector<Position*> arrayRiver,
std::vector<Position*> arrayFortification, std::vector<Position*> arrayUrban,

std::vector<Position*> arraySpecialZone) {

this->n_rows = n_rows;

this->n_cols = n_cols;

cout << n_rows << n_cols;

terrain = new TerrainElement **[n_rows];

for (int i = 0; i < n_rows; i++) {

terrain[i] = new TerrainElement * [n_cols];

for (int x = 0; x < n_cols; x++) {

terrain[i][x] = new Road(Position(i, x));

for (Position* pos : arrayRiver) {

delete terrain[pos->getRow()][pos->getCol()];

terrain[pos->getRow()][pos->getCol()] = new DeepRiver(Position(pos->getRow(),


pos->getCol()));

for (Position* pos : arrayForest) {

delete terrain[pos->getRow()][pos->getCol()];

terrain[pos->getRow()][pos->getCol()] = new ForestedMountain(Position(pos-


>getRow(), pos->getCol()));

for (Position* pos : arrayFortification) {

delete terrain[pos->getRow()][pos->getCol()];
terrain[pos->getRow()][pos->getCol()] = new Fortification(Position(pos-
>getRow(), pos->getCol()));

for (Position* pos : arrayUrban) {

delete terrain[pos->getRow()][pos->getCol()];

terrain[pos->getRow()][pos->getCol()] = new UrbanArea(Position(pos->getRow(),


pos->getCol()));

for (Position* pos : arraySpecialZone) {

delete terrain[pos->getRow()][pos->getCol()];

terrain[pos->getRow()][pos->getCol()] = new DemilitarizedZone(Position(pos-


>getRow(), pos->getCol()));

BattleField::~BattleField() {

for (int i = 0; i < n_rows; i++) {

for (int x = 0; x < n_cols; x++) {

delete terrain[i][x];

delete[] terrain[i];

delete[] terrain;

}
std::string BattleField::str() const{

return "BattleField[n_rows=" + std::to_string(n_rows) +

",n_cols=" + std::to_string(n_cols) + "]";

void BattleField::getEffect(Army* army) {

for (int i = 0; i < n_rows; i++) {

for (int x = 0; x < n_cols; x++) {

terrain[i][x]->getEffect(army);

Configuration::Configuration(const std::string& filepath) {

std::ifstream inputfile(filepath);

std::string line;

if (!inputfile.is_open()) {

std::cerr << "Error opening file: " << filepath << std::endl;

return;

while (std::getline(inputfile, line)) {

std::stringstream linestream{ line };

std::string identifier, content;

std::getline(linestream, identifier, '=');

std::getline(linestream, content);
if (identifier == "NUM_ROWS") {

num_rows = std::stoi(content);

else if (identifier == "NUM_COLS") {

num_cols = std::stoi(content);

else if (identifier == "ARRAY_FOREST") {

Helper::arrayInput(arrayForest, content);

else if (identifier == "ARRAY_RIVER") {

Helper::arrayInput(arrayRiver, content);

else if (identifier == "ARRAY_FORTIFICATION") {

Helper::arrayInput(arrayFortification, content);

else if (identifier == "ARRAY_URBAN") {

Helper::arrayInput(arrayUrban, content);

else if (identifier == "ARRAY_SPECIAL_ZONE") {

Helper::arrayInput(arraySpecialZone, content);

else if (identifier == "EVENT_CODE") {

eventCode = std::max(std::stoi(content) % 100, 0);

else if (identifier == "UNIT_LIST") {

std::stringstream input_stream(content);
char sep; input_stream >> sep;

std::string pos_input, type;

int quantity, weight;

Unit* unit;

bool arvn;

std::vector<Unit*> liberation_units, arvn_units;

while (getline(input_stream, type, '(')) {

if ([Link]()) break;

input_stream >> quantity >> sep >> weight >> sep;

getline(input_stream, pos_input, ')');

pos_input += ')';

input_stream >> sep >> arvn >> sep >> sep;

for (int i = 0; i < 7; i++) {

if (i != 6 && Helper::str_format(type) ==
Helper::infantryTypeToString(InfantryType(i))) {

(arvn ? arvn_units : liberation_units).push_back(

new Infantry(quantity, weight,


Position(pos_input), InfantryType(i)));

else if (Helper::str_format(type) ==
Helper::vehicleTypeToString(VehicleType(i))) {

(arvn ? arvn_units : liberation_units).push_back(

new Vehicle(quantity, weight,


Position(pos_input), VehicleType(i)));

}
}

lib_size = liberation_units.size();

arvn_size = arvn_units.size();

liberationUnits = new Unit * [lib_size];

ARVNUnits = new Unit * [arvn_size];

for (int i = 0; i < lib_size; i++) {

liberationUnits[i] = liberation_units[i];

for (int i = 0; i < arvn_size; i++) {

ARVNUnits[i] = arvn_units[i];

Configuration::~Configuration() {

Helper::clearUnits(liberationUnits, lib_size);

Helper::clearUnits(ARVNUnits, arvn_size);

Helper::clearVector(arrayForest);

Helper::clearVector(arrayRiver);

Helper::clearVector(arrayFortification);

Helper::clearVector(arrayUrban);

Helper::clearVector(arraySpecialZone);

}
string Configuration::str() {

string result = "[num_rows=" + std::to_string(num_rows) +

",num_cols=" + std::to_string(num_cols) +

",arrayForest=" + Helper::pos_vec_to_str(arrayForest) +

",arrayRiver=" + Helper::pos_vec_to_str(arrayRiver) +

",arrayFortification=" + Helper::pos_vec_to_str(arrayFortification) +

",arrayUrban=" + Helper::pos_vec_to_str(arrayUrban) +

",arraySpecialZone=" + Helper::pos_vec_to_str(arraySpecialZone) +

",liberationUnits=[";

for (int i = 0; i < lib_size; i++) {

result += liberationUnits[i]->str();

if (i < lib_size - 1) result += ',';

result += "],ARVNUnits=[";

for (int i = 0; i < arvn_size; i++) {

result += ARVNUnits[i]->str();

if (i < arvn_size - 1) result += ',';

result += "],eventCode=" + std::to_string(eventCode) + "]";

return result;

HCMCampaign::HCMCampaign(const std::string& filepath) {

config = new Configuration(filepath);

battleField = new BattleField(config->num_rows, config->num_cols,


config->arrayForest, config->arrayRiver, config->arrayFortification,

config->arrayUrban, config->arraySpecialZone);

liberationArmy = new LiberationArmy(config->liberationUnits, config->lib_size,


"LIBERATION ARMY", battleField);

arvn = new ::ARVN(config->ARVNUnits, config->arvn_size, "ARVN", battleField);

libOffense = config->eventCode < 75;

liberationArmy->updateUnits();

arvn->updateUnits();

void HCMCampaign::run() {

battleField->getEffect(liberationArmy);

battleField->getEffect(arvn);

liberationArmy->fight(arvn, !libOffense);

arvn->fight(liberationArmy, libOffense);

std::string HCMCampaign::printResult() {

return "LIBERATIONARMY[LF=" + std::to_string(liberationArmy->getLF()) +

",EXP=" + std::to_string(liberationArmy->getEXP()) +

"]-ARVN[LF=" + std::to_string(arvn->getLF()) +

",EXP=" + std::to_string(arvn->getEXP()) + "]";

////////////////////////////////////////////////

/// END OF STUDENT'S ANSWER


////////////////////////////////////////////////

You might also like