Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Language C++ // FILE GameOfLife2.h #pragma once #include // Provides ostream #in

ID: 3845960 • Letter: L

Question

Language C++

// FILE GameOfLife2.h

#pragma once
#include // Provides ostream
#include // String operations
#include // Randomizer


namespace csci2312
{
   using std::string;
   using std::ostream;
   using std::istream;
  
   // PA2: standard exception if memory allcation failed
   using std::bad_alloc;

   // Class Cell stays the same for PA1 and PA2  
   class Cell
   {
      
   public:
       static const char alive ='o'; // alive image
       static const char dead = '-'; // dead image
      
  
       Cell();
       Cell(bool cellState);
       ~Cell();

       // Accessors have no intention to modify the object, so it is a good practice to make them 'const' functions
       bool getState() const;      
       char getFace() const;

       // Mutators
       void setState(bool newState);
          
   private:
       bool state=false;
       char face;      
  
   };

   // PA2: File IO Error custom exception class
   class FileIOException
   {
       // Nothing inside, just a class type to handle exception
   };

   // PA2: Class GameOfLife will have some new and some changed features
class GameOfLife
{
      
public:
       // PA1: maximum display board size
       // PA2: default display board size
       static const unsigned int MAX_BOARD = 30;

       // PA2: New type (pointer to Cell type) handy with dynamic arrays
       typedef Cell* CellPtr;

       // PA1: Default constructor construct a board with all dark cells of MAX_BOARD size
       // GameOfLife();
      
       // PA1: Constructs the board of the requested size
       // GameOfLife(size_t boardSize);
         
       // PA2: Constructs the board of the requested size, can throw exception.
       // If parameter is omitted, it becomes the default constructor, and the board will have MAX_BOARD size
       GameOfLife(size_t boardSize = MAX_BOARD) throw (bad_alloc);

       // PA2: Copy-constructor creates a new instance as a deep copy of the referenced object
       GameOfLife(const GameOfLife& game);

       // PA2: destructor must release memory taken by dynamic arrays
       ~GameOfLife();
     
// Returns board size
       size_t getBoardSize() const;

       // PA1: seeds the board from a file
       // int seedBoard(string fileName);

       // PA2: seeds the board from a file and throws an exception if there was trouble with file
       void seedBoard(string fileName) throw (FileIOException);

       // PA1 and PA2: seeds the board with a given number of seeds at randomized locations
       void seedBoard(size_t seeds);

       // Executes Conway set of rules. Returns next state
       // Needed for TASK #4 to develop a test harness (the files test harness will be provided separately)
       bool executeRules(unsigned int countAlive, bool currentState);
      
       // PA1 and PA2:
       void run();
       void run(unsigned int numberOfIterations);

       // Just an example of an possible accessor which reaches to a private array. Not needed to satisfy PAs
       // A const(!) accessor method that returns a handle to the private currentLife array.
       // The return type must also be 'const' because we return a pointer to a static array, and these are fixed
       // It is just an example. It is not needed if we have a friend operator.      
       // PA1: const Cell(*getCurrentLife() const )[MAX_BOARD+2] { return currentLife; };
       // PA2: const CellPtr* getCurrentLIfe() const { return currentLife; };

       // PA1 and PA2: overloaded output operator to displsy the board
       // friend operator can access private members of GameOfLife
       friend ostream& operator << (ostream& out, const GameOfLife& board);

       // PA2: overloaded input operator to input the board (from file of keyboard)
       friend istream& operator >> (istream& in, GameOfLife& board);
      
private:      
      
       // PA2: Encapsulate next generation calculation in a method.
       void calculateNextGen(CellPtr* current, CellPtr* next);

       // PA1: static arrays of Cells. With "Halo" approach we need a bigger board
       // Cell currentLife[MAX_BOARD + 2][MAX_BOARD + 2];
       // Cell nextLife[MAX_BOARD + 2][MAX_BOARD + 2];

       // PA2: dynamic arrays of Cells. New type CellPtr defined (typedef Cell* CellPtr)
       // currentLife and and nextLife are handles to the dynamic arrays
       CellPtr *currentLife;
       CellPtr *nextLife;
          
       // Just an example how to declare variable cl as a handle to our array of Cells. Not needed to satisfy PAs
       // The accessor method getCurrentLife() above uses the same syntax for the return type
       // PA1 with static arrays: const Cell(*cl)[MAX_BOARD + 2] = currentLife;
       // PA2 with dynamic arrays: const CellPtr* cl = currentLife;
  
