204 lines
6.6 KiB
C++
204 lines
6.6 KiB
C++
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#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;
|
|
}
|
|
} |