9
\$\begingroup\$

This program is a simulation of an ant colony, inspired by SimAnt. It doesn't do it off the batch; there must be code that instructs the ants to follow scent tiles in particular and react to the food.

main.cpp

It's the main file that must be modified to put more/less ants, more/less food/ants (generators or not).

#include "tile.cpp"
#include "foodFactory.cpp"
#include "scent.cpp"
#include "tile.cpp"
#include <fstream>
#include <cstdlib>

using namespace std;

int main() {
    foodFactory a(43, 12);
    a.splatFood();
    antFactory b(12, 95);
    b.makeAnt();
    b.makeAnt();
    b.makeAnt();
    bool exit = false;
    while(exit == false)
    {
        b.tickAnts();
        sleep(500).
        if (cin.good())
        {
            exit = true;
        }
    }
    return 0;
}

antFactory.cpp

Despite the filename, this contains the ant code and the ant factory code. The ant's class code must be modified so they grab food and wander to find food and move to the food and follow scent and the general AI & behaviour.

#pragma once
#include "scent.cpp"
#include <iostream>
#include <vector>

using namespace std;

class ant
{
private:
    int x;
    int y;
    int index;
    antScent newDropScent;
    bool foundFood;
public:
    ant(int nx, int ny, int i)
    {
        x = nx;
        y = ny;
        index = i;
    }
    pair<int, int> moveThisAnt(pair<bool, bool> dir, pair<bool, bool> move)
    {
        if (move.first)
        {
            if (dir.first)
                x += 1;
            else
                x -= 1;
        }
        if (move.second)
        {
            if (dir.second)
                y += 1;
            else
                y -= 1;
        }
        pair<int, int> result;
        result.first = x;
        result.second = y;
        return result;
    }
    void tickThisAnt() {
        cout << "Function is not completed!";
    }
};

class antFactory
{
private:
    int x;
    int y;
    vector<ant> antGenerated;
public:
    ant* makeAnt()
    {
        ant z(x, y, antGenerated.size() + 1);
        antGenerated.push_back(z);
        return &antGenerated[antGenerated.size() - 1];
    }
    antFactory(int nx, int ny) {
        x = nx;
        y = ny;
    }
    ant delAnt(int antindex)
    {
        ant theresult = antGenerated[antindex];
        antGenerated.erase(antGenerated.begin() + antindex);
        return theresult;
    }
    void tickAnts()
    {
        signed int i = 0;
        for (i = 0; i < antGenerated.size(); i++)
        {
            antGenerated[i].tickThisAnt;
        }
    }
};

food.cpp

This is the food's class definition. Not much :/

using namespace std;

class food {
    private:
        short foodSize;
        int x;
        int y;
        int index;
    public:
        food(int nx, int ny, int i, short ns) {
            x = nx;
            y = ny;
            index = i;
            foodSize = ns;
        }
        short beTaken(short biteSize) {
            foodSize -= biteSize;
            return foodSize;
        }
};

foodFactory.cpp

This is the factory that creates and splats the food the ants are going to take.

#include <vector>
#include <cstdlib>
#include "food.cpp"

using namespace std;

class foodFactory {
private:
    int x;
    int y;
    vector<food> foodGenerated;
public:
    foodFactory(int nx, int ny) {
        x = nx;
        y = ny;
    }
    food* splatFood() {
        x = -200 + (rand() % (int)(200 - -200 + 1));
        y = -200 + (rand() % (int)(200 - -200 + 1));
        food z(x, y, (foodGenerated.size() + 1), (5 + (rand() % (int)(50 - 5 + 1))));
        foodGenerated.push_back(z);
        return &foodGenerated[foodGenerated.size()];
    }
};

scent.cpp

The class definition of the scent that guides ants.

#pragma once

using namespace std;

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;
        }
};

tile.cpp

An reserved class that I should have replaced the coordinate system of everything with variables x and y with.

#pragma once
#include "antFactory.cpp"

using namespace std;

class tile
{
private:
    int x;
    int y;
    antScent tileScent;
public:
    tile(int nx, int ny)
    {
        x = nx;
        y = ny;
    }
    tile()
    {
        x = 0;
        y = 0;
    }
    void changeScent(antScent newscent)
    {
        tileScent = newscent;
    }
};

GitHub has a more recent dev version. It is possible that it might be done right off the bat if someone can contribute and do the ant AI there...

See it on GitHub

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Make sure your computer has an "anthill inside" sticker on it ;) \$\endgroup\$
    – user1149
    Jan 8, 2016 at 3:12
  • \$\begingroup\$ give better names than a and b \$\endgroup\$
    – njzk2
    Jan 8, 2016 at 4:53
  • \$\begingroup\$ @njzk2 Done. View in GitHub. \$\endgroup\$
    – wallabra
    Jan 8, 2016 at 16:16
  • \$\begingroup\$ @Gustavo6046 the repo is not really part of the CR, but adding a readme explaining how to build and use your program is always nice \$\endgroup\$
    – njzk2
    Jan 8, 2016 at 17:20

2 Answers 2

