is there a better implementation to deal switches? - c++

I had a class type named reply, its form like this:
class reply {
public:
enum class type {
error = 0,
bulk_string = 1,
simple_string = 2,
null = 3,
integer = 4,
array = 5
};
public:
type get_type(void) const {
return type_;
}
private:
type type_;
};
The reply instance would be returned by other functions, so I would deal with the reply with probing each possible value of the call of get_type. The first solution is to use switch case, but I would like to encapsulate it using 'OOP' thinking as follows:
template<typename Handlers, typename Handlers::type*...types>
class handlers {
private:
static constexpr typename Handlers::type* dealers[] = { types... };
public:
static void deal(const reply& reply) {
dealers[int(reply.get_type())](reply);
}
};
template<typename Handlers>
class handle{
public:
using handles = handlers<Handlers, Handlers::error_handle,
Handlers::bulk_string_handle, Handlers::simple_string_handle,
Handlers::null_handle, Handlers::integer_handle,
Handlers::array_handle>;
};
class handler
{
public:
static void error_handle(const reply&) {
std::cout << "error_handle" << std::endl;
}
static void bulk_string_handle(const reply&) {
std::cout << "bulk_string_handle" << std::endl;
}
static void simple_string_handle(const reply&) {
std::cout << "simple_string_handle" << std::endl;
}
static void null_handle(const reply&) {
std::cout << "null_handle" << std::endl;
}
static void integer_handle(const reply&) {
std::cout << "integer_handle" << std::endl;
}
static void array_handle(const reply&) {
std::cout << "array_handle" << std::endl;
}
public:
using type = decltype(error_handle);
using handles = handle<handler>::handles;
};
Finally, I can deal the reply like this:
int main()
{
reply rep;
handler::handles::deal(rep);
return 0;
}
Note: Each reply has its handler.
What I focus on is whether there is better way to adapt to the solution?

