Werks
This commit is contained in:
		
							
								
								
									
										123
									
								
								src/life.cpp
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								src/life.cpp
									
									
									
									
									
								
							@@ -12,6 +12,8 @@
 | 
			
		||||
const char *const FORMAT_UNDERSCORE = "\033[4m";
 | 
			
		||||
const char *const END_FORMATTING = "\033[0m";
 | 
			
		||||
 | 
			
		||||
const int ANIMATION_SLEEP_MS = 100, ANIMATION_N_GENERATIONS = 20;
 | 
			
		||||
 | 
			
		||||
void printWelcome() {
 | 
			
		||||
    std::cout << "Welcome to the TDDD86 Game of Life,\n"
 | 
			
		||||
              << "a simulation of the lifecycle of a bacteria colony.\n"
 | 
			
		||||
@@ -52,17 +54,19 @@ std::string fileRead(const char *filePath) {
 | 
			
		||||
    return content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum UserAction { NO_ACTION, ACTION, TICK, QUIT };
 | 
			
		||||
enum UserAction { ANIMATE, TICK, QUIT };
 | 
			
		||||
 | 
			
		||||
UserAction askUserForAction() {
 | 
			
		||||
    std::string userInput = input("a)nimate, t)ick, q)uit? ");
 | 
			
		||||
    if (userInput == "a")
 | 
			
		||||
        return UserAction::ACTION;
 | 
			
		||||
    else if (userInput == "t")
 | 
			
		||||
        return UserAction::TICK;
 | 
			
		||||
    else if (userInput == "q")
 | 
			
		||||
        return UserAction::QUIT;
 | 
			
		||||
    return UserAction::NO_ACTION;
 | 
			
		||||
UserAction askUserForANIMATE() {
 | 
			
		||||
    while (true) {
 | 
			
		||||
        std::string userInput = input("a)nimate, t)ick, q)uit? ");
 | 
			
		||||
        if (userInput == "a")
 | 
			
		||||
            return UserAction::ANIMATE;
 | 
			
		||||
        else if (userInput == "t")
 | 
			
		||||
            return UserAction::TICK;
 | 
			
		||||
        else if (userInput == "q")
 | 
			
		||||
            return UserAction::QUIT;
 | 
			
		||||
        std::cout << "The input '" << userInput << "' is an invalid option!\n";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 };
 | 
			
		||||
 | 
			
		||||
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() {
 | 
			
		||||
    printWelcome();
 | 
			
		||||
 | 
			
		||||
@@ -103,10 +176,10 @@ int main() {
 | 
			
		||||
        std::cerr << "No column, row header, in the file!" << std::endl;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    int columns, rows;
 | 
			
		||||
    int rows, columns;
 | 
			
		||||
    try {
 | 
			
		||||
        columns = std::stoi(lines[0]);
 | 
			
		||||
        rows = std::stoi(lines[1]);
 | 
			
		||||
        rows = std::stoi(lines[0]);
 | 
			
		||||
        columns = std::stoi(lines[1]);
 | 
			
		||||
    } catch (const std::invalid_argument &e) {
 | 
			
		||||
        std::cerr << "Column or row wasn't a number" << std::endl;
 | 
			
		||||
        return 1;
 | 
			
		||||
@@ -122,7 +195,7 @@ int main() {
 | 
			
		||||
 | 
			
		||||
    Grid<Cell> grid(columns, rows);
 | 
			
		||||
    for (int x = 0; x < rows; x++) {
 | 
			
		||||
        std::string &row = lines[x];
 | 
			
		||||
        std::string &row = lines[x + 2];
 | 
			
		||||
        if (columns < row.size()) {
 | 
			
		||||
            std::cerr << "There's less columns, than described in the header!"
 | 
			
		||||
                      << 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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user