   // PA1 and PA2, keeps track of the actual board size, set in the constructor
   size_t boardSize;   

       // PA2: A handle to the array that needs to be displyed next.
       CellPtr *displayBoard;

};

}

----------------------------------------------------------------------------------------------------------------------------------------------------------------

// GameOfLife2_TestApp.cpp
#include

#include "ErrorContext.h"
#include "GameOfLife2_Tests.h"

using std::cout;
using std::endl;

using namespace Testing;
using namespace csci2312;

int main() {

   ErrorContext ec(cout);

cout << endl << "Testing PA2!!" << endl << endl;
  
   // Cell tests
   test_cell_smoketest(ec);

   test_cell_setget(ec);


// GameOfLife tests
test_game_smoketest(ec);

   test_game_rules(ec);

   system("pause");

return 0;
}

-------------------------------------------------------------------------------------------------------------------------------------

//ErrorContext.h

#pragma once

/**
* Acknowledgement: Donnie Pinkston, CALTECH
*/

#include
#include
#include

namespace Testing {

using std::set;
using std::ostream;
using std::string;

class ErrorContext // displays test results
{
public:
ErrorContext(ostream &os); // write header to stream
void desc(const char *msg, int line); // write line/description
void desc(string msg, int line);

void result(bool good); // write test result
~ErrorContext(); // write summary info
bool ok() const; // true iff all tests passed

private:
ostream &os; // output stream to use
int passed; // # of tests which passed
int total; // total # of tests
int lastline; // line # of most recent test
set badlines; // line #'s of failed tests
bool skip; // skip a line before title?
};

}

---------------------------------------------------------------------------------------------------------------------------

//GameOfLife2_Tests.cpp

#include
#include
#include
#include


#include "ErrorContext.h"
#include "GameOfLife2_Tests.h"

using std::cout;
using std::endl;
using std::setprecision;

using Testing::ErrorContext;
using csci2312::GameOfLife;

#define DESC(x) desc(x, __LINE__) // ugly hack, but saves some time


///////// STUDENT TASK: Fill in implementatin for Cell tests


// Test Cell constructor and destructor
void test_cell_smoketest(ErrorContext &ec) {
// to do
}

// Test Cell setters and getters
void test_cell_setget(ErrorContext &ec) {
// to do
}


///////// END TASK

// Test GameOfLife constructor and destructor
void test_game_smoketest(ErrorContext &ec) {
bool pass;
   GameOfLife* myGame;  

ec.DESC("--- Test - GameOfLife - Smoketest ---");

ec.DESC("Default Constructor");
pass = true;
// Construct a Default GameOfLife - boardSize should be set to MAX_BOARD
       myGame = new GameOfLife;
       pass = (myGame->getBoardSize() == myGame->MAX_BOARD);
ec.result(pass);
  
   ec.DESC("Destruct Defualt Test Game");
// Cleans up after previous test, destruct the object
   delete myGame;         

   ec.DESC("Custom Constructor requesting a specific boad size");
   pass = true;
   // Construct a Custom GameOfLife - boardSize should be set to what was requested   
   myGame = new GameOfLife(50);
   pass = (myGame->getBoardSize() == 50);
   ec.result(pass);

  
   ec.DESC("Destruct Custom Test Game");
   // Cleans up after previous test, destruct the object
   delete myGame;
  
}

// Game rules test
void test_game_rules(ErrorContext &ec) {
bool pass;
   GameOfLife *myGame;

// Run at least once!!
// assert(numRuns > 0);

ec.DESC("--- Test - Game Rule 110 ---");
  
   pass = true;
   // Construct a Default GameOfLife - boardSize should be set to MAX_BOARD
   myGame = new GameOfLife;
  
   ec.DESC("--------- Alive cell with 2 alive neighbors ---");
   pass = (myGame->executeRules(2, true) == true);
   ec.result(pass);

   ec.DESC("--------- Dead cell with 2 alive neighbors ---");
   pass = (myGame->executeRules(2, false) == false);
   ec.result(pass);

///////// STUDENT TASK: add test for the remaining rule outcomes


///////// END TASK

   // Destruct the object at the end of test
  
   ec.DESC("Destruct Test Game");
   // Cleans up after previous test, destruct the object
   delete myGame;
  
}

