teaching machines

CS 330 Lecture 23 – Inheritance vs. Composition, Iflessness

March 28, 2014 by . Filed under cs330, lectures, spring 2014.

Agenda

Code

raffle.cpp

#include <iostream>
#include <string>
#include <vector>

using std::vector;
using std::string;

class Raffle : private vector<string> {
  public:
    Raffle() :
      vector<string>() {
    }

    int size() {
      return vector<string>::size();
    }

    void Add(const string& name) {
      if (name != "Jill") {
        push_back(name);
      }
    }

    string Draw() {
      int random = (int) (rand() / (float) RAND_MAX * (size() - 1));
      string winner = (*this)[random];

      vector<string>::iterator i = begin() + random;
      erase(i);

      return winner;
    }
};

int main(int argc, char **argv) {

  Raffle raffle;

  raffle.Add("Brendon");
  raffle.Add("John S.");
  raffle.Add("John F.");
  raffle.Add("Lucas N.");
  raffle.Add("Justin");
  raffle.Add("Donatello");
  raffle.Add("Kiernan");
  for (int i = 0; i < 10000; ++i) {
    raffle.Add("Jill");
  }
  std::cout << "raffle.size(): " << raffle.size() << std::endl;

  for (int i = 0; i < 3; ++i) {
    std::cout << "raffle.Draw(): " << raffle.Draw() << std::endl;
  }
  std::cout << "raffle.size(): " << raffle.size() << std::endl;

  return 0;
}

life_sans_if.cpp

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

using std::string;

class GameOfLife {
  public:
    class Cell {
      public:
        virtual bool IsNowLiving(int nliving) const = 0;
        virtual int ToInt() const = 0;

        Cell *Tick(int nliving) {
          Cell *(*GetSingletons[2])() = {
            DeadCell::GetSingleton,
            LiveCell::GetSingleton
          };

          bool is_now_alive = IsNowLiving(nliving);
          return GetSingletons[(int) is_now_alive]();
        }

      protected:
        Cell() {}
    };

    class LiveCell : public Cell {
      public:
        bool IsNowLiving(int nliving) const {
          return nliving == 2 || nliving == 3;
        }

        int ToInt() const {
          return 255;
        }

        static Cell *GetSingleton() {
          static LiveCell singleton;
          return &singleton;
        }

      private:
        LiveCell() {}
    };

    class DeadCell : public Cell {
      public:
        bool IsNowLiving(int nliving) const {
          return nliving == 3;
        }

        int ToInt() const {
          return 0;
        }

        static Cell *GetSingleton() {
          static DeadCell singleton;
          return &singleton;
        }

      private:
        DeadCell() {}
    };

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

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

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

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

    void Tick() {
      GameOfLife oldGame = (*this);

      for (int r = 1; r < height - 1; ++r) {
        for (int c = 1; c < width - 1; ++c) {
          int nliving = oldGame.GetLiveCount(c, r);
          (*this)(c, r) = (*this)(c, r)->Tick(nliving);
        }
      } 
    }

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

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

    Cell **cells;
    int width;
    int height;
};

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

  // An R-pentomino
  /* game(100, 100) = GameOfLife::ALIVE; // center */
  /* game(99, 100) = GameOfLife::ALIVE; // left */
  /* game(100, 99) = GameOfLife::ALIVE; // top */
  /* game(101, 99) = GameOfLife::ALIVE; // top-right */
  /* game(100, 101) = GameOfLife::ALIVE; // bottom */

  // A glider
#if 1
  game(50, 50) = GameOfLife::LiveCell::GetSingleton(); // center
  game(49, 51) = GameOfLife::LiveCell::GetSingleton(); // bottom-left
  game(50, 49) = GameOfLife::LiveCell::GetSingleton(); // top
  game(51, 51) = GameOfLife::LiveCell::GetSingleton(); // bottom-right
  game(51, 50) = GameOfLife::LiveCell::GetSingleton(); // right
#endif

  /* game(49, 50) = GameOfLife::ALIVE; */
  /* game(50, 50) = GameOfLife::ALIVE; */
  /* game(51, 50) = GameOfLife::ALIVE; */
  /* game(52, 50) = GameOfLife::ALIVE; */

  /* game(49, 51) = GameOfLife::ALIVE; */
  /* game(49, 52) = GameOfLife::ALIVE; */

  /* game(52, 51) = GameOfLife::ALIVE; */
  /* game(52, 52) = GameOfLife::ALIVE; */

  /* game(49, 53) = GameOfLife::ALIVE; */
  /* game(50, 53) = GameOfLife::ALIVE; */
  /* game(51, 53) = GameOfLife::ALIVE; */
  /* game(52, 53) = GameOfLife::ALIVE; */

  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

What should we fear more?
Having to make decisions?
Or letting others?