teaching machines

CS 330 Lecture 22 – Vtables and Other C++isms

Agenda

  • what ?s
  • O(1) dynamic dispatch
  • Game of Life with conditionals
  • overloading builtin operators
  • copy constructor
  • formatted output with stringstream
  • references

TODO

  • Optional participation point: write Game of Life without conditionals.

Code

Sizeof.cpp

#include <iostream>

class Int {
  public:
    Int() {}
    virtual int Get() { return i; }
  private:
    int i;
};

int main(int argc, char **argv) {
  std::cout << sizeof(Int) << std::endl;
  return 0;
}

life.cpp

#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>

using std::string;

class GameOfLife {
  public:
    typedef enum {
      DEAD,
      ALIVE
    } cell_t;

    GameOfLife(int width, int height) :
      width(width),
      height(height) {
      cells = new cell_t[width * height];
      for (int i = 0; i < width * height; ++i) {
        cells[i] = DEAD;
      }
    }

    GameOfLife(const GameOfLife& other) :
      width(other.width),
      height(other.height) {
      cells = new cell_t[width * height];
      memcpy(cells, other.cells, sizeof(cell_t) * width * height);
    }


    cell_t operator()(int c, int r) const {
      return cells[r * width + c];
    }

    void Write(const string& path) const {
      std::ofstream out(path.c_str());
      out << "P2" << std::endl;
      out << width << " " << height << std::endl;
      out << 255 << std::endl;
      for (int r = 0; r < height; ++r) {
        for (int c = 0; c < width; ++c) {
          out << ((*this)(c, r) == ALIVE ? 255 : 0) << " ";
        }
        out << std::endl;
      }
      out.close();  
    }

    cell_t& operator()(int c, int r) {
      return cells[r * width + c];
    }

    void Tick() {
      GameOfLife oldGame = (*this);
      for (int r = 0; r < height; ++r) {
        for (int c = 0; c < width; ++c) {
          int nliving = oldGame.GetLiveCount(c, r);
          cell_t state = (*this)(c, r);
          if (state == ALIVE && (nliving == 2 || nliving == 3)) {
            (*this)(c, r) = ALIVE;
          } else if (state == DEAD && nliving == 3) {
            (*this)(c, r) = ALIVE;
          } else {
            (*this)(c, r) = DEAD;
          }
        }
      } 
    }

  private:
    int GetLiveCount(int c, int r) const {
      return ((*this)(c - 1, r - 1) == ALIVE) +
             ((*this)(c - 1, r    ) == ALIVE) +
             ((*this)(c - 1, r + 1) == ALIVE) +
             ((*this)(c    , r - 1) == ALIVE) +
             ((*this)(c    , r + 1) == ALIVE) +
             ((*this)(c + 1, r - 1) == ALIVE) +
             ((*this)(c + 1, r    ) == ALIVE) +
             ((*this)(c + 1, r + 1) == ALIVE);
    }

    cell_t *cells; 
    int width;
    int height;
};

int main(int argc, char **argv) {
  
  GameOfLife game(100, 100);

  // An R-pentomino
  game(50, 50) = GameOfLife::ALIVE; // center
  game(49, 50) = GameOfLife::ALIVE; // left
  game(50, 49) = GameOfLife::ALIVE; // top
  game(51, 49) = GameOfLife::ALIVE; // top-right
  game(50, 51) = GameOfLife::ALIVE; // bottom

  game.Write("images/out0000.pgm"); 
  std::stringstream ss;
  for (int i = 1; i < 100; ++i) {
    game.Tick();
    ss.str("");
    ss << "images/out" << std::setw(4) << std::setfill('0') << i << ".pgm";
    game.Write(ss.str()); 
  }

  return 0;
}

Haiku

“Let’s play Game of Life”
He won’t sleep until we do
One round and he’s out

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *