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