Programming Assignment 2: Game of Life 2 The objective of this programming assignment is to improve several aspects of PA1 implementation, applying concepts learned so far in this course. As before, the GameofLife2-csci2312.h on file has been provided, and should be treated as project requirements. The game's existing API should remain the same only the board implementation will change, as we are replacing static arrays with dynamic arrays, and employing pointers to enhance the board display management. This time, also the matching GameofLife2-csci2312.cpp has also been provided, with placeholders for method implementation to be filled in As before, the GameofLifeApp2-csci2312.cpp (where main is) would have to be written as The PA2 package also includes several files com the test framework. Please see prising section Task #4 below. Task #0 Finish PA1 Please complete all that was missing in PAl, according to the requirements in the new .h file, and as per feedback received. Task #1 Dynamic Arrays Instead of having static arrays of Cells (currentLife and nextLife), where we had to reserve space for a maximum board, regardless of the actually requested size, we will now employ dynamic arrays and size them just as needed (as per boardsize passed into the GameofLife The only change needed will be in the class definitions and the constructors, where the array is built, but the API implementation (seed board, calculate next state, etc) will not have to change. Task #2 Exception Handling Now let us handle exceptions! Two error-prone areas come to mind: seeding a board from a file, where a file may not open successfully allocating dynamic memory, while constructing the GameofLife (more difficult) Please select at least one of the areas, and have a method throw an Exception upon encountering an error. Then invoke that method in a try/catch block and gracefully exit the program, after displaying a meaningful message.

Explanation / Answer

package org.bitstorm.gameoflife;

import java.applet.Applet;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

/**
* The Game Of Life Applet.
* This is the heart of the program. It initializes everything en put it together.
* @author Edwin Martin
*/
public class GameOfLife extends Applet implements Runnable, GameOfLifeControlsListener {
  protected CellGridCanvas gameOfLifeCanvas;
  protected GameOfLifeGrid gameOfLifeGrid;
  protected int cellSize;
  protected int cellCols;
  protected int cellRows;
  protected int genTime;
  protected GameOfLifeControls controls;
  protected static Thread gameThread = null;

  /**
   * Initialize UI.
   * @see java.applet.Applet#init()
   */
  public void init() {
    getParams();

    // set background colour
    setBackground(new Color(0x999999));

    // create gameOfLifeGrid
    gameOfLifeGrid = new GameOfLifeGrid(cellCols, cellRows);
    gameOfLifeGrid.clear();

    // create GameOfLifeCanvas
    gameOfLifeCanvas = new CellGridCanvas(gameOfLifeGrid, cellSize);

    // create GameOfLifeControls
    controls = new GameOfLifeControls();
    controls.addGameOfLifeControlsListener( this );

    // put it all together
        GridBagLayout gridbag = new GridBagLayout();
        setLayout(gridbag);
        GridBagConstraints canvasContraints = new GridBagConstraints();

        canvasContraints.fill = GridBagConstraints.BOTH;
        canvasContraints.gridx = GridBagConstraints.REMAINDER;
        canvasContraints.gridy = 0;
        canvasContraints.weightx = 1;
        canvasContraints.weighty = 1;
        canvasContraints.anchor = GridBagConstraints.CENTER;
        gridbag.setConstraints(gameOfLifeCanvas, canvasContraints);
        add(gameOfLifeCanvas);

        GridBagConstraints controlsContraints = new GridBagConstraints();
        canvasContraints.gridy = 1;
        canvasContraints.gridx = 0;
        controlsContraints.gridx = GridBagConstraints.REMAINDER;
        gridbag.setConstraints(controls, controlsContraints);
        add(controls);
    
        try {
      // Start with a shape (My girlfriend clicked "Start" on a blank screen and wondered why nothing happened).
      setShape( ShapeCollection.getShapeByName( "Glider" ) );
    } catch (ShapeException e) {
      // Ignore. Not going to happen.
    }
    setVisible(true);
    validate();
  }
  
  /**
   * Get params (cellSize, cellCols, cellRows, genTime) from applet-tag
   */
  protected void getParams() {
    cellSize = getParamInteger( "cellsize", 11 );
    cellCols = getParamInteger( "cellcols", 50 );
    cellRows = getParamInteger( "cellrows", 30 );
    genTime  = getParamInteger( "gentime", 1000 );
  }
  
  /**
   * Read applet parameter (int) or, when unavailable, get default value.
   * @param name name of parameter
   * @param defaultParam default when parameter is unavailable
   * @return value of parameter
   */
  protected int getParamInteger( String name, int defaultParam ) {
    String param;
    int paramInt;

    param = getParameter( name );
    if ( param == null )
      paramInt = defaultParam;
    else
      paramInt = Integer.valueOf(param).intValue();
    return paramInt;
  }

