This repository has been archived on 2026-10-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
lightup/model.c
T

443 lines
15 KiB
C

// SDL2 Demo by aurelien.esnard@u-bordeaux.fr
#include "model.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h> // required to load transparent texture from PNG
#include <SDL2/SDL_ttf.h> // required to use TTF fonts
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "game.h"
#include "game_aux.h"
#include "game_ext.h"
#include "game_private.h"
#include "game_tools.h"
/* **************************************************************** */
#define RESTART_UP "./img/restart_up.png"
#define RESTART_DOWN "./img/restart_down.png"
#define UNDO_UP "./img/undo_up.png"
#define UNDO_DOWN "./img/undo_down.png"
#define REDO_UP "./img/redo_up.png"
#define REDO_DOWN "./img/redo_down.png"
#define SOLVE_UP "./img/solve_up.png"
#define SOLVE_DOWN "./img/solve_down.png"
#define LIGHTBULB_WHITE "./img/lightbulb_white.png"
#define LIGHTBULB_BLACK "./img/lightbulb_black.png"
#define FONT "./arial.ttf"
#define FONTSIZE 36
/* **************************************************************** */
struct Env_t {
game g;
SDL_Texture** zero; // array of two texture one white and one red for each number (red color = r:255 g:50 b:50)
SDL_Texture** one;
SDL_Texture** two;
SDL_Texture** three;
SDL_Texture** four;
SDL_Texture** lightbulb; // array of the two lightbulb images first white second red
SDL_Texture** text_restart; // up fist then down
SDL_Texture** text_undo;
SDL_Texture** text_redo;
SDL_Texture** text_solve;
bool pressed_restart;
bool pressed_undo;
bool pressed_redo;
bool pressed_solve;
SDL_Rect* rec_redo; // rectangle of each buttons
SDL_Rect* rec_undo;
SDL_Rect* rec_restart;
SDL_Rect* rec_solve;
SDL_Rect* rec_game; // rectangle of the grid
};
/* **************************************************************** */
void usage(char* argv[]) {
printf("Usage : %s => Joue la partie par défaut\n", argv[0]);
printf(" %s <filename> => Charge la partie sur le fichier <filename>\n", argv[0]);
exit(EXIT_FAILURE);
}
Env* init(SDL_Renderer* ren, int argc, char* argv[]) {
Env* env = malloc(sizeof(struct Env_t));
printf("To win the game, you must satisfy the following conditions:\n");
printf(
"All non-black squares are lit.\nNo light is lit by another light.\nEach numbered black square must be orthogonally adjacent to exactly the given "
"number of lights.\nNon-numbered black squares may have any number of lights adjacent to them.\n");
if (argc == 1) {
// Create new game
env->g = game_default();
} else if (argc == 2) {
char* gameFile = argv[1];
env->g = game_load(gameFile);
} else {
usage(argv);
}
TTF_Font* font = TTF_OpenFont(FONT, FONTSIZE);
if (!font)
fprintf(stderr, "TTF_OpenFont: %s\n", FONT);
TTF_SetFontStyle(font, TTF_STYLE_BOLD);
// color of 0 in black wall
SDL_Color color_w = {255, 255, 255, 255};
// color of 0 in black wall with error
SDL_Color color_r = {255, 0, 0, 255}; /* blue color in RGBA */
/* init zero texture double tab*/
env->zero = malloc(sizeof(SDL_Texture*) * 2);
if (env->zero == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
SDL_Surface* surf = TTF_RenderText_Blended(font, "0", color_w);
env->zero[0] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
// if the case has error
surf = TTF_RenderText_Blended(font, "0", color_r);
env->zero[1] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
/* init one texture double tab*/
env->one = malloc(sizeof(SDL_Texture*) * 2);
if (env->one == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
surf = TTF_RenderText_Blended(font, "1", color_w);
env->one[0] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
// if the case has error
surf = TTF_RenderText_Blended(font, "1", color_r);
env->one[1] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
/* init two texture double tab*/
env->two = malloc(sizeof(SDL_Texture*) * 2);
if (env->two == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
surf = TTF_RenderText_Blended(font, "2", color_w);
env->two[0] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
// if the case has error
surf = TTF_RenderText_Blended(font, "2", color_r);
env->two[1] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
/* init three texture double tab*/
env->three = malloc(sizeof(SDL_Texture*) * 2);
if (env->three == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
surf = TTF_RenderText_Blended(font, "3", color_w);
env->three[0] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
// if the case has error
surf = TTF_RenderText_Blended(font, "3", color_r);
env->three[1] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
/* init four texture double tab*/
env->four = malloc(sizeof(SDL_Texture*) * 2);
if (env->four == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
surf = TTF_RenderText_Blended(font, "4", color_w);
env->four[0] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
// if the case has error
surf = TTF_RenderText_Blended(font, "4", color_r);
env->four[1] = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);
/* init lightbulb texture double tab*/
env->lightbulb = malloc(sizeof(SDL_Texture*) * 2);
if (env->lightbulb == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
env->lightbulb[0] = IMG_LoadTexture(ren, LIGHTBULB_WHITE);
if (!env->lightbulb[0]) ERROR("IMG_LoadTexture: %s\n", LIGHTBULB_WHITE);
// if the case has error
env->lightbulb[1] = IMG_LoadTexture(ren, LIGHTBULB_BLACK);
if (!env->lightbulb[1]) ERROR("IMG_LoadTexture: %s\n", LIGHTBULB_BLACK);
/* init text_restart texture double tab*/
env->text_restart = malloc(sizeof(SDL_Texture*) * 2);
if (env->text_restart == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
env->text_restart[0] = IMG_LoadTexture(ren, RESTART_UP);
if (!env->text_restart[0]) ERROR("IMG_LoadTexture: %s\n", RESTART_UP);
// if the case has error
env->text_restart[1] = IMG_LoadTexture(ren, RESTART_DOWN);
if (!env->text_restart[1]) ERROR("IMG_LoadTexture: %s\n", RESTART_DOWN);
/* init text_undo texture double tab*/
env->text_undo = malloc(sizeof(SDL_Texture*) * 2);
if (env->text_undo == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
env->text_undo[0] = IMG_LoadTexture(ren, UNDO_UP);
if (!env->text_undo[0]) ERROR("IMG_LoadTexture: %s\n", UNDO_UP);
// if the case has error
env->text_undo[1] = IMG_LoadTexture(ren, UNDO_DOWN);
if (!env->text_undo[1]) ERROR("IMG_LoadTexture: %s\n", UNDO_DOWN);
/* init text_redo texture double tab*/
env->text_redo = malloc(sizeof(SDL_Texture*) * 2);
if (env->text_redo == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
env->text_redo[0] = IMG_LoadTexture(ren, REDO_UP);
if (!env->text_redo[0]) ERROR("IMG_LoadTexture: %s\n", REDO_UP);
// if the case has error
env->text_redo[1] = IMG_LoadTexture(ren, REDO_DOWN);
if (!env->text_redo[1]) ERROR("IMG_LoadTexture: %s\n", UNDO_DOWN);
/* init text_solve texture double tab*/
env->text_solve = malloc(sizeof(SDL_Texture*) * 2);
if (env->text_solve == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
// if the case has not error
env->text_solve[0] = IMG_LoadTexture(ren, SOLVE_UP);
if (!env->text_solve[0]) ERROR("IMG_LoadTexture: %s\n", SOLVE_UP);
// if the case has error
env->text_solve[1] = IMG_LoadTexture(ren, SOLVE_DOWN);
if (!env->text_solve[1]) ERROR("IMG_LoadTexture: %s\n", SOLVE_DOWN);
env->rec_redo = malloc(sizeof(SDL_Rect));
if (env->rec_redo == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
env->rec_game = malloc(sizeof(SDL_Rect));
if (env->rec_game == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
env->rec_restart = malloc(sizeof(SDL_Rect));
if (env->rec_restart == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
env->rec_solve = malloc(sizeof(SDL_Rect));
if (env->rec_solve == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
env->rec_undo = malloc(sizeof(SDL_Rect));
if (env->rec_undo == NULL)
fprintf(stderr, "NOT ENOUGTH MEMORY\n");
TTF_CloseFont(font);
return env;
}
/* **************************************************************** */
void render_blank(SDL_Renderer* ren, SDL_Rect* rec, bool lighted) {
if (lighted) {
SDL_SetRenderDrawColor(ren, 255, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(ren, rec);
}
SDL_SetRenderDrawColor(ren, 127, 127, 127, SDL_ALPHA_OPAQUE);
SDL_RenderDrawRect(ren, rec);
}
void render_wall(SDL_Renderer* ren, Env* env, SDL_Rect* rec, int nb, bool error) {
SDL_Rect number;
SDL_SetRenderDrawColor(ren, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(ren, rec);
switch (nb) {
case 0:
SDL_QueryTexture(env->zero[error ? 1 : 0], NULL, NULL, &number.w, &number.h);
number.x = rec->x + rec->w / 2 - number.x / 2;
number.y = rec->y + rec->h / 2 - number.y / 2;
SDL_RenderCopy(ren, env->zero[error ? 1 : 0], NULL, &number);
break;
case 1:
SDL_QueryTexture(env->one[error ? 1 : 0], NULL, NULL, &number.w, &number.h);
number.x = rec->x + rec->w / 2 - number.x / 2;
number.y = rec->y + rec->h / 2 - number.y / 2;
SDL_RenderCopy(ren, env->one[error ? 1 : 0], NULL, &number);
break;
case 2:
SDL_QueryTexture(env->two[error ? 1 : 0], NULL, NULL, &number.w, &number.h);
number.x = rec->x + rec->w / 2 - number.x / 2;
number.y = rec->y + rec->h / 2 - number.y / 2;
SDL_RenderCopy(ren, env->two[error ? 1 : 0], NULL, &number);
break;
case 3:
SDL_QueryTexture(env->three[error ? 1 : 0], NULL, NULL, &number.w, &number.h);
number.x = rec->x + rec->w / 2 - number.x / 2;
number.y = rec->y + rec->h / 2 - number.y / 2;
SDL_RenderCopy(ren, env->three[error ? 1 : 0], NULL, &number);
break;
case 4:
SDL_QueryTexture(env->four[error ? 1 : 0], NULL, NULL, &number.w, &number.h);
number.x = rec->x + rec->w / 2 - number.x / 2;
number.y = rec->y + rec->h / 2 - number.y / 2;
SDL_RenderCopy(ren, env->four[error ? 1 : 0], NULL, &number);
break;
}
}
void render_lightbulb(SDL_Renderer* ren, SDL_Rect* rec, SDL_Texture* lightbulb_texture) {
SDL_Rect lightbulb;
SDL_SetRenderDrawColor(ren, 255, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(ren, rec);
SDL_SetRenderDrawColor(ren, 127, 127, 127, SDL_ALPHA_OPAQUE);
SDL_RenderDrawRect(ren, rec);
lightbulb.h = rec->h - rec->h / 10;
lightbulb.w = rec->w - rec->w / 10;
lightbulb.x = rec->x + rec->w / 2 - lightbulb.w / 2;
lightbulb.y = rec->y + rec->h / 2 - lightbulb.h / 2;
SDL_RenderCopy(ren, lightbulb_texture, NULL, &lightbulb);
}
void render_mark(SDL_Renderer* ren, SDL_Rect* rec, bool lighted) {
if (lighted)
SDL_SetRenderDrawColor(ren, 255, 255, 0, SDL_ALPHA_OPAQUE);
else
SDL_SetRenderDrawColor(ren, 255, 255, 255, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(ren, rec);
SDL_SetRenderDrawColor(ren, 127, 127, 127, SDL_ALPHA_OPAQUE);
SDL_RenderDrawRect(ren, rec);
SDL_SetRenderDrawColor(ren, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_Rect mark;
mark.h = rec->h / 4;
mark.w = rec->w / 4;
mark.x = rec->x + rec->w / 2 - mark.w / 2;
mark.y = rec->y + rec->h / 2 - mark.h / 2;
SDL_RenderFillRect(ren, &mark);
}
void render(SDL_Window* win, SDL_Renderer* ren, Env* env) {
int w, h;
SDL_GetWindowSize(win, &w, &h);
// set background color
SDL_SetRenderDrawColor(ren, 255, 255, 255, SDL_ALPHA_OPAQUE);
SDL_RenderClear(ren);
SDL_Rect rec;
int size_rec = int_min(w / game_nb_cols(env->g), h / game_nb_rows(env->g));
rec.h = size_rec;
rec.w = size_rec;
int rec_x = w / 2 - size_rec * game_nb_cols(env->g) / 2;
int rec_y = h / 2 - size_rec * game_nb_rows(env->g) / 2;
rec.x = rec_x;
rec.y = rec_y;
for (uint i = 0; i < game_nb_rows(env->g); i++) {
for (uint j = 0; j < game_nb_cols(env->g); j++) {
if (game_is_lightbulb(env->g, i, j))
render_lightbulb(ren, &rec, env->lightbulb[game_has_error(env->g, i, j) ? 1 : 0]);
else if (game_is_black(env->g, i, j))
render_wall(ren, env, &rec, game_get_black_number(env->g, i, j), game_has_error(env->g, i, j));
else if (game_is_blank(env->g, i, j))
render_blank(ren, &rec, game_is_lighted(env->g, i, j));
else if (game_is_marked(env->g, i, j))
render_mark(ren, &rec, game_is_lighted(env->g, i, j));
rec.x += size_rec;
}
rec.x = rec_x;
rec.y += size_rec;
}
}
/* **************************************************************** */
bool process(SDL_Window* win, Env* env, SDL_Event* e) {
int w, h;
SDL_GetWindowSize(win, &w, &h);
if (e->type == SDL_QUIT) {
return true;
}
#ifdef _ANDROID_
#else
else if (e->type == SDL_WINDOWEVENT) {
} else if (e->type == SDL_MOUSEMOTION) {
SDL_Point mouse;
SDL_GetMouseState(&mouse.x, &mouse.y);
if (SDL_PointInRect(&mouse, env->rec_restart)) {
env->pressed_restart = true;
} else if (SDL_PointInRect(&mouse, env->rec_undo)) {
env->pressed_undo = true;
} else if (SDL_PointInRect(&mouse, env->rec_redo)) {
env->pressed_redo = true;
} else if (SDL_PointInRect(&mouse, env->rec_solve)) {
env->pressed_solve = true;
} else {
env->pressed_restart = false;
env->pressed_undo = false;
env->pressed_redo = false;
env->pressed_solve = false;
}
} else if (e->type == SDL_MOUSEBUTTONDOWN) {
SDL_Point mouse;
SDL_GetMouseState(&mouse.x, &mouse.y);
if (SDL_PointInRect(&mouse, env->rec_restart)) {
game_restart(env->g);
} else if (SDL_PointInRect(&mouse, env->rec_undo)) {
game_undo(env->g);
} else if (SDL_PointInRect(&mouse, env->rec_redo)) {
game_redo(env->g);
} else if (SDL_PointInRect(&mouse, env->rec_solve)) {
game_solve(env->g);
} else if (SDL_PointInRect(&mouse, env->rec_game)) {
uint i = mouse.y - ((h - (env->rec_game->y)) / 2) / (env->g->height);
uint j = mouse.x - ((w - (env->rec_game->x)) / 2) / (env->g->width);
if (e->button.button == SDL_BUTTON_LEFT) {
if (game_is_blank(env->g, i, j) || game_is_marked(env->g, i, j)) {
game_play_move(env->g, i, j, S_LIGHTBULB);
} else if (game_is_lightbulb(env->g, i, j)) {
game_play_move(env->g, i, j, S_BLANK);
}
}
if (e->button.button == SDL_BUTTON_RIGHT) {
if (game_is_blank(env->g, i, j) || game_is_lightbulb(env->g, i, j)) {
game_play_move(env->g, i, j, S_MARK);
} else if (game_is_marked(env->g, i, j)) {
game_play_move(env->g, i, j, S_BLANK);
}
}
}
}
#endif
return false;
}
/* **************************************************************** */
void clean(Env* env) {
SDL_DestroyTexture(env->zero[0]);
SDL_DestroyTexture(env->zero[1]);
free(env->zero);
SDL_DestroyTexture(env->one[0]);
SDL_DestroyTexture(env->one[1]);
free(env->one);
SDL_DestroyTexture(env->three[0]);
SDL_DestroyTexture(env->three[1]);
free(env->three);
SDL_DestroyTexture(env->four[0]);
SDL_DestroyTexture(env->four[1]);
free(env->four);
/*SDL_DestroyTexture(env->one);
SDL_DestroyTexture(env->two);
SDL_DestroyTexture(env->three);
SDL_DestroyTexture(env->four);
SDL_DestroyTexture(env->lightbulb);
SDL_DestroyTexture(env->text_restart);
SDL_DestroyTexture(env->text_undo);
SDL_DestroyTexture(env->text_redo);
SDL_DestroyTexture(env->text_solve);
SDL_DestroyTexture(env->but_redo_up);
SDL_DestroyTexture(env->but_redo_down);
SDL_DestroyTexture(env->but_solve_up);
SDL_DestroyTexture(env->but_solve_down);
*/
free(env);
}
/* **************************************************************** */