diff --git a/snake/Makefile b/snake/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c7de2e1b31cf45697b72cbb22022f9f29d48015e --- /dev/null +++ b/snake/Makefile @@ -0,0 +1,22 @@ +cc=gcc +LIBS=-Wextra -Wall -g -fsanitize=address -fsanitize=leak -lm -lSDL2 + +snake.x: main.o queue.o snake.o gfx.o + $(cc) -o $@ $^ $(LIBS) + +main.o: main.c + $(cc) -c $^ $(LIBS) + +queue.o: queue.c queue.h + $(cc) -c $^ $(LIBS) + +snake.o: snake.c snake.h + $(cc) -c $^ $(LIBS) + +gfx.o: gfx.c gfx.h + $(cc) -c $^ $(LIBS) + +clean: + rm -f *.o *.x *.gch + +rebuild: clean snake.x \ No newline at end of file diff --git a/snake/gfx.c b/snake/gfx.c new file mode 100644 index 0000000000000000000000000000000000000000..79004048bfce7a015cc4767f9d338daa27156c2f --- /dev/null +++ b/snake/gfx.c @@ -0,0 +1,107 @@ +/// @file gfx.c +/// @author Florent Gluck +/// @date November 6, 2016 +/// Helper routines to render pixels in fullscreen graphic mode. +/// Uses the SDL2 library. + +#include <assert.h> +#include "gfx.h" + +/// Create a fullscreen graphic window. +/// @param title Title of the window. +/// @param width Width of the window in pixels. +/// @param height Height of the window in pixels. +/// @return a pointer to the graphic context or NULL if it failed. +struct gfx_context_t* gfx_create(char *title, uint width, uint height) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) goto error; + SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_MAXIMIZED); + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); + SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + uint32_t *pixels = malloc(width*height*sizeof(uint32_t)); + struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t)); + + if (!window || !renderer || !texture || !pixels || !ctxt) goto error; + + ctxt->renderer = renderer; + ctxt->texture = texture; + ctxt->window = window; + ctxt->width = width; + ctxt->height = height; + ctxt->pixels = pixels; + + SDL_ShowCursor(SDL_DISABLE); + gfx_clear(ctxt, COLOR_BLACK); + return ctxt; + +error: + return NULL; +} + +/// Draw a pixel in the specified graphic context. +/// @param ctxt Graphic context where the pixel is to be drawn. +/// @param x X coordinate of the pixel. +/// @param y Y coordinate of the pixel. +/// @param color Color of the pixel. +void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color) { + if (x < ctxt->width && y < ctxt->height) + ctxt->pixels[ctxt->width*y+x] = color; +} + +/// Get a pixel in the specified graphic context. +/// @param ctxt Graphic context where we want to get the pixel. +/// @param x X coordinate of the pixel. +/// @param y Y coordinate of the pixel. +/// @param color Color of the pixel. +/// @return color at position x, y. +uint32_t gfx_getpixel(struct gfx_context_t *ctxt, int x, int y) { + assert(x >= 0 && x < ctxt->width && y >= 0 && y < ctxt->height); + return ctxt->pixels[ctxt->width*y+x]; +} + +/// Clear the specified graphic context. +/// @param ctxt Graphic context to clear. +/// @param color Color to use. +void gfx_clear(struct gfx_context_t *ctxt, uint32_t color) { + int n = ctxt->width*ctxt->height; + while (n) + ctxt->pixels[--n] = color; +} + +/// Display the graphic context. +/// @param ctxt Graphic context to clear. +void gfx_present(struct gfx_context_t *ctxt) { + SDL_UpdateTexture(ctxt->texture, NULL, ctxt->pixels, ctxt->width*sizeof(uint32_t)); + SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL); + SDL_RenderPresent(ctxt->renderer); +} + +/// Destroy a graphic window. +/// @param ctxt Graphic context of the window to close. +void gfx_destroy(struct gfx_context_t *ctxt) { + SDL_ShowCursor(SDL_ENABLE); + SDL_DestroyTexture(ctxt->texture); + SDL_DestroyRenderer(ctxt->renderer); + SDL_DestroyWindow(ctxt->window); + free(ctxt->pixels); + ctxt->texture = NULL; + ctxt->renderer = NULL; + ctxt->window = NULL; + ctxt->pixels = NULL; + SDL_Quit(); + free(ctxt); +} + +/// If a key was pressed, returns its key code (non blocking call). +/// List of key codes: https://wiki.libsdl.org/SDL_Keycode +/// @return the key that was pressed or 0 if none was pressed. +SDL_Keycode gfx_keypressed() { + SDL_Event event; + if (SDL_PollEvent(&event)) { + if (event.type == SDL_KEYDOWN) + return event.key.keysym.sym; + } + return 0; +} + diff --git a/snake/gfx.h b/snake/gfx.h new file mode 100644 index 0000000000000000000000000000000000000000..8dabbf62946082913faa7368530d6a5bf109d648 --- /dev/null +++ b/snake/gfx.h @@ -0,0 +1,42 @@ +#ifndef _GFX_H_ +#define _GFX_H_ + +#include <stdint.h> +#include <stdbool.h> +#include <SDL2/SDL.h> + +#define MAKE_COLOR(r,g,b) ((uint32_t)b|((uint32_t)g<<8)|((uint32_t)r<<16)) + +#define COLOR_GET_B(color) (color & 0xff) +#define COLOR_GET_G(color) ((color >> 8) & 0xff) +#define COLOR_GET_R(color) ((color >> 16) & 0xff) + +#define COLOR_BLACK 0x00000000 +#define COLOR_RED 0x00FF0000 +#define COLOR_GREEN 0x0000FF00 +#define COLOR_BLUE 0x000000FF +#define COLOR_WHITE 0x00FFFFFF +#define COLOR_YELLOW 0x00FFFF00 + +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned char uchar; + +struct gfx_context_t { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + uint32_t *pixels; + int width; + int height; +}; + +extern uint32_t gfx_getpixel(struct gfx_context_t *ctxt, int x, int y); +extern void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color); +extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color); +extern struct gfx_context_t* gfx_create(char *text, uint width, uint height); +extern void gfx_destroy(struct gfx_context_t *ctxt); +extern void gfx_present(struct gfx_context_t *ctxt); +extern SDL_Keycode gfx_keypressed(); + +#endif diff --git a/snake/main.c b/snake/main.c new file mode 100644 index 0000000000000000000000000000000000000000..2fcfaef4e50809a5e1332bdbc9164a04c95240bb --- /dev/null +++ b/snake/main.c @@ -0,0 +1,64 @@ +#include <stdlib.h> +#include <stdint.h> +#include "snake.h" +#include <unistd.h> + + + +int main(){ +// + int width = 240, height = 135; + int maxFood=10; + + snake snk; + snake_init(&snk, height,width); + + struct gfx_context_t *ctxt = gfx_create("Serpent", width, height); + + if (!ctxt) { + fprintf(stderr, "Graphics initialization failed!\n"); + return EXIT_FAILURE; + } + + + //draw walls + for(int y=0;y<height;y++){ + for(int x=0;x<width;x++){ + if(y==0||x==0||x==width-1||y==height-1){ + gfx_putpixel(ctxt, x,y, wall); + } + } + } + SDL_Keycode key; + while (key != SDLK_ESCAPE) { + key=gfx_keypressed(); + //gfx_clear(ctxt, COLOR_BLACK); + input_handler(&snk,key); + step(&snk, ctxt); + + if(snk.currentFood<maxFood){ + snk.currentFood++; + generateFood(ctxt, width, height); + //printf("%d\n",snk.currentFood); + } + + + element* tmp=snk.body.firstIn; + + while(tmp!=NULL){ + gfx_putpixel(ctxt, tmp->pixel.x,tmp->pixel.y, body); + tmp=tmp->next; + } + usleep(25000); + //uint color = MAKE_COLOR(val, val, val); + //gfx_putpixel(ctxt, x, y, color); + + + + gfx_present(ctxt); + } + + gfx_destroy(ctxt); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/snake/queue.c b/snake/queue.c new file mode 100644 index 0000000000000000000000000000000000000000..eccd95cf879b8d18a37cff46a940a0e2441bbc5e --- /dev/null +++ b/snake/queue.c @@ -0,0 +1,102 @@ +#include "queue.h" +#include <stdio.h> +#include <stdlib.h> + +// typedef struct _element { +// T pixel; +// struct _element *next; +// } element; + +// typedef struct _queue { +// element* firstIn; //head +// element* lastIn; //debut +// } queue; + +pixel pixel_init(int x,int y){ + pixel p; + p.x=x; + p.y=y; + return p; +} + +queue createQ(){ + queue Q; + Q.firstIn=NULL; + Q.lastIn=NULL; + return Q; +} + +void destroyQ(queue *Q){ + + while(Q->firstIn!=NULL){ + element* tmp=Q->firstIn->next; + free(Q->firstIn); + Q->firstIn=tmp; + } +} + +void insertQ(queue *Q, T value){ + element *tmp = malloc(sizeof(element)); + tmp->pixel=value; + tmp->next=NULL; + if(isQueueEmpty(*Q)){ + Q->firstIn=tmp; + }else{ + Q->lastIn->next=tmp; + } + Q->lastIn= tmp; +} + +T extractFirst(queue *Q) { + T val=Q->firstIn->pixel; + element* oldFirst=Q->firstIn; + Q->firstIn=Q->firstIn->next; //next ! + free(oldFirst); + return val; +} + +T getFirst(queue Q){ + return Q.firstIn->pixel; +} + +bool isQueueEmpty(queue Q){ + return Q.firstIn==NULL; +} + +int queueCount(queue Q){ + int count=0; + + while (Q.firstIn!=NULL) { + count++; + Q.firstIn=Q.firstIn->next; + } + return count; +} + +void displayQ(queue Q){ + while (Q.firstIn!=NULL) { + printf("[%d,%d] ",Q.firstIn->pixel.x,Q.firstIn->pixel.y); + Q.firstIn=Q.firstIn->next; + } + printf("\n"); +} + + + + + +// int main() { + +// queue Q = createQ(); + +// for (int i = 0; i < 10; i++) { +// insertQ(&Q, i); +// } +// displayQ(Q); +// extractFirst(&Q); +// displayQ(Q); +// destroyQ(&Q); + + +// return EXIT_SUCCESS; +// } \ No newline at end of file diff --git a/snake/queue.h b/snake/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..50a2e32a9fc53b98beed5dc598b41a14e453e854 --- /dev/null +++ b/snake/queue.h @@ -0,0 +1,40 @@ +#ifndef _QUEUE_LIST_H_ +#define _QUEUE_LIST_H_ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <assert.h> +#include <time.h> + +typedef struct _pixel{ + int x; + int y; +} pixel; + +typedef pixel T; + +typedef struct _element { + T pixel; + struct _element *next; +} element; + +typedef struct _queue { + element* firstIn; //head + element* lastIn; //debut +} queue; + +queue createQ(); +void destroyQ(queue *Q); +void insertQ(queue *Q, T value); //a la fin +T extractFirst(queue *Q); //a l'index 0 +T getFirst(queue Q); +bool isQueueEmpty(queue Q); +int queueCount(queue Q); +void displayQ(queue Q); +pixel pixel_init(int x,int y); +//void start(int height,int width,snake snk); + + +#endif \ No newline at end of file diff --git a/snake/snake.c b/snake/snake.c new file mode 100644 index 0000000000000000000000000000000000000000..9fc152c68ab128003c1502d006682cff3a0fa938 --- /dev/null +++ b/snake/snake.c @@ -0,0 +1,107 @@ +#include "snake.h" +#include <stdint.h> + +// typedef enum _dir{LEFT,RIGHT,TOP,DOWN} dir; + +// typedef struct _snake{ +// queue body; +// dir mvt; +// } snake; + +void snake_init(snake *snk, int height, int width) { + + snk->body = createQ(); // snake's head = lastIn + snk->dir = RIGHT; + snk->currentFood=0; + + pixel p = pixel_init(width / 2, height / 2); + + for (int i = 0; i < 3; i++) { + insertQ(&(snk->body), p); + p.x++; + } +} + +void step(snake *snk, struct gfx_context_t *ctxt) { + + pixel next = snk->body.lastIn->pixel; + + switch (snk->dir) { + case RIGHT: + next.x++; + break; + + case LEFT: + next.x--; + break; + + case UP: + next.y--; + break; + + case DOWN: + next.y++; + break; + } + + insertQ(&(snk->body), next);//new head + //draw + + + + switch(gfx_getpixel(ctxt, next.x, next.y)){ + case wall: + + printf("head in the wall !\n"); + exit(EXIT_SUCCESS); + break; + + case food: + printf("miam\n"); + snk->currentFood--; + break; + + case empty: + gfx_putpixel(ctxt, snk->body.firstIn->pixel.x,snk->body.firstIn->pixel.y, empty); + extractFirst(&(snk->body)); //moves + break; + + case body: + printf("canibalism !\n"); + exit(EXIT_SUCCESS); + break; + } + gfx_putpixel(ctxt, snk->body.lastIn->pixel.x,snk->body.lastIn->pixel.y, body); +} + +void input_handler(snake *snk, SDL_Keycode key){ + + switch(key){ + case SDLK_RIGHT: + snk->dir=RIGHT; + break; + case SDLK_LEFT: + snk->dir=LEFT; + break; + case SDLK_UP: + snk->dir=UP; + break; + case SDLK_DOWN: + snk->dir=DOWN; + break; + } +} + +void generateFood(struct gfx_context_t *ctxt,int width, int height){ + + while(true){ + int x=rand()%width-2; + int y=rand()%height-2; + + if(gfx_getpixel(ctxt, x, y)==empty){ + gfx_putpixel(ctxt, x, y,food); + break; + } + + } +} \ No newline at end of file diff --git a/snake/snake.h b/snake/snake.h new file mode 100644 index 0000000000000000000000000000000000000000..de4bd0716013d7d59c5376ab92e60a287859f22c --- /dev/null +++ b/snake/snake.h @@ -0,0 +1,21 @@ +#ifndef _SNAKE_H_ +#define _SNAKE_H_ +#include "queue.h" +#include "gfx.h" + +typedef enum _dir{LEFT,RIGHT,UP,DOWN} dir; + +typedef enum _map{wall=MAKE_COLOR(255, 255, 255),empty=MAKE_COLOR(0,0,0),food=MAKE_COLOR(0, 255, 0),body=MAKE_COLOR(255, 0, 0)} map; + +typedef struct _snake{ + queue body; + dir dir; + int currentFood; +} snake; + +void snake_init(snake *snk, int height, int width); +void step(snake *snk, struct gfx_context_t *ctxt); +void input_handler(snake *snk,SDL_Keycode key); +void generateFood(struct gfx_context_t *ctxt,int width, int height); + +#endif \ No newline at end of file