segm fault

This commit is contained in:
Rorikstr | Rust Dev 2025-09-29 16:49:02 +03:00
parent 5fd528e22a
commit e9785c4906
10 changed files with 226 additions and 58 deletions

View file

@ -43,6 +43,7 @@ $(LIB_TETRIS): $(TETRIS_OBJ)
$(TARGET): $(LIB_TETRIS) $(CLI_OBJ)
$(CC) $(CLI_OBJ) -L$(BUILDDIR) -ltetris -o $@ $(LDFLAGS)
rm -f $(CLI_OBJ) $(TETRIS_OBJ)
brick_game/tetris/%.o: brick_game/tetris/%.c
$(CC) $(CFLAGS) -c $< -o $@
@ -57,7 +58,7 @@ uninstall:
rm -f $(BINDIR)/$(TARGET)
clean:
rm -f $(CLI_OBJ) $(TETRIS_OBJ) $(TARGET) *.gcda *.gcno *.gcov
rm -f $(CLI_OBJ) $(TETRIS_OBJ) $(TARGET) $(LIB_TETRIS) *.gcda *.gcno *.gcov
test:
@echo "Running tests..."

View file

@ -17,6 +17,7 @@ typedef enum {
RightDown,
LeftDown,
Rotate,
ToDown,
DoNothing
} Moving_t;
@ -44,29 +45,36 @@ typedef struct {
Automato_t state;
Moving_t moving_type;
int field[FIELD_HEIGHT][FIELD_WIDTH];
// int score; // НЕ НУЖЕН, это уже есть в GameInfo_t
// int high_score; // НЕ НУЖЕН, это уже есть в GameInfo_t
// int level; // НЕ НУЖЕН, это уже есть в GameInfo_t
// int speed; // НЕ НУЖЕН, это уже есть в GameInfo_t
long long last_time; // нужно пояснение для чего это
GameInfo_t info;
long long last_time;
} GameState_t;
GameState_t* get_game_state(void);
// Функции состояний
// init
void do_init(void);
void do_spawn(void);
void do_move(void);
void do_moving(void);
void do_attaching(void);
void do_gameover(void);
// Вспомогательные
void place_figure();
// spawn
void do_spawn(void);
// move
void do_move(void);
//moving
void do_moving(void);
// attaching
void do_attaching(void);
int check_collision();
void place_figure();
void clear_lines();
// gameover
void do_gameover(void);
int is_game_over();
// Функции фигур
const int (*get_figure_shape(Sprite_t sprite, int rotation))[4];

View file

