Skip to content

Commit

Permalink
recreated val_in_arr() for use in clear_rows()
Browse files Browse the repository at this point in the history
Found a bug where when an S_PIECE is used to clear a row, it'll add the
same row multiple times to rows_to_clear[]. This wouldn't really be a
problem except it also increments rows_idx, which is used as the number
of rows to clear - so the game could try to clear more than 1 rows
starting with the very bottom, which would be undefined behavior.

asserts are great
  • Loading branch information
0xjmux committed Mar 23, 2024
1 parent 6a23430 commit 99e1e33
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 17 deletions.
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ ENDIF(TETRIS_UNIT_TEST_MACRO)
OPTION(TETRIS_UNIT_TEST_CI "CI-specific path options" OFF) # disabled by default
IF(TETRIS_UNIT_TEST_CI)
target_compile_definitions(test_tetris PUBLIC TETRIS_UNIT_TEST_CI=1)
target_compile_definitions(test_tetris PUBLIC TEST_PRINT_BOARD=1)
ENDIF(TETRIS_UNIT_TEST_CI)

target_link_libraries(test_tetris
Expand Down
9 changes: 9 additions & 0 deletions test/suite_1.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,15 @@ void test_arr_helpers(void) {
TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(arr7_int16, \
arr7_exp, ARR7_SIZE, "arr7 conversion to int16 incorrect");
TEST_ASSERT_EQUAL_INT16(0, smallest_in_arr(arr7_int16, ARR7_SIZE));


// test val_in_arr
TEST_ASSERT_TRUE_MESSAGE(val_in_arr(2, arr7_uint, ARR7_SIZE), "val_in_arr failed to find value 2!");
TEST_ASSERT_TRUE_MESSAGE(val_in_arr(5, arr7_uint, ARR7_SIZE), "val_in_arr failed to find value 5!");
TEST_ASSERT_FALSE_MESSAGE(val_in_arr(30, arr7_uint, ARR7_SIZE), "val_in_arr found nonexistent value!");
uint8_t arr8_uint[4] = {30,30,31};
TEST_ASSERT_TRUE_MESSAGE(val_in_arr(30, arr8_uint, 4), "val_in_arr failed to find value 30 in arr8!");
TEST_ASSERT_FALSE_MESSAGE(val_in_arr(2, arr8_uint, 4), "val_in_arr found nonexistent value in arr8!");
}


Expand Down
4 changes: 2 additions & 2 deletions test/tetris_test_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ void setup_moveCheck(TetrisGame *tg, uint8_t gen_height, \
// render active board with state for debugging
// technically not necessary for this test but very helpful
// to see the game state being tested
TetrisBoard render_board = render_active_board(tg);
printf("Test case: %d\n", *test_state);
render_active_board(tg);

#ifdef TEST_PRINT_BOARD
printf("Test case: %d\n", *test_state);
print_board_state(tg->board, stdout, false);
#endif

Expand Down
33 changes: 18 additions & 15 deletions tetris/tetris.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ bool check_filled_row(TetrisGame *tg, const uint8_t row) {
void clear_rows(TetrisGame *tg, uint8_t top_row, uint8_t num_rows) {
// starting at `row`, go up until you reach cell with value -1
// or the top of the board
assert(num_rows <= 4 && top_row <= TETRIS_ROWS - num_rows);
assert(num_rows <= 4 && top_row <= TETRIS_ROWS - num_rows + 1);

// for each col on the board
for (int col = 0; col < TETRIS_COLS; col++) {
Expand Down Expand Up @@ -533,8 +533,11 @@ uint8_t check_and_clear_rows(TetrisGame *tg, tetris_location *tp_cells) {

// if row is full, add it to list of rows to clear
if(check_filled_row(tg, row_with_offset)) {
rows_to_clear[rows_idx] = row_with_offset;
rows_idx += 1;
// but first, check to make sure we haven't already added it to the list
if (!val_in_arr(row_with_offset, rows_to_clear, rows_idx + 1)) {
rows_to_clear[rows_idx] = row_with_offset;
rows_idx += 1;
}
}

// test each piece location to see if this cell is the new highest occupied cell
Expand Down Expand Up @@ -652,18 +655,18 @@ bool check_game_over(TetrisGame *tg) {
}


///**
// * Very simple inline function for checking if an int
// * is already present in a short array of values
//*/
//inline bool val_in_arr(const int val, const int arr[], const size_t arr_len) {
// for (int i = 0; i < arr_len; i++) {
// if (arr[i] == val)
// return true;
// }
// return false;
//
//}
/**
* Very simple inline function for checking if an int
* is already present in a short array of values
*/
inline bool val_in_arr(uint8_t val, uint8_t arr[], const size_t arr_len) {
for (int i = 0; i < arr_len; i++) {
if (arr[i] == val)
return true;
}
return false;

}

/**
* Simple helper function to return smallest value in array
Expand Down
1 change: 1 addition & 0 deletions tetris/tetris.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ bool check_and_spawn_new_piece(TetrisGame *tg);
bool check_game_over(TetrisGame *tg);

// helper functions
bool val_in_arr(uint8_t val, uint8_t arr[], const size_t arr_len);
int32_t get_elapsed_us(struct timeval before, struct timeval after);
int16_t smallest_in_arr(int16_t arr[], const uint8_t arr_size);
void int16_to_uint8_arr(int16_t *in_arr, uint8_t *out_arr, uint8_t arr_size);
Expand Down

0 comments on commit 99e1e33

Please sign in to comment.