#include <list>
#include <iostream>
using namespace std;

#include <stdlib.h>
#include <time.h>

class Personagem
{
    protected:

        int x;

        static const int MAX;

    public:

        Personagem(int _x = 1):
            x ( _x )
        {
        }

        virtual ~Personagem()
        {
        }

        const int getX() const { return x; }

        static const int getMAX() { return MAX; }

        virtual void movimentar() = 0;

};
const int Personagem::MAX = 20;


class Curupira : public Personagem
{
    private:
        bool empoderado;
        bool avancar; // avançar
        int  nvidas;

    public:
        Curupira(const bool emp = false, const int _x = 1) :
            // atributo emp foi corrigido para bool
            Personagem ( _x  ),
            empoderado ( emp ),
            avancar ( true ),
            nvidas (MAX)
        {

        }

        ~Curupira()
        {
        }

        const bool getEmpoderado() const
        {
            return empoderado;
        }

        const int getNVidas() const
        {
            return nvidas;
        }

        void setNvidas(const int nv)
        {
            nvidas = nv;
        }

        void movimentar()
        {
            if (avancar)
            {
                if (x < MAX)
                {
                    x++;
                }
                else
                {
                    avancar = false;
                    x--;
                }
            }
            else
            {
                if (x > 0)
                {
                    x--;
                }
                else
                {
                    avancar = true;
                    x++;
                }
            }
        }
};


class BoiTata : public Personagem
{
    private:
        int energia;
        Curupira* pCurupira;

    public:

        BoiTata(Curupira* pCur = NULL, const int energ = 0, const int _x = 0):
            Personagem  ( _x ),
            energia     ( energ ),
            pCurupira   ( pCur )
        {
        }

        ~BoiTata()
        {
            energia = -1;
            pCurupira = NULL;
        }

        const int getEnergia() const { return energia; }

        void atacar()
        {
            if (pCurupira)
            {
                if ( pCurupira->getX() == x )
                {
                    if ( pCurupira->getEmpoderado() )
                    {
                        energia--;
                    }
                    else
                    {
                        energia++;
                        int decrementa = pCurupira->getNVidas()-1;
                        pCurupira->setNvidas(decrementa);
                    }
                }
            }
            else
            {
                cout << "Ponteiro de Curupira nulo" << endl;
            }
        }

        void movimentar()
        {
            if ( pCurupira )
            {
                if ( x > pCurupira->getX())
                {
                    x--;
                }
                else
                {
                    if ( x < pCurupira->getX())
                    {
                        x++;

                    }
                }
                atacar();
            }
            else
            {
                cout << "Ponteiro pCurupira nulo em BoiTata. " << endl;
            }
        }
};


class VetorPersonagens
{
    private:
        list<Personagem*> personagens;
        list<Personagem*>::const_iterator itPersonagens; // usei iterador constante dado que não há obste.

    public:

        VetorPersonagens():
            personagens(),
            itPersonagens()
        {
            personagens.clear();
            itPersonagens = personagens.begin();
        }

        ~VetorPersonagens()
        {
            personagens.clear();
        }

        void inserir(Personagem* p)
        {
            if ( p )
            {
                personagens.push_back( p );
            }
            else
            {
                cout << "Ponteiro p de Personagem vazio em VetorPersonagens." << endl;
            }
        }

        Personagem* operator[](const int idx)
        {

            int tam = 0;
            tam = (int)personagens.size();

            if ( (idx >= 0) && (idx < tam) )
            {
                itPersonagens = personagens.begin();
                for (int i = 0; i < idx; i++)
                {
                    itPersonagens++;
                }
                return *itPersonagens;
            }
            else
            {
                cout << "Indíce fora dos limites." << endl;
                return NULL;
            }
        }

        Personagem* excluir(int idx)
        {
            Personagem* p = NULL;
            p = operator[](idx);

            if (p)
            {
                personagens.remove(p);
            }
            else
            {
                cout << "Não houve exclusão - ponteiro nulo." << endl;
            }
            return p;
        }
};

class Jogo
{
    private:

        int quant_bt;

        VetorPersonagens vetPers;

    public:

        Jogo(int qbt = 1) : quant_bt (qbt), vetPers ( )
        {
            time_t t;
            srand((unsigned) time(&t));

            int valor = rand()%2;
            cout << "Numero aleatótio: " << valor << endl;

            int pos = rand()%(Personagem::getMAX());
            cout << "Numero aleatótio: " << pos << endl;

            Curupira* pCur = NULL;
            pCur = new Curupira ((bool)valor, pos);
            if (pCur)
            {
                vetPers.inserir(static_cast<Personagem*>(pCur));
                BoiTata* pBT = NULL;
                int cont = 0;
                for ( int i = 0; i < quant_bt; i++ )
                {
                    pBT = new BoiTata(pCur, i, i);
                    if (pBT)
                    {
                        vetPers.inserir(static_cast<Personagem*>(pBT));
                        cont++;
                    }
                    else
                    {
                        cout << "Boitata " << i << !" não criado!" << endl;
                    }
                    pBT = NULL;
                }

                if (cont)
                {
                    executar();
                }
                else
                {
                    cerr << "Jogo não executado por falta de Bois-Tatas!" << endl;
                }
            }
            else
            {
                cerr << "Curupira não criado, jogo não inicializado!" << endl;
            }
        }

        ~Jogo()
        {
            int total = quant_bt + 1;

            Personagem* pP = NULL;

            for (int i = 0; i < total; i++)
            {
                  pP = vetPers.excluir(0);

                  if (pP)
                  {
                     delete pP;
                  }
                  else
                  {
                      cerr << "Não se pode deletar ponteiro nulo." << endl;
                  }
            }
        }

        void executar()
        {
            int total = quant_bt + 1;
            Personagem* pP = NULL;

            cout << "Entrou." << endl;

            for (int j = 0; j < Personagem::getMAX(); j++)
            {
                for (int i = 0; i < total; i++)
                {
                    pP = vetPers[i]; // pP = vetPers.operator[](i);
                    if (pP)
                    {
                        pP->movimentar();
                    }
                    else
                    {
                        cerr << "Ponteiro pP nulo!" << endl;
                    }
                }
            }

            //cout << "Movimentou." << endl;

            Curupira* pCur = NULL;
            pP = vetPers[0];
            pCur = static_cast<Curupira*>(pP);
            cout << "O valor de vidas do Curupira é: " << pCur->getNVidas() << endl;
            cout << endl;

            BoiTata* pBT = NULL;
            for (int i = 1; i < total; i++)
            {
                  pP = vetPers[i];
                  pBT = static_cast<BoiTata*>(pP);

                  cout << " O " << i << ". Boi Tata tem o seguinte valor de energia: " << pBT->getEnergia() << endl;
            }
        }
};

int main()
{
    Jogo jogo(3);

    return 0;
}

