Project 7 Test Data

There were 27 test cases. The first 23 were worth 4 points each, while the last 4 were worth 2 points each. Each test case is represented by an assertion that must be true for you to pass that test. To run the test cases:

  1. Remove the main routine from your zombies.cpp file.
  2. Replace the body of the implementation of clearScreen with {} (an empty function body).
  3. Append the following text to the end of your zombies.cpp file, and build the resulting program.
  4. For any test case you wish to try, run the program, providing as input the test number.

#include <iostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <cassert>
using namespace std;

class StreambufSwitcher
{
  public:
    StreambufSwitcher(ios& dest, streambuf* sb,
                                        ios::iostate exceptions = ios::goodbit)
     : dest_stream(dest), oldsb(dest.rdbuf(sb)), oldex(dest.exceptions())
    { dest_stream.exceptions(exceptions); }
    StreambufSwitcher(ios& dest, ios& src)
     : StreambufSwitcher(dest, src.rdbuf(), src.exceptions())
    {}
    ~StreambufSwitcher()
    { dest_stream.rdbuf(oldsb); dest_stream.exceptions(oldex); }
  private:
    ios& dest_stream;
    streambuf* oldsb;
    ios::iostate oldex;
};

map<void*, size_t> allocMap;
bool recordaddrs = false;

inline bool isRecordedSize(size_t n)
{
    return n == sizeof(Zombie)  ||  n == sizeof(Player);
}

void* operator new(size_t n)
{
    void* p = malloc(n);
    fill_n(static_cast<char*>(p), n, 0xCA);
    if (recordaddrs  &&  isRecordedSize(n))
    {
        recordaddrs = false;
        allocMap.insert(make_pair(p, n));
        recordaddrs = true;
    }
    return p;
}

void unrecordaddr(void* p)
{
    recordaddrs = false;
    auto it = allocMap.find(p);
    if (it != allocMap.end())
    {
        fill_n(static_cast<char*>(p), it->second, 0xCB);
        allocMap.erase(it);
    }
    recordaddrs = true;
}

#if __cplusplus >= 201402L  &&  ! defined(__clang__)
// Unless clang is supplied the -fsized-deallocation flag, it will
// not call the C++14/17 sized operator delete.

void operator delete(void* p) noexcept
{
    free(p);
}

void operator delete(void* p, size_t n) noexcept
{
    if (recordaddrs  &&  isRecordedSize(n))
        unrecordaddr(p);
    operator delete(p);
}
#else
void operator delete(void* p) noexcept
{
    if (recordaddrs)
        unrecordaddr(p);
    free(p);
}
#endif

bool recommendMove(const Arena& a, int r, int c, int& bestDir);

struct Pos
{
    int r;
    int c;
};

bool noZombiesAround(const Arena& a, Pos z)
{
    for (int dr = -1; dr <= 1; dr++)
    {
        for (int dc = -1; dc <= 1; dc++)
        {
            if ((dr != 0  ||  dc != 0)  &&  a.numberOfZombiesAt(z.r+dr, z.c+dc) != 0)
                return false;
        }
    }
    return true;
}

bool locateTheZombie(const Arena& a, Pos& z, bool shouldHaveMoved)
{
    if (!shouldHaveMoved)
    {
        if (a.numberOfZombiesAt(z.r, z.c) != 1)
            return false;
    }
    else
    {
        if      (a.numberOfZombiesAt(z.r-1, z.c) == 1) z.r--;
        else if (a.numberOfZombiesAt(z.r+1, z.c) == 1) z.r++;
        else if (a.numberOfZombiesAt(z.r, z.c-1) == 1) z.c--;
        else if (a.numberOfZombiesAt(z.r, z.c+1) == 1) z.c++;
        else return false;
    }
    return noZombiesAround(a, z);
}

void encircleWithPoison(Arena& a, Pos z)
{   
    a.setCellStatus(z.r-1, z.c, HAS_POISON);
    a.setCellStatus(z.r+1, z.c, HAS_POISON);
    a.setCellStatus(z.r, z.c-1, HAS_POISON);
    a.setCellStatus(z.r, z.c+1, HAS_POISON);
} 

