]> git.armaanb.net Git - pong.git/blob - pong.c
Sleep during loops
[pong.git] / pong.c
1 #include <ncurses.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6 #include <sys/select.h>
7 #include <time.h>
8 #include <math.h>
9
10 int
11 die(int code)
12 {
13         endwin();
14         exit(code);
15 }
16
17 int
18 randslope(void)
19 {
20         const int low = 2;
21         const int high = 10;
22         return (rand() % (high - low + 1)) + low;
23 }
24
25 double
26 randspeed(void)
27 {
28         const int low = 1;
29         const int high = 2;
30         return ((rand() % (high - low + 1)) + low) / 100.0;
31 }
32
33 int
34 randsign(void)
35 {
36         return pow(-1, rand());
37 }
38
39 void
40 msleep(void)
41 {
42         struct timeval timeout;
43         timeout.tv_usec = 10000;
44         select(NULL, NULL, NULL, NULL, &timeout); // Sleep 100 ms
45 }
46
47 int
48 main(void) {
49         srand((unsigned int)time(NULL));
50         int max_y, max_x, max_y_new, max_x_new;
51         int a_score = 0, b_score = 0;
52         int slope_x = randslope();
53         int index_dir = randsign();
54         int direction = randsign();
55         double speed = randspeed();
56         struct timeval start, stop;
57
58         // Initialize curses
59         initscr();
60         noecho();
61         curs_set(0);
62         nodelay(stdscr, 1); // Don't wait for getch input
63         getmaxyx(stdscr, max_y, max_x);
64         --max_x;
65         --max_y;
66         int y = max_y/2;
67         int x = max_x/2;
68         int pad_h = 0.2 * max_y;
69         int aoff = max_y / 2 - pad_h;
70         int boff = max_y / 2 - pad_h;
71
72         gettimeofday(&start, NULL);
73         while(1) {
74                 // Handle resizes
75                 getmaxyx(stdscr, max_y_new, max_x_new);
76                 --max_x_new;
77                 --max_y_new;
78                 pad_h = 0.2 * max_y;
79                 if (max_y_new != max_y || max_x_new != max_x) {
80                         clear();
81                         max_x = max_x_new;
82                         max_y = max_y_new;
83                 }
84
85                 // Parse keypresses
86                 int key = getch();
87                 if (key == 'q') {
88                         die(0);
89                 } else if (key == 'k') {
90                         if (boff < max_y - pad_h) boff += 2;
91                 } else if (key == 'i') {
92                         if (boff > 0) boff -= 2;
93                 } else if (key == 's') {
94                         if (aoff < max_y - pad_h) aoff += 2;
95                 } else if (key == 'w') {
96                         if (aoff > 0) aoff -= 2;
97                 } else if (key == 27) {
98                         while(1) {
99                                 key = getch();
100                                 mvprintw(0, 0, "PAUSED");
101                                 if (key == 27) {
102                                         clear();
103                                         break;
104                                 } else if (key == 'q') {
105                                         die(0);
106                                 }
107                                 msleep();
108                         }
109                 }
110
111                 // Clear screen
112                 for (int i = 0; i < max_y + 1; i++) {
113                         mvprintw(i, 0, " ");
114                         mvprintw(i, 1, " ");
115                         mvprintw(i, max_x, " ");
116                         mvprintw(i, max_x - 1, " ");
117                 }
118
119                 // Draw paddles
120                 for (int i = aoff; i < aoff + pad_h; i++) {
121                         mvprintw(i, 0, "|");
122                 }
123
124                 for (int i = boff; i < boff + pad_h; i++) {
125                         mvprintw(i, max_x, "|");
126                 }
127
128                 // Draw net
129                 for (int i = 0; i < max_y; i++) {
130                         mvprintw(i, max_x/2, ":");
131                 }
132
133                 // Draw scrores
134                 mvprintw(0, max_x/2 - 2, "%d", a_score);
135                 mvprintw(0, max_x/2 + 2, "%d", b_score);
136
137                 // Move ball if enough time has elapsed
138                 gettimeofday(&stop, NULL);
139                 if ((double)(stop.tv_usec - start.tv_usec) / 1000000 +
140                                 (double)(stop.tv_sec - start.tv_sec) > speed) {
141                         gettimeofday(&start, NULL);
142                         mvprintw(y, x, " ");
143                         x += direction;
144                         if (x % slope_x == 0) y += index_dir;
145                         mvprintw(y, x, "o");
146                 }
147
148                 if ((x >= max_x - 1 && y >= boff && y <= boff + pad_h) ||
149                                 (x <= 1 && y >= aoff && y <= aoff + pad_h)) {
150                         // Ball hits paddle
151
152                         /* Find the distance that the ball hits from the center of the padel and
153                                  accordingly adjust ball path */
154                         int poff = (x <= 1) ? aoff : boff;
155                         double fromc = (fabs(poff + 0.5 * pad_h - y) / 2);
156                         slope_x /= (abs(slope_x) > 25) ? 2 : fromc;
157                         slope_x = (slope_x < 2) ? 2 : slope_x;
158
159                         direction *= -1;
160                         x += direction;
161                         speed *= 0.9;
162                 } else if (x >= max_x - 1 || x <= 1) {
163                         // Ball goes out of bounds
164                         if (x <= 1) {
165                                 b_score += 1;
166                                 mvprintw(0, 0, "PLAYER B SCORES");
167                         } else {
168                                 a_score += 1;
169                                 mvprintw(0, 0, "PLAYER A SCORES");
170                         }
171                         refresh();
172
173                         // Reset to default values
174                         x = max_x/2;
175                         y = max_y / 2;
176                         slope_x = randslope();
177                         index_dir = randsign();
178                         speed = randspeed();
179                         aoff = max_y / 2 - pad_h;
180                         boff = max_y / 2 - pad_h;
181
182                         sleep(1);
183                         clear();
184                 } else if (y == 0 || y == max_y) {
185                         // Ball hits top or bottom wall
186                         index_dir *= -1;
187                         mvprintw(y, x, " ");
188                         y = (y == max_y) ? max_y - 1 : 1;
189                 }
190                 msleep();
191         }
192 }