From 969ea4d21525520c11b167ecfdfb13064365bd03 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Thu, 7 Dec 2023 14:24:30 -0500 Subject: [PATCH 01/22] Added in-class examples. --- in_class/emscripten/Hello.cpp | 11 ++++ in_class/emscripten/build-drawSquare.sh | 1 + in_class/emscripten/build-factorial.sh | 1 + in_class/emscripten/drawSquare.cpp | 45 ++++++++++++++++ in_class/emscripten/drawSquare.html | 9 ++++ in_class/emscripten/factorial.cpp | 10 ++++ in_class/emscripten/factorial.html | 23 +++++++++ in_class/emscripten/power.cpp | 10 ++++ in_class/emscripten/power.html | 25 +++++++++ in_class/emscripten/start-server.sh | 1 + in_class/meta/meta.cpp | 67 ++++++++++++++++++++++++ in_class/meta/meta2.cpp | 68 +++++++++++++++++++++++++ in_class/other/adl.cpp | 22 ++++++++ in_class/other/crtp.cpp | 30 +++++++++++ in_class/other/downto.cpp | 9 ++++ in_class/other/multitype.cpp | 42 +++++++++++++++ in_class/other/template-template.cpp | 22 ++++++++ 17 files changed, 396 insertions(+) create mode 100644 in_class/emscripten/Hello.cpp create mode 100644 in_class/emscripten/build-drawSquare.sh create mode 100644 in_class/emscripten/build-factorial.sh create mode 100644 in_class/emscripten/drawSquare.cpp create mode 100644 in_class/emscripten/drawSquare.html create mode 100644 in_class/emscripten/factorial.cpp create mode 100644 in_class/emscripten/factorial.html create mode 100644 in_class/emscripten/power.cpp create mode 100644 in_class/emscripten/power.html create mode 100644 in_class/emscripten/start-server.sh create mode 100644 in_class/meta/meta.cpp create mode 100644 in_class/meta/meta2.cpp create mode 100644 in_class/other/adl.cpp create mode 100644 in_class/other/crtp.cpp create mode 100644 in_class/other/downto.cpp create mode 100644 in_class/other/multitype.cpp create mode 100644 in_class/other/template-template.cpp diff --git a/in_class/emscripten/Hello.cpp b/in_class/emscripten/Hello.cpp new file mode 100644 index 00000000..93700a2e --- /dev/null +++ b/in_class/emscripten/Hello.cpp @@ -0,0 +1,11 @@ +#include +#include + +int main() { + std::cout << "Hello World" << std::endl; + + std::string text; + std::cin >> text; + + std::cout << "You Entered: " << text << std::endl; +} diff --git a/in_class/emscripten/build-drawSquare.sh b/in_class/emscripten/build-drawSquare.sh new file mode 100644 index 00000000..caa64274 --- /dev/null +++ b/in_class/emscripten/build-drawSquare.sh @@ -0,0 +1 @@ +emcc drawSquare.cpp -o drawSquare.js -s "EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" diff --git a/in_class/emscripten/build-factorial.sh b/in_class/emscripten/build-factorial.sh new file mode 100644 index 00000000..1653cade --- /dev/null +++ b/in_class/emscripten/build-factorial.sh @@ -0,0 +1 @@ +emcc factorial.cpp -s WASM=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']" -o factorial.js diff --git a/in_class/emscripten/drawSquare.cpp b/in_class/emscripten/drawSquare.cpp new file mode 100644 index 00000000..1254bd73 --- /dev/null +++ b/in_class/emscripten/drawSquare.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +int X_pos=50, Y_pos=50; + +extern "C" { + // Function to be called from JavaScript + EMSCRIPTEN_KEEPALIVE + void drawSquare() { + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'red'; + ctx.fillRect($0, $1, 100, 100); // Draw a 100x100 red square + } + }, X_pos, Y_pos); + X_pos += 10; + Y_pos += 10; + } +} + +int main() { + // Use EM_ASM to inject HTML for the button + EM_ASM({ + var button = document.createElement('button'); + button.innerHTML = 'Draw Square'; + button.onclick = function() { + // Call the C++ function drawSquare() + _drawSquare(); + }; + document.body.appendChild(button); + + // Create a canvas element + var canvas = document.createElement('canvas'); + canvas.id = 'canvas'; + canvas.width = 300; + canvas.height = 300; + canvas.style.border = '1px solid black'; + document.body.appendChild(canvas); + }); + + return 0; +} diff --git a/in_class/emscripten/drawSquare.html b/in_class/emscripten/drawSquare.html new file mode 100644 index 00000000..61e223aa --- /dev/null +++ b/in_class/emscripten/drawSquare.html @@ -0,0 +1,9 @@ + + + + Draw Squares with Emscripten + + + + + diff --git a/in_class/emscripten/factorial.cpp b/in_class/emscripten/factorial.cpp new file mode 100644 index 00000000..95d0f90d --- /dev/null +++ b/in_class/emscripten/factorial.cpp @@ -0,0 +1,10 @@ +#include +#include + +extern "C" { + EMSCRIPTEN_KEEPALIVE + int factorial(int n) { + if (n == 0) return 1; + return n * factorial(n - 1); + } +} diff --git a/in_class/emscripten/factorial.html b/in_class/emscripten/factorial.html new file mode 100644 index 00000000..80ef6498 --- /dev/null +++ b/in_class/emscripten/factorial.html @@ -0,0 +1,23 @@ + + + + Factorial Calculator + + +

Factorial Calculator

+ Enter a number: + +
+ + + + + + + diff --git a/in_class/emscripten/power.cpp b/in_class/emscripten/power.cpp new file mode 100644 index 00000000..71220f0b --- /dev/null +++ b/in_class/emscripten/power.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +extern "C" { + EMSCRIPTEN_KEEPALIVE + double power(double base, double exponent) { + return std::pow(base, exponent); + } +} diff --git a/in_class/emscripten/power.html b/in_class/emscripten/power.html new file mode 100644 index 00000000..f87f4513 --- /dev/null +++ b/in_class/emscripten/power.html @@ -0,0 +1,25 @@ + + + + Power Calculator + + +

Power Calculator