Design at least "central points" as possible. Concentrate on making it easy to add new reply types, the design will flow from that assumption. Create separated parts associated with each reply with a single one central point that choose the handler. The central point is called a factory and small parts implement the same interface.
struct handler {
// I do not know, maybe this should store the reply?
// No idea.
virtual void handle(const reply&);
virtual ~handler();
};
struct error_handler : handler {
void handle(const reply&) { /* blabla */ }
handler construct() { return error_handler(); }
};
/* etc. for each handle type */
// TODO: convert to static array to save dynamic allocatiosn
std::map<std::reply::type, std::function<handler()>> handlers_map{
{ std::reply::error, []() { return error_handler(); } },
/* etc. for each handle type */
};
handler handler_factor(const reply& r) {
return handlers_map.at(r.get_type())();
}
#if YAY_AN_ARRAY // an example of converting map to a static array
// TODO: do it as a member function
static handler error_handler_construct() { return error_handler(); }
static std::array<handler (*)(), 1> handlers_array{
&error_handler_construct,
/* etc. */
};
handler handler_factor(const reply &r) {
// remember about error handling
return handlers_array.at(
static_cast<int>(r.get_type())
)();
}
#elif YAY_ANOTHER_ARRAY
static handler (*const handlers_array[])() = {
[static_cast<int>(reply::type::error)] = &error_handler_construct,
/* etc. */
};
handler handler_factor(const reply &r) {
auto t = static_cast<int>(r.get_type();
if (t < 0 || t > sizeof(handlers_array)/sizeof(*handlers_array)) {
abort();
}
return handlers_array[t]();
}
#enidf
int main() {
reply rep;
auto h = handler_factor(rep);
h.handle(rep);
return 0;
}

Related

Is it possible for a class to contain a lambda object that captures the class its in?

Let's just say I have a Window class, and that Window class has event handlers in the form of std::function:
struct Event {};
struct Window
{
std::function<void(Event)> handler;
};
Window wnd;
wnd.handler = [] (Event) { /*some fancy handler*/ };
From inside the handler I don't have access to the window itself, so I can either pass the window pointer to the handler, or I can implicitly have access inside the handler function to the window by capturing it. However in the capturing case I think I run into this problem:
struct Event {};
struct Window
{
std::function<void(Event)> handler;
int member;
};
int main()
{
Window wnd1;
// Capture the window so I can access it inside the handler function
Window wnd2{ [&wnd2](Event) { wnd2.member = 3; } };
wnd1 = std::move(wnd2);
// wnd1 contains a lambda object pointing to wnd2, that's invalid.
Window wnd3 { [&wnd3](int) { wnd3.member = 7; } };
std::vector<Window> wnd_vector{ wnd3 }; // Now when vector reallocates the lambda // object is invalid because of the 'this' pointer, right?
So then the rule I guess is: You can't have a class containing a lambda object if that lambda object has captured the outer class (IF the outer class is movable). I think this problem extends to more general cases:
struct MoveableClass
{
struct Foo { MoveableClass* outer_class_object; };
Foo fooObj{this};
}
I can handle moving this class by using custom move functions. But in the case of std::function or if it contains a lambda, then I can't move it, right?
I propose you such solution:
#include <iostream>
#include <vector>
#include <functional>
struct Event {};
struct Window
{
public:
Window() = default;
Window(std::function<void(Window &, Event)> handler)
: handler(handler)
{}
Window(std::function<void(Window &, Event)> handler,
int member)
: handler(handler),
member(member)
{}
void setHandler(std::function<void(Window &, Event)> newHandler)
{
handler = newHandler;
}
bool callHandler(Event event)
{
if (handler)
{
handler(*this, event);
return true;
}
return false;
}
void setMember(int newMember)
{
member = newMember;
}
int getMember() const
{
return member;
}
private:
std::function<void(Window &, Event)> handler; // if it is not needed to change class members than you can use "const Window &"
int member = 0;
};
void print(const Window & obj)
{
std::cout << "Object: " << static_cast<const void *>(&obj) << ", member: " << obj.getMember() << std::endl;
}
int main()
{
Event event;
bool callResult = false;
Window wnd1;
Window wnd2{ [](Window & obj, Event) { obj.setMember(3); } };
callResult = wnd2.callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd2);
wnd2.setHandler( [](Window & obj, Event) { obj.setMember(1); } );
wnd1 = std::move(wnd2);
callResult = wnd1.callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd1);
Window wnd3 { [](Window & obj, Event) { obj.setMember(7); } };
std::vector<Window> wnd_vector{ wnd3 };
callResult = wnd_vector.front().callHandler(event);
std::cout << "Call result: " << std::boolalpha << callResult << std::endl;
print(wnd_vector.front());
print(wnd3);
return 0;
}
Result:
Call result: true
Object: 0x7ffd57d9ccb0, member: 3
Call result: true
Object: 0x7ffd57d9cc80, member: 1
Call result: true
Object: 0x2263c30, member: 7
Object: 0x7ffd57d9cce0, member: 0

How to handle polymorphism with vectors of a class the right way in C++?

