#include "tetris.h" #include "game_logic.h" #include #include #include #include static GameStateData* get_instance() { static GameStateData instance = {0}; static bool initialized_local = false; if (!initialized_local) { // Инициализация экземпляра for (int i = 0; i < FIELD_HEIGHT; i++) { for (int j = 0; j < FIELD_WIDTH; j++) { instance.game_field[i][j] = 0; } } instance.score = 0; instance.high_score = 0; instance.level = 1; instance.state = FSM_Start; instance.game_over = false; instance.paused = false; initialized_local = true; } return &instance; } void init_game() { GameStateData* state = get_instance(); // Инициализация игрового поля for (int i = 0; i < FIELD_HEIGHT; i++) { for (int j = 0; j < FIELD_WIDTH; j++) { state->game_field[i][j] = 0; } } srand((unsigned int)time(NULL)); state->next_figure.type = get_random_figure(); state->next_figure.x = 0; state->next_figure.y = 0; state->next_figure.rotation = 0; state->score = 0; state->high_score = 0; state->level = 1; state->drop_time = time(NULL) * 1000; state->game_over = false; state->paused = false; state->state = FSM_Start; } void place_figure() { GameStateData* state = get_instance(); Figure* f = &state->current_figure; const int (*shape)[4] = get_figure_shape(f->type, f->rotation); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (shape[i][j]) { int x = f->x + j; int y = f->y + i; if (y >= 0 && y < FIELD_HEIGHT && x >= 0 && x < FIELD_WIDTH) { state->game_field[y][x] = 1; } } } } // Проверяем и удаляем заполненные строки clear_completed_lines(); // Меняем состояние на Spawn для генерации новой фигуры state->state = FSM_Spawn; } void clear_completed_lines() { GameStateData* state = get_instance(); int lines_cleared = 0; int write_row = FIELD_HEIGHT - 1; // Проходим снизу вверх for (int read_row = FIELD_HEIGHT - 1; read_row >= 0; read_row--) { bool line_complete = true; for (int j = 0; j < FIELD_WIDTH; j++) { if (state->game_field[read_row][j] == 0) { line_complete = false; break; } } if (line_complete) { lines_cleared++; } else { // Копируем неполные строки вниз if (write_row != read_row) { for (int j = 0; j < FIELD_WIDTH; j++) { state->game_field[write_row][j] = state->game_field[read_row][j]; } } write_row--; } } // Заполняем пустые строки наверху for (int i = 0; i <= write_row; i++) { for (int j = 0; j < FIELD_WIDTH; j++) { state->game_field[i][j] = 0; } } if (lines_cleared > 0) { // Обновляем счет в соответствии с количеством очищенных линий int points[] = {0, 100, 300, 700, 1500}; // 0, 1, 2, 3, 4 линии int score_points = 0; if (lines_cleared <= 4) { score_points = points[lines_cleared]; } else { score_points = points[4]; // для > 4 линий } state->score += score_points * state->level; if (state->score > state->high_score) { state->high_score = state->score; } // Увеличиваем уровень каждые 600 очков, максимум 10 int new_level = state->score / 600 + 1; if (new_level > 10) new_level = 10; if (new_level != state->level) { state->level = new_level; } } } int get_random_figure() { return rand() % FIGURE_COUNT; } bool check_collision() { GameStateData* state = get_instance(); Figure* f = &state->current_figure; const int (*shape)[4] = get_figure_shape(f->type, f->rotation); bool collision = false; for (int i = 0; !collision && i < 4; i++) { for (int j = 0; !collision && j < 4; j++) { if (shape[i][j]) { int x = f->x + j; int y = f->y + i; if (x < 0 || x >= FIELD_WIDTH || y >= FIELD_HEIGHT || (y >= 0 && state->game_field[y][x] != 0)) { collision = true; } } } } return collision; } void fsm_transition() { GameStateData* state = get_instance(); switch (state->state) { case FSM_Start: state->state = FSM_Spawn; break; case FSM_Spawn: state->current_figure = state->next_figure; state->current_figure.x = FIELD_WIDTH / 2 - 2; state->current_figure.y = 0; state->current_figure.rotation = 0; state->next_figure.type = get_random_figure(); state->next_figure.rotation = 0; if (check_collision()) { state->state = FSM_GameOver; } else { state->state = FSM_Moving; } break; case FSM_Moving: break; case FSM_Move: state->current_figure.y++; if (check_collision()) { state->current_figure.y--; state->state = FSM_Attaching; } else { state->state = FSM_Moving; } break; case FSM_Attaching: place_figure(); state->state = FSM_Spawn; break; case FSM_GameOver: break; } } GameStateData* get_game_state() { return get_instance(); }