#include #include #include "gameoflife.h" // Convert 4 packed uint32 words into a 10x10 binary grid void convert_words_to_grid(const uint32 words[4], int grid[10][10]) { for (int i = 0; i < 100; i++) { int word_index = i / 32; int bit_index = i % 32; int row = i / 10; int col = i % 10; grid[row][col] = (words[word_index] >> bit_index) & 1; } } // Convert a 10x10 binary grid into 4 packed uint32 words void convert_grid_to_words(const int grid[10][10], uint32 words[4]) { for (int w = 0; w < 4; w++) { words[w] = 0; // Clear buffer before OR-masking } for (int i = 0; i < 100; i++) { int word_index = i / 32; int bit_index = i % 32; int row = i / 10; int col = i % 10; if (grid[row][col]) { words[word_index] |= (1U << bit_index); } } } void print_grid(const char *label, const int grid[10][10]) { printf("%s:\n", label); for (int row = 0; row < 10; row++) { for (int col = 0; col < 10; col++) { printf("%c ", grid[row][col] ? '#' : '.'); } printf("\n"); } printf("\n"); } bool run_test_case(const char *test_name, const int input[10][10], const int expected[10][10]) { uint32 hw_in[4]; uint32 hw_out[4] = {0, 0, 0, 0}; int actual[10][10]; convert_grid_to_words(input, hw_in); game_of_life_step(hw_in, hw_out); convert_words_to_grid(hw_out, actual); bool passed = true; for (int row = 0; row < 10; row++) { for (int col = 0; col < 10; col++) { if (actual[row][col] != expected[row][col]) { passed = false; break; } } if (!passed) break; } if (passed) { printf("[PASS] %s\n", test_name); } else { printf("[FAIL] %s\n", test_name); print_grid("Input", input); print_grid("Expected", expected); print_grid("Actual Output", actual); } return passed; } int main(void) { bool all_passed = true; // Test 1: Empty Grid (All 0s -> All 0s) const int t1_input[10][10] = {0}; const int t1_expected[10][10] = {0}; all_passed &= run_test_case("Test 1: All Zero Grid", t1_input, t1_expected); // Test 2: Still Life (2x2 Block & Tub) // A 2x2 block has every cell with 3 neighbors; no outside cell has 3. It must remain identical. const int t2_input[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,0,0,0,0,0,0}, {0,1,1,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,1,0,0,0}, {0,0,0,0,0,1,0,1,0,0}, {0,0,0,0,0,0,1,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; all_passed &= run_test_case("Test 2: Still Life (Block and Tub remain static)", t2_input, t2_input); // Test 3: Oscillator (Blinker - Horizontal to Vertical) // Three cells in a row (horizontal) oscillate to three cells in a column (vertical). const int t3_input[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; const int t3_expected[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; all_passed &= run_test_case("Test 3: Oscillator (Blinker Horizontal -> Vertical)", t3_input, t3_expected); // Test 4: Toroidal Seam / Wrap-around Test // Place a Blinker horizontally straddling the right-to-left border: cells at [0][9], [0][0], [0][1]. // Under toroidal rules, this horizontal line should flip to a vertical line at: // [9][0], [0][0], [1][0] (straddling the top-to-bottom border). const int t4_input[10][10] = { {1,1,0,0,0,0,0,0,0,1}, // row 0: cols 0, 1, and 9 are alive {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; const int t4_expected[10][10] = { {1,0,0,0,0,0,0,0,0,0}, // cell at [0][0] {1,0,0,0,0,0,0,0,0,0}, // cell at [1][0] {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0} // cell at [9][0] (wrapped from top!) }; all_passed &= run_test_case("Test 4: Toroidal Seam Wrap-Around (Blinker across boundaries)", t4_input, t4_expected); // Test 5: Overpopulation Death (Dense 3x3 block) // A solid 3x3 box of live cells. The center has 8 neighbors (dies). // The 4 corners have 3 neighbors (survive). // The 4 edges have 5 neighbors (die). // The 4 adjacent external empty cells have 3 neighbors (birth). // Resulting shape should be an empty diamond / cross outline. const int t5_input[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,1,1,1,0,0,0,0}, {0,0,0,1,1,1,0,0,0,0}, {0,0,0,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; const int t5_expected[10][10] = { {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0}, // Birth at [2][4] {0,0,0,1,0,1,0,0,0,0}, // Corners survive, center edge dies {0,0,1,0,0,0,1,0,0,0}, // Birth at [4][2] & [4][6], center [4][4] dies of overpopulation (8) {0,0,0,1,0,1,0,0,0,0}, // Corners survive, center edge dies {0,0,0,0,1,0,0,0,0,0}, // Birth at [6][4] {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} }; all_passed &= run_test_case("Test 5: Overpopulation & Birth (Solid 3x3 block)", t5_input, t5_expected); // Final result if (all_passed) { printf("\n*************************************\n"); printf("ALL 5 UNIT TESTS PASSED SUCCESSFULLY! \n"); printf("*************************************\n"); return 0; } else { printf("\n[ERROR] One or more tests failed.\n"); return 1; } }