I'm currently implementing an entity component system and working on a way to store vectors of components, each vector of one component type should be contiguous, this is why I'm using vector<Component>* and not vector<Component*>. I'm new to C++ and coming from Java, so I'm still struggling with some concepts regarding memory layout and polymorphism.
I've fully implemented a (seemingly) working version of this. I have a vector for each type of component there is (e.g. PositionComponent, GravityComponent, etc.), because components differ in size. But because the amount of types isn't known in compile time, I need a vector of pointers to point to these ComponentLists of different types. I'm using reinterpret_casts with a map which keeps track of the component types to accomplish this, but there has to be a less undefined way of doing this. (Hopefully!)
Here is a picture of what I want to achieve:
Component List Layout
Edit: I just notices that my program crashes with a segmentation fault after the return 0 in the main function. The call stack seems to be corrupted, as it jumps to some random address instead of actually returning. So my system is definately flawed.
Main function:
int main(int argc, char** argv)
{
EntityComponentSystem ecs;
// Fill with some components
for(int i = 0; i < 5; ++i)
{
ecs.addComponent(AComponent());
ecs.addComponent(BComponent());
ecs.addComponent(CComponent());
}
// Print all components
std::cout << "Components: " << std::endl;
// Print AComponents
std::cout << "A Components: " << std::endl;
ComponentList<AComponent>* aComps = ecs.getComponentList<AComponent>();
aComps->print();
// Print BComponents
std::cout << std::endl << "B Components: " << std::endl;
ComponentList<BComponent>* bComps = ecs.getComponentList<BComponent>();
bComps->print();
// Print CComponents
std::cout << std::endl << "C Components: " << std::endl;
ComponentList<CComponent>* cComps = ecs.getComponentList<CComponent>();
cComps->print();
return 0;
}
EntityComponentSystem class:
class EntityComponentSystem
{
private:
// To shorten some things up
typedef std::vector<ComponentList<Component>*>::iterator ComponentListIterator;
typedef std::unordered_map<std::type_index, Component::TypeID>::iterator MapIterator;
std::vector<ComponentList<Component>*> comps; // Indexed by TypeID
std::unordered_map<std::type_index, Component::TypeID> componentMap; // Maps typeid(Component) to TypeID
public:
EntityComponentSystem() : comps(), componentMap() {}
~EntityComponentSystem()
{
for(ComponentListIterator it = comps.begin(); it < comps.end(); ++it)
{
delete (*it);
}
}
template<typename T>
void addComponent(const T& component)
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");
MapIterator found = componentMap.find(typeid(T));
ComponentList<T>* componentList = nullptr;
if(found == componentMap.end()) // This component derivative hasn't been added yet, so add it
{
componentList = new ComponentList<T>();
int componentId = comps.size();
this->comps.push_back(reinterpret_cast<ComponentList<Component>*>(componentList));
this->componentMap[typeid(T)] = componentId;
}
else
{
componentList = reinterpret_cast<ComponentList<T>*>(comps[found->second]);
}
componentList->push(component);
}
template<typename T>
ComponentList<T>* getComponentList()
{
Component::TypeID id = getComponentTypeId<T>();
if(id == Component::TYPE_ID_UNKNOWN) return nullptr;
return reinterpret_cast<ComponentList<T>*>(comps[id]);
}
template<typename T>
Component::TypeID getComponentTypeId()
{
static_assert(std::is_base_of<Component, T>::value, "T must be of type Component!");
MapIterator found = componentMap.find(typeid(T));
if(found == componentMap.end())
{
return Component::TYPE_ID_UNKNOWN;
}
return found->second;
}
};
ComponentList class:
template<typename T>
class ComponentList
{
private:
std::vector<T> components;
public:
void push(const T& t)
{
this->components.push_back(t);
}
void print()
{
for(typename std::vector<T>::iterator it = components.begin(); it != components.end(); ++it)
{
it->test();
}
}
};
Base Component class and its derivatives:
class Component
{
public:
typedef uint16_t TypeID;
static const TypeID TYPE_ID_UNKNOWN = -1;
virtual ~Component() = default;
virtual void test()
{
std::cout << "I'm the base!" << std::endl;
}
};
class AComponent : public Component
{
private:
static int nextValue;
int someValue; // To test if different sizes of Component derivatives cause any problems!
public:
AComponent()
{
this->someValue = nextValue++;
}
void test()
{
std::cout << "I'm AComponent! Value: " << someValue << std::endl;
}
};
int AComponent::nextValue = 0;
class BComponent : public Component
{
public:
void test()
{
std::cout << "I'm BComponent!" << std::endl;
}
};
class CComponent : public Component
{
public:
void test()
{
std::cout << "I'm CComponent!" << std::endl;
}
};

Return a function from a class

