Thumbnail

rani/games.git

Clone URL: https://git.buni.party/rani/games.git

Viewing file on branch master

1#include <stdlib.h>
2#include <ncurses.h>
3#include <stdbool.h>
4
5
6/* BEGIN CONFIG */
7#ifndef SEED
8#include <time.h>
9#define SEED time(NULL)
10#endif /* SEED */
11/* END CONFIG */
12
13
14#define X COLS
15#define Y LINES
16
17#define N_PIPES (X / 30)
18#define OPENING (Y / 8)
19#define JUMP (Y / 14)
20
21
22enum {
23 YELLOW = 1,
24 GREEN,
25};
26
27
28enum state {
29 GAME_OVER = 0,
30 RUNNING = 1,
31};
32
33
34struct coord {
35 int x, y;
36};
37
38
39int nlen(int n) {
40 int len = 1;
41 while (n > 0) {
42 len++;
43 n /= 10;
44 }
45 return len;
46}
47
48
49int rrand(int hi, int lo) {
50 return rand() % (hi - lo + 1) + lo;
51}
52
53
54int main() {
55 srand(SEED);
56
57 initscr();
58 noecho();
59 curs_set(0);
60
61 timeout(0);
62
63 use_default_colors();
64 start_color();
65 init_pair(YELLOW, COLOR_YELLOW, -1);
66 init_pair(GREEN, COLOR_GREEN, -1);
67
68 while (true) {
69 struct coord bird = {X / (N_PIPES+1), (Y - 1) / 2};
70 int last_movement = 0;
71
72 struct coord pipes[N_PIPES];
73 for (int i = 0; i < N_PIPES; i++) {
74 pipes[i] = (struct coord){X / (N_PIPES+1) + ((X / (N_PIPES+1)) * (i + 1)), rrand(Y-OPENING/2, OPENING/2)};
75 }
76 int curpipe = 0;
77
78 int score = 0;
79
80 enum state state = RUNNING;
81 while (state == RUNNING) {
82 erase();
83
84 move(bird.y, bird.x);
85 attron(COLOR_PAIR(YELLOW));
86 addch('@');
87 attroff(COLOR_PAIR(YELLOW));
88
89 attron(COLOR_PAIR(GREEN));
90 for (int i = 0; i < N_PIPES; i++) {
91 // create the top half of the pipe
92 for (int y = 0; y < pipes[i].y - OPENING / 2; y++) {
93 for (int x = -1; x <= 1; x++) {
94 move(y, pipes[i].x + x);
95 addch('#');
96 }
97 }
98
99 // bottom half
100 for (int y = pipes[i].y + OPENING / 2; y < Y; y++) {
101 for (int x = -1; x <= 1; x++) {
102 move(y, pipes[i].x + x);
103 addch('#');
104 }
105 }
106 }
107 attroff(COLOR_PAIR(GREEN));
108
109 move(0, 0);
110 printw("Score: %d", score);
111
112 refresh();
113
114 // check bird position
115 if (bird.y >= Y) {
116 state = GAME_OVER;
117 break;
118 }
119
120 int px, py;
121 px = pipes[curpipe].x;
122 py = pipes[curpipe].y;
123 if (bird.x >= px - 1 && bird.x <= px + 1 && (bird.y < py - OPENING / 2 || bird.y > py + OPENING / 2)) {
124 state = GAME_OVER;
125 break;
126 } else if (bird.x == pipes[curpipe].x + 1) {
127 score++;
128
129 pipes[curpipe] = (struct coord){X / (N_PIPES+1) + ((X / (N_PIPES+1)) * N_PIPES), rrand(Y-OPENING/2, OPENING/2)};
130
131 curpipe++;
132 if (curpipe >= N_PIPES) curpipe = 0;
133 }
134
135 switch (getch()) {
136 case ' ':
137 last_movement = 0;
138 if (bird.y == 0) break;
139 bird.y -= JUMP;
140
141 if (bird.y < 0) bird.y = 0;
142 break;
143 case 'q':
144 case KEY_RESIZE:
145 goto terminate;
146 break;
147 default:
148 break;
149 }
150
151
152 // move everything now
153 bird.y += ++last_movement / 3;
154
155 for (int i = 0; i < N_PIPES; i++) {
156 pipes[i].x--;
157 }
158
159 napms(100);
160 }
161
162 timeout(-1);
163 switch (state) {
164 case GAME_OVER:
165 attron(A_REVERSE);
166 move(Y / 2, X / 2 - 5);
167 addstr("Game Over!");
168 move(Y / 2 + 1, (X - nlen(score)) / 2 - 6);
169 printw("Final Score: %d", score);
170 attroff(A_REVERSE);
171 refresh();
172
173 napms(500);
174 if (getch() == 'q') goto terminate;
175 break;
176 default: break;
177 }
178 timeout(0);
179 }
180
181 terminate:
182 echo();
183 curs_set(1);
184 endwin();
185}
186