void testone(int n)
{
    StreambufSwitcher sso(cout, cerr);

    switch (n)
    {
                         default: {
        cout << "Bad argument" << endl;
                } break; case  1: {
        int k;
        for (k = 0; k < 300; k++)
        {
            Arena a(1, 20);
            a.addPlayer(1, 3);
            Zombie z(&a, 1, 18);
            assert(z.row() == 1  &&  z.col() == 18);
            z.move(); assert(z.row() == 1);
            if (z.col() != 19)
            {
                assert(z.col() == 17  ||  z.col() == 18);
                continue;
            }
            z.move(); assert(z.row() == 1);
            if (z.col() == 20)
                break;
            assert(z.col() == 18  ||  z.col() == 19);
        }
        assert(k < 300);
                } break; case  2: {
        int k;
        for (k = 0; k < 600; k++)
        {
            Arena a(1, 20);
            a.addPlayer(1, 3);
            Zombie z(&a, 1, 19);
            assert(z.row() == 1  &&  z.col() == 19);
            z.move(); assert(z.row() == 1);
            if (z.col() != 19)
            {
                assert(z.col() == 18  ||  z.col() == 20);
                continue;
            }
            z.move(); assert(z.row() == 1);
            if (z.col() != 19)
            {
                assert(z.col() == 18  ||  z.col() == 20);
                continue;
            }
            z.move(); assert(z.row() == 1);
            if (z.col() != 19)
            {
                assert(z.col() == 18  ||  z.col() == 20);
                continue;
            }
            z.move(); assert(z.row() == 1);
            if (z.col() != 19)
            {
                assert(z.col() == 18  ||  z.col() == 20);
                continue;
            }
            z.move(); assert(z.row() == 1);
            if (z.col() == 18  ||  z.col() == 20)
                break;
            assert(z.col() == 19);
        }
        assert(k < 600);
                    } break; case  3: {
        int k;
        for (k = 0; k < 600; k++)
        {
            Arena a(20, 1);
            a.addPlayer(3, 1);
            Zombie z(&a, 19, 1);
            assert(z.row() == 19  &&  z.col() == 1);
            z.move(); assert(z.col() == 1);
            if (z.row() != 19)
            {
                assert(z.row() == 18  ||  z.row() == 20);
                continue;
            }
            z.move(); assert(z.col() == 1);
            if (z.row() != 19)
            {
                assert(z.row() == 18  ||  z.row() == 20);
                continue;
            }
            z.move(); assert(z.col() == 1);
            if (z.row() != 19)
            {
                assert(z.row() == 18  ||  z.row() == 20);
                continue;
            }
            z.move(); assert(z.col() == 1);
            if (z.row() != 19)
            {
                assert(z.row() == 18  ||  z.row() == 20);
                continue;
            }
            z.move(); assert(z.col() == 1);
            if (z.row() == 18  ||  z.row() == 20)
                break;
            assert(z.row() == 19);
        }
        assert(k < 600);
                    } break; case  4: {
        Arena a(10,20);
        a.addPlayer(9, 19);
        for (int r = 5-2; r <= 5+2; r++)
            for (int c = 10-2; c <= 10+2; c++)
                a.setCellStatus(r, c, HAS_POISON);
        Zombie z(&a, 5, 10);
        z.move();
        assert((z.row() == 5  &&  abs(z.col() - 10) == 1)  ||
               (z.col() == 10  &&  abs(z.row() - 5) == 1));
        int oldr = z.row();
        int oldc = z.col();
        z.move();
        assert(z.row() == oldr  &&  z.col() == oldc);
        z.move();
        assert((z.row() == oldr  &&  abs(z.col() - oldc) == 1)  ||
               (z.col() == oldc  &&  abs(z.row() - oldr) == 1));
                    } break; case  5: {
        Arena a(10,20);
        a.addPlayer(9, 19);
        for (int r = 5-2; r <= 5+2; r++)
            for (int c = 10-2; c <= 10+2; c++)
                if (r != 5  ||  c != 10)
                    a.setCellStatus(r, c, HAS_POISON);
        Zombie z(&a, 5, 10);
        assert(!z.isDead());
        z.move();
        assert((z.row() == 5  &&  abs(z.col() - 10) == 1)  ||
               (z.col() == 10  &&  abs(z.row() - 5) == 1));
        int oldr = z.row();
        int oldc = z.col();
        assert(!z.isDead());
        a.setCellStatus(5, 10, HAS_POISON);
        z.move();
        assert(z.row() == oldr  &&  z.col() == oldc);
        assert(!z.isDead());
        z.move();
        assert((z.row() == oldr  &&  abs(z.col() - oldc) == 1)  ||
               (z.col() == oldc  &&  abs(z.row() - oldr) == 1));
        assert(z.isDead());
                    } break; case  6: {
        Arena a(10,20);
        a.addPlayer(9, 19);
        a.setCellStatus(4, 10, HAS_POISON);
        a.setCellStatus(6, 10, HAS_POISON);
        a.setCellStatus(5, 9, HAS_POISON);
        a.setCellStatus(5, 11, HAS_POISON);
        Zombie z(&a, 5, 10);
        z.move();
        assert((z.row() == 5  &&  abs(z.col() - 10) == 1)  ||
               (z.col() == 10  &&  abs(z.row() - 5) == 1));
        int oldr = z.row();
        int oldc = z.col();
        z.move();
        assert(z.row() == oldr  &&  z.col() == oldc);
        z.move();
        assert((z.row() == oldr  &&  abs(z.col() - oldc) == 1)  ||
               (z.col() == oldc  &&  abs(z.row() - oldr) == 1));
        oldr = z.row();
        oldc = z.col();
        z.move();
        assert(z.row() == oldr  &&  z.col() == oldc);
        a.setCellStatus(oldr-1, oldc, EMPTY);
        a.setCellStatus(oldr+1, oldc, EMPTY);
        a.setCellStatus(oldr, oldc-1, EMPTY);
        a.setCellStatus(oldr, oldc+1, EMPTY);
        z.move();
        assert((z.row() == oldr  &&  abs(z.col() - oldc) == 1)  ||
               (z.col() == oldc  &&  abs(z.row() - oldr) == 1));
                    } break; case  7: {
        Arena a(1, 20);
        a.addPlayer(1, 3);
        Player* p = a.player();
        assert(p->row() == 1  &&  p->col() == 3);
        p->move(WEST); assert(p->row() == 1  &&  p->col() == 2);
        p->move(WEST); assert(p->row() == 1  &&  p->col() == 1);
                    } break; case  8: {
        Arena a(1, 20);
        a.addPlayer(1, 3);
        Player* p = a.player();
        p->move(WEST); assert(p->row() == 1  &&  p->col() == 2);
        p->move(WEST); assert(p->row() == 1  &&  p->col() == 1);
        p->move(WEST); assert(p->row() == 1  &&  p->col() == 1);
        p->move(NORTH); assert(p->row() == 1  &&  p->col() == 1);
        p->move(SOUTH); assert(p->row() == 1  &&  p->col() == 1);
                    } break; case  9: {
        Arena a(10, 20);
        a.addPlayer(3, 6);
        Player* p = a.player();
        assert( ! p->isDead());
        p->setDead();
        assert(p->isDead());
                    } break; case 10: {
        Arena a(20, 1);
        a.addPlayer(1, 1);
        Player* p = a.player();
        assert(p->move(WEST).find(" stands") != string::npos);
        assert(p->move(EAST).find(" stands") != string::npos);
        assert(p->move(NORTH).find(" stands") != string::npos);
        assert(p->move(SOUTH).find(" south") != string::npos);
                    } break; case 11: {
        Arena a(20, 1);
        a.addPlayer(1, 1);
        Player* p = a.player();
        a.addZombie(2, 1);
        assert(p->move(SOUTH).find(" died") != string::npos);
                    } break; case 12: {
        Arena a(20, 1);
        a.addPlayer(1, 1);
        Player* p = a.player();
        a.addZombie(2, 1);
        assert(!p->isDead());
        p->move(SOUTH);
        assert(p->isDead());
                    } break; case 13: {
        Arena a(6, 15);
        assert(a.rows() == 6  &&  a.cols() == 15);
                    } break; case 14: {
        Arena a(10, 20);
        a.addPlayer(3, 6);
        a.addZombie(7, 5);
        assert(a.numberOfZombiesAt(7, 5) == 1  &&  a.zombieCount() == 1);
                    } break; case 15: {
        Arena a(10, 20);
        a.addPlayer(3, 6);
        a.addZombie(7, 5);
        a.addZombie(4, 7);
        a.addZombie(7, 5);
        assert(a.numberOfZombiesAt(7, 5) == 2  &&  a.zombieCount() == 3);
                    } break; case 16: {
        Arena a(1, 20);
        a.addPlayer(1, 8);
        a.addZombie(1, 1);
        a.setCellStatus(1, 2, HAS_POISON);
        a.setCellStatus(1, 3, HAS_POISON);
        a.addZombie(1, 16);
        a.setCellStatus(1, 14, HAS_POISON);
        a.setCellStatus(1, 15, HAS_POISON);
        a.setCellStatus(1, 17, HAS_POISON);
        a.setCellStatus(1, 18, HAS_POISON);
        assert(a.zombieCount() == 2);
        int k;
        for (k = 0; k < 200; k++)
        {
            a.moveZombies();
            int nb1 = (a.getCellStatus(1, 2) == HAS_POISON) +
                  (a.getCellStatus(1, 3) == HAS_POISON);
            int nb2 = (a.getCellStatus(1, 14) == HAS_POISON) +
                  (a.getCellStatus(1, 15) == HAS_POISON) +
                  (a.getCellStatus(1, 17) == HAS_POISON) +
                  (a.getCellStatus(1, 18) == HAS_POISON);
            assert(a.zombieCount() == (nb1 > 0) + (nb2 > 2));
            if (a.zombieCount() == 0)
                break;
        }
        assert(k < 200);
                    } break; case 17: {
        Arena a(1, 3);
        a.addPlayer(1, 1);
        Player* p = a.player();
        for (int j = 0; j < 10; j++)
            a.addZombie(1, 3);
        assert(!p->isDead());
        a.moveZombies();
        int k;
        for (k = 0; k < 100; k++)
        {
            assert(!p->isDead());
            a.moveZombies();
            if (a.numberOfZombiesAt(1, 1) > 0)
            {
                assert(p->isDead());
                break;
            }
        }
        assert(k < 100);
                    } break; case 18: {
        ostringstream oss;
        StreambufSwitcher sso2(cout, oss);
        Arena a(2, 3);
        a.addPlayer(2, 3);
        a.addZombie(2, 1);
        a.addZombie(2, 1);
        a.addZombie(2, 2);
        a.display("");
        assert(oss.str().find("2Z@") != string::npos);
                    } break; case 19: {
        ostringstream oss;
        StreambufSwitcher sso2(cout, oss);
        Arena a(2, 3);
        a.addPlayer(2, 3);
        for (int k = 1; k <= 20; k++)
            a.addZombie(2, 1);
        a.display("");
        assert(oss.str().find("9.@") != string::npos);
                    } break; case 20: {
        recordaddrs = true;
        int n = allocMap.size();
        {
            Arena a(20, 20);
            for (int r = 1; r <= 5; r++)
                for (int c = 11; c <= 20; c++)
                    a.setCellStatus(r, c, HAS_POISON);
            for (int r = 16; r <= 20; r++)
                for (int c = 15; c <= 20; c++)
                    a.setCellStatus(r, c, HAS_POISON);
            a.addPlayer(19, 19);
            int n2 = allocMap.size();
            a.setCellStatus(3, 13, EMPTY);
            a.setCellStatus(3, 18, EMPTY);
            a.addZombie(3, 13);
            a.addZombie(3, 18);
            for (int k = 0; k < 4; k++)
            {
                a.addZombie(1, 1);
                a.addZombie(1, 4);
                a.addZombie(4, 1);
                a.addZombie(4, 4);
            }
            assert(allocMap.size() >= n2 + 18);
            a.moveZombies();
            a.setCellStatus(3, 13, HAS_POISON);
            a.setCellStatus(3, 18, HAS_POISON);
            a.moveZombies();
            a.moveZombies();
            assert(a.zombieCount() == 18-2);
            for (int k = a.zombieCount(); k < MAXZOMBIES; k++)
                assert(a.addZombie(1, 1));
            int j;
            for (j = 0; j < 1000  &&  a.zombieCount() > 20; j++)
            {
                for (int r = 1; r <= 20; r++)
                    for (int c = 1; c <= 20; c++)
                        if (a.numberOfZombiesAt(r, c) == 0  &&  !(r == 19 && c == 19))
                            a.setCellStatus(r, c, HAS_POISON);
                a.moveZombies();
            }
            assert(j < 1000);
            a.setCellStatus(1, 1, EMPTY);
            for (int k = a.zombieCount(); k < MAXZOMBIES; k++)
                assert(a.addZombie(1, 1));
            assert(allocMap.size() >= n2 + MAXZOMBIES);
        }
        assert(allocMap.size() == n);
        recordaddrs = false;
                    } break; case 21: {
        Arena a(20, 20);
        a.addPlayer(19, 19);
        for (int r = 1; r < 19; r++)
            for (int c = 1; c < 19; c++)
                if (r != 10  ||  c != 10)
                    a.setCellStatus(r, c, HAS_POISON);
        for (int k = 0; k < 100; k++)
            a.addZombie(10, 10);
        assert(a.zombieCount() == 100  &&  a.numberOfZombiesAt(10, 10) == 100);
        int nr[1+20][1+20];
        a.moveZombies();
        int tot = 0;
        for (int r = 1; r < 19; r++)
        {
            for (int c = 1; c < 19; c++)
            {
                nr[r][c] = a.numberOfZombiesAt(r, c);
                tot += nr[r][c];
                assert((r == 10  &&  c >= 9 && c <= 11) ||
                       (c == 10  &&  r >= 9 && r <= 11) ||
                       nr[r][c] == 0);
            }
        }
        assert(nr[10][10] == 0  &&  tot == a.zombieCount());
        assert(nr[9][10] == 0  ||  a.getCellStatus(9, 10) == EMPTY);
        assert(nr[11][10] == 0  ||  a.getCellStatus(11, 10) == EMPTY);
        assert(nr[10][9] == 0  ||  a.getCellStatus(10, 9) == EMPTY);
        assert(nr[10][11] == 0  ||  a.getCellStatus(10, 11) == EMPTY);
        a.setCellStatus(10, 10, HAS_POISON);
        a.moveZombies();
        assert(a.numberOfZombiesAt(9, 10) == (nr[9][10] == 0 ? 0 : 1));
        assert(a.numberOfZombiesAt(11, 10) == (nr[11][10] == 0 ? 0 : 1));
        assert(a.numberOfZombiesAt(10, 9) == (nr[10][9] == 0 ? 0 : 1));
        assert(a.numberOfZombiesAt(10, 11) == (nr[10][11] == 0 ? 0 : 1));
        for (int k = 0; k < 17; k++)
        {
            for (int r = 1; r < 19; r++)
                for (int c = 1; c < 19; c++)
                    if (a.numberOfZombiesAt(r, c) == 0)
                        a.setCellStatus(r, c, HAS_POISON);
            a.moveZombies();
        }
        tot = 0;
        for (int r = 1; r < 19; r++)
            for (int c = 1; c < 19; c++)
                tot += a.numberOfZombiesAt(r, c);
        assert(a.zombieCount() == tot  &&  tot < 100);
                    } break; case 22: {
        Arena a(18, 22);
        Pos z[4] = { { 6, 6 }, { 6, 17 }, { 13, 6 }, { 13, 17 } };
        for (int k = 0; k < 4; k++)
            a.addZombie(z[k].r, z[k].c);
        assert(a.zombieCount() == 4);
        for (int k = 0; k < 4; k++)
        {
            assert(locateTheZombie(a, z[k], false));  // none moved at start
            if (k <= 1)
                encircleWithPoison(a, z[k]);
        }
        a.moveZombies();
        assert(a.zombieCount() == 4);
        for (int k = 0; k < 4; k++)
        {
            assert(locateTheZombie(a, z[k], true));  // all moved
            if (k <= 1)
                encircleWithPoison(a, z[k]);
        }
        a.moveZombies();
        assert(a.zombieCount() == 4);
        for (int k = 0; k < 4; k++)
            assert(locateTheZombie(a, z[k], k >= 2));  // two slept, two moved
        a.moveZombies();
        assert(a.zombieCount() == 2);
        for (int k = 0; k < 2; k++)
        {
            assert(a.numberOfZombiesAt(z[k].r, z[k].c) == 0);  // these two died
            assert(noZombiesAround(a, z[k]));
        }
        for (int k = 2; k < 4; k++)
            assert(locateTheZombie(a, z[k], true));  // these two moved
        encircleWithPoison(a, z[2]);
        a.moveZombies();
        assert(a.zombieCount() == 2);
        for (int k = 2; k < 4; k++)
            assert(locateTheZombie(a, z[k], true));  // both moved
        encircleWithPoison(a, z[2]);
        a.moveZombies();
        assert(a.zombieCount() == 2);
        assert(locateTheZombie(a, z[2], false));  // this one slept
        assert(locateTheZombie(a, z[3], true));  // this one moved
        a.moveZombies();
        assert(a.zombieCount() == 1);
        assert(a.numberOfZombiesAt(z[2].r, z[2].c) == 0);  // this one died
        assert(noZombiesAround(a, z[2]));
        assert(locateTheZombie(a, z[3], true));  // this one moved
                    } break; case 23: {
        Arena a(4, 2);
        a.addPlayer(1, 1);
        Player* p = a.player();
        a.addZombie(4, 2);
        for (int k = 0; k < 10000 &&  ! a.player()->isDead()  &&
                        a.zombieCount() != 0; k++)
        {
            int dir;
            if (recommendMove(a, p->row(), p->col(), dir))
                p->move(dir);
            else
                p->dropPoisonedBrain();
            a.moveZombies();
        }
        assert(! a.player()->isDead()  &&  a.zombieCount() == 0);
                    } break; case 24: {
        Arena a(10, 10);
        a.addPlayer(6, 6);
        a.addZombie(5, 6);
        a.addZombie(7, 6);
        a.addZombie(6, 7);
        int dir;
        assert(recommendMove(a, 6, 6, dir)  &&  dir == WEST);
                    } break; case 25: {
        Arena a(10, 10);
        a.addPlayer(6, 6);
        a.addZombie(4, 6);
        a.addZombie(5, 7);
        a.addZombie(6, 8);
        a.addZombie(7, 7);
        a.addZombie(8, 6);
        a.addZombie(7, 5);
        a.addZombie(6, 4);
        a.addZombie(5, 5);
        int dir;
        assert(!recommendMove(a, 6, 6, dir));
                    } break; case 26: {
        Arena a(2, 3);
        a.addPlayer(1, 2);
        a.addZombie(1, 1);
        for (int k = 0; k < 10; k++)
            a.addZombie(2, 3);
        int dir;
        assert(!recommendMove(a, 1, 2, dir));
                    } break; case 27: {
        Arena a(3, 2);
        a.addPlayer(3, 1);
        a.addZombie(1, 1);
        for (int k = 0; k < 10; k++)
            a.addZombie(3, 2);
        int dir;
        assert(recommendMove(a, 3, 1, dir)  &&  dir == NORTH);
                    } break;
    }
}

int main()
{
    cout << "Enter test number (1-27): ";
    int n;
    cin >> n;
    testone(n);
    cout << "Passed!" << endl;
}