Question: //App.h* #pragma once #ifndef APP_H #define APP_H #include wx/wx.h #include MainWindow.h class App : public wxApp { private: //pointer to MainWindow MainWindow* mainWindow; public: App();
//App.h* #pragma once #ifndef APP_H #define APP_H #include "wx/wx.h" #include "MainWindow.h" class App : public wxApp { private: //pointer to MainWindow MainWindow* mainWindow; public: App(); ~App(); virtual bool OnInit();// override; }; #endif //App.cpp* #include "App.h" #include "MainWindow.h" wxIMPLEMENT_APP(App); App::App() { } App::~App() { } bool App::OnInit() { //initializes MainWindow and assigns pointer mainWindow = new MainWindow("Game of Life", wxPoint(0, 0), wxSize(1000, 1000)); //displays main window mainWindow->Show(true); return true; } //DrawingPanel.h* #pragma once #ifndef DRAWINGPANEL_H #define DRAWINGPANEL_H #include "wx/wx.h" //declaration of MainWindow class class MainWindow; class DrawingPanel : public wxPanel { private: //sets gridsize to int int gridSize; //OnPaint method void OnPaint(wxPaintEvent& event); //sets grid size to 15x15 static const int Grid_Size = 15; //mouse event handler void OnLeftMouseUp(wxMouseEvent& event); //pointer to mainWindow MainWindow* mainWindow; //pointer to gameBoard std::vector>* gameBoard; //event table wxDECLARE_EVENT_TABLE(); public: //constructors //DrawingPanel(wxWindow* parent); DrawingPanel(MainWindow* mainWindow); //SetSize void SetSize(const wxSize& size); //SetGridSize method void SetGridSize(int size); //destructor empty ~DrawingPanel(); }; #endif //DrawingPanel.cpp* #include "DrawingPanel.h" #include "wx/graphics.h" #include "wx/dcbuffer.h" #include "MainWindow.h" //event table for DrawingPanel class wxBEGIN_EVENT_TABLE(DrawingPanel, wxPanel) EVT_PAINT(DrawingPanel::OnPaint) EVT_LEFT_UP(DrawingPanel::OnLeftMouseUp) wxEND_EVENT_TABLE() //constructor implementation //DrawingPanel::DrawingPanel(wxWindow* parent) : wxPanel(parent) //constructor implementation DrawingPanel::DrawingPanel(MainWindow* mainWindow) : wxPanel(mainWindow), mainWindow(mainWindow) { //sets background this->SetBackgroundStyle(wxBG_STYLE_PAINT); //connects paint event to handler this->Bind(wxEVT_PAINT, &DrawingPanel::OnPaint, this); //connects nouse event to handler this->Bind(wxEVT_LEFT_UP, &DrawingPanel::OnLeftMouseUp, this); } //destructor implementation DrawingPanel::~DrawingPanel() { } //SetGridSize void DrawingPanel::SetGridSize(int size) { gridSize = size; Refresh(); } //SetSize void DrawingPanel::SetSize(const wxSize& size) { //setsize on base class wxPanel::SetSize(size); //refreshes panel and triggers repaint Refresh(); } //OnPaint void DrawingPanel::OnPaint(wxPaintEvent& event) { //step 11 added code wxAutoBufferedPaintDC dc(this); dc.Clear(); //creates instance of wxGraphicsContext pointer and instantiate wxGraphicsContext* context = wxGraphicsContext::Create(dc); //checks to see if wxGraphicsContext failed if (!context) //if failed exits return; //gets the panel size wxSize panelSize = GetSize(); int panelWidth = panelSize.GetWidth(); int panelHeight = panelSize.GetHeight(); //Calculates cellWidth and cellHeight int cellWidth = panelWidth / Grid_Size; int cellHeight = panelHeight / Grid_Size; //sets pen outline color (black) context->SetPen(*wxBLACK_PEN); //sets brush fill color (white) //context->SetBrush(*wxWHITE_BRUSH); //draws grid of rectangles for (int row = 0; row < Grid_Size; ++row) { for (int col = 0; col < Grid_Size; ++col) { //calculate based on cell width and hight int x = col * cellWidth; int y = row * cellHeight; //checks state of sell on/off grey/white if (mainWindow->gameBoard[row][col]) { //sets brush fill color (grey) context->SetBrush(*wxLIGHT_GREY_BRUSH); } else { //sets brush fill color (white) context->SetBrush(*wxWHITE_BRUSH); } //draw the rectangle based on calculated cellWidth and cellHeight context->DrawRectangle(x, y, cellWidth, cellHeight); } } //cleans graphics context delete context; } //OnMouseUp void DrawingPanel::OnLeftMouseUp(wxMouseEvent& event) { //determines position of mouse click int mouseX = event.GetX(); int mouseY = event.GetY(); int panelWidth = GetSize().GetWidth(); int panelHeight = GetSize().GetHeight(); //calculates cell dimensions int cellWidth = panelWidth / gridSize; int cellHeight = panelHeight / gridSize; //determines which cell clicked int col = mouseX / cellWidth; int row = mouseY / cellHeight; //mouse click toggles cell and reports back cell toggled if (row < gridSize && col < gridSize) { mainWindow->ToggleCellState(row, col); //wxLogMessage("Toggled cell at row %d, column %d", row, col); } //refresh typically after changes Refresh(); } //MainWindow.h* #pragma once #ifndef MAINWINDOW_H #define MAINWINDOW_H #include "wx/wx.h" #include "DrawingPanel.h" #include //declaration class DrawingPanel; class MainWindow : public wxFrame { private: //handler for InitializeGrid void InitializeGrid(); //sets gridsize to 15 int gridSize = 15; //SetGridSize method void SetGridSize(int size); //pointer to the DrawingPanel DrawingPanel* m_drawingPanel; //statusBar, toolBar, and data variables wxStatusBar* m_statusBar; wxToolBar* m_toolBar; int m_generationCount; int m_livingCellsCount; //timer pointer wxTimer* m_timer; //interval in milliseconds int m_timerInterval; //count living neighbors method int CountLivingNeighbors(int row, int col) const; //event handlers void OnPlayButtonClicked(wxCommandEvent& event); void OnPauseButtonClicked(wxCommandEvent& event); void OnNextButtonClicked(wxCommandEvent& event); void OnTrashButtonClicked(wxCommandEvent& event); void OnSizeChange(wxSizeEvent& event); void OnTimer(wxTimerEvent& event); //event table wxDECLARE_EVENT_TABLE(); public: //constructor MainWindow(const wxString& title, const wxPoint& pos, const wxSize& size); //destructor empty ~MainWindow(); //ToggleCellState method void ToggleCellState(int row, int col); //moved from private to public //sets cells to vector of vectors and bool std::vector> gameBoard; //UpdateGeneration method void UpdateGeneration(); //UpdateStatusBar method void UpdateStatusBar(); //Refresh method void RefreshPanel(); //ClearBoard method void ClearBoard(); }; #endif //MainWindow.cpp* #include "MainWindow.h" #include "DrawingPanel.h" //icon files #include "play.xpm" #include "pause.xpm" #include "next.xpm" #include "trash.xpm" //event table wxBEGIN_EVENT_TABLE(MainWindow, wxFrame) EVT_SIZE(MainWindow::OnSizeChange) EVT_MENU(10001, MainWindow::OnPlayButtonClicked) EVT_MENU(10002, MainWindow::OnPauseButtonClicked) EVT_MENU(10003, MainWindow::OnNextButtonClicked) EVT_MENU(10004, MainWindow::OnTrashButtonClicked) EVT_SIZE(MainWindow::OnSizeChange) EVT_TIMER(wxID_ANY, MainWindow::OnTimer) wxEND_EVENT_TABLE() //constructor implementation MainWindow::MainWindow(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size), m_timerInterval(50), m_generationCount(0), m_livingCellsCount(0) { m_timer = new wxTimer(this, wxID_ANY); //creates status bar m_statusBar = this->CreateStatusBar(); //initializes status text UpdateStatusBar(); //creates toolbar m_toolBar = CreateToolBar(); //creates bitmap for icons wxBitmap playIcon(play_xpm); wxBitmap pauseIcon(pause_xpm); wxBitmap nextIcon(next_xpm); wxBitmap trashIcon(trash_xpm); //adds buttons to toolbar m_toolBar->AddTool(10001, "Play", playIcon, "Start the game"); m_toolBar->AddTool(10002, "Pause", pauseIcon, "Pause the game"); m_toolBar->AddTool(10003, "Next", nextIcon, "Next generation"); m_toolBar->AddTool(10004, "Clear", trashIcon, "Clear the grid"); //instantiates DrawingPanel and passes this as the parent m_drawingPanel = new DrawingPanel(this); wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(m_drawingPanel, 1, wxEXPAND | wxALL, 5); SetSizer(sizer); //size event handler SetGridSize(gridSize); this->Bind(wxEVT_SIZE, &MainWindow::OnSizeChange, this); //realize toolbar to display m_toolBar->Realize(); // Bind the toolbar button click event to the handler Bind(wxEVT_TOOL, &MainWindow::OnTrashButtonClicked, this, 10004); InitializeGrid(); //must be at bottom to refresh layout and show status bar this->Layout(); } //InitializeGrid void MainWindow::InitializeGrid() { //resizes outer vector to grid size gameBoard.resize(gridSize); //resizes inner vectors to grid size and sets to 'false' for (int i = 0; i < gridSize; ++i) { gameBoard[i].resize(gridSize, false); } //passes SetGridSize to m_drawingPanel if (m_drawingPanel) { m_drawingPanel->SetGridSize(gridSize); } } //ToggleCellState void MainWindow::ToggleCellState(int row, int col) { if (row >= 0 && row < gameBoard.size() && col >= 0 && col < gameBoard[row].size()) { gameBoard[row][col] = !gameBoard[row][col]; } } //SetGridSize void MainWindow::SetGridSize(int size) { gridSize = size; InitializeGrid(); m_drawingPanel->SetGridSize(size); } //define gameBoard //std::vector> gameBoard; //destructor implementation empty MainWindow::~MainWindow() { } void MainWindow::OnPlayButtonClicked(wxCommandEvent & event) { //handle OnPlayButtonClicked if (!m_timer->IsRunning()) { //start timer with the interval (50) m_timer->Start(m_timerInterval); } } void MainWindow::OnPauseButtonClicked(wxCommandEvent & event) { //handle OnPauseButtonClicked if (m_timer->IsRunning()) { //stop timer m_timer->Stop(); } } void MainWindow::OnNextButtonClicked(wxCommandEvent & event) { //handle OnNextButtonClicked } void MainWindow::OnTrashButtonClicked(wxCommandEvent & event) { //nandle OnTrashButtonClicked ClearBoard(); } //OnsizeChange void MainWindow::OnSizeChange(wxSizeEvent& event) { //gets current window size //wxSize newSize = GetSize(); //sets new window size to drawing panel // m_drawingPanel->SetSize(newSize); if (m_drawingPanel != nullptr) { m_drawingPanel->SetSize(GetClientSize()); //other events to be processed event.Skip(); } } //CountLivingNeighbors int MainWindow::CountLivingNeighbors(int row, int col) const { //accesses size of first vector for number of columns int livingNeighbors = 0; int numRows = gameBoard.size(); int numCols = gameBoard[0].size(); //directions for 8 possible neighbors int directions[8][2] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; for (auto& direction : directions) { int neighborRow = row + direction[0]; int neighborCol = col + direction[1]; //checks bounds before accessing gameBoard if (neighborRow >= 0 && neighborRow < numRows && neighborCol >= 0 && neighborCol < numCols) { if (gameBoard[neighborRow][neighborCol]) { livingNeighbors++; } } } return livingNeighbors; } //UpdateGeneration void MainWindow::UpdateGeneration() { int numRows = gameBoard.size(); int numCols = (numRows > 0) ? gameBoard[0].size() : 0; //create sandbox same size as gameBoard std::vector> sandbox(numRows, std::vector(numCols, false)); //reset living count m_livingCellsCount = 0; for (int row = 0; row < numRows; ++row) { for (int col = 0; col < numCols; ++col) { int livingNeighbors = CountLivingNeighbors(row, col); //applies rules of the Game of Life if (gameBoard[row][col]) { //cell is alive if (livingNeighbors == 2 || livingNeighbors == 3) { sandbox[row][col] = true; m_livingCellsCount++; } } else { //cell is dead if (livingNeighbors == 3) { sandbox[row][col] = true; m_livingCellsCount++; } } } } //swap sandbox with gameBoard for next state gameBoard.swap(sandbox); //updates generation count m_generationCount++; // Update the status bar with the new counts UpdateStatusBar(); } //ClearBoard method void MainWindow::ClearBoard() { int numRows = gameBoard.size(); int numCols = numRows > 0 ? gameBoard[0].size() : 0; // Reset the game board to all false for (int row = 0; row < numRows; ++row) { for (int col = 0; col < numCols; ++col) { gameBoard[row][col] = false; } } //resets living cell count and generation count m_livingCellsCount = 0; m_generationCount = 0; //updates status text UpdateStatusBar(); //refresh drawing panel RefreshPanel(); } //UpdateStatusBar void MainWindow::UpdateStatusBar() { //formats status text wxString statusText = wxString::Format("Generations: %d | Living Cells: %d", m_generationCount, m_livingCellsCount); //updates status bar text SetStatusText(statusText); } void MainWindow::RefreshPanel() { //refresh m_gamePanel m_drawingPanel->Refresh(); m_drawingPanel->Update(); } void MainWindow::OnTimer(wxTimerEvent& event) { // Call your method to proceed to the next generation m_generationCount++; // Optionally update the display or status bar UpdateStatusBar(); } - Render Conway's Game of Life application. A grid should be rendered representing the individual cells. Cells can be turned on and off by clicking on them with the mouse. Once a group of cells are turned on and the game runs they should live or die according the 4 rules of the game.
- Living cells with less than 2 living neighbors die in the next generation.
- Living cells with more than 3 living neighbors die in the next generation.
- Living cells with 2 or 3 living neighbors live in the next generation.
- Dead cells with exactly 3 living neighbors live in the next generation.
- Start, Pause and Next menu items. The game should start running by clicking on a Start menu item. The game should be pause by clicking on a Pause menu item. If currently paused, the game can be advanced 1 generation by clicking on a Next menu item.
- Emptying the universe. The universe should be emptied of all living cells through a New or Clear menu item.
- Status bar. The current generation and number of living cells should be able to be displayed in a status strip.
Step by Step Solution
There are 3 Steps involved in it
1 Expert Approved Answer
Step: 1 Unlock
Question Has Been Solved by an Expert!
Get step-by-step solutions from verified subject matter experts
Step: 2 Unlock
Step: 3 Unlock
