Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Objective in C++ Make a struct in order to store settings for the application Instructions In order to allow the Game of Life to be

Objective in C++

Make a struct in order to store settings for the application

Instructions

  1. In order to allow the Game of Life to be customized, it will be necessary to keep track of a few different settings.  A couple of these settings already have values that are being tracked in the program.  Creating an object for the settings will make it easier to pass around the program from object to object.
  2. Make a struct that for the game settings in a new header file.  No need for a .cpp file in this case.  At a minimum, the struct will need to track the following pieces of data for now.
    1. The color of living cells, stored as unsigned ints representing the Red, Blue, Green, and Alpha values.  Default the RGB values to 128 and the Alpha to 255.
    2. The color of dead cells, stored as unsigned ints representing the Red, Blue, Green, and Alpha values. Default the RGB values to 255 and the Alpha to 255.
      1. It is possible to run into Read Access errors if trying to read a wxColor that has been loaded from file. This is because one of the classes the wxColor inherits from does not like being written to directly. In order to get around this error, don't store wxColor directly. Instead store the Red, Green, Blue, and Alpha values as unsigned ints. wxColor has .GetRed(), .GetGreen(), .GetBlue(), and .GetAlpha() methods that can be used. It may make sense to create a method in the Settings struct that returns a wxColor based on the specific RGBA values that are stored.
    3. The grid size (Default to 15)
    4. The interval (Default to 50)
    5. Eventually information about the window size and location may be added to this struct, as well as other any other options that can be tracked.
  3. It may make sense to add methods for getting the living cell color and getting the dead cell color that returns a wxColor.  Creating setters for living cell color and dead cell color would make sense too.  Those could take in a wxColor and set the RGBA values from those colors.
  4. Add a variable to the main window header for the settings object.  This should not be a pointer.
  5. Since the grid size will now be tracked in the settings object, it will be necessary to remove all existing references to that variable and replace them with the reference to the settings object.
    1. The easiest way to do this is to removethe size variable from the main window header file.
    2. The .cpp file will have many errors at this point.  Each error can be fixed by referencing the appropriate variable in the settings file.
  6. Now that there is a settings object, this can be used to pass data to the drawing panel.  Make a settings pointer in the drawing panel header file.
  7. The value of the settings object pointer can either be set in the drawing panel constructor or through a setter.  The easiest way is likely to create a setter for the settings pointer.
  8. It will again be necessary to remove all existing references to variables in the drawing panel and replace them with the reference to the settings object pointer.
  9. To test, change the default values in the settings object file and open the program.  The interval, grid size, and colors should change based on the default values.

 


wxBEGIN_EVENT_TABLE(DrawingPanel, wxPanel)
EVT_PAINT(DrawingPanel::OnPaint)
EVT_LEFT_UP(DrawingPanel::OnMouseUp)
wxEND_EVENT_TABLE()

DrawingPanel::DrawingPanel(wxFrame* parent, std::vector>& gameBoard) : wxPanel(parent, wxID_ANY, wxPoint(0, 0), wxSize(200, 200)), _gameBoard(gameBoard)
{
this->SetBackgroundStyle(wxBG_STYLE_PAINT);

gridSize = 30;
CalculateCellSize();


}
DrawingPanel::~DrawingPanel()
{

}

void DrawingPanel::CalculateCellSize()
{
wxSize panelSize = GetParent()->GetClientSize();
cellWidth = panelSize.GetWidth() / gridSize;
cellHeight = panelSize.GetHeight() / gridSize;
}

void DrawingPanel::OnPaint(wxPaintEvent& event)
{
wxAutoBufferedPaintDC dc(this);
dc.Clear();

wxGraphicsContext* context = wxGraphicsContext::Create(dc);
if (!context)
{
 return;
}

context->SetPen(*wxBLACK);
context->SetBrush(*wxWHITE);


for (int row = 0; row < gridSize; row++)
{
 for (int col = 0; col < gridSize; col++)
 {
  int x = col * cellWidth;
  int y = row * cellHeight;
  // Checks the corresponding bool in the game board
  if (_gameBoard[row][col])
  {
   context->SetBrush(*wxLIGHT_GREY); // Living cell color
  }
  else
  {
   context->SetBrush(*wxWHITE); // Dead cell color
  }

  context->DrawRectangle(x, y, cellWidth, cellHeight);
 }
}

}
void DrawingPanel::SetGridSize(int size)
{
gridSize = size;
CalculateCellSize(); // Recalculates cell size based on the new grid size
}

void DrawingPanel::SetSize(const wxSize& size)
{
// Call SetSize on base wxPanel class
wxPanel::SetSize(size);

// Call Refresh
Refresh();
}

void DrawingPanel::OnMouseUp(wxMouseEvent& event)
{
int mouseX = event.GetX();
int mouseY = event.GetY();

int row = mouseY / cellHeight;
int col = mouseX / cellWidth;

if (row >= 0 && row < gridSize && col >= 0 && col < gridSize)
{
 // Toggles the state of the clicked cell
 _gameBoard[row][col] = !_gameBoard[row][col];
 Refresh();
}
}

 

 

 


wxBEGIN_EVENT_TABLE(MainWindow, wxFrame)
EVT_SIZE(MainWindow::OnSizeChanged)
EVT_TOOL(TOOLBAR_PLAY_ICON, MainWindow::OnPlay)
EVT_TOOL(TOOLBAR_PAUSE_ICON, MainWindow::OnPause)
EVT_TOOL(TOOLBAR_NEXT_ICON, MainWindow::OnNext)
EVT_TOOL(TOOLBAR_TRASH_ICON, MainWindow::OnTrash)

