HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Quite-Off-The-Bat Complex Console Ant Colony Simulator w/ Partial AI

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thequiteantcolonypartialsimulatorconsoleoffcomplexbat

Problem

As a follow-up of my previous non-off-the-bat Ant Colony Simulator, we have this one that works off-the-bat... quite; the code for when the ants find and take the food isn't really done but it would be almost impossible to do it anyway, if someone wants to contribute directly to the code, please do it in GitHub.

scent.cpp

#ifndef SCENT_CPP_INCLUDED
#define SCENT_CPP_INCLUDED

class AntScent
{
private:
    short power;
    short angle;
    short ScentType;
public:
    short addPower()
    {
        power += 1;
        return power;
    }
    short affectAngle(short vel)
    {
        angle = (vel + angle) / 2;
        return angle;
    }
    void ChangeType(short NewType)
    {
        ScentType = NewType;
    }
    short decreasePower()
    {
        power -= 1;
        return power;
    }
};

#endif // SCENT_CPP_INCLUDED


antFactory.cpp

```
#pragma once
#include "scent.cpp"
#include "randbool.h"
#include
#include
#include
#include "foodFactory.cpp"
#include "board.cpp"
#include "tile.h"
#define DEBUG

#ifndef ANTFACTORY_CPP_INCLUDED
#define ANTFACTORY_CPP_INCLUDED

class Ant
{
private:
int x;
int y;
Board* pertainingBoard;
tile* Position;
int index;
AntScent NewDropScent;
bool bFoundFood = false;
short AntSize;
bool bIsCarryingFood;
std::pair newPos;
std::pair FoodPos;
public:
Ant(int nx, int ny, int i, Board* pb)
{
x = nx;
y = ny;
index = i;
pertainingBoard = pb;
pertainingBoard->addAnt(this);
}
std::pair moveThisAnt(std::pair dir, std::pair move)
{
if (move.first)
{
if (dir.first)
x += 1;
else
x -= 1;
}
if (move.second)
{
if (dir.second)
y += 1;
else
y -= 1;
}
#ifdef DEBUG
std::cout result;
result.first = x;
result.second = y;
return result;
}

Solution

I see a number of things that could help you improve your program.

Don't use #pragma once

No doubt others will disagree on this one, but they can write their own reviews. In my projects, I use #include guards instead. The advantage is that it's specified in the standard, while any #pragma is, by definition, non-standard. Some claim that it's faster to compile when using #pragma once but I'd recommend that you actually measure it both ways and see for yourself.

Don't use #pragma once in a .cpp file

The use of #pragma once (or an #include guard) is for headers that might be included in multiple source files. Neither should be used in .cpp files.

Don't #include a .cpp file

Similar to the first two points, you shouldn't #include a .cpp file within a header file. It is sometimes OK to #include a .cpp file within another .cpp file as for certain kinds of autogenerated source code but this project does not have such special cases and shouldn't #include any .cpp files within either .h or .cpp files. To show how this should be done, here are scent.cpp and scent.h files rewritten to follow these conventions:

scent.h

#ifndef SCENT_H
#define SCENT_H 

class AntScent
{
private:
    short power;
    short angle;
    short ScentType;
public:
    short addPower();
    short affectAngle(short vel);
    void ChangeType(short NewType);
    short decreasePower();
};

#endif // SCENT_H


scent.cpp

#include "scent.h"

short AntScent::addPower()
{
    power += 1;
    return power;
}
short AntScent::affectAngle(short vel)
{
    angle = (vel + angle) / 2;
    return angle;
}
void AntScent::ChangeType(short NewType)
{
    ScentType = NewType;
}
short AntScent::decreasePower()
{
    power -= 1;
    return power;
}


Rethink your classes

There are a lot of classes here, which isn't necessarily a bad sign, but they all seem to rely on each other. In other words, the level of coupling is very high, which is a sign of trouble. For example, the Ant class has pointers to both the Board it is on and the tile it is on as well as its own x and y coordinates and also its own index within a vector which is a private member of the AntFactory class! That is just way too much information for a little Ant to track! If we think about actual ants, individual ants probably don't actually have much concept of these things. Instead, the Board should contain the collection of ants that is currently in the AntFactory class. Next, the AntFactory shoul only generate a new Ant and nothing else. The Board should also keep each Ant's position rather than the Ant itself. Similarly, a Board should include a collection of tile objects. The Board should keep track of the positions of each tile and not each tile.

Simplify your code

If we look at the AntScent::addPower() routine, it is currently this:

short AntScent::addPower()
{
    power += 1;
    return power;
}


However this could be both more idiomatic C++ and also shorter:

short AntScent::addPower()
{
    return ++power;
}


Use a better random number generator

Modern C++ has much better random number generators than rand(). A random variable that only has true or false values is called a Bernoulli distribution and it's already built into C++11's `` header. Use this:

#include 
bool MyRandomBoolean() {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::bernoulli_distribution d;   // default is 50:50 distribution

    return d(gen);
}


There's more, but it's all I have time for at the moment.

Code Snippets

#ifndef SCENT_H
#define SCENT_H 

class AntScent
{
private:
    short power;
    short angle;
    short ScentType;
public:
    short addPower();
    short affectAngle(short vel);
    void ChangeType(short NewType);
    short decreasePower();
};

#endif // SCENT_H
#include "scent.h"

short AntScent::addPower()
{
    power += 1;
    return power;
}
short AntScent::affectAngle(short vel)
{
    angle = (vel + angle) / 2;
    return angle;
}
void AntScent::ChangeType(short NewType)
{
    ScentType = NewType;
}
short AntScent::decreasePower()
{
    power -= 1;
    return power;
}
short AntScent::addPower()
{
    power += 1;
    return power;
}
short AntScent::addPower()
{
    return ++power;
}
#include <random>
bool MyRandomBoolean() {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::bernoulli_distribution d;   // default is 50:50 distribution

    return d(gen);
}

Context

StackExchange Code Review Q#116258, answer score: 6

Revisions (0)

No revisions yet.