I want to be able to return a function from a class, so that I do not need to if-else through a return type.
I have a class that returns multiple strings. Instead, I want to return multiple functions.
#include <iostream>
class Handler
{
private:
public:
int handleMessage(int code)
{
return code+1;
}
};
void func1();
void func2();
void func3();
int main (int argc, char *argv[])
{
Handler handle;
int code = handle.handleMessage(0);
if(code == 1)
{
func1();
}
return 0;
}
void func1(){ std::cout << "1" << std::endl;}
void func2(){ std::cout << "2" << std::endl;}
void func3(){ std::cout << "3" << std::endl;}
What I want is: That the function handleMessage in the class Handler returns something so that in my main application I do not have to use if-else.
So the main looks like this:
function = handle.handleMessage(0);
And the application will choose which function it will run.
for example:
function = handle.handleMessage(0); //will run func1
function = handle.handleMessage(1); //will run func2
You can modify the member function such that it returns a function pointer, e.g.
using fptr = void (*)();
struct Handler
{
fptr handleMessage (int code)
{
if (code == 0)
return &func1;
else if (code == 1)
return &func2;
else
return &func3;
}
};
This can be invoked as follows
Handler handle;
auto f = handle.handleMessage(0);
f();
Note that the above if-else if-else dispatch isn't ideal. Prefer a data member that stores the function pointers and associates them with a code, e.g. using a std::unordered_map.
Note that when you need to return stateful function objects in the future, this approach will fail. Then, you need to embrace std::function which is able to wrap lambdas with closures or custom types with an operator() overload.
There are several ways to do so, the simplest one, you can use an std::function. In this example we returning a lambda function for each case. You can replace it with the functions you just wrote.
class Handler {
public:
std::function<void()> handleMessage(int code) {
code = code + 1; // ++code or whatever
if (code == X) {
return []() { std::cout << "Cool! I'am x!" << std::endl; };
} else if (code == Y) {
return []() { std::cout << "Cool! I'am x!" << std::endl; };
} else if (...) {
...
} else {
....
}
}
};
Then your main function becomes:
int main (int argc, char *argv[]) {
Handler handle;
const auto func = handle.handleMessage(0);
func();
return 0;
}
You can replace the swith/if case statement by an array storing the different functions, like they mentioned in the comments.
If you dont want to pay the extra virtual function call regarding the usage of an std::function, you can use an alias like the answer below or just the auto keyword:
class Handler {
public:
constexpr auto handleMessage(int code) {
code = code + 1; // ++code or whatever
if (code == X) {
return &func1;
} else if (code == Y) {
return &func2;
} else if (...) {
...
} else {
....
}
}
};
std::function is a powerful tool. The tiny brother is a simple function pointer.
I transformed MCVE respectively to return a function pointer:
#include <iostream>
typedef void (*FuncPtr)();
void func1();
void func2();
void func3();
void funcError();
class Handler
{
private:
public:
FuncPtr handleMessage(int code)
{
switch (code + 1) {
case 1: return &func1;
case 2: return &func2;
case 3: return &func3;
default: return &funcError;
}
}
};
int main (int argc, char *argv[])
{
Handler handle;
FuncPtr pFunc = handle.handleMessage(0);
pFunc();
return 0;
}
void func1(){ std::cout << "1" << std::endl;}
void func2(){ std::cout << "2" << std::endl;}
void func3(){ std::cout << "3" << std::endl;}
void funcError(){ std::cout << "ERROR!" << std::endl;}
Output:
1
Live Demo on coliru
You can return a function with return_type(*function_name)(argument_type1, argument_type2...) so a function that looks like:
double f(int a, int b);
has the name double(*f)(int, int).
Worth mentioning is C++11's std::function which requires the <functional> header. It has a more intuitive usage: std::function<double(int, int)> but also adds a bit of overhead.
I would also like to suggest the usage of C++17's std::optional as for the case when the variable code goes out of bounds. This implementation requires the <optional> header.
std::optional<void(*)()> handleMessage(int code){
switch (code) {
case 0: return std::optional(func1);
case 1: return std::optional(func2);
case 2: return std::optional(func3);
}
return std::nullopt; //empty
}
usage in main looks like the following:
Handler handle;
auto func = handle.handleMessage(0);
if (func.has_value()) {
func.value()();
}
as this allows to check if func.has_value() which is quite convenient.
Use an array of functions.
void func1(){ std::cout << "1" << std::endl; }
void func2(){ std::cout << "2" << std::endl; }
void func3(){ std::cout << "3" << std::endl; }
typedef void (* func ) () ;
class Handler {
public:
func handleMessage(int code)const{
static const func F[] = { func1, func2, func3 };
return F[ code ];
}
};
int main()
{
Handler handler;
func f = handler.handleMessage(0); // returns func1
f();
}
live example
you can map the ints to a function or lambda, but read befor what at() does and what happens if the key is not found!!
void function1()
{
std::cout << "q1" << std::endl;
}
void function2()
{
std::cout << "q2" << std::endl;
}
int main(int argc, char* argv[])
{
std::map<int, std::function<void(void)>> map;
map.insert(std::make_pair(1, function1));
map.insert(std::make_pair(1, function2));
map.at(1)();
I would like to offer solution without any if-else block. You just need to templatize your Handler::handleMessage function. Something like this:
// Class declaration
class Handler
{
private:
public:
template<int code>
void handleMessage();
};
and specialize the function template for particular codes:
// Function template specializations.
template<>
void Handler::handleMessage<1>()
{
std::cout << "1" << std::endl;
}
template<>
void Handler::handleMessage<2>()
{
std::cout << "2" << std::endl;;
}
template<>
void Handler::handleMessage<3>()
{
std::cout << "3" << std::endl;;
}
// All cases, except 1, 2 and 3
template<int code>
void Handler::handleMessage()
{
std::cout << "Anything else" << std::endl;;
}
The usage may look like:
Handler h;
h.handleMessage<1>(); // Prints 1
h.handleMessage<2>(); // Prints 2
h.handleMessage<3>(); // Prints 3
h.handleMessage<323>(); // Prints 'Anything else'

C++ enums with attributes like C#

I have the following C# Code which I need to convert into C++ code. I have searched for a bit on how to do C++ Enums with Attributes and can not figure it out.
Basically I need a way to represent the following simplified C# Code in C++ which would do enums with attributes.
C# Code:
public class PSMNameAttribute : Attribute
{
public string PSMName;
public PSMNameAttribute(string _PSMName) { PSMName = _PSMName; }
}
public class PSMNumberAttribute : Attribute
{
public string PSMNumber;
public PSMNumberAttribute(string _PSMNumber) { PSMNumber = _PSMNumber; }
}
public class PSMNumberNameAttribute : Attribute
{
public string PSMNumberName;
public PSMNumberNameAttribute(string _PSMNumberName) { PSMNumberName = _PSMNumberName; }
}
public enum ShippingMethodsTypes
{
[PSMName("ErrorScriptMed")]
[PSMNumber("-5")]
[PSMNumberName("-5 ErrorScriptMed")]
ErrorScriptMed = -5
,
[PSMName("SpecialHandling")]
[PSMNumber("-1")]
[PSMNumberName("-1 SpecialHandling")]
SpecialHandling = -1
,
[PSMName("Error")]
[PSMNumber("0")]
[PSMNumberName("0 Error")]
Error = 0
}
Could this be done like this:
enum Category{
unknown = -1, meat, poultry, seafood, dairy, vegetable,fruit, grain, sweet
};
typedef struct {
float calories; // calories
float carbonhydrates; // grams
float fat; // grams
float cholesterol; // grams
float sodium; // grams
float protein; // grams
Category category ;
}Food;
and if so how would I call the struct values using the enum?
boost::variant and a few visitors should solve it nicely:
#include <boost/variant.hpp>
#include <iostream>
struct get_number : boost::static_visitor<int> {
template<class Method> int operator()(const Method& m) const { return number(m); }
};
struct get_name : boost::static_visitor<std::string> {
template<class Method> const std::string operator()(const Method& m) const { return name(m); }
};
struct ShippingMethodMed {};
static constexpr int number(ShippingMethodMed) { return -5; }
static std::string name(ShippingMethodMed) { return "ErrorScriptMedMed"; }
struct ShippingMethodSpecialHandling { };
static constexpr int number(ShippingMethodSpecialHandling) { return -10; }
static std::string name(ShippingMethodSpecialHandling) { return "SpecialHandling"; }
struct ShippingMethodError {};
static constexpr int number(ShippingMethodError) { return 0; }
static std::string name(ShippingMethodError) { return "Error"; }
using ShippingMethod = boost::variant<ShippingMethodMed, ShippingMethodSpecialHandling, ShippingMethodError>;
int number(ShippingMethod const& sm) {
return boost::apply_visitor(get_number(), sm);
}
std::string name(ShippingMethod const& sm) {
return boost::apply_visitor(get_name(), sm);
}
std::string number_name(ShippingMethod const& sm) {
return std::to_string(number(sm)) + " " + name(sm);
}
int main()
{
ShippingMethod m = ShippingMethodError();
std::cout << number(m) << std::endl;
std::cout << name(m) << std::endl;
std::cout << number_name(m) << std::endl;
m = ShippingMethodSpecialHandling();
std::cout << number(m) << std::endl;
std::cout << name(m) << std::endl;
std::cout << number_name(m) << std::endl;
}
This is not possible with enums alone.
However I think you could solve this by maintaining a string array/vector/map or a combination of those to your enum like:
enum test
{
first = 0,
second, // = 1
// etc...
};
const char* attributes[] =
{
"first attribute",
"second attribute",
};
then you could retrieve this attribute through
const char* firstattribute = attributes[test::first];

Copying object from a superclass pointer

Suppose I have two classes a base class and an inherited class as follows:
class Magic : public Attack
{
public:
Magic(int uID, std::string &name) : Attack(ActionType::MagicAction, uID, name)
{
}
};
class MacroMagic : public Magic
{
MacroMagic(int uID) : Magic(uID, std::string("Testing"))
{
}
void PreUse() override
{
std::cout << "Test" << std::endl;
}
}
I have a shared_ptr to an instance of magic that I would like to copy, but at runtime I will not know whether that pointer points to an instance of Magic, MacroMagic or anything that may have inherited from Magic. I want to be able to copy the object pointed to by the shared_ptr like so:
Battles::magic_ptr mgPtr = MagicNameMap[name];
if (mgPtr.get() != nullptr)
{
return magic_ptr(new Magic(*mgPtr));
}
return mgPtr;
where magic_ptr is a typedef for a shared_ptr around the Magic Class. I could do it by specifying a virtual copy function and calling that, but I'd like to make it less obtuse and easier to maintain. I assume I can do this by a copy constructor, but I'm unsure how to in this instance. The way I have it now, the pointer returned by the above code will not call the override pReUse() function.
A bit of guidance would be much appreciated, thanks
I could do it by specifying a virtual copy function and calling that, but I'd like to make it less obtuse and easier to maintain.
you're working against the language.
you could accomplish what you are after, but i don't recommend it, and it is certainly not easier to setup or maintain than virtual Magic* clone() = 0.
perhaps you could outline the problem that brought you to this conclusion, and then we can help from there. there are usually alternatives which don't fight the language.
EDIT
here's a way around it using an external function table (t_magic_operation_table). you can apply and create several function tables and keep them around. since they exist in the magic object as a single pointer, then you can make these tables quite large (if needed). if your magic types can use the same data/members, then that is one approach. be careful: i threw this together suuuper-fast. it demonstrates the technique, but it's pretty bad otherwise:
#include <iostream>
#include <string>
namespace MONSpiel {
inline unsigned prndm(const unsigned& max) {
return 1 + arc4random() % max;
}
class t_ghoul;
class t_biclops;
class t_magic;
class t_hero {
t_hero();
t_hero(const t_hero&);
t_hero& operator=(const t_hero&);
public:
t_hero(const std::string& inName) : d_name(inName) {
}
const std::string& name() const {
return this->d_name;
}
template<typename TEnemy, typename TMagic>
void attack(TEnemy& enemy, TMagic& magic) const {
if (enemy.isDead()) {
return;
}
enemy.hit(magic.power());
if (enemy.isDead()) {
std::cout << this->name() << ": see you in the prequel...\n\n";
}
else {
std::cout << this->name() << ": have you had enough " << magic.name() << ", " << enemy.name() << "???\n\n";
}
}
/* ... */
private:
const std::string d_name;
};
class t_enemy {
t_enemy();
t_enemy(const t_enemy&);
t_enemy& operator=(const t_enemy&);
public:
t_enemy(const std::string& inName) : d_name(inName), d_lifePoints(1000) {
}
virtual ~t_enemy() {
}
const std::string& name() const {
return this->d_name;
}
bool isDead() const {
return 0 >= this->d_lifePoints;
}
const int& lifePoints() const {
return this->d_lifePoints;
}
void hit(const int& points) {
this->d_lifePoints -= points;
}
/* ... */
private:
const std::string d_name;
int d_lifePoints;
};
class t_ghoul : public t_enemy {
public:
static int MaxDaysAwake() {
return 100;
}
t_ghoul(const std::string& inName) : t_enemy(inName), d_bouyancy(prndm(100)), d_proximityToZebra(prndm(100)), d_daysAwake(prndm(MaxDaysAwake())) {
}
const int& bouyancy() const {
return this->d_bouyancy;
}
const int& proximityToZebra() const {
return this->d_proximityToZebra;
}
const int& daysAwake() const {
return this->d_daysAwake;
}
private:
int d_bouyancy;
int d_proximityToZebra;
int d_daysAwake;
};
class t_biclops : public t_enemy {
public:
t_biclops(const std::string& inName) : t_enemy(inName), d_isTethered(prndm(2)), d_amountOfSunblockApplied(prndm(100)) {
}
const bool& isTethered() const {
return this->d_isTethered;
}
const int& amountOfSunblockApplied() const {
return this->d_amountOfSunblockApplied;
}
private:
bool d_isTethered;
int d_amountOfSunblockApplied;
};
class t_magic_operation_table {
public:
typedef void (*t_ghoul_skirmish_function)(t_magic&, t_ghoul&);
typedef void (*t_biclops_skirmish_function)(t_magic&, t_biclops&);
t_magic_operation_table(t_ghoul_skirmish_function ghoulAttack, t_biclops_skirmish_function biclopsAttack) : d_ghoulAttack(ghoulAttack), d_biclopsAttack(biclopsAttack) {
}
void willSkirmish(t_magic& magic, t_ghoul& ghoul) const {
this->d_ghoulAttack(magic, ghoul);
}
void willSkirmish(t_magic& magic, t_biclops& biclops) const {
this->d_biclopsAttack(magic, biclops);
}
private:
t_ghoul_skirmish_function d_ghoulAttack;
t_biclops_skirmish_function d_biclopsAttack;
};
class t_action {
public:
typedef enum t_type {
NoAction = 0,
MagicAction,
ClubAction,
ClassAction
} t_type;
};
class t_attack {
public:
t_attack(const t_action::t_type& actionType, const int& uID, const std::string& inName) : d_actionType(actionType), d_uID(uID), d_name(inName) {
}
virtual ~t_attack() {
}
void reset() {
/* ... */
}
const std::string& name() const {
return this->d_name;
}
private:
t_action::t_type d_actionType;
int d_uID;
std::string d_name;
};
class t_magic : public t_attack {
t_magic();
t_magic(const t_magic&);
t_magic& operator=(const t_magic&);
static void GhoulSkirmishA(t_magic& magic, t_ghoul& ghoul) {
magic.d_accuracy = ghoul.bouyancy() + prndm(16);
magic.d_power = ghoul.proximityToZebra() + prndm(43);
}
static void GhoulSkirmishB(t_magic& magic, t_ghoul& ghoul) {
magic.d_accuracy = ghoul.bouyancy() / magic.flammability() + prndm(32);
magic.d_power = t_ghoul::MaxDaysAwake() - ghoul.daysAwake() + prndm(23);
}
static void BiclopsSkirmishA(t_magic& magic, t_biclops& biclops) {
if (biclops.isTethered()) {
magic.d_accuracy = 90 + prndm(16);
}
else {
magic.d_accuracy = 40 + prndm(11);
}
magic.d_power = biclops.amountOfSunblockApplied() + prndm(17);
}
static void BiclopsSkirmishB(t_magic& magic, t_biclops& biclops) {
if (biclops.isTethered()) {
magic.d_accuracy = 80 + prndm(80);
}
else {
magic.d_accuracy = 50 + prndm(50);
}
magic.d_power = 80 + prndm(30);
}
const t_magic_operation_table* NextOperationTable() {
static const t_magic_operation_table tables[4] = {
t_magic_operation_table(GhoulSkirmishA, BiclopsSkirmishA),
t_magic_operation_table(GhoulSkirmishB, BiclopsSkirmishB),
t_magic_operation_table(GhoulSkirmishB, BiclopsSkirmishA),
t_magic_operation_table(GhoulSkirmishA, BiclopsSkirmishB)
};
return & tables[arc4random() % 4];
}
public:
t_magic(const int& uID, const std::string& inName) : t_attack(t_action::MagicAction, uID, inName), d_power(-1), d_accuracy(-1), d_operationTable(0) {
}
int flammability() const {
return prndm(73);
}
int power() const {
return this->d_power;
}
void reset() {
t_attack::reset();
this->d_power = -1;
this->d_accuracy = -1;
this->d_operationTable = 0;
}
private:
/* assigns this->d_operationTable */
void updateOperationTableForAttack() {
this->d_operationTable = NextOperationTable();
}
public:
void heroWillAttack(const t_hero& hero, t_ghoul& ghoul) {
this->updateOperationTableForAttack();
this->d_operationTable->willSkirmish(*this, ghoul);
std::cout << hero.name() << " vs. " << ghoul.name() << "(lp:" << ghoul.lifePoints() << ")";
this->printState();
}
void heroWillAttack(const t_hero& hero, t_biclops& biclops) {
this->updateOperationTableForAttack();
this->d_operationTable->willSkirmish(*this, biclops);
std::cout << hero.name() << " vs. " << biclops.name() << "(lp:" << biclops.lifePoints() << ")";
this->printState();
}
void printState() {
std::cout << ": Magic { Power: " << this->d_power << ", Accuracy: " << this->d_accuracy << ", Operation Table: " << this->d_operationTable << "}\n";
}
private:
int d_power;
int d_accuracy;
const t_magic_operation_table* d_operationTable;
};
template<typename TEnemy>
void AttackEnemyWithMagic(t_hero& hero, TEnemy& enemy, t_magic& magic) {
if (!enemy.isDead()) {
magic.heroWillAttack(hero, enemy);
hero.attack(enemy, magic);
magic.reset();
}
}
inline void PlayIt() {
t_hero zoe("Zoe");
t_hero aragosta("Aragosta");
t_ghoul ghoul0("Al Paca");
t_ghoul ghoul1("Spud");
t_ghoul ghoul2("Sleepy");
t_biclops biclops("Scimpanzè");
t_magic hemlock(59, "hemlock");
t_magic babyPowder(91, "baby powder");
for (size_t idx(0); idx < 1000; ++idx) {
AttackEnemyWithMagic(zoe, ghoul1, hemlock);
AttackEnemyWithMagic(aragosta, biclops, babyPowder);
AttackEnemyWithMagic(zoe, ghoul2, hemlock);
AttackEnemyWithMagic(aragosta, ghoul0, babyPowder);
}
}
} /* << MONSpiel */
int main(int argc, char* const argv[]) {
#pragma unused(argc)
#pragma unused(argv)
MONSpiel::PlayIt();
return 0;
}
another option is to simply create stores (e.g. a vector), each with a different magic type. then fill a vector to point to objects in those stores. that way, you can just create one contiguous allocation for each type and randomize and weigh as needed. this is useful if your magic objects' sizes vary considerably.