Werks
This commit is contained in:
		
							
								
								
									
										111
									
								
								src/life.cpp
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								src/life.cpp
									
									
									
									
									
								
							@@ -12,6 +12,8 @@
 | 
				
			|||||||
const char *const FORMAT_UNDERSCORE = "\033[4m";
 | 
					const char *const FORMAT_UNDERSCORE = "\033[4m";
 | 
				
			||||||
const char *const END_FORMATTING = "\033[0m";
 | 
					const char *const END_FORMATTING = "\033[0m";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const int ANIMATION_SLEEP_MS = 100, ANIMATION_N_GENERATIONS = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void printWelcome() {
 | 
					void printWelcome() {
 | 
				
			||||||
    std::cout << "Welcome to the TDDD86 Game of Life,\n"
 | 
					    std::cout << "Welcome to the TDDD86 Game of Life,\n"
 | 
				
			||||||
              << "a simulation of the lifecycle of a bacteria colony.\n"
 | 
					              << "a simulation of the lifecycle of a bacteria colony.\n"
 | 
				
			||||||
@@ -52,17 +54,19 @@ std::string fileRead(const char *filePath) {
 | 
				
			|||||||
    return content;
 | 
					    return content;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum UserAction { NO_ACTION, ACTION, TICK, QUIT };
 | 
					enum UserAction { ANIMATE, TICK, QUIT };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
UserAction askUserForAction() {
 | 
					UserAction askUserForANIMATE() {
 | 
				
			||||||
 | 
					    while (true) {
 | 
				
			||||||
        std::string userInput = input("a)nimate, t)ick, q)uit? ");
 | 
					        std::string userInput = input("a)nimate, t)ick, q)uit? ");
 | 
				
			||||||
        if (userInput == "a")
 | 
					        if (userInput == "a")
 | 
				
			||||||
        return UserAction::ACTION;
 | 
					            return UserAction::ANIMATE;
 | 
				
			||||||
        else if (userInput == "t")
 | 
					        else if (userInput == "t")
 | 
				
			||||||
            return UserAction::TICK;
 | 
					            return UserAction::TICK;
 | 
				
			||||||
        else if (userInput == "q")
 | 
					        else if (userInput == "q")
 | 
				
			||||||
            return UserAction::QUIT;
 | 
					            return UserAction::QUIT;
 | 
				
			||||||
    return UserAction::NO_ACTION;
 | 
					        std::cout << "The input '" << userInput << "' is an invalid option!\n";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<std::string> split(const std::string &s, const char at) {
 | 
					std::vector<std::string> split(const std::string &s, const char at) {
 | 
				
			||||||
@@ -81,6 +85,75 @@ std::vector<std::string> split(const std::string &s, const char at) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum Cell { ALIVE, DEAD };
 | 
					enum Cell { ALIVE, DEAD };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gridPrint(Grid<Cell> &grid) {
 | 
				
			||||||
 | 
					    std::stringstream ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int idxRow = 0; idxRow < grid.numRows(); idxRow++) {
 | 
				
			||||||
 | 
					        for (int idxCol = 0; idxCol < grid.numCols(); idxCol++) {
 | 
				
			||||||
 | 
					            char sign = grid.get(idxRow, idxCol) == Cell::ALIVE ? 'X' : '-';
 | 
				
			||||||
 | 
					            ss << sign;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (idxRow == grid.numRows() - 1)
 | 
				
			||||||
 | 
					            ss << std::endl;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            ss << '\n';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::cout << ss.str();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gridAliveNeighbors(Grid<Cell> &grid, int row, int col) {
 | 
				
			||||||
 | 
					    int alive = 0;
 | 
				
			||||||
 | 
					    for (int rowDelta = -1; rowDelta <= 1; rowDelta++) {
 | 
				
			||||||
 | 
					        int checkRow = row + rowDelta;
 | 
				
			||||||
 | 
					        // Skip out of bounds
 | 
				
			||||||
 | 
					        if (checkRow < 0 || checkRow >= grid.numRows())
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int colDelta = -1; colDelta <= 1; colDelta++) {
 | 
				
			||||||
 | 
					            // Don't check the original piece
 | 
				
			||||||
 | 
					            if (rowDelta == 0 && colDelta == 0)
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            int checkCol = col + colDelta;
 | 
				
			||||||
 | 
					            // Skip out of bounds
 | 
				
			||||||
 | 
					            if (checkCol < 0 || checkCol >= grid.numCols())
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            if (grid.get(checkCol, checkRow) == Cell::ALIVE)
 | 
				
			||||||
 | 
					                alive++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return alive;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Run one Game of Life tick.
 | 
				
			||||||
 | 
					 * Cells (X) live and die by the following rules:
 | 
				
			||||||
 | 
					 *    - A cell with 1 or fewer neighbours dies.
 | 
				
			||||||
 | 
					 *    - Locations with 2 neighbours remain stable.
 | 
				
			||||||
 | 
					 *    - Locations with 3 neighbours will create life.
 | 
				
			||||||
 | 
					 *    - A cell with 4 or more neighbours dies.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Grid<Cell> gridTick(Grid<Cell> &grid) {
 | 
				
			||||||
 | 
					    Grid<Cell> nextGrid = grid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int row = 0; row < grid.numRows(); row++) {
 | 
				
			||||||
 | 
					        for (int col = 0; col < grid.numCols(); col++) {
 | 
				
			||||||
 | 
					            int alive = gridAliveNeighbors(grid, row, col);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (alive == 1)
 | 
				
			||||||
 | 
					                nextGrid.set(row, col, Cell::DEAD);
 | 
				
			||||||
 | 
					            else if (alive == 2)
 | 
				
			||||||
 | 
					                nextGrid.set(row, col, grid.get(row, col));
 | 
				
			||||||
 | 
					            else if (alive == 3)
 | 
				
			||||||
 | 
					                nextGrid.set(row, col, Cell::ALIVE);
 | 
				
			||||||
 | 
					            else if (alive == 4)
 | 
				
			||||||
 | 
					                nextGrid.set(row, col, Cell::DEAD);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return nextGrid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main() {
 | 
					int main() {
 | 
				
			||||||
    printWelcome();
 | 
					    printWelcome();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,10 +176,10 @@ int main() {
 | 
				
			|||||||
        std::cerr << "No column, row header, in the file!" << std::endl;
 | 
					        std::cerr << "No column, row header, in the file!" << std::endl;
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    int columns, rows;
 | 
					    int rows, columns;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        columns = std::stoi(lines[0]);
 | 
					        rows = std::stoi(lines[0]);
 | 
				
			||||||
        rows = std::stoi(lines[1]);
 | 
					        columns = std::stoi(lines[1]);
 | 
				
			||||||
    } catch (const std::invalid_argument &e) {
 | 
					    } catch (const std::invalid_argument &e) {
 | 
				
			||||||
        std::cerr << "Column or row wasn't a number" << std::endl;
 | 
					        std::cerr << "Column or row wasn't a number" << std::endl;
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
@@ -122,7 +195,7 @@ int main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Grid<Cell> grid(columns, rows);
 | 
					    Grid<Cell> grid(columns, rows);
 | 
				
			||||||
    for (int x = 0; x < rows; x++) {
 | 
					    for (int x = 0; x < rows; x++) {
 | 
				
			||||||
        std::string &row = lines[x];
 | 
					        std::string &row = lines[x + 2];
 | 
				
			||||||
        if (columns < row.size()) {
 | 
					        if (columns < row.size()) {
 | 
				
			||||||
            std::cerr << "There's less columns, than described in the header!"
 | 
					            std::cerr << "There's less columns, than described in the header!"
 | 
				
			||||||
                      << std::endl;
 | 
					                      << std::endl;
 | 
				
			||||||
@@ -146,6 +219,28 @@ int main() {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    gridPrint(grid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UserAction ANIMATE;
 | 
				
			||||||
 | 
					    while ((ANIMATE = askUserForANIMATE()) != UserAction::QUIT) {
 | 
				
			||||||
 | 
					        // We don't have to handle QUIT, since we do in the while check
 | 
				
			||||||
 | 
					        switch (ANIMATE) {
 | 
				
			||||||
 | 
					        case UserAction::TICK:
 | 
				
			||||||
 | 
					            grid = gridTick(grid);
 | 
				
			||||||
 | 
					            gridPrint(grid);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case UserAction::ANIMATE:
 | 
				
			||||||
 | 
					            for (int i = 0; i < ANIMATION_N_GENERATIONS; i++) {
 | 
				
			||||||
 | 
					                grid = gridTick(grid);
 | 
				
			||||||
 | 
					                clearConsole();
 | 
				
			||||||
 | 
					                gridPrint(grid);
 | 
				
			||||||
 | 
					                pause(ANIMATION_SLEEP_MS);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::cout << "Have a nice Life!" << std::endl;
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user