@ -1,43 +1,47 @@
#include "01_automato.h"
#include <stdlib.h>
void userInput(UserAction_t action, bool hold) {
GameState_t* g_state = get_game_state();
GameInfo_t* g_info = get_info_state();
(void)hold; // заглушка
GameState_t* state = get_game_state();
switch (action) {
case Start:
g_state->state = Init;
state->state = Init;
break;
case Terminate:
if (g_info->score > g_info->high_score) {
g_info->high_score = g_info->score;
if (state->info.score > state->info.high_score) {
state->info.high_score = state->info.score;
}
state->state = GameOver;
break;
case Left:
g_state->state = Moving;
g_state->moving_type = LeftDown;
state->state = Moving;
state->moving_type = LeftDown;
break;
case Right:
g_state->state = Moving;
g_state->moving_type = RightDown;
state->state = Moving;
state->moving_type = RightDown;
break;
case Action:
g_state->state = Moving;
g_state->moving_type = Rotate;
state->state = Moving;
state->moving_type = Rotate;
break;
case Down:
// Ускорение падения — будет обрабатываться в do_move
state->state = Moving;
state->moving_type = ToDown;
break;
case Pause:
state->info.pause = !state->info.pause;
break;
default:
break; // pause и down - не нужны в backend логике.
break;
}
}
GameInfo_t updateCurrentState() {
GameState_t* g_state = get_game_state();
switch (g_state->state) {
case Start:
GameState_t* state = get_game_state();
switch (state->state) {
case Init:
do_init();
break;
case Spawn:
@ -57,9 +61,9 @@ GameInfo_t updateCurrentState() {
break;
}
GameInfo_t info = {0};
info.field = (int**)g_state->field;
info.next = (int**)g_state->next.mtrx; // теперь next.mtrx
GameInfo_t info = state->info;
info.field = (int**)state->field;
info.next = (int**)state->next.mtrx;
info.pause = 0;
return info;
}

View file

@ -1,13 +1,11 @@
#include "01_automato.h"
static GameState_t g_state = {0};
GameState_t* get_game_state(void) {
static GameInfo_t instance = {0};
static int is_init = 0;
if (!is_init) {
g_state.state = GameOver;
is_init = 1;
static GameState_t state = {0};
static int initialized = 0;
if (!initialized) {
state.state = GameOver;
initialized = 1;
}
return &g_state;
return &state;
}

View file

@ -1,15 +1,14 @@
#include "01_automato.h"
void do_init(void) {
GameState_t* g_state = get_game_state();
GameInfo_t* g_info = get_game_info();
GameState_t* state = get_game_state();
// Очистка поля
for (int i = 0; i < FIELD_HEIGHT; ++i)
for (int j = 0; j < FIELD_WIDTH; ++j)
g_state->field[i][j] = 0;
state->field[i][j] = 0;
g_info->score = 0;
g_info->level = 1;
g_info->speed = 1;
g_state->state = Spawn;
state->info.score = 0;
state->info.level = 1;
state->info.speed = 1;
state->state = Spawn;
}

View file

@ -1,8 +1,26 @@
#include <time.h>
#include "01_automato.h"
long long get_time_ms() {
return (long long)time(NULL) * 1000;
}
void do_move(void) {
GameState_t* state = get_game_state();
// Проверка таймера и перемещение вниз
// Если hold Down — ускорение
// Если коллизия — переход в Attaching
long long current_time = get_time_ms();
int delay = (state->moving_type == ToDown) ? 50 : (1000 / state->info.speed);
if (current_time - state->last_time < delay) {
return; // ещё не время
}
state->last_time = current_time;
// Двигаем вниз
state->curr.y++;
if (check_collision()) {
state->curr.y--; // откат
state->state = Attaching; // переход в Attaching
}
}

View file

@ -2,7 +2,47 @@
void do_moving(void) {
GameState_t* state = get_game_state();
// Обработка Left/Right/Action
// Проверка коллизии
// Возврат в Move или остаться в Moving
switch (state->moving_type) {
case LeftDown:
case RightDown:
case Rotate:
// Обработка движения/поворота
Figure_t old = state->curr;
switch (state->moving_type) {
case LeftDown:
state->curr.x--;
break;
case RightDown:
state->curr.x++;
break;
case Rotate:
state->curr.rotation = (state->curr.rotation + 1) % 4;
const int (*shape)[4] = get_figure_shape(state->curr.sprite, state->curr.rotation);
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
state->curr.mtrx[i][j] = shape[i][j];
break;
default:
break;
}
if (check_collision()) {
state->curr = old; // откат
}
state->state = Move;
break;
case ToDown:
// Мгновенное падение: двигаем вниз, пока не упрёмся
do {
state->curr.y++;
} while (!check_collision());
state->curr.y--; // откат на 1 назад
state->state = Attaching; // сразу в Attaching
break;
case DoNothing:
state->state = Move;
break;
}
}

View file

@ -15,4 +15,82 @@ void do_attaching(void) {
} else {
state->state = Spawn;
}
}
int check_collision() {
GameState_t* state = get_game_state();
Figure_t* fig = &state->curr;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if (fig->mtrx[i][j]) {
int x = fig->x + j;
int y = fig->y + i;
if (x < 0 || x >= FIELD_WIDTH || y >= FIELD_HEIGHT) {
return 1; // коллизия
}
if (y >= 0 && state->field[y][x]) {
return 1; // коллизия с другой фигурой
}
}
}
}
return 0; // нет коллизии
}
void place_figure() {
GameState_t* state = get_game_state();
Figure_t* fig = &state->curr;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if (fig->mtrx[i][j]) {
int x = fig->x + j;
int y = fig->y + i;
if (y >= 0 && y < FIELD_HEIGHT && x >= 0 && x < FIELD_WIDTH) {
state->field[y][x] = 2; // закреплённая фигура
}
}
}
}
}
void clear_lines() {
GameState_t* state = get_game_state();
int lines_cleared = 0;
for (int i = FIELD_HEIGHT - 1; i >= 0; --i) {
int full = 1;
for (int j = 0; j < FIELD_WIDTH; ++j) {
if (state->field[i][j] != 2) {
full = 0;
break;
}
}
if (full) {
// Сдвигаем строки вниз
for (int y = i; y > 0; --y) {
for (int x = 0; x < FIELD_WIDTH; ++x) {
state->field[y][x] = state->field[y - 1][x];
}
}
// Очищаем верхнюю строку
for (int x = 0; x < FIELD_WIDTH; ++x) {
state->field[0][x] = 0;
}
lines_cleared++;
i++; // проверяем эту строку снова
}
}
// Начисление очков
if (lines_cleared > 0) {
int points[] = {0, 100, 300, 700, 1500};
state->info.score += points[lines_cleared];
if (state->info.score / 600 > state->info.level - 1) {
state->info.level++;
state->info.speed = state->info.level;
}
}
}

View file

@ -3,7 +3,19 @@
void do_gameover(void) {
GameState_t* state = get_game_state();
// Сброс next в пустую фигуру
const int (*shape)[4] = empty_fig();
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
state->next.mtrx[i][j] = 0;
state->next.mtrx[i][j] = shape[i][j];
}
int is_game_over() {
GameState_t* state = get_game_state();
// Проверяем, есть ли блоки в верхних рядах
for (int j = 0; j < FIELD_WIDTH; ++j) {
if (state->field[0][j] || state->field[1][j]) {
return 1;
}
}
return 0;
}

View file

@ -3,13 +3,23 @@
#include "../../brick_game/tetris/00_tetris.h"
void display_game() {
printf("DEBUG: display_game called\n");
clear();
GameInfo_t game_state = updateCurrentState();
printf("DEBUG: Got game state, field: %p, next: %p\n",
game_state.field, game_state.next);
// Проверяем, является ли состояние GameOver
if (game_state.next[0][0] == 0 && game_state.next[0][1] == 0 && game_state.next[0][2] == 0 && game_state.next[0][3] == 0) {
mvprintw(FIELD_HEIGHT / 2, FIELD_WIDTH - 4, "GAME OVER");
refresh();
return;
}
// Проверяем pause
if (game_state.pause) {
mvprintw(FIELD_HEIGHT / 2, FIELD_WIDTH - 4, "PAUSED");
refresh();
return;
}
// Отображение игрового поля
for (int i = 0; i < FIELD_HEIGHT; ++i) {