#include <SDL2/SDL.h>
#include <stdbool.h>
#include <time.h>
#include <stdlib.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define GRID_WIDTH 10
#define GRID_HEIGHT 20
#define CELL_SIZE 30
typedef struct {
int x, y;
} Point;
typedef struct {
Point blocks[4];
Point position;
SDL_Color color;
} Tetromino;
// Tetris pieces (I, O, T, S, Z, J, L)
Tetromino tetrominoes[7] = {
{{ {0, 0}, {0, 1}, {0, 2}, {0, 3} }, {GRID_WIDTH / 2 - 2, 0}, {0, 255, 255, 255}}, // I
{{ {0, 0}, {0, 1}, {1, 0}, {1, 1} }, {GRID_WIDTH / 2 - 1, 0}, {255, 255, 0, 255}}, // O
{{ {0, 0}, {1, 0}, {2, 0}, {1, 1} }, {GRID_WIDTH / 2 - 1, 0}, {128, 0, 128, 255}}, // T
{{ {0, 1}, {1, 1}, {1, 0}, {2, 0} }, {GRID_WIDTH / 2 - 1, 0}, {0, 255, 0, 255}}, // S
{{ {0, 0}, {1, 0}, {1, 1}, {2, 1} }, {GRID_WIDTH / 2 - 1, 0}, {255, 0, 0, 255}}, // Z
{{ {0, 1}, {1, 1}, {2, 1}, {2, 0} }, {GRID_WIDTH / 2 - 1, 0}, {0, 0, 255, 255}}, // J
{{ {0, 0}, {0, 1}, {1, 1}, {2, 1} }, {GRID_WIDTH / 2 - 1, 0}, {255, 165, 0, 255}} // L
};
int grid[GRID_HEIGHT][GRID_WIDTH] = {0};
bool check_collision(Tetromino *tetromino, int offsetX, int offsetY) {
for (int i = 0; i < 4; i++) {
int newX = tetromino->blocks[i].x + tetromino->position.x + offsetX;
int newY = tetromino->blocks[i].y + tetromino->position.y + offsetY;
if (newX < 0 || newX >= GRID_WIDTH || newY < 0 || newY >= GRID_HEIGHT || grid[newY][newX]) {
return true;
}
}
return false;
}
void lock_tetromino(Tetromino *tetromino) {
for (int i = 0; i < 4; i++) {
int x = tetromino->blocks[i].x + tetromino->position.x;
int y = tetromino->blocks[i].y + tetromino->position.y;
grid[y][x] = 1;
}
}
void render_grid(SDL_Renderer *renderer) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
for (int y = 0; y < GRID_HEIGHT; y++) {
for (int x = 0; x < GRID_WIDTH; x++) {
if (grid[y][x]) {
SDL_Rect cell = { x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE };
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, &cell);
}
}
}
}
void render_tetromino(SDL_Renderer *renderer, Tetromino *tetromino) {
SDL_SetRenderDrawColor(renderer, tetromino->color.r, tetromino->color.g, tetromino->color.b, tetromino->color.a);
for (int i = 0; i < 4; i++) {
SDL_Rect block = { (tetromino->blocks[i].x + tetromino->position.x) * CELL_SIZE,
(tetromino->blocks[i].y + tetromino->position.y) * CELL_SIZE,
CELL_SIZE, CELL_SIZE };
SDL_RenderFillRect(renderer, &block);
}
}
int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("SDL_Init Error: %s\n", SDL_GetError());
return 1;
}
SDL_Window *window = SDL_CreateWindow("Tetris", 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL) {
printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == NULL) {
SDL_DestroyWindow(window);
printf("SDL_CreateRenderer Error: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
srand(time(NULL));
Tetromino current_tetromino = tetrominoes[rand() % 7];
bool running = true;
SDL_Event event;
Uint32 lastTick = SDL_GetTicks(), currentTick;
while (running) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
} else if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
case SDLK_LEFT:
if (!check_collision(¤t_tetromino, -1, 0)) {
current_tetromino.position.x -= 1;
}
break;
case SDLK_RIGHT:
if (!check_collision(¤t_tetromino, 1, 0)) {
current_tetromino.position.x += 1;
}
break;
case SDLK_DOWN:
if (!check_collision(¤t_tetromino, 0, 1)) {
current_tetromino.position.y += 1;
}
break;
}
}
}
currentTick = SDL_GetTicks();
if (currentTick - lastTick > 500) {
if (!check_collision(¤t_tetromino, 0, 1)) {
current_tetromino.position.y += 1;
} else {
lock_tetromino(¤t_tetromino);
current_tetromino = tetrominoes[rand() % 7];
if (check_collision(¤t_tetromino, 0, 0)) {
running = false; // Game over
}
}
lastTick = currentTick;
}
render_grid(renderer);
render_tetromino(renderer, ¤t_tetromino);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}