8
\$\begingroup\$

Generating better random numbers

Don't use rand(). It's a horrible, deprecated function that doesn't actually generate numbers that seem to be truly random. At a quick glance it seems like it, but don't be fooled - it's not.

If you want to generate true-ish random numbers, you're going to need to include the following header to start off:

#include <random>

Next, you want to create a random engine. Since we don't want to re-create our random engine every time we want to generate a number, we're going to create the following helper function to create an engine for us:

// credit: http://cpp.indi.frih.net/blog/2014/12/the-bell-has-tolled-for-rand/
std::mt19937& random_engine()
{
    thread_local static std::random_device random_device { };
    thread_local static std::mt19937       engine { random_device() };
    return engine;
}

Next, in order to use, it, all you have to do is this:

thread_local static std::uniform_int_distribution<> distribution { a, b };
int result = distribution(random_engine())

Just replace a and b with the low and high numbers in your range.

The above examples should work, but I didn't have time to test them, so please notify me if it doesn't work.


Class definition and declaration

Traditionally, if your class is long enough, instead of declaring a class and defining its methods, you'd declare it something like this:

class MyClass
{
public:
    type foo;
    type bar;

    MyClass(type foo, type bar)
        : foo(foo)
        , bar(bar)
    {}

    void doSomething();
    void doOtherthing();
};

And then implement the methods somewhere else, usually in a different file:

MyClass::doSomething()
{
    ...
}

MyClass::doOtherthing()
{
    ...
}

In addition, you should initialize class properties inside the constructor using an initialization list, like this:

Constructor(type a, type b, type c)
    : a(a)
    , b(b)
    , c(c)
{}

It's also worth noting that the arguments to your constructor don't need to be named differently than the class properties that they represent.

using a namespace named std

Never write this line of code:

using namespace std;

This is a mistake that beginners often make due to a bad online tutorial, or a beginners C++ book using it. There are many bad things that can go quite wrong here. The bad things that can happen are best described on this Stack Overflow question, but I'll outline a few here:

  • Name conflicts between std and another namespace.
  • Function conflicts between std and another namespace.
  • Function conflicts between std and another namespace with the same arguments. (This is especially bad.)

In the end, having to prefix some names with std:: is much better than the adverse side effects that come about due to using namespace std;.


Stuff related to styling/Nitpicks

You're inconsistent on how you're styling your classes. Sometimes you write them like this:

class Foo {
public:
    ...

private:
    ...
}

Other times you're writing them like this:

class Foo {
    public:
        ...

    private:
        ...
}

The overall idea I'm trying to convey is to be consistent. When you, and others are reading or working on your code, it's important that it's as clear as possible. Code that is written using inconsistent styles and techniques is always bad on some level, in some way.

While there is no true official standard for naming classes in C++, most people usually name their classes in the naming style PascalCase, not camelCase.

The following line of code at the end of main is redundant:

return 0;

Most, if not all, modern C++ compilers will automatically insert return 0; into main.

Finally, if you want a reliable std::string in your code, you should be including the following header whenever you're using strings:

#include <string>
\$\endgroup\$
3
  • \$\begingroup\$ I am not using strings :) I already used std::strings before so I know how it is. \$\endgroup\$
    – wallabra
    Jan 8, 2016 at 12:17
  • 1
    \$\begingroup\$ @Gustavo6046 Regardless, if you do want std::string to be reliable and produce consistent results in your code, you need to #include <string>. \$\endgroup\$ Jan 8, 2016 at 12:49
  • \$\begingroup\$ "While there is no true official standard for naming classes in C++" : Unless you consider the class names present in the ISO standard, which set the example of using lower case and underscores. \$\endgroup\$
    – JDługosz
    Aug 10, 2021 at 15:52
4
\$\begingroup\$
using namespace std;

class tile

and

using namespace std;

class antScent {

and

using namespace std;

class food {

You may have already seen Why is “using namespace std;” considered bad practice?

There is an additional reason to avoid it here. It's not doing anything. None of those files actually use anything from std.

I find it quite possible that std will add a std::tile in the future. If it does, your code won't compile.

using namespace std;

class foodFactory {
private:
    int x;
    int y;
    vector<food> foodGenerated;

OK! Here it is: an actual use of something from std. But why the using? It's much shorter, not to mention more readable, to say

class foodFactory {
private:
    int x;
    int y;
    std::vector<food> foodGenerated;

Now I can see from that line alone that you are using the vector from std. It gets rid of using namespace ; at the cost of adding ::. That seems worthwhile.

    bool exit = false;
    while(exit == false)
    {
        b.tickAnts();
        sleep(500).
        if (cin.good())
        {
            exit = true;
        }
    }

Why make extra work for yourself? Instead consider

    while (true)
    {
        b.tickAnts();
        sleep(500).
        if (std::cin.good())
        {
            break;
        }
    }

Now you don't need an exit variable at all.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Your last point can go a step further, to get do { b.tickAnts(); sleep(500); } while (!std::cin.good()); \$\endgroup\$ Jan 8, 2016 at 0:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.