+ Enter a base: + Enter an exponent: + +
+ + + + + + + diff --git a/in_class/emscripten/start-server.sh b/in_class/emscripten/start-server.sh new file mode 100644 index 00000000..846e5104 --- /dev/null +++ b/in_class/emscripten/start-server.sh @@ -0,0 +1 @@ +python3 -m http.server diff --git a/in_class/meta/meta.cpp b/in_class/meta/meta.cpp new file mode 100644 index 00000000..319af905 --- /dev/null +++ b/in_class/meta/meta.cpp @@ -0,0 +1,67 @@ +#include +#include +//#include + +// static size_t NextID() { +// static size_t next_id = 0; +// return ++next_id; +// } + +// template +// static size_t ToID() { +// static size_t this_id = NextID(); +// return this_id; +// } + +template +constexpr bool SameType(T1, T2) { + return false; +} + +template +constexpr bool SameType(T1, T1) { + return true; +} + +template +constexpr bool SameType(T1) { + return true; +} + +template +constexpr bool SameType(T1 v1, T2 v2, extraTs... extra_values) { + return SameType(v1,v2) && SameType(v1, extra_values...); +} + +void TestFun(int) { std::cout << "int version!" << std::endl; } +void TestFun(bool) { std::cout << "bool version!" << std::endl; } +void TestFun(...) { std::cout << "extra version!" << std::endl; } + +int main() +{ + int u = 5, v = 11, w = 22, x = 10, y = 1; + double z = 3.14159265358979; + std::string s("test"); + + std::cout << "SameType(x,y) = " << SameType(x,y) << std::endl; + std::cout << "SameType(x,z) = " << SameType(x,z) << std::endl; + std::cout << "SameType(x,s) = " << SameType(x,s) << std::endl; + std::cout << "SameType(x,1) = " << SameType(x,1) << std::endl; + std::cout << "SameType(x) = " << SameType(x) << std::endl; + std::cout << "SameType(u,v,w,x,y) = " << SameType(u,v,w,x,y) << std::endl; + std::cout << "SameType(u,v,w,x,y,z) = " << SameType(u,v,w,x,y,z) << std::endl; + + // TestFun(5); + // TestFun(true); + // std::string str("Hello."); + // TestFun(str); + // TestFun("what will this do?"); + // TestFun('a'); + + // std::cout << "int: " << ToID() << std::endl; + // std::cout << "int: " << ToID() << std::endl; + // std::cout << "double: " << ToID() << std::endl; + // std::cout << "std::string: " << ToID() << std::endl; + // std::cout << "char: " << ToID() << std::endl; + // std::cout << "int: " << ToID() << std::endl; +} \ No newline at end of file diff --git a/in_class/meta/meta2.cpp b/in_class/meta/meta2.cpp new file mode 100644 index 00000000..18126701 --- /dev/null +++ b/in_class/meta/meta2.cpp @@ -0,0 +1,68 @@ +#include +#include + +struct Animal { + std::string name; + void PrintName() const { std::cout << name << std::endl; }; +}; + +struct Dog : Animal { + void Herd() { } + void Hunt() { } + int GetStrength() { return 10; } +}; +struct Sheep : Animal { + void Graze() { } + int GetStrength() { return 5; } +}; +struct Lion : Animal { + void Roar() { } + int Hunt() { return 1; } + int GetStrength() { return 100; } +}; + +template +concept CanHunt = requires(T animal) { + { animal.Hunt() } -> std::same_as; +}; + +template +void ManageHunt(T & hunter) { + hunter.Hunt(); +} + +template +void PrintNames(Ts &... animals) { + (std::cout << ... << animals.name) << std::endl; + // (..., animals.PrintName()); +} + +template +int TotalStrength(Ts &... animals) { + return (animals.GetStrength() + ...); +} + +template +auto Multiply(Ts... values) { + return (... * values); +} + +template +int MultStrength(Ts &... animals) { + return Multiply(animals.GetStrength() ...); +} + +int main() +{ + Lion l; l.name = "Oscar"; + Dog d; d.name = "Spot"; + Sheep s; s.name = "Baaaa"; + + PrintNames(l, d, s, l, l); + std::cout << "Total = " << TotalStrength(l, d, s, l, l) << std::endl; + std::cout << "Product = " << MultStrength(l, d, s, l, l) << std::endl; + + ManageHunt(l); + // ManageHunt(d); + // ManageHunt(s); +} \ No newline at end of file diff --git a/in_class/other/adl.cpp b/in_class/other/adl.cpp new file mode 100644 index 00000000..cd6ecd4a --- /dev/null +++ b/in_class/other/adl.cpp @@ -0,0 +1,22 @@ +#include +#include + +namespace mynamespace { + struct MyClass { int x = 5; }; + + template + int fun(T in) { return in.x; } +} + +struct MyClass2 { int x = 10; }; + + template + int fun(T in) { return in.x + 1; } + +int main() +{ + mynamespace::MyClass obj; + MyClass2 obj2; + + std::cout << fun(obj) << std::endl; +} \ No newline at end of file diff --git a/in_class/other/crtp.cpp b/in_class/other/crtp.cpp new file mode 100644 index 00000000..5456c661 --- /dev/null +++ b/in_class/other/crtp.cpp @@ -0,0 +1,30 @@ +#include +#include + +struct VehicleBase { + +}; + +template +struct Vehicle : public VehicleBase { + std::string name; + std::string owner; + virtual double GetSpeed() const { return 0; } + DERIVED_T & Derived() { return *static_cast(this); } + + DERIVED_T & SetName(std::string in) { name = in; return Derived(); } + DERIVED_T & SetOwner(std::string in) { owner = in; return Derived(); } +}; + +struct Quinjet : public Vehicle { + int num_missiles = 100; + double GetSpeed() const override { return 1000000.0; } + + Quinjet & SetNumMissiles(int in) { num_missiles = in; return *this; } +}; + +int main() +{ + Quinjet q1; + q1.SetName("q1").SetOwner("Avengers").SetNumMissiles(2000); +} \ No newline at end of file diff --git a/in_class/other/downto.cpp b/in_class/other/downto.cpp new file mode 100644 index 00000000..2051a2d0 --- /dev/null +++ b/in_class/other/downto.cpp @@ -0,0 +1,9 @@ +#include + +int main() +{ + int x = 10; + while (x --> 0) { + std::cout << x << std::endl; + } +} diff --git a/in_class/other/multitype.cpp b/in_class/other/multitype.cpp new file mode 100644 index 00000000..d44e3ffb --- /dev/null +++ b/in_class/other/multitype.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +struct BaseNode { + virtual void Print() = 0; +}; + +template +struct Node : public BaseNode { + T value; + + Node(T value) : value(value) { } + + void Print() override { + std::cout << value << std::endl; + } +}; + +struct Container { + std::vector values; + + template + void AddValue(T in) { + values.push_back( new Node(in) ); + } + + void Print() { + for (auto ptr : values) ptr->Print(); + } +}; + + +int main() +{ + Container c; + c.AddValue(10); + c.AddValue("Test"); + c.AddValue('x'); + c.Print(); +} \ No newline at end of file diff --git a/in_class/other/template-template.cpp b/in_class/other/template-template.cpp new file mode 100644 index 00000000..2a7329b0 --- /dev/null +++ b/in_class/other/template-template.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +template typename CONTAINER_T=std::vector> +struct String { + CONTAINER_T str; + + size_t size() { return str.size(); } +}; + +int main() +{ + String str1; + String str2; + + str1.str.resize(10,' '); + str2.str.resize(15,'x'); + + std::cout << str1.size() << std::endl; + std::cout << str2.size() << std::endl; +} \ No newline at end of file From 72817116976099d6ee788784f7b6fb18bd067d8c Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 9 Dec 2023 20:30:18 -0500 Subject: [PATCH 02/22] Some type fixes for packets and removed problematic ranges code. --- source/Interfaces/MainInterface.hpp | 2 +- source/Interfaces/NetWorth/client/ClientInterface.hpp | 2 +- source/Interfaces/NetWorth/client/ClientManager.hpp | 2 +- source/Interfaces/NetWorth/server/ServerInterface.hpp | 2 +- source/Interfaces/NetWorth/server/ServerManager.hpp | 6 +++--- source/Worlds/ProgramExecutor.hpp | 10 +++++++--- source/group_5_client_main.cpp | 2 +- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/source/Interfaces/MainInterface.hpp b/source/Interfaces/MainInterface.hpp index ffea9faa..ced28d25 100644 --- a/source/Interfaces/MainInterface.hpp +++ b/source/Interfaces/MainInterface.hpp @@ -113,7 +113,7 @@ namespace i_2D { void ChooseTexture(); - bool SetLargeGrid(bool b){ mGridSizeLarge = b; } + void SetLargeGrid(bool b){ mGridSizeLarge = b; } void Notify(const std::string & message, const std::string & /*msg_type*/="none") override diff --git a/source/Interfaces/NetWorth/client/ClientInterface.hpp b/source/Interfaces/NetWorth/client/ClientInterface.hpp index f0f3f913..5b46c536 100644 --- a/source/Interfaces/NetWorth/client/ClientInterface.hpp +++ b/source/Interfaces/NetWorth/client/ClientInterface.hpp @@ -94,7 +94,7 @@ namespace netWorth{ itemMap, agentMap); // Send instruction to server - sendPkt << actionID; + sendPkt << static_cast(actionID); sendPacket(sendPkt, m_ip.value(), m_port); m_manager->clearActionMap(); diff --git a/source/Interfaces/NetWorth/client/ClientManager.hpp b/source/Interfaces/NetWorth/client/ClientManager.hpp index 6832d1c2..f0df132d 100644 --- a/source/Interfaces/NetWorth/client/ClientManager.hpp +++ b/source/Interfaces/NetWorth/client/ClientManager.hpp @@ -41,7 +41,7 @@ namespace netWorth{ * @param pkt received packet */ void packetToActionMap(sf::Packet pkt) { - size_t dataSize, agentID, actionID; + uint64_t dataSize, agentID, actionID; pkt >> dataSize; for (size_t i = 0; i < dataSize; i++) { pkt >> agentID >> actionID; diff --git a/source/Interfaces/NetWorth/server/ServerInterface.hpp b/source/Interfaces/NetWorth/server/ServerInterface.hpp index e8615992..42cca916 100644 --- a/source/Interfaces/NetWorth/server/ServerInterface.hpp +++ b/source/Interfaces/NetWorth/server/ServerInterface.hpp @@ -167,7 +167,7 @@ namespace netWorth // receive player input sf::Packet recvPkt; - size_t actionID; + uint64_t actionID; receivePacket(recvPkt, m_ip, m_port); recvPkt >> actionID; diff --git a/source/Interfaces/NetWorth/server/ServerManager.hpp b/source/Interfaces/NetWorth/server/ServerManager.hpp index 346b2ce5..43d4e714 100644 --- a/source/Interfaces/NetWorth/server/ServerManager.hpp +++ b/source/Interfaces/NetWorth/server/ServerManager.hpp @@ -82,9 +82,9 @@ namespace netWorth{ sf::Packet pkt; // serialize action map - pkt << m_action_map.size(); - for (auto pair: m_action_map) { - pkt << pair.first << pair.second; + pkt << static_cast(m_action_map.size()); + for (auto [agent_id, action_id]: m_action_map) { + pkt << static_cast(agent_id) << static_cast(action_id); } return pkt; diff --git a/source/Worlds/ProgramExecutor.hpp b/source/Worlds/ProgramExecutor.hpp index d7e1da97..bda12cdd 100644 --- a/source/Worlds/ProgramExecutor.hpp +++ b/source/Worlds/ProgramExecutor.hpp @@ -465,7 +465,7 @@ namespace worldlang { } while (!(has(values.back()) && static_cast(as(values.back())) == "__INTERNAL_ENDARGS")); values.pop_back(); // don't keep that one - std::ranges::reverse(values); + std::reverse(values.begin(), values.end()); return values; } @@ -657,8 +657,12 @@ namespace worldlang { } // Convert to identifiers specifically std::vector< Identifier > identifiers; - std::ranges::transform(identifier_values, std::back_inserter(identifiers), [this](const Value& v){ return as(v); }); - //ex. a,b,c=1,2,3 becomes the follwoing units + std::transform( + identifier_values.begin(), identifier_values.end(), + std::back_inserter(identifiers), + [this](const Value& v){ return as(v); } + ); + //ex. a,b,c=1,2,3 becomes the following units // . a b c . 1 2 3 = // v: 3 2 1 // i: c b a diff --git a/source/group_5_client_main.cpp b/source/group_5_client_main.cpp index ded9e2eb..b26f528d 100644 --- a/source/group_5_client_main.cpp +++ b/source/group_5_client_main.cpp @@ -23,7 +23,7 @@ void terminateClient() { // Request connection to server sf::Packet sendPkt; std::optional ipAddr = sf::IpAddress::resolve(clientKillIP); - sendPkt << static_cast(9999); + sendPkt << static_cast(9999); if (clientKillSocket->send(sendPkt, ipAddr.value(), clientKillPort) != sf::Socket::Status::Done) { std::cerr << "Failed to send" << std::endl; } From a9fc7f77f2093d0f7d5b66c1e99e0d1477a99862 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 9 Dec 2023 20:51:38 -0500 Subject: [PATCH 03/22] Cleaned up some unused variable warnings. --- source/Agents/GP/CGPGenotype.hpp | 5 +++-- source/Agents/GP/GPAgentAnalyze.h | 2 +- source/Agents/GP/GPTrainingLoop.hpp | 18 +++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/source/Agents/GP/CGPGenotype.hpp b/source/Agents/GP/CGPGenotype.hpp index ca9495ec..99d786ec 100644 --- a/source/Agents/GP/CGPGenotype.hpp +++ b/source/Agents/GP/CGPGenotype.hpp @@ -714,12 +714,13 @@ namespace cowboys { // Check if everything is correct assert(nodes.size() == params.GetFunctionalNodeCount()); for (size_t i = 1; i < params.num_layers + 1; ++i) { - size_t layer_start = (i - 1) * params.num_nodes_per_layer; + [[maybe_unused]] size_t layer_start = (i - 1) * params.num_nodes_per_layer; size_t layer_size = i == params.num_layers + 1 ? params.num_outputs : params.num_nodes_per_layer; size_t valid_layers_back = std::min(params.layers_back, i); for (size_t j = 0; j < layer_size; ++j) { // Check that the number of connections is correct - size_t num_connections = valid_layers_back * params.num_nodes_per_layer; + [[maybe_unused]] size_t num_connections = + valid_layers_back * params.num_nodes_per_layer; if (i <= params.layers_back) { num_connections -= params.num_nodes_per_layer; num_connections += params.num_inputs; diff --git a/source/Agents/GP/GPAgentAnalyze.h b/source/Agents/GP/GPAgentAnalyze.h index bcf3569b..d485bae5 100644 --- a/source/Agents/GP/GPAgentAnalyze.h +++ b/source/Agents/GP/GPAgentAnalyze.h @@ -90,7 +90,7 @@ namespace cowboys { // write the data to the file file << "average_fitness,max_fitness,average_elite_score,best_agent_weighted_score,agents_with_max_fitness\n"; - for (int i = 0; i < average_fitness.size(); i++) { + for (size_t i = 0; i < average_fitness.size(); i++) { file << average_fitness[i] << "," << max_fitness[i] << "," << elite_score[i] << "," << average_score[i] << "," << max_agents[i] << "\n"; } std::cout << "Saved GP Agent Analyzer data to gp_agent_analyzer.csv" << std::endl; diff --git a/source/Agents/GP/GPTrainingLoop.hpp b/source/Agents/GP/GPTrainingLoop.hpp index 523b20b0..ff4ea8ab 100644 --- a/source/Agents/GP/GPTrainingLoop.hpp +++ b/source/Agents/GP/GPTrainingLoop.hpp @@ -680,11 +680,11 @@ namespace cowboys { Printgrid(endPositions[bestAgent.first][bestAgent.second], 'A'); - auto& agent = agents[bestAgent.first][bestAgent.second]; + // auto& agent = agents[bestAgent.first][bestAgent.second]; auto& startPosition = STARTPOSITIONS; auto& endPosition = endPositions[bestAgent.first][bestAgent.second]; - auto& world = environments[bestAgent.first]; + // auto& world = environments[bestAgent.first]; auto calculateDistance = [](const cse491::GridPosition& startPosition, const cse491::GridPosition & currentPosition) { @@ -1048,18 +1048,18 @@ namespace cowboys { for (size_t a = 0; a < agents[arena].size(); ++a) { std::vector scores = independentAgentFitness[arena][a]; - auto computeMedian = [&scores]() -> double { - std::vector temp(scores); // Copy the data - std::sort(temp.begin(), temp.end()); + // auto computeMedian = [&scores]() -> double { + // std::vector temp(scores); // Copy the data + // std::sort(temp.begin(), temp.end()); - size_t n = temp.size(); - return n % 2 ? temp[n / 2] : (temp[n / 2 - 1] + temp[n / 2]) / 2.0; - }; + // size_t n = temp.size(); + // return n % 2 ? temp[n / 2] : (temp[n / 2 - 1] + temp[n / 2]) / 2.0; + // }; // TEMPAgentFitness[arena][a] /= STARTPOSITIONS.size(); // TEMPAgentFitness[arena][a] += computeMedian(); - double min = *std::min_element(scores.begin(), scores.end()); +// double min = *std::min_element(scores.begin(), scores.end()); [[maybe_unused]] double avg = TEMPAgentFitness[arena][a] / STARTPOSITIONS.size(); // TEMPAgentFitness[arena][a] = 0.7 * min + 0.3 * avg; // TEMPAgentFitness[arena][a] = min; From 7cac504a06854c4efdfaa8ad3569d73cee8967e9 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 9 Dec 2023 23:09:03 -0500 Subject: [PATCH 04/22] Cleanup of warnings (unused variables and comparison type mismatches) --- source/Agents/GP/GPAgentsRegisters.hpp | 4 ++-- source/Interfaces/MainInterface.cpp | 8 +++++--- source/Interfaces/Menu.cpp | 2 +- source/Interfaces/TextBox.cpp | 4 ++-- source/Interfaces/TextBox.hpp | 2 +- source/Worlds/BiomeGenerator.hpp | 2 +- source/Worlds/ProgramExecutor.hpp | 2 +- source/core/EasyLogging.hpp | 4 ++-- source/group_6_main.cpp | 1 + 9 files changed, 16 insertions(+), 13 deletions(-) diff --git a/source/Agents/GP/GPAgentsRegisters.hpp b/source/Agents/GP/GPAgentsRegisters.hpp index 84a5779f..e151ea8d 100644 --- a/source/Agents/GP/GPAgentsRegisters.hpp +++ b/source/Agents/GP/GPAgentsRegisters.hpp @@ -64,9 +64,9 @@ class GPAgentRegisters { * @brief Get the number of registers * @return size of the registers */ - int getNumRegisters() { return registers.size(); } + size_t getNumRegisters() { return registers.size(); } - int size() { return registers.size(); } + size_t size() { return registers.size(); } /** * @brief Iterator class for GPAgentRegisters diff --git a/source/Interfaces/MainInterface.cpp b/source/Interfaces/MainInterface.cpp index 5c673811..efb6146e 100644 --- a/source/Interfaces/MainInterface.cpp +++ b/source/Interfaces/MainInterface.cpp @@ -139,7 +139,9 @@ namespace i_2D { // Create a render texture to draw the grid sf::RenderTexture renderTexture; - renderTexture.create({static_cast(drawSpaceWidth), static_cast(drawSpaceHeight)}); + [[maybe_unused]] bool success = + renderTexture.create({static_cast(drawSpaceWidth), static_cast(drawSpaceHeight)}); + renderTexture.clear(sf::Color::White); for (size_t iterY = 0; iterY < symbol_grid.size(); ++iterY) { @@ -225,9 +227,9 @@ namespace i_2D { // Create a new symbol grid for the 9x23 display window std::vector display_grid; - for (size_t iterY = 0; iterY < ROW; ++iterY) { + for (int iterY = 0; iterY < ROW; ++iterY) { std::string row; - for (size_t iterX = 0; iterX < COL; ++iterX) { + for (int iterX = 0; iterX < COL; ++iterX) { int posX = topLeftX + iterX; int posY = topLeftY + iterY; diff --git a/source/Interfaces/Menu.cpp b/source/Interfaces/Menu.cpp index 18ae7d75..139d8717 100644 --- a/source/Interfaces/Menu.cpp +++ b/source/Interfaces/Menu.cpp @@ -59,7 +59,7 @@ namespace i_2D { * @param window the main window of the graphic interface */ void Menu::HandleMouseMove(sf::RenderWindow &window) { - for (int i = 0; i < mMenuBar.size(); ++i) { + for (size_t i = 0; i < mMenuBar.size(); ++i) { if (mMenuBar[i]->isMouseOver(window)) { mMenuBar[i]->setBackColor(sf::Color::Magenta); } else { diff --git a/source/Interfaces/TextBox.cpp b/source/Interfaces/TextBox.cpp index 9ca603d4..87ec1b86 100644 --- a/source/Interfaces/TextBox.cpp +++ b/source/Interfaces/TextBox.cpp @@ -61,9 +61,9 @@ void i_2D::TextBox::TypedOn(sf::Event input) { int charTyped = static_cast(input.text.unicode); if(charTyped < 128){ if(hasLimit){ - if(static_cast(mText.str().length()) <= MAX_CHAR){ + if (mText.str().length() <= MAX_CHAR){ InputLogic(charTyped); - }else if( static_cast(mText.str().length()) > MAX_CHAR && charTyped == DELETE_KEY){ + } else if ( mText.str().length() > MAX_CHAR && charTyped == DELETE_KEY){ DeleteLastChar(); } }else{ diff --git a/source/Interfaces/TextBox.hpp b/source/Interfaces/TextBox.hpp index 0701b8b5..e1f9d05b 100644 --- a/source/Interfaces/TextBox.hpp +++ b/source/Interfaces/TextBox.hpp @@ -26,7 +26,7 @@ namespace i_2D { bool isSelected = false; /// Flag for checking text mode bool hasLimit = false; /// Flag for checking limit mode int limit = 10000; /// The limit of characters allowed - const int MAX_CHAR = 60; ///< max character per line in the textbox + const size_t MAX_CHAR = 60; ///< max character per line in the textbox // Draw the border around the TextBox sf::RectangleShape mBorderRect; diff --git a/source/Worlds/BiomeGenerator.hpp b/source/Worlds/BiomeGenerator.hpp index 3c00f448..7b610026 100644 --- a/source/Worlds/BiomeGenerator.hpp +++ b/source/Worlds/BiomeGenerator.hpp @@ -32,7 +32,7 @@ namespace group6 { class BiomeGenerator { private: const double frequency = 8.0; ///< [0.1, 64.0] - const int octaves = 8; ///< [1, 16] + // const int octaves = 8; ///< [1, 16] PerlinNoise perlinNoise; ///< The Perlin Noise procedural generation algorithm diff --git a/source/Worlds/ProgramExecutor.hpp b/source/Worlds/ProgramExecutor.hpp index bda12cdd..17613ab2 100644 --- a/source/Worlds/ProgramExecutor.hpp +++ b/source/Worlds/ProgramExecutor.hpp @@ -114,7 +114,7 @@ namespace worldlang { } }); // Log some values - registerFunction("print", [this](ProgramExecutor& pe){ + registerFunction("print", [](ProgramExecutor& pe){ auto args = pe.popArgs(); for (auto a : args){ if (pe.has(a)){ diff --git a/source/core/EasyLogging.hpp b/source/core/EasyLogging.hpp index defae490..92d0802a 100644 --- a/source/core/EasyLogging.hpp +++ b/source/core/EasyLogging.hpp @@ -293,11 +293,11 @@ class Logger { class Logger { public: template - Logger &operator<<(const T &value) { + Logger &operator<<(const T & /*value*/) { return *this; } - Logger &operator<<(std::ostream &(*manipulator)(std::ostream &)) { + Logger &operator<<(std::ostream &(* /*manipulator*/)(std::ostream &)) { return *this; } diff --git a/source/group_6_main.cpp b/source/group_6_main.cpp index c1e7a0d2..5384f051 100644 --- a/source/group_6_main.cpp +++ b/source/group_6_main.cpp @@ -23,6 +23,7 @@ void timer(GenerativeWorld& world, int duration) { } void runWorld(BiomeType biome, int width, int height, const unsigned int SEED, int timerDuration = -1) { + (void) SEED; // Need to plug in seed. std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution distribution(0, 1000000); From 73c67c514b5d463cfb240dc0135664b6ff11b1c5 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 9 Dec 2023 23:32:12 -0500 Subject: [PATCH 05/22] Ran all of core through clang-format --- source/core/AgentBase.hpp | 292 +++++++++++++++-------------- source/core/CoreObject.hpp | 264 +++++++++++++------------- source/core/Data.hpp | 94 +++++----- source/core/EasyLogging.hpp | 89 ++++----- source/core/Entity.hpp | 280 +++++++++++++++------------- source/core/GridPosition.hpp | 136 +++++++------- source/core/InterfaceBase.hpp | 58 +++--- source/core/ItemBase.hpp | 222 +++++++++++----------- source/core/WorldBase.hpp | 217 +++++++++++----------- source/core/WorldGrid.hpp | 338 +++++++++++++++++----------------- 10 files changed, 980 insertions(+), 1010 deletions(-) diff --git a/source/core/AgentBase.hpp b/source/core/AgentBase.hpp index 6fd3132b..b8f82efb 100644 --- a/source/core/AgentBase.hpp +++ b/source/core/AgentBase.hpp @@ -11,160 +11,158 @@ #include #include +#include "../DataCollection/AgentData.hpp" #include "Data.hpp" #include "Entity.hpp" #include "GridPosition.hpp" #include "WorldGrid.hpp" -#include "../DataCollection/AgentData.hpp" namespace cse491 { - enum State /// States that an agent can be in. - { - Healthy, - Taking_Damage, - Dying, - Deceased - }; - - class AgentBase : public Entity { - protected: - size_t grid_id=0; ///< Which grid is this agent on? - - /// A map of names to IDs for each available action - std::unordered_map action_map; - int action_result=0; ///< Usually a one (success) or zero (failure). - - int action; // The action that the agent is currently performing - - State agent_state = Healthy; /// Default value upon initialization - - public: - AgentBase(size_t id, const std::string & name) : Entity(id, name) {} - ~AgentBase() = default; // Already virtual from Entity - - [[nodiscard]] size_t GetGridID() const { return grid_id; } - [[nodiscard]] bool IsOnGrid(size_t in_grid_id) const { return grid_id == in_grid_id; } - - // -- World Interactions -- - - /// @brief Run AFTER the world configures the agent, for additional tests or setup. - /// @return Was the initialization successful? - virtual bool Initialize() { return true; } - - // -- Entity Overrides -- - - bool IsAgent() const override { return true; } - - // -- Agent Interaction -- - - /// @brief Get the current state of the Agent - /// @return State enum of agent_state - State GetAgentState() { return agent_state; } - - /// @brief Updates an Agent's state depending on health - /// @param agent The agent whose state to update - /// If the agent's health is between Max_health and 3 -> Healthy - /// If the agent's health is between 0 and 3 -> Dying - /// If the agent is Taking_Damage -> Taking_Damage - /// If the agent is at 0 or below -> Dead - /// @see TakeDamage - /// @return None - void UpdateAgentState(cse491::AgentBase & agent) { - if(agent.HasProperty("Health")){ - if(agent.GetProperty("Health") <= agent.GetProperty("Max_Health") - && agent.GetProperty("Health") > 3){ - agent.agent_state = Healthy; - } - else if(agent.GetProperty("Health") <= 3 && agent.GetProperty("Health") > 0){ - agent.agent_state = Dying; - } - else if(agent.GetProperty("Health") <= 0){ - agent.agent_state = Deceased; - } - } - if(agent.HasProperty("Taking_Damage")){ - if(agent.GetProperty("Taking_Damage") == true){ - agent.agent_state = Taking_Damage; - } +enum State /// States that an agent can be in. +{ + Healthy, + Taking_Damage, + Dying, + Deceased +}; + +class AgentBase : public Entity { + protected: + size_t grid_id = 0; ///< Which grid is this agent on? + + /// A map of names to IDs for each available action + std::unordered_map action_map; + int action_result = 0; ///< Usually a one (success) or zero (failure). + + int action; // The action that the agent is currently performing + + State agent_state = Healthy; /// Default value upon initialization + + public: + AgentBase(size_t id, const std::string &name) : Entity(id, name) {} + ~AgentBase() = default; // Already virtual from Entity + + [[nodiscard]] size_t GetGridID() const { return grid_id; } + [[nodiscard]] bool IsOnGrid(size_t in_grid_id) const { return grid_id == in_grid_id; } + + // -- World Interactions -- + + /// @brief Run AFTER the world configures the agent, for additional tests or setup. + /// @return Was the initialization successful? + virtual bool Initialize() { return true; } + + // -- Entity Overrides -- + + bool IsAgent() const override { return true; } + + // -- Agent Interaction -- + + /// @brief Get the current state of the Agent + /// @return State enum of agent_state + State GetAgentState() { return agent_state; } + + /// @brief Updates an Agent's state depending on health + /// @param agent The agent whose state to update + /// If the agent's health is between Max_health and 3 -> Healthy + /// If the agent's health is between 0 and 3 -> Dying + /// If the agent is Taking_Damage -> Taking_Damage + /// If the agent is at 0 or below -> Dead + /// @see TakeDamage + /// @return None + void UpdateAgentState(cse491::AgentBase &agent) { + if (agent.HasProperty("Health")) { + if (agent.GetProperty("Health") <= agent.GetProperty("Max_Health") && + agent.GetProperty("Health") > 3) { + agent.agent_state = Healthy; + } else if (agent.GetProperty("Health") <= 3 && agent.GetProperty("Health") > 0) { + agent.agent_state = Dying; + } else if (agent.GetProperty("Health") <= 0) { + agent.agent_state = Deceased; } } - - /// @brief If the agent is in State::Taking_Damage, decrease the health - /// by the damage factor once per timestep. - void TakeDamage(cse491::AgentBase & agent){ - agent.SetProperty("Health", agent.GetProperty("Health") - - agent.GetProperty("Taking_Damage")); - UpdateAgentState(agent); - } - - // -- Action management -- - - /// Test if agent already has a specified action. - [[nodiscard]] bool HasAction(const std::string & action_name) const { - return action_map.count(action_name); - } - - /// Return an action ID *if* that action exists, otherwise return zero. - [[nodiscard]] size_t GetActionID(const std::string & action_name) const { - auto it = action_map.find(action_name); - if (it == action_map.end()) return 0; - return it->second; - } - - void storeActionMap(std::string name) { - DataCollection::AgentData data(name); - data.StoreAction(action_map); - } - - /// Allow derived agents to provide an arbitrary next position for the world to move the agent to - [[nodiscard]] virtual GridPosition GetNextPosition() { return Entity::GetPosition(); } - - /// Provide a new action that this agent can take. - virtual AgentBase & AddAction(const std::string & action_name, size_t action_id) { - assert(!HasAction(action_name)); // Cannot add existing action name. - action_map[action_name] = action_id; - return *this; - } - - /// @brief Decide the next action for this agent to perform; should be overridden! - /// @param grid The agent is provided with the current WorldGrid - /// @return ID associated with the action to perform; (zero is always "no action") - [[nodiscard]] virtual size_t SelectAction( - [[maybe_unused]] const WorldGrid & grid, - [[maybe_unused]] const type_options_t & type_options, - [[maybe_unused]] const item_map_t & item_map, - [[maybe_unused]] const agent_map_t & agent_map - ) - { return 0; } - - /// Retrieve the result of the most recent action. - [[nodiscard]] int GetActionResult() const { return action_result; } - - /// Update the result from the most recent action. - void SetActionResult(int result) { action_result = result; } - - /// @brief Send a notification to this agent, typically from the world. - /// @param message Contents of the notification - /// @param msg_type Category of message, such as "item_alert", "damage", or "enemy" - /// This function is useful to notify users of events in the world, such as them taking - /// damage, finding an item, etc. The message type can potentially also provide - /// information to an autonomous agent assuming we come up with a standard list of types. - virtual void Notify(const std::string & /*message*/,const std::string & /*msg_type*/="none") { } - - /** - * Serialize agent (assume no properties) - * @param os ostream - */ - void Serialize(std::ostream &os) override { - os << name << '\n'; - os << id << '\n'; - os << position.GetX() << '\n'; - os << position.GetY() << '\n'; - if (HasProperty("symbol")) os << GetProperty("symbol") << '\n'; - else os << '*' << std::endl; + if (agent.HasProperty("Taking_Damage")) { + if (agent.GetProperty("Taking_Damage") == true) { + agent.agent_state = Taking_Damage; + } } - - }; - -} // End of namespace cse491 + } + + /// @brief If the agent is in State::Taking_Damage, decrease the health + /// by the damage factor once per timestep. + void TakeDamage(cse491::AgentBase &agent) { + agent.SetProperty( + "Health", agent.GetProperty("Health") - agent.GetProperty("Taking_Damage")); + UpdateAgentState(agent); + } + + // -- Action management -- + + /// Test if agent already has a specified action. + [[nodiscard]] bool HasAction(const std::string &action_name) const { + return action_map.count(action_name); + } + + /// Return an action ID *if* that action exists, otherwise return zero. + [[nodiscard]] size_t GetActionID(const std::string &action_name) const { + auto it = action_map.find(action_name); + if (it == action_map.end()) return 0; + return it->second; + } + + void storeActionMap(std::string name) { + DataCollection::AgentData data(name); + data.StoreAction(action_map); + } + + /// Allow derived agents to provide an arbitrary next position for the world to move the agent to + [[nodiscard]] virtual GridPosition GetNextPosition() { return Entity::GetPosition(); } + + /// Provide a new action that this agent can take. + virtual AgentBase &AddAction(const std::string &action_name, size_t action_id) { + assert(!HasAction(action_name)); // Cannot add existing action name. + action_map[action_name] = action_id; + return *this; + } + + /// @brief Decide the next action for this agent to perform; should be overridden! + /// @param grid The agent is provided with the current WorldGrid + /// @return ID associated with the action to perform; (zero is always "no action") + [[nodiscard]] virtual size_t SelectAction([[maybe_unused]] const WorldGrid &grid, + [[maybe_unused]] const type_options_t &type_options, + [[maybe_unused]] const item_map_t &item_map, + [[maybe_unused]] const agent_map_t &agent_map) { + return 0; + } + + /// Retrieve the result of the most recent action. + [[nodiscard]] int GetActionResult() const { return action_result; } + + /// Update the result from the most recent action. + void SetActionResult(int result) { action_result = result; } + + /// @brief Send a notification to this agent, typically from the world. + /// @param message Contents of the notification + /// @param msg_type Category of message, such as "item_alert", "damage", or "enemy" + /// This function is useful to notify users of events in the world, such as them taking + /// damage, finding an item, etc. The message type can potentially also provide + /// information to an autonomous agent assuming we come up with a standard list of types. + virtual void Notify(const std::string & /*message*/, const std::string & /*msg_type*/ = "none") {} + + /** + * Serialize agent (assume no properties) + * @param os ostream + */ + void Serialize(std::ostream &os) override { + os << name << '\n'; + os << id << '\n'; + os << position.GetX() << '\n'; + os << position.GetY() << '\n'; + if (HasProperty("symbol")) + os << GetProperty("symbol") << '\n'; + else + os << '*' << std::endl; + } +}; + +} // End of namespace cse491 diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index 88ddf737..1040369b 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -2,10 +2,10 @@ * This file is part of the Fall 2023, CSE 491 course project. * @brief A common interface class for core objects that sets up required functionality. * @note Status: PROPOSAL - * + * * This CoreObject class builds an interface for all of the core object, ensuring that * they can be properly serialized. - * + * * Derived classes must implement: * GetTypeName_impl() - To return the qualified type name. * Serialize_impl() - To store the object in a stream. @@ -18,19 +18,15 @@ */ #ifndef NDEBUG -#define EXPERIMENTAL_FUNCTION \ - __attribute__((annotate("experimental_function"))) +#define EXPERIMENTAL_FUNCTION __attribute__((annotate("experimental_function"))) -#define EXPERIMENTAL_CLASS \ - __attribute__((annotate("experimental_class"))) +#define EXPERIMENTAL_CLASS __attribute__((annotate("experimental_class"))) #else -#define EXPERIMENTAL_CLASS \ - __attribute__(( \ - annotate("experimental_class"), \ - warning( \ - "This is an experimental class and should be used with caution."))) +#define EXPERIMENTAL_CLASS \ + __attribute__((annotate("experimental_class"), \ + warning("This is an experimental class and should be used with caution."))) #define EXPERIMENTAL_FUNCTION \ __attribute__((annotate("experimental_function"), \ warning("This is an experimental function and should be " \ @@ -46,135 +42,127 @@ namespace cse491 { - /// @class WorldGrid - /// @brief A common interface class for core objects that sets up required functionality. - /// This class ensures that objects can be serialized (saved), deserialized (restored) - /// and provides helper functions. - class CoreObject { - protected: - // -- Required functionality in all core classes -- - // These functions are core functionality that must be implemented in all derived - // classes. They will enable the public interface to behave correctly. - - /// @brief Override to allow access the derived name for this type. - /// @return A unique typename, ideally the exact name for this class (with scope) - /// This member function will be helpful for serialization and debugging. It should - /// return a fully scoped typename, such as "cse491::WorldGrid". - virtual std::string GetTypeName_impl() const = 0; - - /// @brief Override to store the current state of this object for later extraction. - /// @param [in,out] output_stream An ostream that the required information should be stored in. - virtual void Serialize_impl(std::ostream &) const = 0; - - /// @brief Override to restore the state of this object from the provided stream - /// @param [in,out] input_stream The istream with full details about this object. - virtual void Deserialize_impl(std::istream &) = 0; - - - // -- Helper functions -- - // The functions below can be used in derived classes to implement above functionality. - - /// @brief Set up beginning of the serialization for this class (allows checking later) - /// @param os Output stream to Serialize into. - void StartSerialize(std::ostream & os) const { - os << ":::START " << GetTypeName() << "\n"; +/// @class WorldGrid +/// @brief A common interface class for core objects that sets up required functionality. +/// This class ensures that objects can be serialized (saved), deserialized (restored) +/// and provides helper functions. +class CoreObject { + protected: + // -- Required functionality in all core classes -- + // These functions are core functionality that must be implemented in all derived + // classes. They will enable the public interface to behave correctly. + + /// @brief Override to allow access the derived name for this type. + /// @return A unique typename, ideally the exact name for this class (with scope) + /// This member function will be helpful for serialization and debugging. It should + /// return a fully scoped typename, such as "cse491::WorldGrid". + virtual std::string GetTypeName_impl() const = 0; + + /// @brief Override to store the current state of this object for later extraction. + /// @param [in,out] output_stream An ostream that the required information should be stored in. + virtual void Serialize_impl(std::ostream &) const = 0; + + /// @brief Override to restore the state of this object from the provided stream + /// @param [in,out] input_stream The istream with full details about this object. + virtual void Deserialize_impl(std::istream &) = 0; + + // -- Helper functions -- + // The functions below can be used in derived classes to implement above functionality. + + /// @brief Set up beginning of the serialization for this class (allows checking later) + /// @param os Output stream to Serialize into. + void StartSerialize(std::ostream &os) const { os << ":::START " << GetTypeName() << "\n"; } + + /// @brief Set up end of the serialization for this class (allows checking later) + /// @param os Output stream to Serialize into. + void EndSerialize(std::ostream &os) const { os << ":::END " << GetTypeName() << "\n"; } + + /// @brief Set up beginning of the deserialization for this class (does type checking) + /// @param is Input stream to deserialize from. + /// @return success (true/false) + bool StartDeserialize(std::istream &is) { + std::string line; + std::getline(is, line); + std::string expected = ":::START " + GetTypeName(); + if (line != expected) { + std::cerr << "Deserialization error. Expected: " << expected << "...Found: " << line; + return false; } - - /// @brief Set up end of the serialization for this class (allows checking later) - /// @param os Output stream to Serialize into. - void EndSerialize(std::ostream & os) const { - os << ":::END " << GetTypeName() << "\n"; - } - - /// @brief Set up beginning of the deserialization for this class (does type checking) - /// @param is Input stream to deserialize from. - /// @return success (true/false) - bool StartDeserialize(std::istream & is) { - std::string line; - std::getline(is, line); - std::string expected = ":::START " + GetTypeName(); - if (line != expected) { - std::cerr << "Deserialization error. Expected: " << expected - << "...Found: " << line; - return false; - } - return true; - } - - /// @brief Set up end of the deserialization for this class (does type checking) - /// @param is Input stream to deserialize from. - /// @return success (true/false) - bool EndDeserialize(std::istream & is) { - std::string line; - std::getline(is, line); - std::string expected = ":::END " + GetTypeName(); - if (line != expected) { - std::cerr << "Deserialization error. Expected: " << expected - << "...Found: " << line; - return false; - } - return true; - } - - public: - virtual ~CoreObject() { } - - /// @brief Access the derived name for this type. - /// @return A unique typename, ideally the exact name for this class (with scope) - /// This member function will be helpful for serialization and debugging. It should - /// return a fully scoped typename, such as "cse491::WorldGrid". - std::string GetTypeName() const { return GetTypeName_impl(); } - - /// @brief Store the current state of this object for later extraction. - /// @param [in,out] output_stream An ostream that the required information should be stored in. - /// A derived class is required to store all information about itself in Serialize() - /// and clearly note the end of storage to simplify de-serializing the data. - /// This function will automatic add a start line that reads ":::START" followed by the - /// typename, and an end line with ":::END" followed by the typename again. - void Serialize(std::ostream & os) const { - StartSerialize(os); - Serialize_impl(os); - EndSerialize(os); - } - - /// @brief Restore the state of this object, extracting it from the provided stream - /// @param [in,out] input_stream The istream with full details about this object. - /// This function takes in an istream that was previously written using the paired - /// Serialize() function and restores the associated class. It should stop loading - /// when all data is finished; this may be signalled by the ":::END" directive. The - /// stream should end ready for the next extraction. - void Deserialize(std::istream & is) { - StartDeserialize(is); - Deserialize_impl(is); - EndDeserialize(is); + return true; + } + + /// @brief Set up end of the deserialization for this class (does type checking) + /// @param is Input stream to deserialize from. + /// @return success (true/false) + bool EndDeserialize(std::istream &is) { + std::string line; + std::getline(is, line); + std::string expected = ":::END " + GetTypeName(); + if (line != expected) { + std::cerr << "Deserialization error. Expected: " << expected << "...Found: " << line; + return false; } - - /// @brief A version of Serialize that accepts a filename for saving just this object - /// @param [in] filename The name of the file to create for storing this object. - /// @return Success (true/false) - bool Serialize(std::string filename) const { - std::ofstream os(filename); - if (!os.is_open()) { - std::cerr << "Could not open file '" << filename << "' for Serialize()." << std::endl; - return false; - } - Serialize(os); - return true; + return true; + } + + public: + virtual ~CoreObject() {} + + /// @brief Access the derived name for this type. + /// @return A unique typename, ideally the exact name for this class (with scope) + /// This member function will be helpful for serialization and debugging. It should + /// return a fully scoped typename, such as "cse491::WorldGrid". + std::string GetTypeName() const { return GetTypeName_impl(); } + + /// @brief Store the current state of this object for later extraction. + /// @param [in,out] output_stream An ostream that the required information should be stored in. + /// A derived class is required to store all information about itself in Serialize() + /// and clearly note the end of storage to simplify de-serializing the data. + /// This function will automatic add a start line that reads ":::START" followed by the + /// typename, and an end line with ":::END" followed by the typename again. + void Serialize(std::ostream &os) const { + StartSerialize(os); + Serialize_impl(os); + EndSerialize(os); + } + + /// @brief Restore the state of this object, extracting it from the provided stream + /// @param [in,out] input_stream The istream with full details about this object. + /// This function takes in an istream that was previously written using the paired + /// Serialize() function and restores the associated class. It should stop loading + /// when all data is finished; this may be signalled by the ":::END" directive. The + /// stream should end ready for the next extraction. + void Deserialize(std::istream &is) { + StartDeserialize(is); + Deserialize_impl(is); + EndDeserialize(is); + } + + /// @brief A version of Serialize that accepts a filename for saving just this object + /// @param [in] filename The name of the file to create for storing this object. + /// @return Success (true/false) + bool Serialize(std::string filename) const { + std::ofstream os(filename); + if (!os.is_open()) { + std::cerr << "Could not open file '" << filename << "' for Serialize()." << std::endl; + return false; } - - /// @brief A version of Deserialize that accepts a filename to read this object from - /// @param [in] filename The name of the file to open to load this object from. - /// @return Success (true/false) - bool Deserialize(std::string filename) { - std::ifstream is(filename); - if (!is.is_open()) { - std::cerr << "Could not open file '" << filename << "' for Serialize()." << std::endl; - return false; - } - Deserialize(is); - return true; + Serialize(os); + return true; + } + + /// @brief A version of Deserialize that accepts a filename to read this object from + /// @param [in] filename The name of the file to open to load this object from. + /// @return Success (true/false) + bool Deserialize(std::string filename) { + std::ifstream is(filename); + if (!is.is_open()) { + std::cerr << "Could not open file '" << filename << "' for Serialize()." << std::endl; + return false; } + Deserialize(is); + return true; + } +}; - }; - -} // End of namespace cse491 \ No newline at end of file +} // End of namespace cse491 \ No newline at end of file diff --git a/source/core/Data.hpp b/source/core/Data.hpp index 81532f80..cea66827 100644 --- a/source/core/Data.hpp +++ b/source/core/Data.hpp @@ -8,55 +8,53 @@ #include #include +#include #include #include -#include namespace cse491 { - - /// @brief Simple data structure to hold info about a TYPE of cell in the world. - struct CellType { - std::string name; ///< Unique name for this type of cell (e.g., "wall", "tree", "moon") - std::string desc; ///< Full description of what this type of cell is - char symbol; ///< Symbol for text representations (files or interface) - std::set properties{}; ///< Set of properties for this cell type. - - /// Adds the specifed property to this CellType. - CellType& SetProperty(const std::string& property){ - properties.insert(property); - return *this; - } - - /// Removes the specifed property from this CellType. - CellType& RemoveProperty(const std::string& property){ - properties.erase(property); - return *this; - } - - /// Checks if the given property is set on this CellType. - bool HasProperty(const std::string& property) const { - return properties.count(property); - } - - constexpr static char CELL_WALL[] = "wall"; - constexpr static char CELL_WATER[] = "water"; - }; - - /// @brief Available CellTypes will be passed around as a vector of options. - using type_options_t = std::vector; - - class ItemBase; - /// @brief Maps of item IDs to item pointers - using item_map_t = std::map>; - - class AgentBase; - /// @brief Maps of agent IDs to agent pointers - using agent_map_t = std::map>; - - /// @brief Common types of properties in network serialization - enum class PropertyType {t_double, t_int, t_char, t_string, t_other}; - - /// @brief Enum for World types in network serialization - enum class WorldType {w_maze, w_second, w_generative, w_manual}; - -} + +/// @brief Simple data structure to hold info about a TYPE of cell in the world. +struct CellType { + std::string name; ///< Unique name for this type of cell (e.g., "wall", "tree", "moon") + std::string desc; ///< Full description of what this type of cell is + char symbol; ///< Symbol for text representations (files or interface) + std::set properties{}; ///< Set of properties for this cell type. + + /// Adds the specifed property to this CellType. + CellType& SetProperty(const std::string& property) { + properties.insert(property); + return *this; + } + + /// Removes the specifed property from this CellType. + CellType& RemoveProperty(const std::string& property) { + properties.erase(property); + return *this; + } + + /// Checks if the given property is set on this CellType. + bool HasProperty(const std::string& property) const { return properties.count(property); } + + constexpr static char CELL_WALL[] = "wall"; + constexpr static char CELL_WATER[] = "water"; +}; + +/// @brief Available CellTypes will be passed around as a vector of options. +using type_options_t = std::vector; + +class ItemBase; +/// @brief Maps of item IDs to item pointers +using item_map_t = std::map>; + +class AgentBase; +/// @brief Maps of agent IDs to agent pointers +using agent_map_t = std::map>; + +/// @brief Common types of properties in network serialization +enum class PropertyType { t_double, t_int, t_char, t_string, t_other }; + +/// @brief Enum for World types in network serialization +enum class WorldType { w_maze, w_second, w_generative, w_manual }; + +} // namespace cse491 diff --git a/source/core/EasyLogging.hpp b/source/core/EasyLogging.hpp index 92d0802a..2b8bf86c 100644 --- a/source/core/EasyLogging.hpp +++ b/source/core/EasyLogging.hpp @@ -53,15 +53,13 @@ const LogLevel LOGLEVEL = LogLevel::DEBUG; ? std::string(file).substr(std::string(file).find_last_of("/\\") + 1) \ : std::string(file)) -#define LOG_RELLINE \ - "File: " << RELATIVE_PATH(__FILE__) << "::->::Line(" << __LINE__ << ")" +#define LOG_RELLINE "File: " << RELATIVE_PATH(__FILE__) << "::->::Line(" << __LINE__ << ")" #define LOG_FNC "Function: " << __func__ << " " /// Not a fan of this practice /// But would prefer not to use parenthesis - /** * @brief Logger class with colors and team names * @author @amantham20 @chatGPT @@ -109,7 +107,6 @@ class Logger { return *this; } - /** * @brief Manipulator for endl so that we can reset the values when a team is * done logging @@ -121,8 +118,7 @@ class Logger { typedef std::ostream &(*EndlManipulator)(std::ostream &); // Compare the function pointers - if (manipulator == static_cast(std::endl) || - manipulator == endl) { + if (manipulator == static_cast(std::endl) || manipulator == endl) { // Handle std::endl here currentTeam = Team::NA; currentLogLevel = LogLevel::DEBUG; @@ -156,8 +152,7 @@ class Logger { // added additional flag in case one wants to compile without colors (or) // if the terminal does not support colors #ifndef D_ANSI_COLOR_CODES - std::string colorStart = - "\033[" + std::to_string(static_cast(currentColor)) + "m"; + std::string colorStart = "\033[" + std::to_string(static_cast(currentColor)) + "m"; std::string colorEnd = "\033[0m"; #else std::string colorStart = ""; @@ -179,36 +174,34 @@ class Logger { return *this; } + /** + * Only instance of the logger once + * Changes requested from Dr.@ofria + * + * @authors @mercere99 + * @return + */ + static Logger &Log() { + static Logger instance; // Guaranteed to be initialized only once. + return instance; + } - /** - * Only instance of the logger once - * Changes requested from Dr.@ofria - * - * @authors @mercere99 - * @return - */ - static Logger& Log() { - static Logger instance; // Guaranteed to be initialized only once. - return instance; - } - - /** - * Only instance of the logger once - * Changes requested from Dr.@ofria - * - * @authors @mercere99 - * @return - */ - template - static Logger & Log(T && arg1, EXTRA_Ts &&... extra_args) { - Log() << std::forward(arg1); // Log the first argument. - if constexpr (sizeof...(EXTRA_Ts) == 0) { // No arguments left. - return Log() << Logger::endl; // Trigger a flush. - } else { - return Log(std::forward(extra_args)...); // Log remaining arguments. - } + /** + * Only instance of the logger once + * Changes requested from Dr.@ofria + * + * @authors @mercere99 + * @return + */ + template + static Logger &Log(T &&arg1, EXTRA_Ts &&...extra_args) { + Log() << std::forward(arg1); // Log the first argument. + if constexpr (sizeof...(EXTRA_Ts) == 0) { // No arguments left. + return Log() << Logger::endl; // Trigger a flush. + } else { + return Log(std::forward(extra_args)...); // Log remaining arguments. } - + } /** * @brief Custom endl to reset the values @@ -238,11 +231,10 @@ class Logger { * */ std::map teamToStringMap = { - {Team::TEAM_1, "Team 1"}, {Team::TEAM_2, "Team 2"}, - {Team::TEAM_3, "Team 3"}, {Team::TEAM_4, "Team 4"}, - {Team::TEAM_5, "Team 5"}, {Team::TEAM_6, "Team 6"}, - {Team::TEAM_7, "Team 7"}, {Team::TEAM_8, "Team 8"}, - {Team::TEAM_9, "Team 9"}, {Team::GENERAL, "General"}}; + {Team::TEAM_1, "Team 1"}, {Team::TEAM_2, "Team 2"}, {Team::TEAM_3, "Team 3"}, + {Team::TEAM_4, "Team 4"}, {Team::TEAM_5, "Team 5"}, {Team::TEAM_6, "Team 6"}, + {Team::TEAM_7, "Team 7"}, {Team::TEAM_8, "Team 8"}, {Team::TEAM_9, "Team 9"}, + {Team::GENERAL, "General"}}; /** * @brief Converts Team enum to string @@ -280,15 +272,13 @@ class Logger { } }; - - #else #define LOGLINE "" #define LOG_RELLINE "" #define LOG_FNC "" -//#define log Log() +// #define log Log() class Logger { public: @@ -297,20 +287,17 @@ class Logger { return *this; } - Logger &operator<<(std::ostream &(* /*manipulator*/)(std::ostream &)) { - return *this; - } + Logger &operator<<(std::ostream &(* /*manipulator*/)(std::ostream &)) { return *this; } static std::ostream &endl(std::ostream &os) { return os; } - static Logger& Log() { - static Logger instance; // Guaranteed to be initialized only once. + static Logger &Log() { + static Logger instance; // Guaranteed to be initialized only once. return instance; } - }; -//Logger Logger::log; +// Logger Logger::log; #endif } // namespace clogged diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index 01dd5f2c..e039d0fe 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -6,15 +6,15 @@ #pragma once +#include #include +#include #include #include #include -#include -#include -#include "GridPosition.hpp" #include "Data.hpp" +#include "GridPosition.hpp" namespace cse491 { @@ -22,143 +22,157 @@ class WorldBase; class Entity { private: - WorldBase * world_ptr = nullptr; ///< Track the world this entity is in (private to protect pointer) + WorldBase *world_ptr = + nullptr; ///< Track the world this entity is in (private to protect pointer) protected: - const size_t id=0; ///< Unique ID for this entity (zero is use for "no ID") - std::string name = ""; ///< Name for this entity (E.g., "Player 1" or "+2 Sword") - GridPosition position; ///< Where on the grid is this entity? - - std::vector inventory; - - struct PropertyBase { - virtual ~PropertyBase() { } - }; - - template - struct Property : public PropertyBase { - T value; - Property(const T & in) : value(in) { } - Property(T && in) : value(in) { } - }; - - /// Every entity can have a simple set of properties (with values) associated with it. - std::unordered_map> property_map; - std::unordered_map property_type_map; - - // -- Helper Functions -- - - template - Property & AsProperty(const std::string & name) const { - assert( HasProperty(name) ); - PropertyBase * raw_ptr = property_map.at(name).get(); - assert( dynamic_cast *>(raw_ptr) ); - auto property_ptr = static_cast *>(raw_ptr); - return *property_ptr; - } - - public: - Entity(size_t id, const std::string & name) : id(id), name(name) { } - Entity(const Entity &) = delete; // Entities must be unique and shouldn't be copied. - Entity(Entity &&) = default; - virtual ~Entity() = default; + const size_t id = 0; ///< Unique ID for this entity (zero is use for "no ID") + std::string name = ""; ///< Name for this entity (E.g., "Player 1" or "+2 Sword") + GridPosition position; ///< Where on the grid is this entity? - Entity & operator=(const Entity &) = delete; // Entities must be unique and shouldn't be copied. - Entity & operator=(Entity &&) = delete; // Entities should never have IDs change. - - // -- Accessors -- - [[nodiscard]] size_t GetID() const { return id; } - [[nodiscard]] const std::string & GetName() const { return name; } - [[nodiscard]] GridPosition GetPosition() const { return position; } - [[nodiscard]] WorldBase & GetWorld() const { assert(world_ptr); return *world_ptr; } - - [[nodiscard]] bool HasWorld() const { return world_ptr != nullptr;} - Entity & SetName(const std::string in_name) { name = in_name; return *this; } - Entity & SetPosition(GridPosition in_pos, size_t grid_id=0); - Entity & SetPosition(double x, double y) { position = GridPosition{x,y}; return *this; } - virtual Entity & SetWorld(WorldBase & in_world) { world_ptr = &in_world; return *this; } - - virtual bool IsAgent() const { return false; } ///< Is Entity an autonomous agent? - virtual bool IsItem() const { return false; } ///< Is Entity an item? - virtual bool IsInterface() const { return false; } ///< Is Entity an interface for a human? - - - // -- Property Management -- - - /// Does this agent have a property with the specified name? - [[nodiscard]] bool HasProperty(const std::string & name) const { - return property_map.count(name); - } - - /// Return the current value of the specified property. - template - [[nodiscard]] const T & GetProperty(const std::string & name) const { - assert(HasProperty(name)); // Break if property does not already exist. - return AsProperty(name).value; - } + std::vector inventory; - [[nodiscard]] PropertyType GetPropertyType(const std::string &key) const { - return property_type_map.at(key); - } - - template - void SetPropertyType(const std::string & name) { - if (std::is_same::value) property_type_map[name] = PropertyType::t_double; - else if (std::is_same::value) property_type_map[name] = PropertyType::t_int; - else if (std::is_same::value) property_type_map[name] = PropertyType::t_char; - else if (std::is_same::value) property_type_map[name] = PropertyType::t_string; - else property_type_map[name] = PropertyType::t_other; - } - - /// Change the value of the specified property (will create if needed) - template - Entity & SetProperty(const std::string & name, const T & value) { - if (HasProperty(name)) { - AsProperty(name).value = value; - } else { - property_map[name] = std::make_unique>(value); - SetPropertyType(name); - } - return *this; - } - - /// Allow for setting multiple properties at once. - Entity & SetProperties() { return *this; } - - template - Entity & SetProperties(const std::string & name, VALUE_T && value, EXTRA_Ts &&... extras) { - SetProperty(name, std::forward(value)); // Set the first property... - return SetProperties(std::forward(extras)...); // And any additional properties... - } + struct PropertyBase { + virtual ~PropertyBase() {} + }; - /// Completely remove a property from an Entity. - Entity & RemoveProperty(const std::string & name) { - property_map.erase(name); - property_type_map.erase(name); - return *this; - } + template + struct Property : public PropertyBase { + T value; + Property(const T &in) : value(in) {} + Property(T &&in) : value(in) {} + }; + /// Every entity can have a simple set of properties (with values) associated with it. + std::unordered_map> property_map; + std::unordered_map property_type_map; - /// return the property map for the entity - std::unordered_map> & GetProprtyMap() { return property_map; } + // -- Helper Functions -- + template + Property &AsProperty(const std::string &name) const { + assert(HasProperty(name)); + PropertyBase *raw_ptr = property_map.at(name).get(); + assert(dynamic_cast *>(raw_ptr)); + auto property_ptr = static_cast *>(raw_ptr); + return *property_ptr; + } - /// Inventory Management - bool HasItem(size_t id) const { - return std::find(inventory.begin(), inventory.end(), id) != inventory.end(); + public: + Entity(size_t id, const std::string &name) : id(id), name(name) {} + Entity(const Entity &) = delete; // Entities must be unique and shouldn't be copied. + Entity(Entity &&) = default; + virtual ~Entity() = default; + + Entity &operator=(const Entity &) = delete; // Entities must be unique and shouldn't be copied. + Entity &operator=(Entity &&) = delete; // Entities should never have IDs change. + + // -- Accessors -- + [[nodiscard]] size_t GetID() const { return id; } + [[nodiscard]] const std::string &GetName() const { return name; } + [[nodiscard]] GridPosition GetPosition() const { return position; } + [[nodiscard]] WorldBase &GetWorld() const { + assert(world_ptr); + return *world_ptr; + } + + [[nodiscard]] bool HasWorld() const { return world_ptr != nullptr; } + Entity &SetName(const std::string in_name) { + name = in_name; + return *this; + } + Entity &SetPosition(GridPosition in_pos, size_t grid_id = 0); + Entity &SetPosition(double x, double y) { + position = GridPosition{x, y}; + return *this; + } + virtual Entity &SetWorld(WorldBase &in_world) { + world_ptr = &in_world; + return *this; + } + + virtual bool IsAgent() const { return false; } ///< Is Entity an autonomous agent? + virtual bool IsItem() const { return false; } ///< Is Entity an item? + virtual bool IsInterface() const { return false; } ///< Is Entity an interface for a human? + + // -- Property Management -- + + /// Does this agent have a property with the specified name? + [[nodiscard]] bool HasProperty(const std::string &name) const { return property_map.count(name); } + + /// Return the current value of the specified property. + template + [[nodiscard]] const T &GetProperty(const std::string &name) const { + assert(HasProperty(name)); // Break if property does not already exist. + return AsProperty(name).value; + } + + [[nodiscard]] PropertyType GetPropertyType(const std::string &key) const { + return property_type_map.at(key); + } + + template + void SetPropertyType(const std::string &name) { + if (std::is_same::value) + property_type_map[name] = PropertyType::t_double; + else if (std::is_same::value) + property_type_map[name] = PropertyType::t_int; + else if (std::is_same::value) + property_type_map[name] = PropertyType::t_char; + else if (std::is_same::value) + property_type_map[name] = PropertyType::t_string; + else + property_type_map[name] = PropertyType::t_other; + } + + /// Change the value of the specified property (will create if needed) + template + Entity &SetProperty(const std::string &name, const T &value) { + if (HasProperty(name)) { + AsProperty(name).value = value; + } else { + property_map[name] = std::make_unique>(value); + SetPropertyType(name); } - - Entity & AddItem(size_t id); - Entity & AddItem(Entity & item) { return AddItem(item.GetID()); } - - Entity & RemoveItem(size_t id); - Entity & RemoveItem(Entity & item) { return RemoveItem(item.GetID()); } - - /// @brief Serialize entity (pure virtual) - /// @param ostream - virtual void Serialize(std::ostream &os) = 0; - - [[nodiscard]] std::vector GetInventory() const { return inventory; } - - }; -} // End of namespace cse491 + return *this; + } + + /// Allow for setting multiple properties at once. + Entity &SetProperties() { return *this; } + + template + Entity &SetProperties(const std::string &name, VALUE_T &&value, EXTRA_Ts &&...extras) { + SetProperty(name, std::forward(value)); // Set the first property... + return SetProperties(std::forward(extras)...); // And any additional properties... + } + + /// Completely remove a property from an Entity. + Entity &RemoveProperty(const std::string &name) { + property_map.erase(name); + property_type_map.erase(name); + return *this; + } + + /// return the property map for the entity + std::unordered_map> &GetProprtyMap() { + return property_map; + } + + /// Inventory Management + bool HasItem(size_t id) const { + return std::find(inventory.begin(), inventory.end(), id) != inventory.end(); + } + + Entity &AddItem(size_t id); + Entity &AddItem(Entity &item) { return AddItem(item.GetID()); } + + Entity &RemoveItem(size_t id); + Entity &RemoveItem(Entity &item) { return RemoveItem(item.GetID()); } + + /// @brief Serialize entity (pure virtual) + /// @param ostream + virtual void Serialize(std::ostream &os) = 0; + + [[nodiscard]] std::vector GetInventory() const { return inventory; } +}; +} // End of namespace cse491 diff --git a/source/core/GridPosition.hpp b/source/core/GridPosition.hpp index e398cbce..d6f9bbfd 100644 --- a/source/core/GridPosition.hpp +++ b/source/core/GridPosition.hpp @@ -4,13 +4,12 @@ * @note Status: PROPOSAL **/ - #pragma once #include -#include // For operator<=> -#include // For size_t -#include // For sqrt and std::nan() +#include // For sqrt and std::nan() +#include // For operator<=> +#include // For size_t namespace cse491 { @@ -21,90 +20,93 @@ namespace cse491 { /// a grid), but is easily converted to size_t for grid-cell identification. class GridPosition { private: - double x = 0.0; - double y = 0.0; + double x = 0.0; + double y = 0.0; public: - GridPosition() = default; - GridPosition(double x, double y) : x(x), y(y) { } - GridPosition(const GridPosition &) = default; + GridPosition() = default; + GridPosition(double x, double y) : x(x), y(y) {} + GridPosition(const GridPosition &) = default; - ~GridPosition() = default; + ~GridPosition() = default; - GridPosition & operator=(const GridPosition &) = default; + GridPosition &operator=(const GridPosition &) = default; - // -- Accessors -- + // -- Accessors -- - [[nodiscard]] double GetX() const { return x; } - [[nodiscard]] double GetY() const { return y; } - [[nodiscard]] size_t CellX() const { return static_cast(x); } - [[nodiscard]] size_t CellY() const { return static_cast(y); } + [[nodiscard]] double GetX() const { return x; } + [[nodiscard]] double GetY() const { return y; } + [[nodiscard]] size_t CellX() const { return static_cast(x); } + [[nodiscard]] size_t CellY() const { return static_cast(y); } - /// Enable all comparison operators (==, !=, <, <=, >, >=) - auto operator<=>(const GridPosition &) const = default; + /// Enable all comparison operators (==, !=, <, <=, >, >=) + auto operator<=>(const GridPosition &) const = default; - [[nodiscard]] bool IsValid() const { return !(std::isnan(x) || std::isnan(y)); } + [[nodiscard]] bool IsValid() const { return !(std::isnan(x) || std::isnan(y)); } - // -- Modifiers -- + // -- Modifiers -- - GridPosition & Set(double in_x, double in_y) { - x=in_x; y=in_y; - return *this; - } - GridPosition & Shift(double shift_x, double shift_y) { - x += shift_x; y += shift_y; - return *this; - } + GridPosition &Set(double in_x, double in_y) { + x = in_x; + y = in_y; + return *this; + } + GridPosition &Shift(double shift_x, double shift_y) { + x += shift_x; + y += shift_y; + return *this; + } - GridPosition & operator+=(const GridPosition & in) { return Shift(in.x, in.y); } - GridPosition & operator-=(const GridPosition & in) { return Shift(-in.x, -in.y); } + GridPosition &operator+=(const GridPosition &in) { return Shift(in.x, in.y); } + GridPosition &operator-=(const GridPosition &in) { return Shift(-in.x, -in.y); } - GridPosition & MakeInvalid() { x = y = std::nan("NAN(0)"); return *this; } + GridPosition &MakeInvalid() { + x = y = std::nan("NAN(0)"); + return *this; + } - // -- Const Operations -- + // -- Const Operations -- - /// Return a the GridPosition at the requested offset. - [[nodiscard]] GridPosition GetOffset(double offset_x, double offset_y) const { - return GridPosition{x+offset_x,y+offset_y}; - } + /// Return a the GridPosition at the requested offset. + [[nodiscard]] GridPosition GetOffset(double offset_x, double offset_y) const { + return GridPosition{x + offset_x, y + offset_y}; + } - /// Return a grid position above this one (by default, directly above) - [[nodiscard]] GridPosition Above(double dist=1.0) const { return GetOffset(0.0, -dist); } + /// Return a grid position above this one (by default, directly above) + [[nodiscard]] GridPosition Above(double dist = 1.0) const { return GetOffset(0.0, -dist); } - /// Return a grid position below this one (by default, directly below) - [[nodiscard]] GridPosition Below(double dist=1.0) const { return GetOffset(0.0, dist); } + /// Return a grid position below this one (by default, directly below) + [[nodiscard]] GridPosition Below(double dist = 1.0) const { return GetOffset(0.0, dist); } - /// Return a grid position to the left of this one (by default, directly left) - [[nodiscard]] GridPosition ToLeft(double dist=1.0) const { return GetOffset(-dist, 0.0); } + /// Return a grid position to the left of this one (by default, directly left) + [[nodiscard]] GridPosition ToLeft(double dist = 1.0) const { return GetOffset(-dist, 0.0); } - /// Return a grid position to the right of this one (by default, directly right) - [[nodiscard]] GridPosition ToRight(double dist=1.0) const { return GetOffset(dist, 0.0); } + /// Return a grid position to the right of this one (by default, directly right) + [[nodiscard]] GridPosition ToRight(double dist = 1.0) const { return GetOffset(dist, 0.0); } - /// Add together two grid positions and return the result. - [[nodiscard]] GridPosition operator+(GridPosition in) const { - return GetOffset(in.x, in.y); - } + /// Add together two grid positions and return the result. + [[nodiscard]] GridPosition operator+(GridPosition in) const { return GetOffset(in.x, in.y); } - [[nodiscard]] double Distance(GridPosition pos2) const { - const double dist1 = x - pos2.x; - const double dist2 = y - pos2.y; - return sqrt(dist1*dist1 + dist2*dist2); - } + [[nodiscard]] double Distance(GridPosition pos2) const { + const double dist1 = x - pos2.x; + const double dist2 = y - pos2.y; + return sqrt(dist1 * dist1 + dist2 * dist2); + } - /// @brief Manhattan distance between grid positions - /// @param pos2 Position to compare to - /// @return Manhattan distance - [[nodiscard]] double MDistance(GridPosition pos2) const { - const double dist1 = x - pos2.x; - const double dist2 = y - pos2.y; - return abs(dist1) + abs(dist2); - } + /// @brief Manhattan distance between grid positions + /// @param pos2 Position to compare to + /// @return Manhattan distance + [[nodiscard]] double MDistance(GridPosition pos2) const { + const double dist1 = x - pos2.x; + const double dist2 = y - pos2.y; + return abs(dist1) + abs(dist2); + } - [[nodiscard]] bool IsNear(GridPosition pos2, double max_dist=1.0) const { - const double dist1 = x - pos2.x; - const double dist2 = y - pos2.y; - return (dist1*dist1 + dist2*dist2) <= (max_dist * max_dist); - } + [[nodiscard]] bool IsNear(GridPosition pos2, double max_dist = 1.0) const { + const double dist1 = x - pos2.x; + const double dist2 = y - pos2.y; + return (dist1 * dist1 + dist2 * dist2) <= (max_dist * max_dist); + } }; -} // End of namespace cse491 +} // End of namespace cse491 diff --git a/source/core/InterfaceBase.hpp b/source/core/InterfaceBase.hpp index 0f977986..fee7f647 100644 --- a/source/core/InterfaceBase.hpp +++ b/source/core/InterfaceBase.hpp @@ -8,46 +8,42 @@ #include +#include "../DataCollection/DataManager.hpp" #include "AgentBase.hpp" #include "ItemBase.hpp" -#include "../DataCollection/DataManager.hpp" namespace cse491 { - class InterfaceBase : public AgentBase { - protected: - static void exitCleanup() - { - DataCollection::DataManager::GetInstance().WriteToJson(); - exit(0); - } - - - public: - InterfaceBase(size_t id, const std::string & name) : AgentBase(id, name) { } - ~InterfaceBase() = default; // Already virtual from Entity - - // -- Entity Overrides -- +class InterfaceBase : public AgentBase { + protected: + static void exitCleanup() { + DataCollection::DataManager::GetInstance().WriteToJson(); + exit(0); + } - bool IsInterface() const override { return true; } + public: + InterfaceBase(size_t id, const std::string& name) : AgentBase(id, name) {} + ~InterfaceBase() = default; // Already virtual from Entity + // -- Entity Overrides -- - // -- AgentBase overrides -- - // - // Multiple functions defined as virtual in AgentBase can also be overridden from - // custom Interfaces. Specific available function to override include: + bool IsInterface() const override { return true; } - // bool Initialize() { return true; } - // - // Initialize is run AFTER the world configures the interface with actions, etc, allowing - // for additional setup, such as targeted buttons. + // -- AgentBase overrides -- + // + // Multiple functions defined as virtual in AgentBase can also be overridden from + // custom Interfaces. Specific available function to override include: + // bool Initialize() { return true; } + // + // Initialize is run AFTER the world configures the interface with actions, etc, allowing + // for additional setup, such as targeted buttons. - // size_t SelectAction([[maybe_unused]] const WorldGrid & grid) { return 0; } - // - // SelectAction is run when the world is given the player an opportunity to choose - // and action to perform. The interface will be provided with the current WorldGrid - // Return the ID associated with the action to perform; (zero is always "no action") - }; + // size_t SelectAction([[maybe_unused]] const WorldGrid & grid) { return 0; } + // + // SelectAction is run when the world is given the player an opportunity to choose + // and action to perform. The interface will be provided with the current WorldGrid + // Return the ID associated with the action to perform; (zero is always "no action") +}; -} // End of namespace cse491 +} // End of namespace cse491 diff --git a/source/core/ItemBase.hpp b/source/core/ItemBase.hpp index 26993f59..913a9843 100644 --- a/source/core/ItemBase.hpp +++ b/source/core/ItemBase.hpp @@ -15,118 +15,122 @@ namespace cse491 { - class ItemBase : public Entity { - protected: - enum OwnerType { NONE=0, GRID, ITEM, AGENT }; - OwnerType owner_type = OwnerType::NONE; - size_t owner_id = 0; - - public: - ItemBase(size_t id, const std::string & name) : Entity(id, name) { } - ~ItemBase() = default; // Already virtual from Entity - - // -- Entity Overrides -- - - bool IsItem() const override { return true; } - - // -- Ownership Info -- - [[nodiscard]] bool IsOnGrid() const { return owner_type == OwnerType::GRID; } - [[nodiscard]] bool IsOwnedByItem() const { return owner_type == OwnerType::ITEM; } - [[nodiscard]] bool IsOwnedByAgent() const { return owner_type == OwnerType::AGENT; } - [[nodiscard]] bool IsOwned() const { return IsOwnedByItem() || IsOwnedByAgent(); } - [[nodiscard]] bool IsOnGrid(size_t grid_id) const { - return IsOnGrid() && owner_id == grid_id; - } - [[nodiscard]] bool IsOwnedByItem(size_t item_id) const { - return IsOwnedByItem() && owner_id == item_id; - } - [[nodiscard]] bool IsOwnedByAgent(size_t agent_id) const { - return IsOwnedByAgent() && owner_id == agent_id; - } - [[nodiscard]] bool IsOwnedBy(size_t entity_id) const { - return IsOwned() && owner_id == entity_id; - } - [[nodiscard]] size_t GetOwnerID() const { return owner_id; } - - /// @brief Identify the entity (item or agent) that now owns this item. - /// @param owner The new owning entity. - /// @return A reference to this item. - ItemBase & SetOwner(const Entity & owner) { - if (owner.IsItem()) owner_type = OwnerType::ITEM; - else if (owner.IsAgent()) owner_type = OwnerType::AGENT; - else owner_type = OwnerType::NONE; // Error? - owner_id = owner.GetID(); - position.MakeInvalid(); - return *this; - } - - ItemBase & SetGrid(size_t grid_id=0) { - owner_type = OwnerType::GRID; - owner_id = grid_id; - return *this; - } - ItemBase & SetUnowned() { owner_type = OwnerType::NONE; return *this; } - - /// @brief Serialize item - /// @param ostream - void Serialize(std::ostream &os) override { - os << name << '\n'; - os << position.GetX() << '\n'; - os << position.GetY() << '\n'; - os << property_map.size() << '\n'; - for (const auto & property : property_map) { - os << property.first << '\n'; - - // Get property type - PropertyType type = GetPropertyType(property.first); - os << static_cast(type) << '\n'; - - // serialize property value - if (type == PropertyType::t_double) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_int) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_char) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_string) { - os << AsProperty(property.first).value << '\n'; - } else { - // unknown type, do nothing - os << '\n'; - } +class ItemBase : public Entity { + protected: + enum OwnerType { NONE = 0, GRID, ITEM, AGENT }; + OwnerType owner_type = OwnerType::NONE; + size_t owner_id = 0; + + public: + ItemBase(size_t id, const std::string &name) : Entity(id, name) {} + ~ItemBase() = default; // Already virtual from Entity + + // -- Entity Overrides -- + + bool IsItem() const override { return true; } + + // -- Ownership Info -- + [[nodiscard]] bool IsOnGrid() const { return owner_type == OwnerType::GRID; } + [[nodiscard]] bool IsOwnedByItem() const { return owner_type == OwnerType::ITEM; } + [[nodiscard]] bool IsOwnedByAgent() const { return owner_type == OwnerType::AGENT; } + [[nodiscard]] bool IsOwned() const { return IsOwnedByItem() || IsOwnedByAgent(); } + [[nodiscard]] bool IsOnGrid(size_t grid_id) const { return IsOnGrid() && owner_id == grid_id; } + [[nodiscard]] bool IsOwnedByItem(size_t item_id) const { + return IsOwnedByItem() && owner_id == item_id; + } + [[nodiscard]] bool IsOwnedByAgent(size_t agent_id) const { + return IsOwnedByAgent() && owner_id == agent_id; + } + [[nodiscard]] bool IsOwnedBy(size_t entity_id) const { + return IsOwned() && owner_id == entity_id; + } + [[nodiscard]] size_t GetOwnerID() const { return owner_id; } + + /// @brief Identify the entity (item or agent) that now owns this item. + /// @param owner The new owning entity. + /// @return A reference to this item. + ItemBase &SetOwner(const Entity &owner) { + if (owner.IsItem()) + owner_type = OwnerType::ITEM; + else if (owner.IsAgent()) + owner_type = OwnerType::AGENT; + else + owner_type = OwnerType::NONE; // Error? + owner_id = owner.GetID(); + position.MakeInvalid(); + return *this; + } + + ItemBase &SetGrid(size_t grid_id = 0) { + owner_type = OwnerType::GRID; + owner_id = grid_id; + return *this; + } + ItemBase &SetUnowned() { + owner_type = OwnerType::NONE; + return *this; + } + + /// @brief Serialize item + /// @param ostream + void Serialize(std::ostream &os) override { + os << name << '\n'; + os << position.GetX() << '\n'; + os << position.GetY() << '\n'; + os << property_map.size() << '\n'; + for (const auto &property : property_map) { + os << property.first << '\n'; + + // Get property type + PropertyType type = GetPropertyType(property.first); + os << static_cast(type) << '\n'; + + // serialize property value + if (type == PropertyType::t_double) { + os << AsProperty(property.first).value << '\n'; + } else if (type == PropertyType::t_int) { + os << AsProperty(property.first).value << '\n'; + } else if (type == PropertyType::t_char) { + os << AsProperty(property.first).value << '\n'; + } else if (type == PropertyType::t_string) { + os << AsProperty(property.first).value << '\n'; + } else { + // unknown type, do nothing + os << '\n'; } } - - /// @brief Deserialize item - /// @param istream - void Deserialize(std::istream &is) { - std::string x_str, y_str; - std::getline(is, name, '\n'); - std::getline(is, x_str, '\n'); - std::getline(is, y_str, '\n'); - position.Set(stoi(x_str), stoi(y_str)); - - std::string property, type_str, value_str; + } + + /// @brief Deserialize item + /// @param istream + void Deserialize(std::istream &is) { + std::string x_str, y_str; + std::getline(is, name, '\n'); + std::getline(is, x_str, '\n'); + std::getline(is, y_str, '\n'); + position.Set(stoi(x_str), stoi(y_str)); + + std::string property, type_str, value_str; + std::getline(is, property, '\n'); + int num_properties = stoi(property); + for (int i = 0; i < num_properties; i++) { std::getline(is, property, '\n'); - int num_properties = stoi(property); - for (int i = 0; i < num_properties; i++) { - std::getline(is, property, '\n'); - std::getline(is, type_str, '\n'); - std::getline(is, value_str, '\n'); - - // Set property based on type - auto type = static_cast(stoi(type_str)); - if (type == PropertyType::t_double) { - SetProperty(property, stod(value_str)); - } else if (type == PropertyType::t_int) { - SetProperty(property, stoi(value_str)); - } else if (type == PropertyType::t_char) { - SetProperty(property, value_str[0]); - } else if (type == PropertyType::t_string) { - SetProperty(property, value_str); - } + std::getline(is, type_str, '\n'); + std::getline(is, value_str, '\n'); + + // Set property based on type + auto type = static_cast(stoi(type_str)); + if (type == PropertyType::t_double) { + SetProperty(property, stod(value_str)); + } else if (type == PropertyType::t_int) { + SetProperty(property, stoi(value_str)); + } else if (type == PropertyType::t_char) { + SetProperty(property, value_str[0]); + } else if (type == PropertyType::t_string) { + SetProperty(property, value_str); } } - }; + } +}; -} // End of namespace cse491 +} // End of namespace cse491 diff --git a/source/core/WorldBase.hpp b/source/core/WorldBase.hpp index 2993cf0e..92c9f0ad 100644 --- a/source/core/WorldBase.hpp +++ b/source/core/WorldBase.hpp @@ -11,63 +11,62 @@ #include #include #include +#include #include #include -#include #include "../DataCollection/AgentReciever.hpp" #include "AgentBase.hpp" #include "Data.hpp" -#include "ItemBase.hpp" -#include "WorldGrid.hpp" -#include "../DataCollection/AgentReciever.hpp" #include "DataCollection/DataManager.hpp" -#include "Interfaces/NetWorth/server/ServerManager.hpp" +#include "Interfaces/NetWorth/client/ClientInterface.hpp" #include "Interfaces/NetWorth/client/ClientManager.hpp" #include "Interfaces/NetWorth/client/ControlledAgent.hpp" -#include "Interfaces/NetWorth/client/ClientInterface.hpp" +#include "Interfaces/NetWorth/server/ServerManager.hpp" +#include "ItemBase.hpp" +#include "WorldGrid.hpp" // Forward declaration -namespace worldlang{ - class ProgramExecutor; +namespace worldlang { +class ProgramExecutor; } namespace cse491 { class DataReceiver; class WorldBase { -public: + public: static constexpr size_t npos = static_cast(-1); - netWorth::ServerManager *server_manager = nullptr; /// Server manager for world if used - netWorth::ClientManager *client_manager = nullptr; /// Client manager for world if used + netWorth::ServerManager *server_manager = nullptr; /// Server manager for world if used + netWorth::ClientManager *client_manager = nullptr; /// Client manager for world if used /// Helper function that is run whenever a new agent is created. /// @note Override this function to provide agents with actions or other /// setup. virtual void ConfigAgent(AgentBase & /* agent */) const {} -protected: + protected: /// Derived worlds may choose to have more than one grid. std::unordered_map grids; - WorldGrid &main_grid; ///< Main grid for this world; shortcut to `grids["main"]` - type_options_t type_options; ///< Vector of types of cells in grids for this world. + WorldGrid &main_grid; ///< Main grid for this world; shortcut to `grids["main"]` + type_options_t type_options; ///< Vector of types of cells in grids for this world. - item_map_t item_map; ///< Map of IDs to pointers to non-agent entities - agent_map_t agent_map; ///< Map of IDs to pointers to agent entities - size_t last_entity_id = 0; ///< The last Entity ID used; increment at each creation + item_map_t item_map; ///< Map of IDs to pointers to non-agent entities + agent_map_t agent_map; ///< Map of IDs to pointers to agent entities + size_t last_entity_id = 0; ///< The last Entity ID used; increment at each creation - bool run_over = false; ///< Should the run end? + bool run_over = false; ///< Should the run end? - bool world_running = true; ///< Is the world currently running? + bool world_running = true; ///< Is the world currently running? - std::string action; ///< The action that the agent is currently performing + std::string action; ///< The action that the agent is currently performing std::shared_ptr agent_receiver; - unsigned int seed; ///< Seed used for generator - std::mt19937 random_gen; ///< Random number generator - std::uniform_real_distribution<> uni_dist; ///< Uniform distribution of doubles, 0 to 1 - std::normal_distribution<> norm_dist; ///< Normal distribution; mean 0, std 1 + unsigned int seed; ///< Seed used for generator + std::mt19937 random_gen; ///< Random number generator + std::uniform_real_distribution<> uni_dist; ///< Uniform distribution of doubles, 0 to 1 + std::normal_distribution<> norm_dist; ///< Normal distribution; mean 0, std 1 /// Helper function to set the next entity id. size_t NextEntityID() { return ++last_entity_id; } @@ -83,25 +82,22 @@ class WorldBase { /// line) /// @return A unique ID associated with this cell type (position in /// type_options vector) - size_t AddCellType(const std::string &name, const std::string &desc = "", - char symbol = '\0') { + size_t AddCellType(const std::string &name, const std::string &desc = "", char symbol = '\0') { type_options.push_back(CellType{name, desc, symbol}); return type_options.size() - 1; } -public: + public: /// Initializes world with cell types and random generator /// @param seed Seed used for RNG. Use 0 for a non-deterministic result. - WorldBase(unsigned int seed=0) - : grids(), main_grid(grids[0]), seed(seed) - { + WorldBase(unsigned int seed = 0) : grids(), main_grid(grids[0]), seed(seed) { // The first cell type (ID 0) should be reserved for errors or empty spots in a grid. AddCellType("Unknown", "This is an invalid cell type and should not be reachable."); // Initialize the random number generator. if (seed == 0) { - std::random_device rd; // An expensive "true" random number generator. - seed = rd(); // Change the seed to a random value. + std::random_device rd; // An expensive "true" random number generator. + seed = rd(); // Change the seed to a random value. } random_gen.seed(seed); } @@ -130,40 +126,40 @@ class WorldBase { [[nodiscard]] bool HasAgent(size_t id) const { return agent_map.count(id); } /// Return a reference to an agent with a given ID. - [[nodiscard]] ItemBase & GetItem(size_t id) { + [[nodiscard]] ItemBase &GetItem(size_t id) { assert(HasItem(id)); return *item_map[id]; } /// Return a reference to an agent with a given ID. - [[nodiscard]] AgentBase & GetAgent(size_t id) { + [[nodiscard]] AgentBase &GetAgent(size_t id) { assert(HasAgent(id)); return *agent_map[id]; } /// Return the ID of an item with a given name. - [[nodiscard]] size_t GetItemID(const std::string & name) { - for (auto & [id, ptr] : item_map) { + [[nodiscard]] size_t GetItemID(const std::string &name) { + for (auto &[id, ptr] : item_map) { if (ptr->GetName() == name) return id; } return npos; } /// Return the ID of an agent with a given name. - [[nodiscard]] size_t GetAgentID(const std::string & name) { - for (auto & [id, ptr] : agent_map) { + [[nodiscard]] size_t GetAgentID(const std::string &name) { + for (auto &[id, ptr] : agent_map) { if (ptr->GetName() == name) return id; } return npos; } /// Return an editable version of the current grid for this world (main_grid by default) - virtual WorldGrid & GetGrid() { return main_grid; } - virtual WorldGrid & GetGrid(size_t grid_id) { return grids[grid_id]; } + virtual WorldGrid &GetGrid() { return main_grid; } + virtual WorldGrid &GetGrid(size_t grid_id) { return grids[grid_id]; } /// Return a const grid for this world (main_grid by default) - virtual const WorldGrid & GetGrid() const { return main_grid; } - virtual const WorldGrid & GetGrid(size_t grid_id) const { return grids.at(grid_id); } + virtual const WorldGrid &GetGrid() const { return main_grid; } + virtual const WorldGrid &GetGrid(size_t grid_id) const { return grids.at(grid_id); } /// Determine if the run has ended. virtual bool GetRunOver() const { return run_over; } @@ -203,8 +199,8 @@ class WorldBase { /// @param agent_name The name of this agent /// @param properties Name/value pairs for any properties set at creation /// @return A reference to the newly created agent - template - AgentBase & AddAgent(std::string agent_name = "None", PROPERTY_Ts... properties) { + template + AgentBase &AddAgent(std::string agent_name = "None", PROPERTY_Ts... properties) { std::mutex agent_map_lock; agent_map_lock.lock(); const size_t agent_id = NextEntityID(); @@ -213,18 +209,17 @@ class WorldBase { agent_ptr->SetProperties(std::forward(properties)...); ConfigAgent(*agent_ptr); if (agent_ptr->Initialize() == false) { - std::cerr << "Failed to initialize agent '" << agent_name << "'." - << std::endl; + std::cerr << "Failed to initialize agent '" << agent_name << "'." << std::endl; } agent_map[agent_id] = std::move(agent_ptr); - AgentBase & agentReturn = *agent_map[agent_id]; - agent_map_lock.unlock(); + AgentBase &agentReturn = *agent_map[agent_id]; + agent_map_lock.unlock(); return agentReturn; } /// @brief Add a new, already-built item /// @return A reference to the newly created item - ItemBase & AddItem(std::unique_ptr item_ptr) { + ItemBase &AddItem(std::unique_ptr item_ptr) { assert(item_ptr); // item_ptr must not be null. assert(item_ptr->GetID() != 0); // item_ptr must have had a non-zero ID assigned. item_ptr->SetWorld(*this); @@ -238,8 +233,8 @@ class WorldBase { /// @param item_name The name of this item /// @param properties Name/value pairs for any properties set at creation /// @return A reference to the newly created item - template - ItemBase & AddItem(std::string item_name="None", PROPERTY_Ts... properties) { + template + ItemBase &AddItem(std::string item_name = "None", PROPERTY_Ts... properties) { auto item_ptr = std::make_unique(NextEntityID(), item_name); item_ptr->SetProperties(std::forward(properties)...); return AddItem(std::move(item_ptr)); @@ -248,7 +243,7 @@ class WorldBase { /// @brief Remove an agent from the agent map /// @param agent_id The unique ID this agent /// @return A reference to this world. - WorldBase & RemoveAgent(size_t agent_id) { + WorldBase &RemoveAgent(size_t agent_id) { agent_map.erase(agent_id); return *this; } @@ -256,27 +251,25 @@ class WorldBase { /// @brief Remove an item from the item map /// @param item_id The unique ID this item /// @return A reference to this world. - WorldBase & RemoveItem(size_t item_id) { + WorldBase &RemoveItem(size_t item_id) { item_map.erase(item_id); return *this; } - + /// @brief Remove an agent from the agent map by name /// @param agent_name The name of this agent /// @return This world WorldBase &RemoveAgent(std::string agent_name = "None") { - assert(agent_name != "Interface"); // We are not allowed to remove interfaces. + assert(agent_name != "Interface"); // We are not allowed to remove interfaces. return RemoveAgent(GetAgentID(agent_name)); } /// @brief Remove an item from the item map by name /// @param item_id The ID of this item /// @return This world - WorldBase &RemoveItem(std::string item_name) { - return RemoveItem(GetItemID(item_name)); - } - - WorldBase & AddItemToGrid(size_t item_id, GridPosition pos, size_t grid_id=0) { + WorldBase &RemoveItem(std::string item_name) { return RemoveItem(GetItemID(item_name)); } + + WorldBase &AddItemToGrid(size_t item_id, GridPosition pos, size_t grid_id = 0) { item_map[item_id]->SetPosition(pos, grid_id); return *this; } @@ -294,7 +287,7 @@ class WorldBase { /// @note Override this function if you want to control which grid the agents /// receive. virtual void RunAgents() { - for (auto & [id, agent_ptr] : agent_map) { + for (auto &[id, agent_ptr] : agent_map) { size_t action_id = agent_ptr->SelectAction(main_grid, type_options, item_map, agent_map); agent_ptr->storeActionMap(agent_ptr->GetName()); int result = DoAction(*agent_ptr, action_id); @@ -305,7 +298,7 @@ class WorldBase { /// @brief RunAgents, but with extra features for client-side /// @note Override this function if you want to control which grid the agents receive. virtual void RunClientAgents() { - for (auto & [id, agent_ptr] : agent_map) { + for (auto &[id, agent_ptr] : agent_map) { size_t action_id = agent_ptr->SelectAction(main_grid, type_options, item_map, agent_map); agent_ptr->storeActionMap(agent_ptr->GetName()); int result = DoAction(*agent_ptr, action_id); @@ -325,13 +318,14 @@ class WorldBase { virtual void RunServerAgents() { std::set to_delete; - for (auto & [id, agent_ptr] : agent_map) { + for (auto &[id, agent_ptr] : agent_map) { // wait until clients have connected to run - while (!server_manager->hasAgentsPresent()|| !world_running) {} + while (!server_manager->hasAgentsPresent() || !world_running) { + } // select action and send to client size_t action_id = agent_ptr->SelectAction(main_grid, type_options, item_map, agent_map); - server_manager->writeToActionMap(id, action_id); + server_manager->writeToActionMap(id, action_id); agent_ptr->storeActionMap(agent_ptr->GetName()); int result = DoAction(*agent_ptr, action_id); agent_ptr->SetActionResult(result); @@ -342,27 +336,25 @@ class WorldBase { // delete agents for (size_t id : to_delete) { - RemoveAgent(id); + RemoveAgent(id); } // send updates to client for deleted agents if (!to_delete.empty()) { - std::ostringstream os; - SerializeAgentSet(os); - std::string data = os.str(); - server_manager->setSerializedAgents(data); - server_manager->setNewAgent(true); - server_manager->sendGameUpdates(); + std::ostringstream os; + SerializeAgentSet(os); + std::string data = os.str(); + server_manager->setSerializedAgents(data); + server_manager->setNewAgent(true); + server_manager->sendGameUpdates(); } } void CollectData() { - for (const auto & [id, agent_ptr] : agent_map) { - DataCollection::DataManager::GetInstance().GetAgentReceiver().StoreData( - agent_ptr->GetName(), - agent_ptr->GetPosition(), agent_ptr->GetActionResult() - ); - } + for (const auto &[id, agent_ptr] : agent_map) { + DataCollection::DataManager::GetInstance().GetAgentReceiver().StoreData( + agent_ptr->GetName(), agent_ptr->GetPosition(), agent_ptr->GetActionResult()); + } } /// @brief UpdateWorld() is run after every agent has a turn. @@ -384,7 +376,7 @@ class WorldBase { run_over = false; client_manager = manager; while (!run_over) { - if (world_running){ + if (world_running) { RunClientAgents(); CollectData(); UpdateWorld(); @@ -397,7 +389,7 @@ class WorldBase { run_over = false; server_manager = manager; while (!run_over) { - if (world_running){ + if (world_running) { RunServerAgents(); CollectData(); UpdateWorld(); @@ -406,50 +398,43 @@ class WorldBase { } /// @brief Set if world is running or not for concurrency purposes - virtual void SetWorldRunning(bool running){ - world_running = running; - } + virtual void SetWorldRunning(bool running) { world_running = running; } // CellType management. // Return a const vector of all of the possible cell types. - [[nodiscard]] const type_options_t &GetCellTypes() const { - return type_options; - } + [[nodiscard]] const type_options_t &GetCellTypes() const { return type_options; } /// @brief Return the ID associated with the cell type name. /// @param name The unique name of the cell type /// @return The unique ID of the cell type (or 0 if it doesn't exist.) [[nodiscard]] size_t GetCellTypeID(const std::string &name) const { for (size_t i = 1; i < type_options.size(); ++i) { - if (type_options[i].name == name) - return i; + if (type_options[i].name == name) return i; } return 0; } [[nodiscard]] const std::string &GetCellTypeName(size_t id) const { - if (id >= type_options.size()) - return type_options[0].name; + if (id >= type_options.size()) return type_options[0].name; return type_options[id].name; } [[nodiscard]] char GetCellTypeSymbol(size_t id) const { - if (id >= type_options.size()) - return type_options[0].symbol; + if (id >= type_options.size()) return type_options[0].symbol; return type_options[id].symbol; } - // -- Grid Analysis Helpers -- /// @brief Lookup IDs for all items at a given grid position. /// @param pos Grid position to look up. /// @param grid_id ID of grid we are examining (default: main grid) /// @return A vector of item IDs at the target position. - [[nodiscard]] virtual std::vector FindItemsAt(GridPosition pos, size_t grid_id=0) const { + [[nodiscard]] virtual std::vector FindItemsAt(GridPosition pos, + size_t grid_id = 0) const { std::vector item_ids; - for (const auto & [id, item_ptr] : item_map) { + for (const auto &[id, item_ptr] : item_map) { if (item_ptr->IsOnGrid(grid_id) && item_ptr->GetPosition() == pos) item_ids.push_back(id); } return item_ids; @@ -458,9 +443,10 @@ class WorldBase { /// @brief Lookup IDs for all agents at a given grid position. /// @param pos Grid position to look up. /// @return A vector of agent IDs at the target position. - [[nodiscard]] virtual std::vector FindAgentsAt(GridPosition pos, size_t grid_id=0) const { + [[nodiscard]] virtual std::vector FindAgentsAt(GridPosition pos, + size_t grid_id = 0) const { std::vector agent_ids; - for (const auto & [id, agent_ptr] : agent_map) { + for (const auto &[id, agent_ptr] : agent_map) { if (agent_ptr->IsOnGrid(grid_id) && agent_ptr->GetPosition() == pos) agent_ids.push_back(id); } return agent_ids; @@ -470,9 +456,10 @@ class WorldBase { /// @param pos Grid position to look up. /// @param dist Maximum distance away from pos for an item to be included. /// @return A vector of item IDs within dist of the target position. - [[nodiscard]] virtual std::vector FindItemsNear(GridPosition pos, double dist=1.0, size_t grid_id=0) const { + [[nodiscard]] virtual std::vector FindItemsNear(GridPosition pos, double dist = 1.0, + size_t grid_id = 0) const { std::vector item_ids; - for (const auto & [id, item_ptr] : item_map) { + for (const auto &[id, item_ptr] : item_map) { if (item_ptr->IsOnGrid(grid_id) && item_ptr->GetPosition().IsNear(pos, dist)) { item_ids.push_back(id); } @@ -484,9 +471,10 @@ class WorldBase { /// @param pos Grid position to look up. /// @param dist Maximum distance away from pos for an agent to be included. /// @return A vector of agent IDs within dist of the target position. - [[nodiscard]] virtual std::vector FindAgentsNear(GridPosition pos, double dist=1.0, size_t grid_id=0) const { + [[nodiscard]] virtual std::vector FindAgentsNear(GridPosition pos, double dist = 1.0, + size_t grid_id = 0) const { std::vector agent_ids; - for (const auto & [id, agent_ptr] : agent_map) { + for (const auto &[id, agent_ptr] : agent_map) { if (agent_ptr->IsOnGrid(grid_id) && agent_ptr->GetPosition().IsNear(pos, dist)) { agent_ids.push_back(id); } @@ -498,7 +486,8 @@ class WorldBase { /// @author @mdkdoc15 /// @param pos The grid position we are checking /// @return If an agent should be allowed on this square - [[nodiscard]] virtual bool IsTraversable(const AgentBase & /*agent*/, cse491::GridPosition /*pos*/) const { + [[nodiscard]] virtual bool IsTraversable(const AgentBase & /*agent*/, + cse491::GridPosition /*pos*/) const { return true; } @@ -507,13 +496,13 @@ class WorldBase { /// @brief Serialize agent data into an ostream /// @param os ostream void SerializeAgentSet(std::ostream &os) { - os << ":::START agent_set\n"; - os << last_entity_id << '\n'; + os << ":::START agent_set\n"; + os << last_entity_id << '\n'; - for (const auto &agent: agent_map) { - agent.second->Serialize(os); - } - os << ":::END agent_set\n"; + for (const auto &agent : agent_map) { + agent.second->Serialize(os); + } + os << ":::END agent_set\n"; } /// @brief Add deserialized agents to world with a manager @@ -570,13 +559,15 @@ class WorldBase { // may be gaps between IDs id = stoi(id_string); - while (last_entity_id + 1 != id){ + while (last_entity_id + 1 != id) { last_entity_id++; } // is this new agent NOT the client interface if (last_entity_id + 1 != client_id) { - AddAgent(name, "manager", manager).SetPosition(stoi(x), stoi(y)).SetProperty("symbol", symbol_string[0]); + AddAgent(name, "manager", manager) + .SetPosition(stoi(x), stoi(y)) + .SetProperty("symbol", symbol_string[0]); } else { // client interface still exists; do nothing last_entity_id++; @@ -597,8 +588,8 @@ class WorldBase { os << ":::START item_set\n"; os << item_map.size() << '\n'; - for (const auto &item: item_map) { - item.second->Serialize(os); + for (const auto &item : item_map) { + item.second->Serialize(os); } os << ":::END item_set\n"; } @@ -654,4 +645,4 @@ class WorldBase { friend worldlang::ProgramExecutor; }; -} // End of namespace cse491 +} // End of namespace cse491 diff --git a/source/core/WorldGrid.hpp b/source/core/WorldGrid.hpp index b71e7f49..2f3582a6 100644 --- a/source/core/WorldGrid.hpp +++ b/source/core/WorldGrid.hpp @@ -4,7 +4,6 @@ * @note Status: PROPOSAL **/ - #pragma once #include @@ -14,190 +13,183 @@ #include #include "CoreObject.hpp" -#include "GridPosition.hpp" #include "Data.hpp" +#include "GridPosition.hpp" namespace cse491 { - /// @class WorldGrid - /// @brief Represents a 2D grid of cells. - /// This class provides utilities to manage, access, and modify cells within a grid. - class WorldGrid : public CoreObject { - protected: - size_t width = 0; ///< Number of cells in each row of the grid. - size_t height = 0; ///< Number of rows of cells in the grid. - std::vector cells; ///< All cells, grouped by full rows, top to bottom - - // -- Helper functions -- - - /// Convert an X and a Y value to the index in the vector. - [[nodiscard]] inline size_t ToIndex(size_t x, size_t y) const { - return x + y * width; - } - - // -- Serialize and Deserialize functions -- - // Mechanisms to efficiently save and load the exact state of the grid. - // File format is width and height followed by all - // values in the grid on each line thereafter. - - std::string GetTypeName_impl() const override { return "cse491::WorldGrid"; } - - /// Write the current state of this grid into the provided stream. - void Serialize_impl(std::ostream & os) const override { - os << width << " " << height; - for (size_t state : cells) os << ' ' << state; - os << std::endl; - } - - /// Read the state of the grid out of the provided stream. - void Deserialize_impl(std::istream & is) override { - is >> width >> height; - cells.resize(width * height); - for (size_t & state : cells) is >> state; - - // add one to the position - // EndDeserialize seems to be getting the end of the current line - // but, it expects the next line - int curr_pos = is.tellg(); - is.seekg(curr_pos + 1); - } - - public: - WorldGrid() = default; - WorldGrid(size_t width, size_t height, size_t default_type=0) - : width(width), height(height), cells(width*height, default_type) { } - WorldGrid(const WorldGrid &) = default; - WorldGrid(WorldGrid &&) = default; - - WorldGrid & operator=(const WorldGrid &) = default; - WorldGrid & operator=(WorldGrid &&) = default; - - // -- Accessors -- - [[nodiscard]] size_t GetWidth() const { return width; } - [[nodiscard]] size_t GetHeight() const { return height; } - [[nodiscard]] size_t GetNumCells() const { return cells.size(); } - - /// Test if specific coordinates are in range for this GridWorld. - [[nodiscard]] bool IsValid(double x, double y) const { - return x >= 0.0 && x < width && y >= 0.0 && y < height; - } - - /// Test if a GridPosition is in range for this GridWorld. - [[nodiscard]] bool IsValid(GridPosition pos) const { - return IsValid(pos.GetX(), pos.GetY()); - } - - /// @return The grid state at the provided x and y coordinates - [[nodiscard]] size_t At(size_t x, size_t y) const { - assert(IsValid(x,y)); - return cells[ToIndex(x,y)]; - } - - /// @return A reference to the grid state at the provided x and y coordinates - [[nodiscard]] size_t & At(size_t x, size_t y) { - assert(IsValid(x,y)); - return cells[ToIndex(x,y)]; - } - - /// @return The state at a given GridPosition. - [[nodiscard]] size_t At(GridPosition p) const { return At(p.CellX(), p.CellY()); } - - /// @return A reference to the state at a given GridPosition. - [[nodiscard]] size_t & At(GridPosition p) { return At(p.CellX(), p.CellY()); } - - [[nodiscard]] size_t operator[](GridPosition p) const { return At(p); } - [[nodiscard]] size_t & operator[](GridPosition p) { return At(p); } - - - // Size adjustments. - void Resize(size_t new_width, size_t new_height, size_t default_type=0) { - // Create a new vector of the correct size. - std::vector new_cells(new_width*new_height, default_type); - - // Copy the overlapping portions of the two grids. - size_t min_width = std::min(width, new_width); - size_t min_height = std::min(height, new_height); - for (size_t x = 0; x < min_width; ++x) { - for (size_t y = 0; y < min_height; ++y) { - new_cells[x+y*new_width] = cells[ToIndex(x,y)]; - } +/// @class WorldGrid +/// @brief Represents a 2D grid of cells. +/// This class provides utilities to manage, access, and modify cells within a grid. +class WorldGrid : public CoreObject { + protected: + size_t width = 0; ///< Number of cells in each row of the grid. + size_t height = 0; ///< Number of rows of cells in the grid. + std::vector cells; ///< All cells, grouped by full rows, top to bottom + + // -- Helper functions -- + + /// Convert an X and a Y value to the index in the vector. + [[nodiscard]] inline size_t ToIndex(size_t x, size_t y) const { return x + y * width; } + + // -- Serialize and Deserialize functions -- + // Mechanisms to efficiently save and load the exact state of the grid. + // File format is width and height followed by all + // values in the grid on each line thereafter. + + std::string GetTypeName_impl() const override { return "cse491::WorldGrid"; } + + /// Write the current state of this grid into the provided stream. + void Serialize_impl(std::ostream &os) const override { + os << width << " " << height; + for (size_t state : cells) os << ' ' << state; + os << std::endl; + } + + /// Read the state of the grid out of the provided stream. + void Deserialize_impl(std::istream &is) override { + is >> width >> height; + cells.resize(width * height); + for (size_t &state : cells) is >> state; + + // add one to the position + // EndDeserialize seems to be getting the end of the current line + // but, it expects the next line + int curr_pos = is.tellg(); + is.seekg(curr_pos + 1); + } + + public: + WorldGrid() = default; + WorldGrid(size_t width, size_t height, size_t default_type = 0) + : width(width), height(height), cells(width * height, default_type) {} + WorldGrid(const WorldGrid &) = default; + WorldGrid(WorldGrid &&) = default; + + WorldGrid &operator=(const WorldGrid &) = default; + WorldGrid &operator=(WorldGrid &&) = default; + + // -- Accessors -- + [[nodiscard]] size_t GetWidth() const { return width; } + [[nodiscard]] size_t GetHeight() const { return height; } + [[nodiscard]] size_t GetNumCells() const { return cells.size(); } + + /// Test if specific coordinates are in range for this GridWorld. + [[nodiscard]] bool IsValid(double x, double y) const { + return x >= 0.0 && x < width && y >= 0.0 && y < height; + } + + /// Test if a GridPosition is in range for this GridWorld. + [[nodiscard]] bool IsValid(GridPosition pos) const { return IsValid(pos.GetX(), pos.GetY()); } + + /// @return The grid state at the provided x and y coordinates + [[nodiscard]] size_t At(size_t x, size_t y) const { + assert(IsValid(x, y)); + return cells[ToIndex(x, y)]; + } + + /// @return A reference to the grid state at the provided x and y coordinates + [[nodiscard]] size_t &At(size_t x, size_t y) { + assert(IsValid(x, y)); + return cells[ToIndex(x, y)]; + } + + /// @return The state at a given GridPosition. + [[nodiscard]] size_t At(GridPosition p) const { return At(p.CellX(), p.CellY()); } + + /// @return A reference to the state at a given GridPosition. + [[nodiscard]] size_t &At(GridPosition p) { return At(p.CellX(), p.CellY()); } + + [[nodiscard]] size_t operator[](GridPosition p) const { return At(p); } + [[nodiscard]] size_t &operator[](GridPosition p) { return At(p); } + + // Size adjustments. + void Resize(size_t new_width, size_t new_height, size_t default_type = 0) { + // Create a new vector of the correct size. + std::vector new_cells(new_width * new_height, default_type); + + // Copy the overlapping portions of the two grids. + size_t min_width = std::min(width, new_width); + size_t min_height = std::min(height, new_height); + for (size_t x = 0; x < min_width; ++x) { + for (size_t y = 0; y < min_height; ++y) { + new_cells[x + y * new_width] = cells[ToIndex(x, y)]; } - - // Swap the new grid in; let the old grid be deallocated in its place. - std::swap(cells, new_cells); - width = new_width; - height = new_height; } - // -- Read and Write functions -- - // These are the same idea as Save and Load, but they are human readable, but they - // also require that each state has been assigned a unique character symbol. - - /// @brief Write out a human-readable version of the current WorldGrid - /// @param os Stream to write to - /// @param types A vector of CellTypes for symbol identification - void Write(std::ostream & os, const type_options_t & types) const { - size_t cell_id = 0; - for (size_t y=0; y < height; ++y) { - for (size_t x=0; x < width; ++x) { - os << types[ cells[cell_id++] ].symbol; - } - os << '\n'; + // Swap the new grid in; let the old grid be deallocated in its place. + std::swap(cells, new_cells); + width = new_width; + height = new_height; + } + + // -- Read and Write functions -- + // These are the same idea as Save and Load, but they are human readable, but they + // also require that each state has been assigned a unique character symbol. + + /// @brief Write out a human-readable version of the current WorldGrid + /// @param os Stream to write to + /// @param types A vector of CellTypes for symbol identification + void Write(std::ostream &os, const type_options_t &types) const { + size_t cell_id = 0; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + os << types[cells[cell_id++]].symbol; } - os.flush(); + os << '\n'; } - - /// Helper function to specify a file name to write the grid state to. - bool Write(std::string filename, const type_options_t & types) const { - std::ofstream os(filename); - if (!os.is_open()) { - std::cerr << "Could not open file '" << filename << "' to write grid." << std::endl; - return false; - } - Write(os, types); - return true; + os.flush(); + } + + /// Helper function to specify a file name to write the grid state to. + bool Write(std::string filename, const type_options_t &types) const { + std::ofstream os(filename); + if (!os.is_open()) { + std::cerr << "Could not open file '" << filename << "' to write grid." << std::endl; + return false; } - - void Read(std::istream & is, const type_options_t & types) { - // Build a symbol chart for conversions back. - std::unordered_map symbol_map; - for (size_t i=0; i < types.size(); ++i) { - symbol_map[types[i].symbol] = i; - } - - // Load the file into memory. - std::vector char_grid; - std::string line; - width = 0; - while (std::getline(is, line)) { - char_grid.push_back(line); - if (line.size() > width) width = line.size(); - } - height = char_grid.size(); - - // Convert each symbol to the appropriate value. - cells.resize(width * height); - size_t cell_id = 0; - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) { - // Use the cell values provided, or zero if a cell position is missing. - cells[cell_id++] = - (x < char_grid[y].size()) ? symbol_map[char_grid[y][x]] : 0; - } - } + Write(os, types); + return true; + } + + void Read(std::istream &is, const type_options_t &types) { + // Build a symbol chart for conversions back. + std::unordered_map symbol_map; + for (size_t i = 0; i < types.size(); ++i) { + symbol_map[types[i].symbol] = i; } - /// Helper function to specify a file name to read the grid state from. - bool Read(std::string filename, const type_options_t & types) { - std::ifstream is(filename); - if (!is.is_open()) { - std::cerr << "Could not open file '" << filename << "' to write grid." << std::endl; - return false; + // Load the file into memory. + std::vector char_grid; + std::string line; + width = 0; + while (std::getline(is, line)) { + char_grid.push_back(line); + if (line.size() > width) width = line.size(); + } + height = char_grid.size(); + + // Convert each symbol to the appropriate value. + cells.resize(width * height); + size_t cell_id = 0; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + // Use the cell values provided, or zero if a cell position is missing. + cells[cell_id++] = (x < char_grid[y].size()) ? symbol_map[char_grid[y][x]] : 0; } - Read(is, types); - return true; } - - }; + } + + /// Helper function to specify a file name to read the grid state from. + bool Read(std::string filename, const type_options_t &types) { + std::ifstream is(filename); + if (!is.is_open()) { + std::cerr << "Could not open file '" << filename << "' to write grid." << std::endl; + return false; + } + Read(is, types); + return true; + } +}; -} // End of namespace cse491 +} // End of namespace cse491 From 4c3f0a5112b734c4940a1dafc7a8e52a7cafca20 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sat, 9 Dec 2023 23:34:28 -0500 Subject: [PATCH 06/22] Added a .clang-format for the project --- .clang-format | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..305f1fce --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: google +ColumnLimit: 100 From 866efd342cda87f01a0305224be74d6a133dc8bd Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 10:24:49 -0500 Subject: [PATCH 07/22] Setup access mods (private, public, protects) to line up with 'class'. --- .clang-format | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clang-format b/.clang-format index 305f1fce..8309462e 100644 --- a/.clang-format +++ b/.clang-format @@ -1,2 +1,4 @@ BasedOnStyle: google ColumnLimit: 100 +AccessModifierOffset: -2 + From 69b3cf17412caeae2670f328528d6a576610a5ef Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 10:25:58 -0500 Subject: [PATCH 08/22] Moved grid_id to entity; cleaned up property type; updated formatting. --- source/core/AgentBase.hpp | 15 ++----- source/core/CoreObject.hpp | 4 +- source/core/Data.hpp | 2 +- source/core/EasyLogging.hpp | 6 +-- source/core/Entity.hpp | 78 ++++++++++++++++++++++------------- source/core/GridPosition.hpp | 9 +++- source/core/InterfaceBase.hpp | 4 +- source/core/ItemBase.hpp | 4 +- source/core/WorldBase.hpp | 6 +-- source/core/WorldGrid.hpp | 4 +- 10 files changed, 75 insertions(+), 57 deletions(-) diff --git a/source/core/AgentBase.hpp b/source/core/AgentBase.hpp index b8f82efb..bd92fea6 100644 --- a/source/core/AgentBase.hpp +++ b/source/core/AgentBase.hpp @@ -28,24 +28,17 @@ enum State /// States that an agent can be in. }; class AgentBase : public Entity { - protected: - size_t grid_id = 0; ///< Which grid is this agent on? - - /// A map of names to IDs for each available action - std::unordered_map action_map; +protected: + std::unordered_map action_map; ///< Map of names to action ids. + int action; ///< Action that agent is currently performing int action_result = 0; ///< Usually a one (success) or zero (failure). - int action; // The action that the agent is currently performing - State agent_state = Healthy; /// Default value upon initialization - public: +public: AgentBase(size_t id, const std::string &name) : Entity(id, name) {} ~AgentBase() = default; // Already virtual from Entity - [[nodiscard]] size_t GetGridID() const { return grid_id; } - [[nodiscard]] bool IsOnGrid(size_t in_grid_id) const { return grid_id == in_grid_id; } - // -- World Interactions -- /// @brief Run AFTER the world configures the agent, for additional tests or setup. diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index 1040369b..e1a3b38d 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -47,7 +47,7 @@ namespace cse491 { /// This class ensures that objects can be serialized (saved), deserialized (restored) /// and provides helper functions. class CoreObject { - protected: +protected: // -- Required functionality in all core classes -- // These functions are core functionality that must be implemented in all derived // classes. They will enable the public interface to behave correctly. @@ -105,7 +105,7 @@ class CoreObject { return true; } - public: +public: virtual ~CoreObject() {} /// @brief Access the derived name for this type. diff --git a/source/core/Data.hpp b/source/core/Data.hpp index cea66827..7d6a075b 100644 --- a/source/core/Data.hpp +++ b/source/core/Data.hpp @@ -52,7 +52,7 @@ class AgentBase; using agent_map_t = std::map>; /// @brief Common types of properties in network serialization -enum class PropertyType { t_double, t_int, t_char, t_string, t_other }; +enum class PropertyType { t_double, t_int, t_char, t_string, t_position, t_other }; /// @brief Enum for World types in network serialization enum class WorldType { w_maze, w_second, w_generative, w_manual }; diff --git a/source/core/EasyLogging.hpp b/source/core/EasyLogging.hpp index 2b8bf86c..653fd0e5 100644 --- a/source/core/EasyLogging.hpp +++ b/source/core/EasyLogging.hpp @@ -69,7 +69,7 @@ const LogLevel LOGLEVEL = LogLevel::DEBUG; * the console. */ class Logger { - public: +public: /** * @brief Sets the Team name for the current log * @@ -214,7 +214,7 @@ class Logger { return os; } - private: +private: /// @brief Current team for that is going to log Team currentTeam = Team::NA; @@ -281,7 +281,7 @@ class Logger { // #define log Log() class Logger { - public: +public: template Logger &operator<<(const T & /*value*/) { return *this; diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index e039d0fe..a978902c 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A base class for all items or agents that can exist on the grid. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once @@ -21,31 +21,63 @@ namespace cse491 { class WorldBase; class Entity { - private: - WorldBase *world_ptr = - nullptr; ///< Track the world this entity is in (private to protect pointer) +private: + WorldBase *world_ptr = nullptr; ///< Track world this entity is in - protected: - const size_t id = 0; ///< Unique ID for this entity (zero is use for "no ID") +protected: + const size_t id = 0; ///< Unique ID for this entity (0 is used for "no ID") std::string name = ""; ///< Name for this entity (E.g., "Player 1" or "+2 Sword") + + size_t grid_id = 0; ///< Which grid is this entity on? GridPosition position; ///< Where on the grid is this entity? - std::vector inventory; + std::vector inventory; ///< What entity ids are held by this entity? struct PropertyBase { virtual ~PropertyBase() {} + virtual PropertyType GetType() const = 0; + virtual std::string GetTypeName() const = 0; + virtual std::string AsString() const = 0; }; + // For the moment, properties can be char, int, double, string, or GridPosition template struct Property : public PropertyBase { T value; Property(const T &in) : value(in) {} Property(T &&in) : value(in) {} + + PropertyType GetType() const override { + if constexpr (std::is_same()) return PropertyType::t_char; + if constexpr (std::is_same()) return PropertyType::t_int; + if constexpr (std::is_same()) return PropertyType::t_double; + if constexpr (std::is_same()) return PropertyType::t_string; + if constexpr (std::is_same()) return PropertyType::t_position; + return PropertyType::t_other; + } + + std::string GetTypeName() const override { + if constexpr (std::is_same()) return "char"; + if constexpr (std::is_same()) return "int"; + if constexpr (std::is_same()) return "double"; + if constexpr (std::is_same()) return "string"; + if constexpr (std::is_same()) return "GridPosition"; + return "unknown"; + } + + std::string AsString() const override { + if constexpr (std::is_same()) return std::string(1, value); + if constexpr (std::is_same()) return std::to_string(value); + if constexpr (std::is_same()) return std::to_string(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return value.AsString(); + return "unknown"; + } }; /// Every entity can have a simple set of properties (with values) associated with it. - std::unordered_map> property_map; - std::unordered_map property_type_map; + using property_map_t = std::unordered_map>; + property_map_t property_map; // -- Helper Functions -- @@ -58,7 +90,7 @@ class Entity { return *property_ptr; } - public: +public: Entity(size_t id, const std::string &name) : id(id), name(name) {} Entity(const Entity &) = delete; // Entities must be unique and shouldn't be copied. Entity(Entity &&) = default; @@ -75,6 +107,8 @@ class Entity { assert(world_ptr); return *world_ptr; } + [[nodiscard]] size_t GetGridID() const { return grid_id; } + [[nodiscard]] bool IsOnGrid(size_t in_grid_id) const { return grid_id == in_grid_id; } [[nodiscard]] bool HasWorld() const { return world_ptr != nullptr; } Entity &SetName(const std::string in_name) { @@ -107,22 +141,10 @@ class Entity { return AsProperty(name).value; } - [[nodiscard]] PropertyType GetPropertyType(const std::string &key) const { - return property_type_map.at(key); - } - - template - void SetPropertyType(const std::string &name) { - if (std::is_same::value) - property_type_map[name] = PropertyType::t_double; - else if (std::is_same::value) - property_type_map[name] = PropertyType::t_int; - else if (std::is_same::value) - property_type_map[name] = PropertyType::t_char; - else if (std::is_same::value) - property_type_map[name] = PropertyType::t_string; - else - property_type_map[name] = PropertyType::t_other; + [[nodiscard]] PropertyType GetPropertyType(const std::string &name) const { + auto it = property_map.find(name); + if (it == property_map.end()) return PropertyType::t_other; + return it->second->GetType(); } /// Change the value of the specified property (will create if needed) @@ -132,7 +154,6 @@ class Entity { AsProperty(name).value = value; } else { property_map[name] = std::make_unique>(value); - SetPropertyType(name); } return *this; } @@ -149,12 +170,11 @@ class Entity { /// Completely remove a property from an Entity. Entity &RemoveProperty(const std::string &name) { property_map.erase(name); - property_type_map.erase(name); return *this; } /// return the property map for the entity - std::unordered_map> &GetProprtyMap() { + property_map_t &GetPropertyMap() { return property_map; } diff --git a/source/core/GridPosition.hpp b/source/core/GridPosition.hpp index d6f9bbfd..99e97960 100644 --- a/source/core/GridPosition.hpp +++ b/source/core/GridPosition.hpp @@ -19,11 +19,11 @@ namespace cse491 { /// The position is stored as floating-point values (to allow for smooth motion through /// a grid), but is easily converted to size_t for grid-cell identification. class GridPosition { - private: +private: double x = 0.0; double y = 0.0; - public: +public: GridPosition() = default; GridPosition(double x, double y) : x(x), y(y) {} GridPosition(const GridPosition &) = default; @@ -107,6 +107,11 @@ class GridPosition { const double dist2 = y - pos2.y; return (dist1 * dist1 + dist2 * dist2) <= (max_dist * max_dist); } + + [[nodiscard]] std::string AsString() const { + std::stringstream ss; + ss << '(' << x << ',' << y << ')'; + } }; } // End of namespace cse491 diff --git a/source/core/InterfaceBase.hpp b/source/core/InterfaceBase.hpp index fee7f647..b372e237 100644 --- a/source/core/InterfaceBase.hpp +++ b/source/core/InterfaceBase.hpp @@ -15,13 +15,13 @@ namespace cse491 { class InterfaceBase : public AgentBase { - protected: +protected: static void exitCleanup() { DataCollection::DataManager::GetInstance().WriteToJson(); exit(0); } - public: +public: InterfaceBase(size_t id, const std::string& name) : AgentBase(id, name) {} ~InterfaceBase() = default; // Already virtual from Entity diff --git a/source/core/ItemBase.hpp b/source/core/ItemBase.hpp index 913a9843..2d2498b5 100644 --- a/source/core/ItemBase.hpp +++ b/source/core/ItemBase.hpp @@ -16,12 +16,12 @@ namespace cse491 { class ItemBase : public Entity { - protected: +protected: enum OwnerType { NONE = 0, GRID, ITEM, AGENT }; OwnerType owner_type = OwnerType::NONE; size_t owner_id = 0; - public: +public: ItemBase(size_t id, const std::string &name) : Entity(id, name) {} ~ItemBase() = default; // Already virtual from Entity diff --git a/source/core/WorldBase.hpp b/source/core/WorldBase.hpp index 92c9f0ad..5067faec 100644 --- a/source/core/WorldBase.hpp +++ b/source/core/WorldBase.hpp @@ -35,7 +35,7 @@ namespace cse491 { class DataReceiver; class WorldBase { - public: +public: static constexpr size_t npos = static_cast(-1); netWorth::ServerManager *server_manager = nullptr; /// Server manager for world if used netWorth::ClientManager *client_manager = nullptr; /// Client manager for world if used @@ -45,7 +45,7 @@ class WorldBase { /// setup. virtual void ConfigAgent(AgentBase & /* agent */) const {} - protected: +protected: /// Derived worlds may choose to have more than one grid. std::unordered_map grids; @@ -87,7 +87,7 @@ class WorldBase { return type_options.size() - 1; } - public: +public: /// Initializes world with cell types and random generator /// @param seed Seed used for RNG. Use 0 for a non-deterministic result. WorldBase(unsigned int seed = 0) : grids(), main_grid(grids[0]), seed(seed) { diff --git a/source/core/WorldGrid.hpp b/source/core/WorldGrid.hpp index 2f3582a6..131f7618 100644 --- a/source/core/WorldGrid.hpp +++ b/source/core/WorldGrid.hpp @@ -22,7 +22,7 @@ namespace cse491 { /// @brief Represents a 2D grid of cells. /// This class provides utilities to manage, access, and modify cells within a grid. class WorldGrid : public CoreObject { - protected: +protected: size_t width = 0; ///< Number of cells in each row of the grid. size_t height = 0; ///< Number of rows of cells in the grid. std::vector cells; ///< All cells, grouped by full rows, top to bottom @@ -59,7 +59,7 @@ class WorldGrid : public CoreObject { is.seekg(curr_pos + 1); } - public: +public: WorldGrid() = default; WorldGrid(size_t width, size_t height, size_t default_type = 0) : width(width), height(height), cells(width * height, default_type) {} From f1ea8549004c1c39f55847812210a8f853a0b1e5 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 10:31:22 -0500 Subject: [PATCH 09/22] Cleaned up CoreObject; bumped to ALPHA status. --- source/core/CoreObject.hpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index e1a3b38d..8e566dd7 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -1,29 +1,33 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A common interface class for core objects that sets up required functionality. - * @note Status: PROPOSAL + * @note Status: ALPHA * * This CoreObject class builds an interface for all of the core object, ensuring that * they can be properly serialized. * * Derived classes must implement: - * GetTypeName_impl() - To return the qualified type name. - * Serialize_impl() - To store the object in a stream. - * Deserialize_impl() - To restore the object from a stream. + * GetTypeName_impl() - Return the qualified type name. + * Serialize_impl(std::ostream &) - Store the object in a stream. + * Deserialize_impl(std::istream &) - Restore the object from a stream. **/ + +#pragma once + +#include +#include +#include + /** * @author @amantham20 - * uses as attibute to mark experimental classes and functions + * uses as attribute to mark experimental classes and functions */ #ifndef NDEBUG - #define EXPERIMENTAL_FUNCTION __attribute__((annotate("experimental_function"))) - #define EXPERIMENTAL_CLASS __attribute__((annotate("experimental_class"))) -#else - +#else // NDEBUG *not* set, so debug mode. #define EXPERIMENTAL_CLASS \ __attribute__((annotate("experimental_class"), \ warning("This is an experimental class and should be used with caution."))) @@ -31,15 +35,8 @@ __attribute__((annotate("experimental_function"), \ warning("This is an experimental function and should be " \ "used with caution."))) - #endif -#pragma once - -#include -#include -#include - namespace cse491 { /// @class WorldGrid From 36a54adae25540c446bf9373e8977ef795a90f7b Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 12:06:43 -0500 Subject: [PATCH 10/22] Fixed spelling of GetPropertyMap in ManualWorld. --- source/Worlds/ManualWorld.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Worlds/ManualWorld.hpp b/source/Worlds/ManualWorld.hpp index c89f58f9..c59d854f 100644 --- a/source/Worlds/ManualWorld.hpp +++ b/source/Worlds/ManualWorld.hpp @@ -186,7 +186,7 @@ namespace cse491_team8 { { if (item->IsOwnedBy(agent.GetID())) { - for (const auto & [name, entity] : item->GetProprtyMap()) + for (const auto & [name, entity] : item->GetPropertyMap()) { if (name == "Uses" || name == "Strength" || name == "Healing") { @@ -197,7 +197,7 @@ namespace cse491_team8 { } } output += "\nProperties of the player:\n"; - for (const auto & [name, entity] : agent.GetProprtyMap()) + for (const auto & [name, entity] : agent.GetPropertyMap()) { if (name == "Strength" || name == "Health" || name == "Max_Health") { From bce64b5f882ae88fe89f099e15577e21eda25a60 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 12:08:52 -0500 Subject: [PATCH 11/22] In GridPosition, change AsString to ToString and added FromString for loading --- source/core/Entity.hpp | 6 +++--- source/core/GridPosition.hpp | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index a978902c..f68972b0 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -37,7 +37,7 @@ class Entity { virtual ~PropertyBase() {} virtual PropertyType GetType() const = 0; virtual std::string GetTypeName() const = 0; - virtual std::string AsString() const = 0; + virtual std::string ToString() const = 0; }; // For the moment, properties can be char, int, double, string, or GridPosition @@ -65,12 +65,12 @@ class Entity { return "unknown"; } - std::string AsString() const override { + std::string ToString() const override { if constexpr (std::is_same()) return std::string(1, value); if constexpr (std::is_same()) return std::to_string(value); if constexpr (std::is_same()) return std::to_string(value); if constexpr (std::is_same()) return value; - if constexpr (std::is_same()) return value.AsString(); + if constexpr (std::is_same()) return value.ToString(); return "unknown"; } }; diff --git a/source/core/GridPosition.hpp b/source/core/GridPosition.hpp index 99e97960..2709628c 100644 --- a/source/core/GridPosition.hpp +++ b/source/core/GridPosition.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A mechanism of identifying a grid cell, as well as a position within the cell. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once @@ -10,6 +10,8 @@ #include // For sqrt and std::nan() #include // For operator<=> #include // For size_t +#include // For std::stringstream +#include namespace cse491 { @@ -42,7 +44,8 @@ class GridPosition { /// Enable all comparison operators (==, !=, <, <=, >, >=) auto operator<=>(const GridPosition &) const = default; - [[nodiscard]] bool IsValid() const { return !(std::isnan(x) || std::isnan(y)); } + [[nodiscard]] bool IsInvalid() const { return std::isnan(x) || std::isnan(y); } + [[nodiscard]] bool IsValid() const { return !IsInvalid(); } // -- Modifiers -- @@ -108,9 +111,33 @@ class GridPosition { return (dist1 * dist1 + dist2 * dist2) <= (max_dist * max_dist); } - [[nodiscard]] std::string AsString() const { + [[nodiscard]] std::string ToString() const { std::stringstream ss; ss << '(' << x << ',' << y << ')'; + return ss.str(); + } + + GridPosition & FromStream(std::istream & ss) { + // Format should be "(x,y)" with values filled in. + // Any deviation from this format produces an undefined position. + char c = '\0'; + ss >> c; + if (c != '(') return MakeInvalid(); + ss >> x; + ss >> c; + if (c != ',') return MakeInvalid(); + ss >> y; + ss >> c; + if (c != ')') return MakeInvalid(); + + return *this; + } + + GridPosition & FromString(std::string in_str) { + // Format should be "(x,y)" with values filled in. + // Any deviation from this format produces an undefined position. + std::stringstream ss(in_str); + return FromStream(ss); } }; From f5805491af22199f707c482d49b4993e52cc1535 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 12:09:30 -0500 Subject: [PATCH 12/22] Added unit tests for GridPosition. --- tests/unit/core/GridPosition.cpp | 136 +++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/unit/core/GridPosition.cpp diff --git a/tests/unit/core/GridPosition.cpp b/tests/unit/core/GridPosition.cpp new file mode 100644 index 00000000..ebbd03d3 --- /dev/null +++ b/tests/unit/core/GridPosition.cpp @@ -0,0 +1,136 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief Unit tests for GridPosition.hpp in source/core + **/ + +// Catch2 +#define CATCH_CONFIG_MAIN +#include + +// Class project +#include "core/GridPosition.hpp" + +TEST_CASE("GridPosition Construction", "[core][grid]") { + cse491::GridPosition default_pos; + CHECK(default_pos.GetX() == 0.0); + CHECK(default_pos.GetY() == 0.0); + CHECK(default_pos.CellX() == 0); + CHECK(default_pos.CellY() == 0); + CHECK(default_pos.IsValid() == true); + CHECK(default_pos.IsInvalid() == false); + + cse491::GridPosition zero_pos(0.0, 0.0); + CHECK(zero_pos.GetX() == 0.0); + CHECK(zero_pos.GetY() == 0.0); + CHECK(zero_pos.CellX() == 0); + CHECK(zero_pos.CellY() == 0); + CHECK(zero_pos.IsValid() == true); + CHECK(zero_pos.IsInvalid() == false); + CHECK(zero_pos == default_pos); + + cse491::GridPosition set_pos(3.0, 4.0); + CHECK(set_pos.GetX() == 3.0); + CHECK(set_pos.GetY() == 4.0); + CHECK(set_pos.CellX() == 3); + CHECK(set_pos.CellY() == 4); + CHECK(set_pos.IsValid() == true); + CHECK(set_pos.IsInvalid() == false); + CHECK(set_pos != default_pos); + + cse491::GridPosition copy_pos(set_pos); + CHECK(copy_pos.GetX() == 3.0); + CHECK(copy_pos.GetY() == 4.0); + CHECK(copy_pos.CellX() == 3); + CHECK(copy_pos.CellY() == 4); + CHECK(copy_pos.IsValid() == true); + CHECK(copy_pos.IsInvalid() == false); + CHECK(copy_pos != default_pos); + CHECK(copy_pos == set_pos); +} + +TEST_CASE("GridPosition Mathematical Methods", "[core][grid]") { + cse491::GridPosition pos1(0.0, 0.0); + cse491::GridPosition pos2(3.0, 4.0); + cse491::GridPosition pos3(1.0, 2.0); + + pos1.Set(7.0,7.0); + CHECK(pos1.GetX() == 7.0); + CHECK(pos1.GetY() == 7.0); + + pos1.Shift(-7.0,1.0); + CHECK(pos1.GetX() == 0.0); + CHECK(pos1.GetY() == 8.0); + + pos1 += pos2; + CHECK(pos1.GetX() == 3.0); + CHECK(pos1.GetY() == 12.0); + + pos1 -= pos3; + CHECK(pos1.GetX() == 2.0); + CHECK(pos1.GetY() == 10.0); + + pos1.MakeInvalid(); + CHECK(pos1.IsInvalid() == true); + CHECK(pos1.IsValid() == false); + + pos1 = pos2.GetOffset(10.0, 20.0); + CHECK(pos1.GetX() == 13.0); + CHECK(pos1.GetY() == 24.0); + + CHECK(pos1.Above().GetX() == 13.0); + CHECK(pos1.Above().GetY() == 23.0); + CHECK(pos1.Below().GetX() == 13.0); + CHECK(pos1.Below().GetY() == 25.0); + CHECK(pos1.ToLeft().GetX() == 12.0); + CHECK(pos1.ToLeft().GetY() == 24.0); + CHECK(pos1.ToRight().GetX() == 14.0); + CHECK(pos1.ToRight().GetY() == 24.0); + + pos1 = pos2 + pos3; + CHECK(pos1.GetX() == 4.0); + CHECK(pos1.GetY() == 6.0); + + double dist = pos1.Distance(pos3); + CHECK(dist > 4.999); + CHECK(dist < 5.001); + + dist = pos1.MDistance(pos3); // Manhattan distance + CHECK(dist > 6.999); + CHECK(dist < 7.001); + + CHECK(pos1.IsNear(pos3) == false); + CHECK(pos1.IsNear(pos3, 4.9) == false); + CHECK(pos1.IsNear(pos3, 5.0) == true); + CHECK(pos1.IsNear(pos3, 5.1) == true); +} + +TEST_CASE("GridPosition String Methods", "[core][grid]") { + cse491::GridPosition pos1(0.0, 0.0); + cse491::GridPosition pos2(3.0, 4.0); + cse491::GridPosition pos3(1.0, 2.0); + + CHECK(pos1.ToString() == "(0,0)"); + CHECK(pos2.ToString() == "(3,4)"); + CHECK(pos3.ToString() == "(1,2)"); + + pos1.FromString("(10,11)"); + pos2.FromString("(12345,67890)"); + pos3.FromString("(-1.0,2.5)"); + CHECK(pos1.GetX() == 10.0); + CHECK(pos1.GetY() == 11.0); + CHECK(pos2.GetX() == 12345.0); + CHECK(pos2.GetY() == 67890.0); + CHECK(pos3.GetX() == -1.0); + CHECK(pos3.GetY() == 2.5); + + CHECK(pos1.ToString() == "(10,11)"); + CHECK(pos2.ToString() == "(12345,67890)"); + CHECK(pos3.ToString() == "(-1,2.5)"); + + pos1.FromString("(10,11"); + pos2.FromString("(1234567890)"); + pos3.FromString("-1.0,2.5)"); + CHECK(pos1.IsValid() == false); + CHECK(pos2.IsValid() == false); + CHECK(pos3.IsValid() == false); +} From 0b1c74edad4628e745c5793d806f6dfa38289f38 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 16:50:22 -0500 Subject: [PATCH 13/22] Added a wide range of serialization helper functions to CoreObject. --- source/core/CoreObject.hpp | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index 8e566dd7..2d9d9ddf 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -16,8 +16,12 @@ #pragma once #include +#include #include +#include +#include #include +#include /** * @author @amantham20 @@ -39,6 +43,18 @@ namespace cse491 { +// Type trait to determine if we are working with a vector. +template struct is_vector : std::false_type {}; +template struct is_vector> : std::true_type {}; + +// Type trait to determine if we are working with any type of map. +template +struct is_any_map : std::false_type {}; +template +struct is_any_map> : std::true_type {}; +template +struct is_any_map> : std::true_type {}; + /// @class WorldGrid /// @brief A common interface class for core objects that sets up required functionality. /// This class ensures that objects can be serialized (saved), deserialized (restored) @@ -102,9 +118,129 @@ class CoreObject { return true; } + /// @brief Helper function to serialize a single member variable. + /// @param os Output stream to write to. + /// @param var Variable to serialize. + template + void SerializeValue(std::ostream & os, const T & var) const { + if constexpr (std::is_enum()) { + os << static_cast(var) << std::endl; + } else if constexpr (is_vector()) { + SerializeValue_Vector(os, var); + } else if constexpr (is_any_map()) { + SerializeValue_Map(os, var); + } else { + os << var << '\n'; + } + } + + /// @brief Helper specialty function to serialize a vector-based member variable. + /// @param os Output stream to write to. + /// @param var Variable to serialize. + template + void SerializeValue_Vector(std::ostream & os, const std::vector & var) const { + SerializeValue(os, var.size()); + for (const auto & x : var) { + SerializeValue(os, x); + } + } + + /// @brief Helper specialty function to serialize a unordered_map member variable. + /// @param os Output stream to write to. + /// @param var Variable to serialize. + template + void SerializeValue_Map(std::ostream & os, const T & var) const { + SerializeValue(os, var.size()); + for (const auto & [key, value] : var) { + SerializeValue(os, key); + SerializeValue(os, value); + } + } + + /// @brief Helper function to serialize a single member variable. + /// @param os Output stream to write to. + /// @param var Variable to deserialize. + template + void DeserializeValue(std::istream & is, T & var) const { + static_assert(!std::is_const(), "Cannot deserialize const variables."); + + // If we are loading a string, load it directly. + if constexpr (std::is_same, std::string>()) { + std::getline(is, var, '\n'); + } else if constexpr (is_vector()) { + DeserializeValue_Vector(is, var); + } else if constexpr (is_any_map()) { + DeserializeValue_Map(is, var); + } else { + // @CAO: This can be streamlined to use only the original is, and based on type. + // For example, "is << var" followed by "is.peek()" to make sure we have a + // newline, and then "is.ignore()" to skip the newline. + std::string str; + std::getline(is, str, '\n'); + std::stringstream ss(str); + if constexpr (std::is_enum()) { // enums must be converted properly. + int enum_val; + ss >> enum_val; + var = static_cast(enum_val); + } else { + ss >> var; + } + } + } + + /// @brief Helper function to serialize a member variables from a function + /// @param os Output stream to write to. + /// @param var Variable to serialize. + template + void DeserializeFunction(std::istream & is, std::function set_fun) const { + std::string str; + std::getline(is, str, '\n'); + if constexpr (std::is_same, std::string>()) { + set_fun(str); + } else if constexpr (std::is_same, int>()) { + set_fun(stoi(str)); + } else if constexpr (std::is_same, double>()) { + set_fun(stod(str)); + } else { + T var; + std::stringstream ss(str); + ss >> var; + set_fun(var); + } + } + + /// @brief Helper specialty function to deserialize a vector-based member variable. + /// @param os Input stream to read from. + /// @param var Variable to deserialize. + template + void DeserializeValue_Vector(std::istream & is, std::vector & var) const { + DeserializeFunction(is, [&var](size_t in_size){ var.resize(in_size); } ); + for (auto & x : var) { + DeserializeValue(is, x); + } + } + + /// @brief Helper specialty function to deserialize a unordered_map member variable. + /// @param is Input stream to read from. + /// @param var Variable to deserialize. + template + void DeserializeValue_Map(std::istream & is, MAP_T & var) const { + size_t map_size = 0; + typename MAP_T::key_type key; + typename MAP_T::mapped_type value; + DeserializeValue(is, map_size); + for (size_t i = 0; i < map_size; ++i) { + DeserializeValue(is, key); + DeserializeValue(is, value); + var[key] = value; + } + } + public: virtual ~CoreObject() {} + auto operator<=>(const CoreObject &) const = default; + /// @brief Access the derived name for this type. /// @return A unique typename, ideally the exact name for this class (with scope) /// This member function will be helpful for serialization and debugging. It should From bc2253856bef7f4f5bce302bb48744ee2d96ae93 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 16:53:19 -0500 Subject: [PATCH 14/22] Added GridPosition base class CoreObject, serialization, Invalid creator, & construct from string. --- source/core/GridPosition.hpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/source/core/GridPosition.hpp b/source/core/GridPosition.hpp index 2709628c..f897b27a 100644 --- a/source/core/GridPosition.hpp +++ b/source/core/GridPosition.hpp @@ -13,6 +13,8 @@ #include // For std::stringstream #include +#include "CoreObject.hpp" + namespace cse491 { /// @class GridPosition @@ -20,7 +22,7 @@ namespace cse491 { /// This class provides utilities to manage a position in 2D space. /// The position is stored as floating-point values (to allow for smooth motion through /// a grid), but is easily converted to size_t for grid-cell identification. -class GridPosition { +class GridPosition : public CoreObject { private: double x = 0.0; double y = 0.0; @@ -28,6 +30,7 @@ class GridPosition { public: GridPosition() = default; GridPosition(double x, double y) : x(x), y(y) {} + GridPosition(const std::string & str) { FromString(str); } GridPosition(const GridPosition &) = default; ~GridPosition() = default; @@ -54,6 +57,9 @@ class GridPosition { y = in_y; return *this; } + GridPosition &SetX(double in) { x = in; return *this; } + GridPosition &SetY(double in) { y = in; return *this; } + GridPosition &Shift(double shift_x, double shift_y) { x += shift_x; y += shift_y; @@ -63,11 +69,19 @@ class GridPosition { GridPosition &operator+=(const GridPosition &in) { return Shift(in.x, in.y); } GridPosition &operator-=(const GridPosition &in) { return Shift(-in.x, -in.y); } + /// @brief Make this grid position invalid, by setting both coords to "not-a-number" + /// @return This object. GridPosition &MakeInvalid() { x = y = std::nan("NAN(0)"); return *this; } + // A static function to request an invalid grid position. + static const GridPosition & Invalid() { + static GridPosition invalid_pos(std::nan("NAN(0)"), std::nan("NAN(0)")); + return invalid_pos; + } + // -- Const Operations -- /// Return a the GridPosition at the requested offset. @@ -139,6 +153,21 @@ class GridPosition { std::stringstream ss(in_str); return FromStream(ss); } + + + // -- CoreObject Operations -- + std::string GetTypeName_impl() const override { return "cse491::GridPosition"; } + + void Serialize_impl(std::ostream & os) const override { + SerializeValue(os, x); + SerializeValue(os, y); + }; + + void Deserialize_impl(std::istream & is) override { + DeserializeValue(is, x); + DeserializeValue(is, y); + }; + }; } // End of namespace cse491 From 21255cbced4a7a362bd4684cb9d47ed2a54a1376 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 16:54:30 -0500 Subject: [PATCH 15/22] Added explicity converters for Properties and Serialization in Entity. --- source/core/Entity.hpp | 136 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 5 deletions(-) diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index f68972b0..387bb39e 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -8,11 +8,14 @@ #include #include +#include #include +#include #include #include #include +#include "CoreObject.hpp" #include "Data.hpp" #include "GridPosition.hpp" @@ -20,12 +23,12 @@ namespace cse491 { class WorldBase; -class Entity { +class Entity : public CoreObject { private: WorldBase *world_ptr = nullptr; ///< Track world this entity is in protected: - const size_t id = 0; ///< Unique ID for this entity (0 is used for "no ID") + size_t id = 0; ///< Unique ID for this entity (0 is used for "no ID") std::string name = ""; ///< Name for this entity (E.g., "Player 1" or "+2 Sword") size_t grid_id = 0; ///< Which grid is this entity on? @@ -38,6 +41,10 @@ class Entity { virtual PropertyType GetType() const = 0; virtual std::string GetTypeName() const = 0; virtual std::string ToString() const = 0; + virtual char ToChar() const = 0; + virtual double ToDouble() const = 0; + virtual int ToInt() const = 0; + virtual GridPosition ToGridPosition() const = 0; }; // For the moment, properties can be char, int, double, string, or GridPosition @@ -73,6 +80,42 @@ class Entity { if constexpr (std::is_same()) return value.ToString(); return "unknown"; } + + char ToChar() const override { + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value.size() ? value[0] : '\0'; + if constexpr (std::is_same()) return '\0'; // No conversion. + return '\0'; + } + + double ToDouble() const override { + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return std::stod(value); + if constexpr (std::is_same()) return std::nan("nan"); // No conversion. + return std::nan("nan"); + } + + int ToInt() const override { + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return std::stoi(value); + if constexpr (std::is_same()) return 0; // No conversion. + return 0; + } + + GridPosition ToGridPosition() const override { + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition(value); + if constexpr (std::is_same()) return value; + return GridPosition::Invalid(); + } }; /// Every entity can have a simple set of properties (with values) associated with it. @@ -189,10 +232,93 @@ class Entity { Entity &RemoveItem(size_t id); Entity &RemoveItem(Entity &item) { return RemoveItem(item.GetID()); } - /// @brief Serialize entity (pure virtual) - /// @param ostream - virtual void Serialize(std::ostream &os) = 0; + /// @brief Serialize entity-specific values. + /// @param os ostream to write contents to. + void Serialize_impl(std::ostream &os) const override { + SerializeValue(os, id); + SerializeValue(os, name); + SerializeValue(os, grid_id); + SerializeValue(os, position.GetX()); + SerializeValue(os, position.GetY()); + SerializeValue(os, inventory); + + SerializeValue(os, property_map.size()); + for (const auto & [name, ptr] : property_map) { + SerializeValue(os, name); + PropertyType type = ptr->GetType(); + SerializeValue(os, static_cast(type)); + + switch (type) { + using enum PropertyType; + case t_char: + SerializeValue(os, ptr->ToChar()); + break; + case t_double: + SerializeValue(os, ptr->ToDouble()); + break; + case t_int: + SerializeValue(os, ptr->ToInt()); + break; + case t_string: + SerializeValue(os, ptr->ToString()); + break; + case t_position: + ptr->ToGridPosition().Serialize(os); + break; + case t_other: + assert(false); // Cannot serialize this type... + } + } + } + + /// @brief Serialize entity-specific values. + /// @param os ostream to write contents to. + void Deserialize_impl(std::istream &is) override { + DeserializeValue(is, id); + DeserializeValue(is, name); + DeserializeValue(is, grid_id); + DeserializeFunction(is, [this](double x){ position.SetX(x); }); + DeserializeFunction(is, [this](double y){ position.SetX(y); }); + DeserializeValue(is, inventory); + + size_t num_properties = 0; + property_map.clear(); + std::string name; + PropertyType type; + char val_c; double val_d; int val_i; std::string val_s; GridPosition val_g; + DeserializeValue(is, num_properties); + for (size_t i = 0; i < num_properties; ++i) { + DeserializeValue(is, name); + DeserializeValue(is, type); + switch (type) { + using enum PropertyType; + case t_char: + DeserializeValue(is, val_c); + SetProperty(name, val_c); + break; + case t_double: + DeserializeValue(is, val_d); + SetProperty(name, val_d); + break; + case t_int: + DeserializeValue(is, val_i); + SetProperty(name, val_i); + break; + case t_string: + DeserializeValue(is, val_s); + SetProperty(name, val_s); + break; + case t_position: + val_g.Deserialize(is); + SetProperty(name, val_g); + break; + case t_other: + assert(false); // Cannot deserialize this type... + } + } + } [[nodiscard]] std::vector GetInventory() const { return inventory; } }; + } // End of namespace cse491 From ed65648fa4742c2d17ea79873e6b97d0b8a390d1 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Sun, 10 Dec 2023 16:55:11 -0500 Subject: [PATCH 16/22] Updated serialization for AgentBase and ItemBase --- source/core/AgentBase.hpp | 33 +++++++++++------- source/core/ItemBase.hpp | 71 ++++++++------------------------------- 2 files changed, 34 insertions(+), 70 deletions(-) diff --git a/source/core/AgentBase.hpp b/source/core/AgentBase.hpp index bd92fea6..f64d35fc 100644 --- a/source/core/AgentBase.hpp +++ b/source/core/AgentBase.hpp @@ -142,19 +142,26 @@ class AgentBase : public Entity { /// information to an autonomous agent assuming we come up with a standard list of types. virtual void Notify(const std::string & /*message*/, const std::string & /*msg_type*/ = "none") {} - /** - * Serialize agent (assume no properties) - * @param os ostream - */ - void Serialize(std::ostream &os) override { - os << name << '\n'; - os << id << '\n'; - os << position.GetX() << '\n'; - os << position.GetY() << '\n'; - if (HasProperty("symbol")) - os << GetProperty("symbol") << '\n'; - else - os << '*' << std::endl; + std::string GetTypeName_impl() const override { return "cse491::AgentBase"; } + + /// @brief Serialize item-specific values and call Entity's Serialize_impl. + /// @param os ostream to write contents to. + void Serialize_impl(std::ostream &os) const override { + Entity::Serialize_impl(os); + SerializeValue(os, action_map); + SerializeValue(os, action); + SerializeValue(os, action_result); + SerializeValue(os, agent_state); + } + + /// @brief Deserialize item-specific values and call Entity's Deserialize_impl. + /// @param is istream to read contents from. + void Deserialize_impl(std::istream &is) override { + Entity::Deserialize_impl(is); + DeserializeValue(is, action_map); + DeserializeValue(is, action); + DeserializeValue(is, action_result); + DeserializeValue(is, agent_state); } }; diff --git a/source/core/ItemBase.hpp b/source/core/ItemBase.hpp index 2d2498b5..677c5de4 100644 --- a/source/core/ItemBase.hpp +++ b/source/core/ItemBase.hpp @@ -71,65 +71,22 @@ class ItemBase : public Entity { return *this; } - /// @brief Serialize item - /// @param ostream - void Serialize(std::ostream &os) override { - os << name << '\n'; - os << position.GetX() << '\n'; - os << position.GetY() << '\n'; - os << property_map.size() << '\n'; - for (const auto &property : property_map) { - os << property.first << '\n'; - - // Get property type - PropertyType type = GetPropertyType(property.first); - os << static_cast(type) << '\n'; - - // serialize property value - if (type == PropertyType::t_double) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_int) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_char) { - os << AsProperty(property.first).value << '\n'; - } else if (type == PropertyType::t_string) { - os << AsProperty(property.first).value << '\n'; - } else { - // unknown type, do nothing - os << '\n'; - } - } + std::string GetTypeName_impl() const override { return "cse491::ItemBase"; } + + /// @brief Serialize item-specific values and call Entity's Serialize_impl. + /// @param os ostream to write contents to. + void Serialize_impl(std::ostream &os) const override { + Entity::Serialize_impl(os); + SerializeValue(os, owner_type); + SerializeValue(os, owner_id); } - /// @brief Deserialize item - /// @param istream - void Deserialize(std::istream &is) { - std::string x_str, y_str; - std::getline(is, name, '\n'); - std::getline(is, x_str, '\n'); - std::getline(is, y_str, '\n'); - position.Set(stoi(x_str), stoi(y_str)); - - std::string property, type_str, value_str; - std::getline(is, property, '\n'); - int num_properties = stoi(property); - for (int i = 0; i < num_properties; i++) { - std::getline(is, property, '\n'); - std::getline(is, type_str, '\n'); - std::getline(is, value_str, '\n'); - - // Set property based on type - auto type = static_cast(stoi(type_str)); - if (type == PropertyType::t_double) { - SetProperty(property, stod(value_str)); - } else if (type == PropertyType::t_int) { - SetProperty(property, stoi(value_str)); - } else if (type == PropertyType::t_char) { - SetProperty(property, value_str[0]); - } else if (type == PropertyType::t_string) { - SetProperty(property, value_str); - } - } + /// @brief Deserialize item-specific values and call Entity's Deserialize_impl. + /// @param is istream to read contents from. + void Deserialize_impl(std::istream &is) override { + Entity::Deserialize_impl(is); + DeserializeValue(is, owner_type); + DeserializeValue(is, owner_id); } }; From 359f143a2c6e24bc59ddc8d5ff38fe7dcdc412ec Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 00:20:06 -0500 Subject: [PATCH 17/22] Made serialization helpers static functions; fixed some issues --- source/core/CoreObject.hpp | 58 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index 2d9d9ddf..ee696d3f 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -43,11 +43,11 @@ namespace cse491 { -// Type trait to determine if we are working with a vector. +/// Type trait to determine if we are working with a vector. template struct is_vector : std::false_type {}; template struct is_vector> : std::true_type {}; -// Type trait to determine if we are working with any type of map. +/// Type trait to determine if we are working with any type of map. template struct is_any_map : std::false_type {}; template @@ -55,6 +55,18 @@ struct is_any_map> : std::true_type {}; template struct is_any_map> : std::true_type {}; +/// Concept to identify if a type can be sent into an ostream. +template +concept CanStreamTo = requires(STREAM_T & stream, OBJ_T value) { + { stream << value } -> std::convertible_to; +}; + +/// Concept to identify if a type can be set from an istream. +template +concept CanStreamFrom = requires(STREAM_T & stream, OBJ_T value) { + { stream >> value } -> std::convertible_to; +}; + /// @class WorldGrid /// @brief A common interface class for core objects that sets up required functionality. /// This class ensures that objects can be serialized (saved), deserialized (restored) @@ -122,15 +134,18 @@ class CoreObject { /// @param os Output stream to write to. /// @param var Variable to serialize. template - void SerializeValue(std::ostream & os, const T & var) const { + static void SerializeValue(std::ostream & os, const T & var) { if constexpr (std::is_enum()) { os << static_cast(var) << std::endl; } else if constexpr (is_vector()) { SerializeValue_Vector(os, var); } else if constexpr (is_any_map()) { SerializeValue_Map(os, var); - } else { + } else if constexpr (std::is_base_of()) { + var.Serialize(os); + } else if constexpr (CanStreamTo) { os << var << '\n'; + } else { } } @@ -138,7 +153,7 @@ class CoreObject { /// @param os Output stream to write to. /// @param var Variable to serialize. template - void SerializeValue_Vector(std::ostream & os, const std::vector & var) const { + static void SerializeValue_Vector(std::ostream & os, const std::vector & var) { SerializeValue(os, var.size()); for (const auto & x : var) { SerializeValue(os, x); @@ -149,7 +164,7 @@ class CoreObject { /// @param os Output stream to write to. /// @param var Variable to serialize. template - void SerializeValue_Map(std::ostream & os, const T & var) const { + static void SerializeValue_Map(std::ostream & os, const T & var) { SerializeValue(os, var.size()); for (const auto & [key, value] : var) { SerializeValue(os, key); @@ -157,11 +172,11 @@ class CoreObject { } } - /// @brief Helper function to serialize a single member variable. - /// @param os Output stream to write to. + /// @brief Helper function to deserialize a single member variable. + /// @param os Input stream to write from. /// @param var Variable to deserialize. template - void DeserializeValue(std::istream & is, T & var) const { + static void DeserializeValue(std::istream & is, T & var) { static_assert(!std::is_const(), "Cannot deserialize const variables."); // If we are loading a string, load it directly. @@ -171,6 +186,8 @@ class CoreObject { DeserializeValue_Vector(is, var); } else if constexpr (is_any_map()) { DeserializeValue_Map(is, var); + } else if constexpr (std::is_base_of()) { + var.Deserialize(is); } else { // @CAO: This can be streamlined to use only the original is, and based on type. // For example, "is << var" followed by "is.peek()" to make sure we have a @@ -182,17 +199,19 @@ class CoreObject { int enum_val; ss >> enum_val; var = static_cast(enum_val); - } else { + } else if constexpr (CanStreamFrom) { ss >> var; + } else { + // Finally, ignore this value? Most likely a pointer. } } } - /// @brief Helper function to serialize a member variables from a function - /// @param os Output stream to write to. + /// @brief Helper function to deserialize a member variables from a function + /// @param os Input stream to write from. /// @param var Variable to serialize. template - void DeserializeFunction(std::istream & is, std::function set_fun) const { + static void DeserializeFunction(std::istream & is, std::function set_fun) { std::string str; std::getline(is, str, '\n'); if constexpr (std::is_same, std::string>()) { @@ -209,11 +228,20 @@ class CoreObject { } } + /// @brief Helper function to deserialize and return a specified type + /// @param os Input stream to write from. + template + static T DeserializeAs(std::istream & is) { + T value; + DeserializeValue(is, value); + return value; + } + /// @brief Helper specialty function to deserialize a vector-based member variable. /// @param os Input stream to read from. /// @param var Variable to deserialize. template - void DeserializeValue_Vector(std::istream & is, std::vector & var) const { + static void DeserializeValue_Vector(std::istream & is, std::vector & var) { DeserializeFunction(is, [&var](size_t in_size){ var.resize(in_size); } ); for (auto & x : var) { DeserializeValue(is, x); @@ -224,7 +252,7 @@ class CoreObject { /// @param is Input stream to read from. /// @param var Variable to deserialize. template - void DeserializeValue_Map(std::istream & is, MAP_T & var) const { + static void DeserializeValue_Map(std::istream & is, MAP_T & var) { size_t map_size = 0; typename MAP_T::key_type key; typename MAP_T::mapped_type value; From 5502860811b7955207a0daf2aae9f3924c6ce319 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 00:20:33 -0500 Subject: [PATCH 18/22] Minor comment fixes. --- source/core/EasyLogging.hpp | 13 +++++++++---- tests/unit/core/WorldGrid.cpp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/source/core/EasyLogging.hpp b/source/core/EasyLogging.hpp index 653fd0e5..45ac48cf 100644 --- a/source/core/EasyLogging.hpp +++ b/source/core/EasyLogging.hpp @@ -1,3 +1,9 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief Tools for debug-logging that can be easily controlled. + * @note Status: ALPHA + **/ + #pragma once #include @@ -9,13 +15,11 @@ namespace clogged { /** * @brief Log levels for logging - * */ enum class LogLevel { DEBUG, INFO, WARNING, ERR, NA }; /** * @brief Teams Names for logging - * */ enum class Team { TEAM_1, @@ -179,7 +183,7 @@ class Logger { * Changes requested from Dr.@ofria * * @authors @mercere99 - * @return + * @return a unique Logger instance */ static Logger &Log() { static Logger instance; // Guaranteed to be initialized only once. @@ -191,7 +195,8 @@ class Logger { * Changes requested from Dr.@ofria * * @authors @mercere99 - * @return + * @param arg1 Set of values that you want to have logged. + * @return Unique Logger instance */ template static Logger &Log(T &&arg1, EXTRA_Ts &&...extra_args) { diff --git a/tests/unit/core/WorldGrid.cpp b/tests/unit/core/WorldGrid.cpp index b8bc6597..c7721c0f 100644 --- a/tests/unit/core/WorldGrid.cpp +++ b/tests/unit/core/WorldGrid.cpp @@ -1,6 +1,6 @@ /** * This file is part of the Fall 2023, CSE 491 course project. - * @brief Unit tests for Data.hpp in source/core + * @brief Unit tests for WorldGrid.hpp in source/core **/ // Catch2 From a399bd083d95f8ca59136886b5bece00ab270bac Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 00:21:24 -0500 Subject: [PATCH 19/22] Moved Property into its own file. --- source/core/Entity.hpp | 134 +++------------------------------------ source/core/Property.hpp | 114 +++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 126 deletions(-) create mode 100644 source/core/Property.hpp diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index 387bb39e..0de07477 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -18,6 +18,7 @@ #include "CoreObject.hpp" #include "Data.hpp" #include "GridPosition.hpp" +#include "Property.hpp" namespace cse491 { @@ -36,88 +37,6 @@ class Entity : public CoreObject { std::vector inventory; ///< What entity ids are held by this entity? - struct PropertyBase { - virtual ~PropertyBase() {} - virtual PropertyType GetType() const = 0; - virtual std::string GetTypeName() const = 0; - virtual std::string ToString() const = 0; - virtual char ToChar() const = 0; - virtual double ToDouble() const = 0; - virtual int ToInt() const = 0; - virtual GridPosition ToGridPosition() const = 0; - }; - - // For the moment, properties can be char, int, double, string, or GridPosition - template - struct Property : public PropertyBase { - T value; - Property(const T &in) : value(in) {} - Property(T &&in) : value(in) {} - - PropertyType GetType() const override { - if constexpr (std::is_same()) return PropertyType::t_char; - if constexpr (std::is_same()) return PropertyType::t_int; - if constexpr (std::is_same()) return PropertyType::t_double; - if constexpr (std::is_same()) return PropertyType::t_string; - if constexpr (std::is_same()) return PropertyType::t_position; - return PropertyType::t_other; - } - - std::string GetTypeName() const override { - if constexpr (std::is_same()) return "char"; - if constexpr (std::is_same()) return "int"; - if constexpr (std::is_same()) return "double"; - if constexpr (std::is_same()) return "string"; - if constexpr (std::is_same()) return "GridPosition"; - return "unknown"; - } - - std::string ToString() const override { - if constexpr (std::is_same()) return std::string(1, value); - if constexpr (std::is_same()) return std::to_string(value); - if constexpr (std::is_same()) return std::to_string(value); - if constexpr (std::is_same()) return value; - if constexpr (std::is_same()) return value.ToString(); - return "unknown"; - } - - char ToChar() const override { - if constexpr (std::is_same()) return value; - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return value.size() ? value[0] : '\0'; - if constexpr (std::is_same()) return '\0'; // No conversion. - return '\0'; - } - - double ToDouble() const override { - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return value; - if constexpr (std::is_same()) return std::stod(value); - if constexpr (std::is_same()) return std::nan("nan"); // No conversion. - return std::nan("nan"); - } - - int ToInt() const override { - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return value; - if constexpr (std::is_same()) return static_cast(value); - if constexpr (std::is_same()) return std::stoi(value); - if constexpr (std::is_same()) return 0; // No conversion. - return 0; - } - - GridPosition ToGridPosition() const override { - if constexpr (std::is_same()) return GridPosition::Invalid(); - if constexpr (std::is_same()) return GridPosition::Invalid(); - if constexpr (std::is_same()) return GridPosition::Invalid(); - if constexpr (std::is_same()) return GridPosition(value); - if constexpr (std::is_same()) return value; - return GridPosition::Invalid(); - } - }; - /// Every entity can have a simple set of properties (with values) associated with it. using property_map_t = std::unordered_map>; property_map_t property_map; @@ -245,29 +164,8 @@ class Entity : public CoreObject { SerializeValue(os, property_map.size()); for (const auto & [name, ptr] : property_map) { SerializeValue(os, name); - PropertyType type = ptr->GetType(); - SerializeValue(os, static_cast(type)); - - switch (type) { - using enum PropertyType; - case t_char: - SerializeValue(os, ptr->ToChar()); - break; - case t_double: - SerializeValue(os, ptr->ToDouble()); - break; - case t_int: - SerializeValue(os, ptr->ToInt()); - break; - case t_string: - SerializeValue(os, ptr->ToString()); - break; - case t_position: - ptr->ToGridPosition().Serialize(os); - break; - case t_other: - assert(false); // Cannot serialize this type... - } + SerializeValue(os, ptr->GetType()); + SerializeValue(os, ptr->ToString()); } } @@ -285,33 +183,17 @@ class Entity : public CoreObject { property_map.clear(); std::string name; PropertyType type; - char val_c; double val_d; int val_i; std::string val_s; GridPosition val_g; DeserializeValue(is, num_properties); for (size_t i = 0; i < num_properties; ++i) { DeserializeValue(is, name); DeserializeValue(is, type); switch (type) { using enum PropertyType; - case t_char: - DeserializeValue(is, val_c); - SetProperty(name, val_c); - break; - case t_double: - DeserializeValue(is, val_d); - SetProperty(name, val_d); - break; - case t_int: - DeserializeValue(is, val_i); - SetProperty(name, val_i); - break; - case t_string: - DeserializeValue(is, val_s); - SetProperty(name, val_s); - break; - case t_position: - val_g.Deserialize(is); - SetProperty(name, val_g); - break; + case t_char: SetProperty(name, DeserializeAs(is)); break; + case t_double: SetProperty(name, DeserializeAs(is)); break; + case t_int: SetProperty(name, DeserializeAs(is)); break; + case t_string: SetProperty(name, DeserializeAs(is)); break; + case t_position: SetProperty(name, DeserializeAs(is)); break; case t_other: assert(false); // Cannot deserialize this type... } diff --git a/source/core/Property.hpp b/source/core/Property.hpp new file mode 100644 index 00000000..b055586a --- /dev/null +++ b/source/core/Property.hpp @@ -0,0 +1,114 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief A class to maintain arbitrary data and facilitate its use. + * @note Status: ALPHA + **/ + +#pragma once + +#include +#include + +#include "CoreObject.hpp" +#include "Data.hpp" +#include "GridPosition.hpp" + +namespace cse491 { + +struct PropertyBase : public CoreObject { + virtual ~PropertyBase() {} + virtual PropertyType GetType() const = 0; + virtual std::string GetTypeName() const = 0; + virtual std::string ToString() const = 0; + virtual char ToChar() const = 0; + virtual double ToDouble() const = 0; + virtual int ToInt() const = 0; + virtual GridPosition ToGridPosition() const = 0; +}; + +// For the moment, properties can be char, int, double, string, or GridPosition +template +struct Property : public PropertyBase { + T value; + Property(const T &in) : value(in) {} + Property(T &&in) : value(in) {} + + PropertyType GetType() const override { + if constexpr (std::is_same()) return PropertyType::t_char; + if constexpr (std::is_same()) return PropertyType::t_int; + if constexpr (std::is_same()) return PropertyType::t_double; + if constexpr (std::is_same()) return PropertyType::t_string; + if constexpr (std::is_same()) return PropertyType::t_position; + return PropertyType::t_other; + } + + std::string GetTypeName() const override { + if constexpr (std::is_same()) return "char"; + if constexpr (std::is_same()) return "int"; + if constexpr (std::is_same()) return "double"; + if constexpr (std::is_same()) return "string"; + if constexpr (std::is_same()) return "GridPosition"; + return "unknown"; + } + + std::string ToString() const override { + if constexpr (std::is_same()) return std::string(1, value); + if constexpr (std::is_same()) return std::to_string(value); + if constexpr (std::is_same()) return std::to_string(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return value.ToString(); + return "unknown"; + } + + char ToChar() const override { + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value.size() ? value[0] : '\0'; + if constexpr (std::is_same()) return '\0'; // No conversion. + return '\0'; + } + + double ToDouble() const override { + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return std::stod(value); + if constexpr (std::is_same()) return std::nan("nan"); // No conversion. + return std::nan("nan"); + } + + int ToInt() const override { + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return value; + if constexpr (std::is_same()) return static_cast(value); + if constexpr (std::is_same()) return std::stoi(value); + if constexpr (std::is_same()) return 0; // No conversion. + return 0; + } + + GridPosition ToGridPosition() const override { + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition::Invalid(); + if constexpr (std::is_same()) return GridPosition(value); + if constexpr (std::is_same()) return value; + return GridPosition::Invalid(); + } + + // --- CoreObject Functionality --- + std::string GetTypeName_impl() const override { + return std::string("cse491::Property<") + GetTypeName() + ">"; + } + + void Serialize_impl(std::ostream & os) const override { + SerializeValue(os, value); + }; + + void Deserialize_impl(std::istream & is) override { + DeserializeValue(is, value); + }; +}; + + +} // End of namespace cse491 From 89ac0cf5c57a31ab4b284d56e27945a303ac22c8 Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 11:09:40 -0500 Subject: [PATCH 20/22] Move Serialize helper functions into their own file. --- source/core/CoreObject.hpp | 159 +----------------------------- source/core/Serialize.hpp | 196 +++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 157 deletions(-) create mode 100644 source/core/Serialize.hpp diff --git a/source/core/CoreObject.hpp b/source/core/CoreObject.hpp index ee696d3f..a97698c0 100644 --- a/source/core/CoreObject.hpp +++ b/source/core/CoreObject.hpp @@ -23,6 +23,8 @@ #include #include +#include "Serialize.hpp" + /** * @author @amantham20 * uses as attribute to mark experimental classes and functions @@ -43,30 +45,6 @@ namespace cse491 { -/// Type trait to determine if we are working with a vector. -template struct is_vector : std::false_type {}; -template struct is_vector> : std::true_type {}; - -/// Type trait to determine if we are working with any type of map. -template -struct is_any_map : std::false_type {}; -template -struct is_any_map> : std::true_type {}; -template -struct is_any_map> : std::true_type {}; - -/// Concept to identify if a type can be sent into an ostream. -template -concept CanStreamTo = requires(STREAM_T & stream, OBJ_T value) { - { stream << value } -> std::convertible_to; -}; - -/// Concept to identify if a type can be set from an istream. -template -concept CanStreamFrom = requires(STREAM_T & stream, OBJ_T value) { - { stream >> value } -> std::convertible_to; -}; - /// @class WorldGrid /// @brief A common interface class for core objects that sets up required functionality. /// This class ensures that objects can be serialized (saved), deserialized (restored) @@ -130,139 +108,6 @@ class CoreObject { return true; } - /// @brief Helper function to serialize a single member variable. - /// @param os Output stream to write to. - /// @param var Variable to serialize. - template - static void SerializeValue(std::ostream & os, const T & var) { - if constexpr (std::is_enum()) { - os << static_cast(var) << std::endl; - } else if constexpr (is_vector()) { - SerializeValue_Vector(os, var); - } else if constexpr (is_any_map()) { - SerializeValue_Map(os, var); - } else if constexpr (std::is_base_of()) { - var.Serialize(os); - } else if constexpr (CanStreamTo) { - os << var << '\n'; - } else { - } - } - - /// @brief Helper specialty function to serialize a vector-based member variable. - /// @param os Output stream to write to. - /// @param var Variable to serialize. - template - static void SerializeValue_Vector(std::ostream & os, const std::vector & var) { - SerializeValue(os, var.size()); - for (const auto & x : var) { - SerializeValue(os, x); - } - } - - /// @brief Helper specialty function to serialize a unordered_map member variable. - /// @param os Output stream to write to. - /// @param var Variable to serialize. - template - static void SerializeValue_Map(std::ostream & os, const T & var) { - SerializeValue(os, var.size()); - for (const auto & [key, value] : var) { - SerializeValue(os, key); - SerializeValue(os, value); - } - } - - /// @brief Helper function to deserialize a single member variable. - /// @param os Input stream to write from. - /// @param var Variable to deserialize. - template - static void DeserializeValue(std::istream & is, T & var) { - static_assert(!std::is_const(), "Cannot deserialize const variables."); - - // If we are loading a string, load it directly. - if constexpr (std::is_same, std::string>()) { - std::getline(is, var, '\n'); - } else if constexpr (is_vector()) { - DeserializeValue_Vector(is, var); - } else if constexpr (is_any_map()) { - DeserializeValue_Map(is, var); - } else if constexpr (std::is_base_of()) { - var.Deserialize(is); - } else { - // @CAO: This can be streamlined to use only the original is, and based on type. - // For example, "is << var" followed by "is.peek()" to make sure we have a - // newline, and then "is.ignore()" to skip the newline. - std::string str; - std::getline(is, str, '\n'); - std::stringstream ss(str); - if constexpr (std::is_enum()) { // enums must be converted properly. - int enum_val; - ss >> enum_val; - var = static_cast(enum_val); - } else if constexpr (CanStreamFrom) { - ss >> var; - } else { - // Finally, ignore this value? Most likely a pointer. - } - } - } - - /// @brief Helper function to deserialize a member variables from a function - /// @param os Input stream to write from. - /// @param var Variable to serialize. - template - static void DeserializeFunction(std::istream & is, std::function set_fun) { - std::string str; - std::getline(is, str, '\n'); - if constexpr (std::is_same, std::string>()) { - set_fun(str); - } else if constexpr (std::is_same, int>()) { - set_fun(stoi(str)); - } else if constexpr (std::is_same, double>()) { - set_fun(stod(str)); - } else { - T var; - std::stringstream ss(str); - ss >> var; - set_fun(var); - } - } - - /// @brief Helper function to deserialize and return a specified type - /// @param os Input stream to write from. - template - static T DeserializeAs(std::istream & is) { - T value; - DeserializeValue(is, value); - return value; - } - - /// @brief Helper specialty function to deserialize a vector-based member variable. - /// @param os Input stream to read from. - /// @param var Variable to deserialize. - template - static void DeserializeValue_Vector(std::istream & is, std::vector & var) { - DeserializeFunction(is, [&var](size_t in_size){ var.resize(in_size); } ); - for (auto & x : var) { - DeserializeValue(is, x); - } - } - - /// @brief Helper specialty function to deserialize a unordered_map member variable. - /// @param is Input stream to read from. - /// @param var Variable to deserialize. - template - static void DeserializeValue_Map(std::istream & is, MAP_T & var) { - size_t map_size = 0; - typename MAP_T::key_type key; - typename MAP_T::mapped_type value; - DeserializeValue(is, map_size); - for (size_t i = 0; i < map_size; ++i) { - DeserializeValue(is, key); - DeserializeValue(is, value); - var[key] = value; - } - } public: virtual ~CoreObject() {} diff --git a/source/core/Serialize.hpp b/source/core/Serialize.hpp new file mode 100644 index 00000000..ed3f70b6 --- /dev/null +++ b/source/core/Serialize.hpp @@ -0,0 +1,196 @@ +/** + * This file is part of the Fall 2023, CSE 491 course project. + * @brief Tools to simplify serializing classes. + * @note Status: ALPHA + **/ + + +#pragma once + +#include +#include +#include +#include + +namespace cse491 { + +// --- Pre-declarations of Functions --- +template static void SerializeValue_Vector(std::ostream &, const std::vector &); +template static void SerializeValue_Map(std::ostream &, const T &); +template static void DeserializeValue_Vector(std::istream &, std::vector &); +template static void DeserializeValue_Map(std::istream &, T &); + + +// --- Type Traits --- + +/// Type trait to determine if we are working with a vector. +template struct is_vector : std::false_type {}; +template struct is_vector> : std::true_type {}; + +/// Type trait to determine if we are working with any type of map. +template +struct is_any_map : std::false_type {}; +template +struct is_any_map> : std::true_type {}; +template +struct is_any_map> : std::true_type {}; + +/// Concept to identify if a type can be sent into an ostream. +template +concept CanStreamTo = requires(STREAM_T & stream, OBJ_T value) { + { stream << value } -> std::convertible_to; +}; + +/// Concept to identify if a type can be set from an istream. +template +concept CanStreamFrom = requires(STREAM_T & stream, OBJ_T value) { + { stream >> value } -> std::convertible_to; +}; + +/// Concept to identify if a type has a Serialize() member function. +template +concept HasSerialize = requires(OBJ_T value) { + { value.Serialize(std::cout) } -> std::same_as; +}; + +/// Concept to identify if a type has a Deserialize() member function. +template +concept HasDeserialize = requires(OBJ_T value) { + { value.Deserialize(std::cout) } -> std::same_as; +}; + +/// @brief Helper function to serialize a single member variable. +/// @param os Output stream to write to. +/// @param var Variable to serialize. +template +static void SerializeValue(std::ostream & os, const T & var) { + if constexpr (std::is_enum()) { + os << static_cast(var) << std::endl; + } else if constexpr (is_vector()) { + SerializeValue_Vector(os, var); + } else if constexpr (is_any_map()) { + SerializeValue_Map(os, var); + } else if constexpr (HasSerialize) { + var.Serialize(os); + } else if constexpr (CanStreamTo) { + os << var << '\n'; + } else { + } +} + +/// @brief Helper specialty function to serialize a vector-based member variable. +/// @param os Output stream to write to. +/// @param var Variable to serialize. +template +static void SerializeValue_Vector(std::ostream & os, const std::vector & var) { + SerializeValue(os, var.size()); + for (const auto & x : var) { + SerializeValue(os, x); + } +} + +/// @brief Helper specialty function to serialize a unordered_map member variable. +/// @param os Output stream to write to. +/// @param var Variable to serialize. +template +static void SerializeValue_Map(std::ostream & os, const T & var) { + SerializeValue(os, var.size()); + for (const auto & [key, value] : var) { + SerializeValue(os, key); + SerializeValue(os, value); + } +} + +/// @brief Helper function to deserialize a single member variable. +/// @param os Input stream to write from. +/// @param var Variable to deserialize. +template +static void DeserializeValue(std::istream & is, T & var) { + static_assert(!std::is_const(), "Cannot deserialize const variables."); + + // If we are loading a string, load it directly. + if constexpr (std::is_same, std::string>()) { + std::getline(is, var, '\n'); + } else if constexpr (is_vector()) { + DeserializeValue_Vector(is, var); + } else if constexpr (is_any_map()) { + DeserializeValue_Map(is, var); + } else if constexpr (HasDeserialize) { + var.Deserialize(is); + } else { + // @CAO: This can be streamlined to use only the original is, and based on type. + // For example, "is << var" followed by "is.peek()" to make sure we have a + // newline, and then "is.ignore()" to skip the newline. + std::string str; + std::getline(is, str, '\n'); + std::stringstream ss(str); + if constexpr (std::is_enum()) { // enums must be converted properly. + int enum_val; + ss >> enum_val; + var = static_cast(enum_val); + } else if constexpr (CanStreamFrom) { + ss >> var; + } else { + // Finally, ignore this value? Most likely a pointer. + } + } +} + +/// @brief Helper function to deserialize a member variables from a function +/// @param os Input stream to write from. +/// @param var Variable to serialize. +template +static void DeserializeFunction(std::istream & is, std::function set_fun) { + std::string str; + std::getline(is, str, '\n'); + if constexpr (std::is_same, std::string>()) { + set_fun(str); + } else if constexpr (std::is_same, int>()) { + set_fun(stoi(str)); + } else if constexpr (std::is_same, double>()) { + set_fun(stod(str)); + } else { + T var; + std::stringstream ss(str); + ss >> var; + set_fun(var); + } +} + +/// @brief Helper function to deserialize and return a specified type +/// @param os Input stream to write from. +template +static T DeserializeAs(std::istream & is) { + T value; + DeserializeValue(is, value); + return value; +} + +/// @brief Helper specialty function to deserialize a vector-based member variable. +/// @param os Input stream to read from. +/// @param var Variable to deserialize. +template +static void DeserializeValue_Vector(std::istream & is, std::vector & var) { + DeserializeFunction(is, [&var](size_t in_size){ var.resize(in_size); } ); + for (auto & x : var) { + DeserializeValue(is, x); + } +} + +/// @brief Helper specialty function to deserialize a unordered_map member variable. +/// @param is Input stream to read from. +/// @param var Variable to deserialize. +template +static void DeserializeValue_Map(std::istream & is, MAP_T & var) { + size_t map_size = 0; + typename MAP_T::key_type key; + typename MAP_T::mapped_type value; + DeserializeValue(is, map_size); + for (size_t i = 0; i < map_size; ++i) { + DeserializeValue(is, key); + DeserializeValue(is, value); + var[key] = value; + } +} + +} // End of namespace cse491 From 13efe59bb62957d2bc4072bb95eb03be0adcd5fd Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 11:19:34 -0500 Subject: [PATCH 21/22] Set all core files to be ALPHA instead of PROPOSAL. --- source/core/AgentBase.hpp | 2 +- source/core/Data.hpp | 2 +- source/core/GridPosition.hpp | 2 +- source/core/InterfaceBase.hpp | 2 +- source/core/ItemBase.hpp | 2 +- source/core/WorldBase.hpp | 5 ++--- source/core/WorldGrid.hpp | 2 +- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/source/core/AgentBase.hpp b/source/core/AgentBase.hpp index f64d35fc..360ea7d0 100644 --- a/source/core/AgentBase.hpp +++ b/source/core/AgentBase.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A base class interface for all agent types. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once diff --git a/source/core/Data.hpp b/source/core/Data.hpp index 7d6a075b..6c8efddb 100644 --- a/source/core/Data.hpp +++ b/source/core/Data.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief Set of types used throughout the codebase - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once diff --git a/source/core/GridPosition.hpp b/source/core/GridPosition.hpp index f897b27a..3decc2d5 100644 --- a/source/core/GridPosition.hpp +++ b/source/core/GridPosition.hpp @@ -155,7 +155,7 @@ class GridPosition : public CoreObject { } - // -- CoreObject Operations -- + // -- CoreObject Functionality -- std::string GetTypeName_impl() const override { return "cse491::GridPosition"; } void Serialize_impl(std::ostream & os) const override { diff --git a/source/core/InterfaceBase.hpp b/source/core/InterfaceBase.hpp index b372e237..169ececd 100644 --- a/source/core/InterfaceBase.hpp +++ b/source/core/InterfaceBase.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A base class for all player-interface types. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once diff --git a/source/core/ItemBase.hpp b/source/core/ItemBase.hpp index 677c5de4..e0347484 100644 --- a/source/core/ItemBase.hpp +++ b/source/core/ItemBase.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A base class interface for all non-agent item types. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once diff --git a/source/core/WorldBase.hpp b/source/core/WorldBase.hpp index 5067faec..f9339fb1 100644 --- a/source/core/WorldBase.hpp +++ b/source/core/WorldBase.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A base class for all World modules. - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once @@ -56,8 +56,7 @@ class WorldBase { agent_map_t agent_map; ///< Map of IDs to pointers to agent entities size_t last_entity_id = 0; ///< The last Entity ID used; increment at each creation - bool run_over = false; ///< Should the run end? - + bool run_over = false; ///< Should the run end? bool world_running = true; ///< Is the world currently running? std::string action; ///< The action that the agent is currently performing diff --git a/source/core/WorldGrid.hpp b/source/core/WorldGrid.hpp index 131f7618..d7d6d08d 100644 --- a/source/core/WorldGrid.hpp +++ b/source/core/WorldGrid.hpp @@ -1,7 +1,7 @@ /** * This file is part of the Fall 2023, CSE 491 course project. * @brief A simple 2D Grid container - * @note Status: PROPOSAL + * @note Status: ALPHA **/ #pragma once From 7d825659d615713bac5bb1ccfffb9642fbeac67d Mon Sep 17 00:00:00 2001 From: Charles Ofria Date: Mon, 11 Dec 2023 14:58:48 -0500 Subject: [PATCH 22/22] Simplified serialize of Entity position. --- source/core/Entity.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/core/Entity.hpp b/source/core/Entity.hpp index 0de07477..8136e07b 100644 --- a/source/core/Entity.hpp +++ b/source/core/Entity.hpp @@ -157,8 +157,7 @@ class Entity : public CoreObject { SerializeValue(os, id); SerializeValue(os, name); SerializeValue(os, grid_id); - SerializeValue(os, position.GetX()); - SerializeValue(os, position.GetY()); + SerializeValue(os, position); SerializeValue(os, inventory); SerializeValue(os, property_map.size()); @@ -175,8 +174,7 @@ class Entity : public CoreObject { DeserializeValue(is, id); DeserializeValue(is, name); DeserializeValue(is, grid_id); - DeserializeFunction(is, [this](double x){ position.SetX(x); }); - DeserializeFunction(is, [this](double y){ position.SetX(y); }); + DeserializeValue(is, position); DeserializeValue(is, inventory); size_t num_properties = 0;