commit 59c8971cfb441034c4e8e3ccfa5611a65ea008e6
Author: rani <clagv.randomgames@gmail.com>
Date: Thu Aug 03 23:11:18 2023 +0000
diff --git a/bejeweled/README.md b/bejeweled/README.md
new file mode 100644
index 0000000..2e412d0
--- /dev/null
+++ b/bejeweled/README.md
@@ -00 +112 @@
+# Bejeweled
+
+Tile match game. Click on a tile to select it, click on another tile directly adjacent to swap the two. Click on a selected tile to deselect it. Press 'r' to restart the game with a new board.
+
+## Config
+
+* `X`: Width of the board
+* `Y`: Height of the board
+* `HIGHLIGHT`: Either `true` or `false`, whether or not to highlight tiles
+* `SHIFT_DELAY`: The delay between shifts of tiles above each other when a match is made
+* `MATCH_DELAY`: The delay after a successful match
+* `BAD_MATCH_DELAY`: The delay after a non successful match
diff --git a/bejeweled/bejeweled.c b/bejeweled/bejeweled.c
new file mode 100644
index 0000000..bca6b21
--- /dev/null
+++ b/bejeweled/bejeweled.c
@@ -00 +1389 @@
+#include <time.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <stdbool.h>
+
+
+#ifndef HIGHLIGHT
+#define HIGHLIGHT false
+#endif /* HIGHLIGHT */
+
+#ifndef X
+#define X 16
+#endif /* X */
+
+#ifndef Y
+#define Y 16
+#endif /* Y */
+
+#ifndef SHIFT_DELAY
+#define SHIFT_DELAY 25
+#endif /* SHIFT_DELAY */
+
+#ifndef MATCH_DELAY
+#define MATCH_DELAY 750
+#endif /* MATCH_DELAY */
+
+#ifndef BAD_MATCH_DELAY
+#define BAD_MATCH_DELAY 750
+#endif /* BAD_MATCH_DELAY */
+
+#define SQUARE_C '#'
+#define CIRCLE_C 'O'
+#define TRIANGLE_C 'A'
+#define RHOMBUS_C '='
+#define DIAMOND_C 'm'
+#define HEXAGON_C '&'
+
+
+#define POP (1<<9)
+
+#define ISPOP(g) (g & POP)
+#define GETGEM(g) (g & 0xFF)
+
+
+enum gem {
+ SQUARE,
+ CIRCLE,
+ TRIANGLE,
+ RHOMBUS,
+ DIAMOND,
+ HEXAGON,
+ LAST_GEM
+};
+
+
+enum {
+ RED = 1,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+};
+
+
+struct coord {
+ int x, y;
+};
+
+
+char gemc[] = {
+ [SQUARE] = SQUARE_C,
+ [CIRCLE] = CIRCLE_C,
+ [TRIANGLE] = TRIANGLE_C,
+ [RHOMBUS] = RHOMBUS_C,
+ [DIAMOND] = DIAMOND_C,
+ [HEXAGON] = HEXAGON_C,
+};
+
+const struct coord invc = {-1, -1};
+enum gem grid[X][Y];
+struct coord first = {-1, -1};
+int score = 0;
+
+
+inline int getcolor(enum gem g) {
+ return COLOR_PAIR(g + 1);
+}
+
+
+inline bool valid(int x, int y) {
+ return x < X && y < Y && x >= 0 && y >= 0;
+}
+
+
+int abs(int n) {
+ return n < 0 ? -n : n;
+}
+
+
+int nlen(int n) {
+ int len = 0;
+ while (n > 0) {
+ len++;
+ n /= 10;
+ }
+ return len;
+}
+
+
+void newgem(struct coord c) {
+ int x = c.x;
+ int y = c.y;
+
+ bool done;
+ do {
+ done = true;
+ grid[x][y] = rand() % LAST_GEM;
+ if (valid(x - 1, y) && grid[x][y] == grid[x - 1][y]) done = false;
+ if (valid(x, y - 1) && grid[x][y] == grid[x][y - 1]) done = false;
+ } while (!done);
+}
+
+
+void display(void) {
+ erase();
+ for (int x = 0; x < X; x++) addstr("+ - ");
+ addstr("+\n");
+ for (int y = 0; y < Y; y++) {
+ for (int x = 0; x < X; x++) {
+ addstr("| ");
+ int cp = getcolor(GETGEM(grid[x][y]));
+ bool reverse = false;
+ if (HIGHLIGHT) reverse = true;;
+ if (first.x == x && first.y == y) reverse = !reverse;
+ if (ISPOP(grid[x][y])) reverse = !reverse;
+ if (reverse) cp |= A_REVERSE;
+ attron(cp);
+ addch(gemc[GETGEM(grid[x][y])]);
+ attroff(cp);
+ addch(' ');
+ }
+ addstr("|\n");
+ for (int x = 0; x < X; x++) addstr("+ - ");
+ addstr("+\n");
+ }
+
+ attron(A_REVERSE);
+ move(Y*2+1, (X*4+2)/2 - (nlen(score) + 8)/2);
+ printw("Score: %d", score);
+ attroff(A_REVERSE);
+ move(Y*2+1, 0);
+ addstr("r to restart");
+
+ refresh();
+}
+
+
+int checkvert(int x, int y, struct coord vc[]) {
+ int s = 0;
+
+ int n = y;
+ while (valid(x, n) && grid[x][n] == grid[x][y]) {
+ vc[s++] = (struct coord){x, n};
+ n++;
+ }
+ n = y - 1;
+ while (valid(x, n) && grid[x][n] == grid[x][y]) {
+ vc[s++] = (struct coord){x, n};
+ n--;
+ }
+
+ return s;
+}
+
+
+int checkhoriz(int x, int y, struct coord hc[]) {
+ int s = 0;
+
+ int n = x;
+ while (valid(n, y) && grid[n][y] == grid[x][y]) {
+ hc[s++] = (struct coord){n, y};
+ n++;
+ }
+ n = x - 1;
+ while (valid(n, y) && grid[n][y] == grid[x][y]) {
+ hc[s++] = (struct coord){n, y};
+ n--;
+ }
+
+ return s;
+}
+
+
+void shift(struct coord s[], int n) {
+ for (int i = 0; i < n; i++) {
+ struct coord sc = s[i];
+ for (int n = sc.y; n > 0; n--) {
+ grid[sc.x][n] = grid[sc.x][n - 1];
+ display();
+ napms(SHIFT_DELAY);
+ }
+
+ newgem((struct coord){sc.x, 0});
+ }
+}
+
+
+void makepop(struct coord s[], int n) {
+ for (int i = 0; i < n; i++) {
+ struct coord c = s[i];
+ grid[c.x][c.y] |= POP;
+ }
+}
+
+
+void sort(struct coord s[], int n) {
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n - 1; j++) {
+ if (s[j].y > s[j + 1].y) {
+ struct coord t = s[j];
+ s[j] = s[j + 1];
+ s[j + 1] = t;
+ }
+ }
+ }
+}
+
+
+int main(void) {
+ srand(time(NULL));
+
+ initscr();
+ noecho();
+ curs_set(0);
+ keypad(stdscr, TRUE);
+
+ mousemask(BUTTON1_CLICKED, NULL);
+
+ use_default_colors();
+ start_color();
+ init_pair(RED, COLOR_RED, -1);
+ init_pair(GREEN, COLOR_GREEN, -1);
+ init_pair(YELLOW, COLOR_YELLOW, -1);
+ init_pair(BLUE, COLOR_BLUE, -1);
+ init_pair(MAGENTA, COLOR_MAGENTA, -1);
+ init_pair(CYAN, COLOR_CYAN, -1);
+
+ restart:
+ while (true) {
+ // generate a grid where each element is unique from its direct neighbors
+ for (int x = 0; x < X; x++) {
+ for (int y = 0; y < Y; y++) {
+ newgem((struct coord){x, y});
+ }
+ }
+
+ first = invc;
+
+ while (true) {
+ display();
+
+
+ switch (getch()) {
+ case 'r':
+ goto restart;
+ case KEY_MOUSE:;
+ MEVENT e;
+ if (getmouse(&e) != OK) break;
+
+ // get and validate x and y coords
+ if (e.x % 4 == 0 || e.y % 2 == 0) break;
+ int x = (e.x - 2) / 4;
+ int y = (e.y - 1) / 2;
+ if ((e.x - 1) % 4 == 0) x++;
+ if (!valid(x, y)) break;
+
+ if (first.x == -1 && first.y == -1) {
+ first.x = x;
+ first.y = y;
+ break;
+ }
+
+ if (first.x == x && first.y == y) {
+ first = invc;
+ break;
+ }
+
+ if (abs(first.x - x) + abs(first.y - y) > 1) {
+ first = invc;
+ break;
+ }
+
+ // swap the gems and see what happens
+ enum gem t = grid[first.x][first.y];
+ grid[first.x][first.y] = grid[x][y];
+ grid[x][y] = t;
+
+ struct coord vc[Y];
+ int v = checkvert(x, y, vc);
+ struct coord hc[X];
+ int h = checkhoriz(x, y, hc);
+
+ if (v >= 3) {
+ first = invc;
+ sort(vc, v);
+ makepop(vc, v);
+ display();
+ napms(MATCH_DELAY);
+ shift(vc, v);
+
+ score += 1000;
+ v -= 3;
+ score += 2000*v;
+ } else if (h >= 3) {
+ first = invc;
+ makepop(hc, h);
+ display();
+ napms(MATCH_DELAY);
+ shift(hc, h);
+
+ score += 1000;
+ h -= 3;
+ score += 2000*h;
+ } else {
+ // no matches
+ struct coord c = first;
+ first.x = x;
+ first.y = y;
+ display();
+ napms(BAD_MATCH_DELAY);
+ first = c;
+ enum gem t = grid[first.x][first.y];
+ grid[first.x][first.y] = grid[x][y];
+ grid[x][y] = t;
+
+ first = invc;
+ }
+
+ // hacky, ugly way to clear all gems
+ int nc;
+ do {
+ nc = 0;
+
+ for (int nx = 0; nx < X; nx++) {
+ for (int ny = 0; ny < Y; ny++) {
+ struct coord vc[Y];
+ int v = checkvert(nx, ny, vc);
+ struct coord hc[X];
+ int h = checkhoriz(nx, ny, hc);
+ if (v >= 3) {
+ nc += v;
+
+ sort(vc, v);
+ makepop(vc, v);
+ display();
+ napms(750);
+ shift(vc, v);
+
+ score += 1000;
+ v -= 3;
+ score += 2000*v;
+ } else if (h >= 3) {
+ nc += h;
+
+ makepop(hc, h);
+ display();
+ napms(750);
+ shift(hc, h);
+
+ score += 1000;
+ h -= 3;
+ score += 2000*h;
+ }
+ }
+ }
+ } while (nc != 0);
+ break;
+ case 'q':
+ goto terminate;
+ }
+ }
+ }
+
+ terminate:
+ echo();
+ curs_set(1);
+ endwin();
+}