EVT_TIMER(wxID_ANY, MainWindow::OnTimer)
wxEND_EVENT_TABLE();

MainWindow::MainWindow() :wxFrame(nullptr, wxID_ANY, "Game of Life", wxPoint(0, 0), wxSize(200, 200))
{
_drawingPanel = new DrawingPanel(this, _gameBoard);


_sizer = new wxBoxSizer(wxVERTICAL);

_toolbar = CreateToolBar();

this->Bind(wxEVT_SIZE, &MainWindow::OnSizeChanged, this);

// Adds Play button to the toolbar
wxBitmap playIcon(play_xpm);
_toolbar->AddTool(TOOLBAR_PLAY_ICON, "Play", playIcon);

// Adds Pause button to the toolbar
wxBitmap pauseIcon(pause_xpm);
_toolbar->AddTool(TOOLBAR_PAUSE_ICON, "Pause", pauseIcon);

// Adds Next button to the toolbar
wxBitmap nextIcon(next_xpm);
_toolbar->AddTool(TOOLBAR_NEXT_ICON, "Next", nextIcon);

// Adds Trash button to the toolbar
wxBitmap trashIcon(trash_xpm);
_toolbar->AddTool(TOOLBAR_PLAY_ICON, "Trash", trashIcon);

 

gameTimer = new wxTimer(this);
timerInterval = 50;

 

_toolbar->Realize();


_sizer->Add(_drawingPanel, 1, wxEXPAND | wxALL);

// Initializes the status bar
statusBar = CreateStatusBar();

SetSizer(_sizer);
InitializeGameBoard();

this->Layout();


}
MainWindow::~MainWindow()
{
gameTimer->Stop(); // Stop the timer before destroying the frame
delete gameTimer;
}
void MainWindow::OnSizeChanged(wxSizeEvent& event)
{
// Save the size of the window
wxSize windowSize = event.GetSize();

// Pass the size to DrawingPanel
_drawingPanel->SetSize(windowSize);

// Stop other events from being processed
event.Skip();
}

void MainWindow::InitializeGameBoard()
{
_gameBoard.resize(gridSize); // Resizes the game board vector to the grid size

for (int i = 0; i < gridSize; i++)
{
 _gameBoard[i].resize(gridSize); // Resizes each sub-vector to the grid size
}

_drawingPanel->SetGridSize(gridSize); // Passes the grid size to the drawing panel
}

void MainWindow::UpdateStatusBar()
{
wxString statusText = wxString::Format("Generation: %d   Living Cells: %d", generationCount, livingCellsCount);
statusBar->SetStatusText(statusText, 0);
}

// Event handler for the Play button
void MainWindow::OnPlay(wxCommandEvent& event)
{
gameTimer->Start(timerInterval);
}

// Event handler for the Pause button
void MainWindow::OnPause(wxCommandEvent& event)
{
gameTimer->Stop();
}

// Event handler for the Next button
void MainWindow::OnNext(wxCommandEvent& event)
{
CalculateNextGeneration();
}

// Event handler for the Trash button
void MainWindow::OnTrash(wxCommandEvent& event)
{
for (int row = 0; row < gridSize; ++row)
{
 for (int col = 0; col < gridSize; ++col)
 {
  _gameBoard[row][col] = false;
 }
}

generationCount = 0;
livingCellsCount = 0;

UpdateStatusBar();

_drawingPanel->Refresh();
}


void MainWindow::OnTimer(wxTimerEvent& event)
{
CalculateNextGeneration();
}

int MainWindow::GetNeighborCount(int row, int col)
{
int count = 0;

for (int r = row - 1; r <= row + 1; r++)
{
 for (int c = col - 1; c <= col + 1; c++)
 {

  // Makes sure index is valid
  if (r >= 0 && r < gridSize && c >= 0 && c < gridSize)
  {

   
   if (!(r == row && c == col))
   {

    if (_gameBoard[r][c])
    {
     count++;
    }

   }

  }

 }
}

return count;
}

void MainWindow::CalculateNextGeneration()
{
// Sandbox with the same data type as the game board
std::vector> sandbox(gridSize, std::vector(gridSize, false));

// Iterates through the game board to calculate the next generation
int newLivingCellsCount = 0;

for (int row = 0; row < gridSize; ++row)
{
 for (int col = 0; col < gridSize; ++col)
 {
  // Counts the number of living neighbors for the current cell
  int neighborCount = GetNeighborCount(row, col);

 
  if (_gameBoard[row][col])
  {
   if (neighborCount < 2 || neighborCount > 3)
   {
    // Cell dies in the next generation
    sandbox[row][col] = false;
   }
   else
   {
    // Cell survives to the next generation
    sandbox[row][col] = true;
    ++newLivingCellsCount;
   }
  }
  else
  {
   if (neighborCount == 3)
   {
    // Dead cell becomes alive in the next generation
    sandbox[row][col] = true;
    ++newLivingCellsCount;
   }
  }
 }
}

// Updates the game board with the new generation using swap
_gameBoard.swap(sandbox);

// Updates counts and status bar
++generationCount;
livingCellsCount = newLivingCellsCount;
UpdateStatusBar();


_drawingPanel->Refresh();
}



Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Smith and Roberson Business Law

Authors: Richard A. Mann, Barry S. Roberts

15th Edition

1285141903, 1285141903, 9781285141909, 978-0538473637

More Books

Students also viewed these Algorithms questions

Question

Why are stocks usually more risky than bonds?

Answered: 1 week ago