  /**
   * Starts creating new generations.
   * No start() to prevent starting immediately.
   */
  public synchronized void start2() {
    controls.start();
    if (gameThread == null) {
      gameThread = new Thread(this);
      gameThread.start();
    }
  }

  /**
   * @see java.applet.Applet#stop()
   */
  public void stop() {
    controls.stop();
    gameThread = null;
  }

  /**
   * @see java.lang.Runnable#run()
   */
  public synchronized void run() {
    while (gameThread != null) {
      nextGeneration();
      try {
        Thread.sleep(genTime);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
  
  /**
   * Is the applet running?
   * @return true: applet is running
   */
  public boolean isRunning() {
    return gameThread != null;
  }
  
  /**
   * Go to the next generation.
   */
  public void nextGeneration() {
    gameOfLifeGrid.next();
    gameOfLifeCanvas.repaint();
    showGenerations();
  }
  
  /**
   * Set the new shape
   * @param shape name of shape
   */
  public void setShape( Shape shape ) {
    if ( shape == null )
      return;

    try {
      gameOfLifeCanvas.setShape( shape );
      reset();
    } catch (ShapeException e) {
      alert( e.getMessage() );
    }
  }
  
  /**
   * Resets applet (after loading new shape)
   */
  public void reset() {
    stop(); // might otherwise confuse user
    gameOfLifeCanvas.repaint();
    showGenerations();
    showStatus( "" );
  }

  /**
   * @see java.applet.Applet#getAppletInfo()
   */
  public String getAppletInfo() {
    return "Game Of Life v. 1.5 Copyright 1996-2004 Edwin Martin";
  }

  /**
   * Show number of generations.
   */
  private void showGenerations() {
    controls.setGeneration( gameOfLifeGrid.getGenerations() );
  }
  
  /**
   * Set speed of new generations.
   * @param fps generations per second
   */
  public void setSpeed( int fps ) {
    genTime = fps;
  }
  
  /**
   * Sets cell size.
   * @param p size of cell in pixels
   */
  public void setCellSize( int p ) {
    cellSize = p;
    gameOfLifeCanvas.setCellSize( cellSize );
  }
  
  /**
   * Gets cell size.
   * @return size of cell
   */
  public int getCellSize() {
    return cellSize;
  }
  
  /**
   * Shows an alert
   * @param s text to show
   */
  public void alert( String s ) {
    showStatus( s );
  }

  /** Callback from GameOfLifeControlsListener
   * @see org.bitstorm.gameoflife.GameOfLifeControlsListener#startStopButtonClicked(org.bitstorm.gameoflife.GameOfLifeControlsEvent)
   */
  public void startStopButtonClicked( GameOfLifeControlsEvent e ) {
    if ( isRunning() ) {
      stop();
    } else {
      start2();
    }
  }

  /** Callback from GameOfLifeControlsListener
   * @see org.bitstorm.gameoflife.GameOfLifeControlsListener#nextButtonClicked(org.bitstorm.gameoflife.GameOfLifeControlsEvent)
   */
  public void nextButtonClicked(GameOfLifeControlsEvent e) {
    nextGeneration();
  }

  /** Callback from GameOfLifeControlsListener
   * @see org.bitstorm.gameoflife.GameOfLifeControlsListener#speedChanged(org.bitstorm.gameoflife.GameOfLifeControlsEvent)
   */
  public void speedChanged(GameOfLifeControlsEvent e) {
    setSpeed( e.getSpeed() );
  }

  /** Callback from GameOfLifeControlsListener
   * @see org.bitstorm.gameoflife.GameOfLifeControlsListener#speedChanged(org.bitstorm.gameoflife.GameOfLifeControlsEvent)
   */
  public void zoomChanged(GameOfLifeControlsEvent e) {
    setCellSize( e.getZoom() );
  }

  /** Callback from GameOfLifeControlsListener
   * @see org.bitstorm.gameoflife.GameOfLifeControlsListener#shapeSelected(org.bitstorm.gameoflife.GameOfLifeControlsEvent)
   */
  public void shapeSelected(GameOfLifeControlsEvent e) {
    String shapeName = (String) e.getShapeName();
    Shape shape;
    try {
      shape = ShapeCollection.getShapeByName( shapeName );
      setShape( shape );
    } catch (ShapeException e1) {
      // Ignore. Not going to happen.
    }
  }
}