commit 1a564b75ca727a47c448df67cbb6cc8ac0f93a01 Author: Hadeed Ahmad Date: Wed Sep 11 22:48:22 2024 +0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f4bbab --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +life diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..163d034 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# Written with extensive help from https://makefiletutorial.com + +CC = g++ + +TARGET_EXEC = life + +SRC_DIR = src +INC_DIR = include +BUILD_DIR = build + +CFLAGS = -I $(INC_DIR) -MMD -MP -I c:/SDL2/include -I c:/SDL2/include/SDL2 -Dmain=SDL_main +LDFLAGS = -L c:/SDL2/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -static-libstdc++ -static-libgcc + +SRC = $(wildcard $(SRC_DIR)/*.cpp) +OBJ = $(SRC:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o) +DEP = $(OBJ:%.o=%.d) + +$(TARGET_EXEC): $(OBJ) + $(CC) $(OBJ) -o $(TARGET_EXEC) $(LDFLAGS) + +$(OBJ): $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp + @mkdir -p $(BUILD_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + @rm -rf $(BUILD_DIR) $(TARGET_EXEC) + +-include $(DEP) diff --git a/README.md b/README.md new file mode 100644 index 0000000..279a401 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Game of life + +A CS100 project. The git history is lost because the original git repository was deleted, this one was reconstructed from the files I submitted. A compiled version for windows is provided, you can compile for mac and linux using the provided makefile, minor changes to makefile might be required. diff --git a/include/drawing.h b/include/drawing.h new file mode 100644 index 0000000..08b0eeb --- /dev/null +++ b/include/drawing.h @@ -0,0 +1,11 @@ +#ifndef DRAWING_H +#define DRAWING_H + +// Public +void draw(); + +// Private +static void draw_grid_lines(); +static void draw_cells(); + +#endif diff --git a/include/events.h b/include/events.h new file mode 100644 index 0000000..875acbb --- /dev/null +++ b/include/events.h @@ -0,0 +1,13 @@ +#ifndef EVENTS_H +#define EVENTS_H + +#include + +// Public +void handle_events(); + +//Private +void handle_key_event(SDL_Keycode key_pressed); +void handle_mouse_event(int x, int y); + +#endif diff --git a/include/game.h b/include/game.h new file mode 100644 index 0000000..c853edb --- /dev/null +++ b/include/game.h @@ -0,0 +1,13 @@ +#ifndef GAME_H +#define GAME_H + +// Public +void start_game(); +void toggle_pause(); + +extern bool paused; + +// Private +static void game_loop(); + +#endif diff --git a/include/globals.h b/include/globals.h new file mode 100644 index 0000000..4eddd18 --- /dev/null +++ b/include/globals.h @@ -0,0 +1,17 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define CELL_SIZE 20 + +#define GRID_WIDTH 64 +#define GRID_HEIGHT 48 + +#define WINDOW_WIDTH GRID_WIDTH * CELL_SIZE +#define WINDOW_HEIGHT GRID_HEIGHT * CELL_SIZE + +#define FRAMES_PER_SECOND 60 +#define UPDATES_PER_SECOND 5 + +#define ALIVE true +#define DEAD false +#endif diff --git a/include/grid.h b/include/grid.h new file mode 100644 index 0000000..2a68185 --- /dev/null +++ b/include/grid.h @@ -0,0 +1,12 @@ +#ifndef GRID_H +#define GRID_H + +#include "globals.h" + +// Public +void clear_grid(); +void iterate_grid(); + +extern bool grid[GRID_HEIGHT][GRID_WIDTH]; + +#endif diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..417678c --- /dev/null +++ b/include/main.h @@ -0,0 +1,14 @@ +#ifndef MAIN_H +#define MAIN_H + +#include + +// Public +void quit_application(int exit_code); + +extern SDL_Window *window; + +// Private +static void init(); + +#endif diff --git a/include/timing.h b/include/timing.h new file mode 100644 index 0000000..2888a47 --- /dev/null +++ b/include/timing.h @@ -0,0 +1,9 @@ +#ifndef TIMING_H +#define TIMING_H + +// Public +void limit_fps(); + +extern double delta_time; + +#endif diff --git a/src/drawing.cpp b/src/drawing.cpp new file mode 100644 index 0000000..33a5803 --- /dev/null +++ b/src/drawing.cpp @@ -0,0 +1,93 @@ +#include + +#include "drawing.h" // This file +#include "game.h" // Get paused state +#include "globals.h" // Size macros +#include "grid.h" // Get grid state +#include "main.h" // Get window + +void clear_window() { + SDL_Surface *surface = SDL_GetWindowSurface(window); + + Uint32 background = SDL_MapRGB(surface->format, 0x2E, 0x34, 0x40); + + SDL_FillRect(surface, NULL, background); +} + +SDL_Surface* grid_lines_surface() { + Uint32 rmask, gmask, bmask, amask; + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; + + SDL_Surface *grid_lines = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, 32, rmask, gmask, bmask, amask); + + Uint32 lines_color = SDL_MapRGB(grid_lines->format, 0x3B, 0x42, 0x52); + + SDL_Surface *vertical = SDL_CreateRGBSurface(0, 2, WINDOW_HEIGHT, 32, rmask, gmask, bmask, amask); + SDL_FillRect(vertical, NULL, lines_color); + for (int i = 0; i <= GRID_WIDTH; i++) { + SDL_Rect destination; + destination.x = i * CELL_SIZE - 1; + destination.y = 0; + + SDL_BlitSurface(vertical, NULL, grid_lines, &destination); + } + SDL_FreeSurface(vertical); + + SDL_Surface *horizontal = SDL_CreateRGBSurface(0, WINDOW_WIDTH, 2, 32, rmask, gmask, bmask, amask); + SDL_FillRect(horizontal, NULL, lines_color); + for (int i = 0; i <= GRID_HEIGHT; i++) { + SDL_Rect destination; + destination.x = 0; + destination.y = i * CELL_SIZE - 1; + + SDL_BlitSurface(horizontal, NULL, grid_lines, &destination); + } + SDL_FreeSurface(horizontal); + + return grid_lines; +} + +SDL_Surface* cell_surface() { + SDL_Surface *cell = SDL_CreateRGBSurface(0, CELL_SIZE, CELL_SIZE, 32, 0, 0, 0, 0); + + Uint32 cell_color = SDL_MapRGB(cell->format, 0xE5, 0xE9, 0xF0); + SDL_FillRect(cell, NULL, cell_color); + + return cell; +} + +void draw() { + clear_window(); + + draw_cells(); + + if (paused) draw_grid_lines(); + + SDL_UpdateWindowSurface(window); +} + +void draw_grid_lines() { + SDL_Surface *surface = SDL_GetWindowSurface(window); + static SDL_Surface *grid_lines = grid_lines_surface(); + + SDL_BlitSurface(grid_lines, NULL, surface, &surface->clip_rect); +} + +void draw_cells() { + SDL_Surface *surface = SDL_GetWindowSurface(window); + static SDL_Surface *cell = cell_surface(); + + for (int i = 0; i < GRID_HEIGHT; i++) + for (int j = 0; j < GRID_WIDTH; j++) { + if (grid[i][j] == ALIVE) { + SDL_Rect destination; + destination.x = j * CELL_SIZE; + destination.y = i * CELL_SIZE; + + SDL_BlitSurface(cell, NULL, surface, &destination); + } + } +} diff --git a/src/events.cpp b/src/events.cpp new file mode 100644 index 0000000..f64fc9e --- /dev/null +++ b/src/events.cpp @@ -0,0 +1,49 @@ +#include + +#include "events.h" // This file +#include "game.h" // Get and set paused state +#include "globals.h" // Cell size macros +#include "grid.h" // Set grid +#include "main.h" // Quit + +void handle_events() { + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + handle_key_event(event.key.keysym.sym); + break; + case SDL_MOUSEBUTTONDOWN: + handle_mouse_event(event.button.x, event.button.y); + break; + case SDL_QUIT: + quit_application(0); + break; + } + } +} + +void handle_key_event(SDL_Keycode key_pressed) { + switch (key_pressed) { + case SDLK_q: + quit_application(0); + break; + case SDLK_SPACE: + case SDLK_RETURN: + toggle_pause(); + break; + case SDLK_r: + if (paused) clear_grid(); + break; + } +} + +void handle_mouse_event(int x, int y) { + if (!paused) return; + + int i = y / CELL_SIZE; + int j = x / CELL_SIZE; + + grid[i][j] = !grid[i][j]; +} diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..fcdced3 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,43 @@ +#include + +#include "drawing.h" // Draw in game loop +#include "events.h" // Handle events in loop +#include "game.h" // This file +#include "globals.h" // Timing macros +#include "grid.h" // Iterate the grid +#include "timing.h" // Timings + +// Public +bool paused; + +// Private +const double req_update_time = 1.0 / UPDATES_PER_SECOND; +double time_since_update; + +void start_game() { + clear_grid(); + paused = true; + time_since_update = 0; + + while(true) { + game_loop(); + + limit_fps(); + } +} + +void game_loop() { + handle_events(); + + if (!paused) if ((time_since_update += delta_time) >= req_update_time) { + iterate_grid(); + time_since_update -= req_update_time; + } + + draw(); +} + +void toggle_pause() { + paused = !paused; + time_since_update = 0; +} diff --git a/src/grid.cpp b/src/grid.cpp new file mode 100644 index 0000000..b0eac8b --- /dev/null +++ b/src/grid.cpp @@ -0,0 +1,46 @@ +#include "globals.h" // Grid size macros + +bool grid[GRID_HEIGHT][GRID_WIDTH]; + +void clear_grid() { + for (int i = 0; i < GRID_HEIGHT; i++) + for (int j = 0; j < GRID_WIDTH; j++) grid[i][j] = DEAD; +} + +int count_alive_neighbours(int x, int y) { + int count = 0; + + for (int i = x - 1; i <= x + 1; i++) + for (int j = y - 1; j <= y + 1; j++){ + if (i == x && j == y) continue; + + int m = (i + GRID_HEIGHT) % GRID_HEIGHT; + int n = (j + GRID_WIDTH) % GRID_WIDTH; + + if (grid[m][n] == ALIVE) count++; + } + + return count; +} + +void iterate_grid() { + bool new_grid[GRID_HEIGHT][GRID_WIDTH]; + + for (int i = 0; i < GRID_HEIGHT; i++) + for (int j = 0; j < GRID_WIDTH; j++) { + int neighbours = count_alive_neighbours(i, j); + + if (grid[i][j] == ALIVE) { + if (neighbours < 2) new_grid[i][j] = DEAD; + else if (neighbours == 2 || neighbours == 3) new_grid[i][j] = ALIVE; + else new_grid[i][j] = DEAD; + } else { + if (neighbours == 3) new_grid[i][j] = ALIVE; + else new_grid[i][j] = DEAD; + } + } + + + for (int i = 0; i < GRID_HEIGHT; i++) + for (int j = 0; j < GRID_WIDTH; j++) grid[i][j] = new_grid[i][j]; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..a1df726 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,44 @@ +#include +#include + +#include + +#include "game.h" // To start the game +#include "globals.h" // Window dimensions +#include "main.h" // This file + +// Public +SDL_Window *window; + +int main(int argc, char** argv) { + init(); + + start_game(); + + quit_application(0); +} + +void init() { + if(SDL_Init(SDL_INIT_VIDEO) != 0) { + printf("Could not start SDL.\nSDL error: %s\n", SDL_GetError()); + quit_application(1); + } + + window = SDL_CreateWindow("Game of Life", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + WINDOW_WIDTH, WINDOW_HEIGHT, 0); + + if (window == NULL) { + printf("Could not create window: %s\n", SDL_GetError()); + quit_application(1); + } +} + +void quit_application(int exit_code) { + if (window != NULL) SDL_DestroyWindow(window); + + SDL_Quit(); + + exit(exit_code); +} diff --git a/src/timing.cpp b/src/timing.cpp new file mode 100644 index 0000000..c6e28a8 --- /dev/null +++ b/src/timing.cpp @@ -0,0 +1,27 @@ +#include + +#include "globals.h" // Timing macros +#include "timing.h" // This file + +// Public +double delta_time; + +// Private +const double req_delta_time = 1.0 / FRAMES_PER_SECOND; + +int t_start = 0; + +void limit_fps() { + int t_end = SDL_GetTicks(); + delta_time = (t_end - t_start) / 1000.0; + + double extra_time = req_delta_time - delta_time; + + int sleep_time = extra_time * 1000; + if (sleep_time > 0) SDL_Delay(sleep_time); + + t_end = SDL_GetTicks(); + delta_time = (t_end - t_start) / 1000.0; + + t_start = t_end; +}