From e6840b03f4251cd6a46510b7af9c6b2ab466ce0e Mon Sep 17 00:00:00 2001 From: nemo Date: Mon, 17 Feb 2025 09:35:46 +0100 Subject: [PATCH] begin dora 07 --- .gitignore | 2 + 06-spaghetti-vs-bolognese/Makefile | 2 +- 07-dora/Makefile | 11 + 07-dora/main.c | 336 +++++++++++++++++++++++++++++ 4 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 07-dora/Makefile create mode 100644 07-dora/main.c diff --git a/.gitignore b/.gitignore index 61a2a02..77be4cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ spaghetti-vs-bolognese spaghetti-vs-bolognese.exe +dora +dora.exe diff --git a/06-spaghetti-vs-bolognese/Makefile b/06-spaghetti-vs-bolognese/Makefile index a36acd0..42c6dd6 100644 --- a/06-spaghetti-vs-bolognese/Makefile +++ b/06-spaghetti-vs-bolognese/Makefile @@ -8,4 +8,4 @@ win: x86_64-w64-mingw32-gcc -Wall -Wextra main.c -o spaghetti-vs-bolognese -I../lib -L../lib -l:../lib/windows-libraylib.a -lgdi32 -lwinmm clean: - rm spaghetti-vs-bolognese + rm spaghetti-vs-bolognese spaghetti-vs-bolognese.exe diff --git a/07-dora/Makefile b/07-dora/Makefile new file mode 100644 index 0000000..2dc1448 --- /dev/null +++ b/07-dora/Makefile @@ -0,0 +1,11 @@ +all: + gcc -Wall -Wextra main.c -o dora -I../lib -l:../lib/libraylib.a -lm + +run: all + ./dora + +win: + x86_64-w64-mingw32-gcc -Wall -Wextra main.c -o dora -I../lib -L../lib -l:../lib/windows-libraylib.a -lgdi32 -lwinmm + +clean: + rm dora dora.exe diff --git a/07-dora/main.c b/07-dora/main.c new file mode 100644 index 0000000..f02c967 --- /dev/null +++ b/07-dora/main.c @@ -0,0 +1,336 @@ +#include +#include + +#include "raylib.h" +#include "raymath.h" + +#define MAP_WIDTH_MAX 5 +#define MAP_HEIGHT_MAX 5 + +#define MAX_ATOUT (4*4 - 3) +#define MAX_PLAYER 6 +#define MAX_PIOCHE (4*13 + 2 - 6) +#define MAX_MAIN (MAX_PIOCHE - 3*5) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +typedef enum CarteType { + CARTE_COEUR, + CARTE_TREFLE, + CARTE_CARREAU, + CARTE_PIQUE, + CARTE_TYPE_COUNT, +} CarteType; + +typedef enum CarteValue { + CARTE_VALET = 11, + CARTE_REINE, + CARTE_ROI, + CARTE_AS, + CARTE_JOKER, + CARTE_VALUE_COUNT, +} CarteValue; + +typedef struct Carte { + CarteValue value; + CarteType type; +} Carte; + +typedef struct Map { + int width, height; + int spawn_x, spawn_y; + Carte cartes[MAP_WIDTH_MAX*MAP_HEIGHT_MAX]; +} Map; + +#define O (Carte) {.value = -1, .type = -1} +#define X (Carte) {.value = 2, .type = 0} +Map default_map = {3, 3, 1, 1, { + X, X, X, + X, X, X, + X, X, X, +}}; +Map grande_map = {5, 5, 2, 2, { + O, O, X, O, O, + O, X, X, X, O, + X, X, X, X, X, + O, X, X, X, O, + O, O, X, O, O, +}}; +#undef O +#undef X + +typedef struct Player { + int x, y; + Carte role; + int nb_atout; + Carte atouts[MAX_ATOUT]; + int nb_cartes; + Carte cartes[MAX_MAIN]; +} Player; + +typedef struct Game { + int nb_player; + Player players[MAX_PLAYER]; + int pioche_len; + Carte pioche[MAX_PIOCHE]; + Map map; +} Game; + +// name = 7C, TK JK +// will write only 2 char in buff +void carte_name(Carte carte, char* buff) +{ + if (carte.value < 10 && carte.value > 1) { + buff[0] = '0' + carte.value; + } else { + switch (carte.value) { + case 10: buff[0] = 'T'; break; + case CARTE_VALET: buff[0] = 'V'; break; + case CARTE_REINE: buff[0] = 'Q'; break; + case CARTE_ROI: buff[0] = 'K'; break; + case CARTE_AS: buff[0] = 'A'; break; + case CARTE_JOKER: buff[0] = 'J'; break; + default: buff[0] = '?'; break; + } + } + switch (carte.type) { + case CARTE_COEUR: buff[1] = 'C'; break; + case CARTE_TREFLE: buff[1] = 'T'; break; + case CARTE_CARREAU: buff[1] = 'K'; break; + case CARTE_PIQUE: buff[1] = 'P'; break; + default: buff[1] = '?'; break; + } +} + +int valid_carte(Carte carte) +{ + return !(carte.value < 2 || carte.value > CARTE_JOKER || + carte.type < CARTE_COEUR || carte.type >= CARTE_TYPE_COUNT); +} + +Vector2 window = {1920, 1080}; + +void game_init(Game* game, Map map, int nb_player) +{ + if (nb_player < 3) return; + + Carte roles[] = { + {CARTE_REINE, CARTE_COEUR}, // dora, always in game + {CARTE_VALET, CARTE_CARREAU}, // babouche + {CARTE_REINE, CARTE_TREFLE}, // chipeur + {CARTE_ROI, CARTE_PIQUE}, // grumpy + {CARTE_VALET, CARTE_COEUR}, // malveillant + {CARTE_ROI, CARTE_CARREAU}, // diego + }; + int len = sizeof(roles)/sizeof(*roles); + + if (nb_player > len) return; + + // pioche + + int count = 0; + for (CarteType type = 0; type < CARTE_TYPE_COUNT; type++) { + for (CarteValue value = 2; value <= CARTE_AS; value++) { + int i; + for (i = 0; i < len; i++) { + if (roles[i].value == value && roles[i].type == type) break; + } + if (i < len) continue; + + game->pioche[count] = (Carte) {value, type}; + count++; + } + } + game->pioche[count++] = (Carte) {CARTE_JOKER, CARTE_COEUR}; + game->pioche[count++] = (Carte) {CARTE_JOKER, CARTE_PIQUE}; + game->pioche_len = count; + + for (int i = 0; i < game->pioche_len; i++) { + int idx = GetRandomValue(0, game->pioche_len-1); + Carte swap = game->pioche[i]; + game->pioche[i] = game->pioche[idx]; + game->pioche[idx] = swap; + } + + // player + + int picked[sizeof(roles)/sizeof(*roles)] = {0}; + int nb_atout[MAX_PLAYER] = {0}; + + int dora_idx = GetRandomValue(0, nb_player-1); + game->players[dora_idx].role = roles[0]; + picked[0] = 1; + game->players[dora_idx].x = map.spawn_x; + game->players[dora_idx].y = map.spawn_y; + + for (int i = 0; i < nb_player; i++) { + if (i == dora_idx) continue; + + int idx; + do { + idx = GetRandomValue(1, len-1); + } while (picked[idx]); + + picked[idx] = 1; + game->players[i].role = roles[idx]; + game->players[i].x = map.spawn_x; + game->players[i].y = map.spawn_y; + } + + for (int i = 0; i < nb_player; i++) { + for (int c = 0; c < 5; c++) { + game->players[i].cartes[c] = game->pioche[--game->pioche_len]; + } + game->players[i].nb_cartes = 5; + } + + game->nb_player = nb_player; + + // map + + for (int i = 0; i < map.width*map.height; i++) { + if (!valid_carte(map.cartes[i])) { + game->map.cartes[i] = (Carte) {-1, -1}; + } else { + game->map.cartes[i] = game->pioche[--game->pioche_len]; + } + } + game->map.width = map.width; + game->map.height = map.height; + game->map.spawn_x = map.spawn_x; + game->map.spawn_y = map.spawn_y; +} + + +void attack(Game* game, int player, int carte, int x, int y) +{ + if (x < 0 || x >= game->map.width || y < 0 || y >= game->map.height) return; + + Carte c = game->players[player].cartes[carte]; + + switch (c.type) { + case CARTE_PIQUE: + // attaquer joueur + break; + case CARTE_TREFLE: + // poser piege + break; + case CARTE_COEUR: + case CARTE_CARREAU: + default: + return; + } + + // Player p = game->players[player]; + Carte to = game->map.cartes[y*game->map.width + x]; + + char buff[3]; + carte_name(to, buff); + buff[2] = 0; + printf("to %s\n", buff); + + (void) game; +} + +int main() +{ + InitWindow(window.x, window.y, "DORA"); + SetWindowState(/*FLAG_FULLSCREEN_MODE|*/FLAG_WINDOW_RESIZABLE); + SetTargetFPS(60); + + Game game = {0}; + game_init(&game, grande_map, 5); + + while (!WindowShouldClose()) { + + // update + + if (IsWindowResized()) { + window.x = GetScreenWidth(); + window.y = GetScreenHeight(); + } + + static int player = 0; + if (IsKeyPressed(KEY_SPACE)) + player = (player+1)%game.nb_player; + if (IsKeyPressed(KEY_S)) + game.players[player].y++; + if (IsKeyPressed(KEY_W)) + game.players[player].y--; + if (IsKeyPressed(KEY_D)) + game.players[player].x++; + if (IsKeyPressed(KEY_A)) + game.players[player].x--; + + static unsigned int carte = 4269+1; + if (IsKeyPressed(KEY_E)) + carte++; + if (IsKeyPressed(KEY_Q)) + carte--; + + // code skibidi degeu, parti draw() a refaire plus tard + BeginDrawing(); + { + ClearBackground(GRAY); + + Vector2 off = {0, 0}; + int size = 0; + if (window.x < window.y) { + size = window.x / game.map.width; + off.y = (window.y - window.x) / 2; + } else { + size = window.y / game.map.height; + off.x = (window.x - window.y) / 2; + } + + for (int y = 0; y < game.map.height; y++) { + for (int i = 0; i < game.map.width; i++) { + Carte carte = game.map.cartes[y*game.map.width+i]; + if (!valid_carte(carte)) + continue; + + Rectangle tile = {off.x+size*i, off.y+size*y, size, size}; + DrawRectangleRec(tile, BLACK); + + char buff[3]; + carte_name(carte, buff); + buff[2] = 0; + DrawText(buff, tile.x, tile.y, size/5, ORANGE); + } + } + + Vector2 mouse = GetMousePosition(); + Vector2 hover = {mouse.x * game.map.height / window.y, mouse.y * game.map.height / window.y}; + hover.x -= 2; + Rectangle tile = {off.x+size*(int)hover.x, off.y+size*(int)hover.y, size, size}; + DrawRectangleRec(tile, IsMouseButtonDown(MOUSE_BUTTON_LEFT) ? RED : WHITE); + + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) + attack(&game, player, carte%game.players[player].nb_cartes, hover.x, hover.y); + + for (int i = 0; i < game.nb_player; i++) { + char buff[3]; + carte_name(game.players[i].role, buff); + buff[2] = 0; + Rectangle tile = {off.x+size*(game.players[i].x), off.y+size*(game.players[i].y), size, size}; + DrawText(buff, tile.x+size-MeasureText(buff, size/5)-5, tile.y+size-size/5, + i == player + ? size/4 + : size/5, + i == player + ? WHITE + : ColorFromHSV(((float)i/MAX_PLAYER)*360, 1, 1) + ); + } + + for (int i = 0; i < game.players[player].nb_cartes; i++) { + char buff[3]; + carte_name(game.players[player].cartes[i], buff); + buff[2] = 0; + DrawText(buff, 0, size/5*i, size/5, i == (int)carte%game.players[player].nb_cartes ? WHITE : RED); + } + } + EndDrawing(); + } +}