s21_tetris/src/brick_game/tetris/game_logic.c
2025-09-28 17:01:42 +03:00

215 lines
No EOL
6.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "tetris.h"
#include "game_logic.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
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();
}