pong.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include <ncurses.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #define BALL_SYMBOL "O"
  5. #define BORDER "#"
  6. #define PADDLE "||"
  7. struct Ball {
  8. int px, py, dx, dy;
  9. };
  10. struct Paddle {
  11. int px, py, length;
  12. };
  13. int main(void) {
  14. int sleep_time = 20000;
  15. int time = 0;
  16. int hits = 0, misses = 0, best = 0, streak = 0, quit = 0, frame = 1, left_score = 0, right_score = 0;
  17. int max_y, max_x;
  18. struct Ball ball;
  19. struct Paddle paddle1, paddle2;
  20. int i;
  21. system("clear");
  22. initscr();
  23. curs_set(0);
  24. cbreak();
  25. noecho();
  26. nodelay(stdscr, 1);
  27. start_color();
  28. init_pair(1, COLOR_CYAN, COLOR_BLACK);
  29. init_pair(2, COLOR_YELLOW, COLOR_BLACK);
  30. init_pair(3, COLOR_GREEN, COLOR_BLACK);
  31. getmaxyx(stdscr, max_y, max_x);
  32. // Initialize ball
  33. ball.py = max_y / 2;
  34. ball.px = max_x / 2;
  35. ball.dy = rand() & 1 ? 1 : -1;
  36. ball.dx = rand() & 1 ? 1 : -1;
  37. // Initialize paddles
  38. paddle1.length = 6;
  39. paddle1.py = (max_y / 2) - (paddle1.length / 2);
  40. paddle1.px = max_x - 3;
  41. paddle2.length = 6;
  42. paddle2.py = (max_y / 2) - (paddle2.length / 2);
  43. paddle2.px = 1;
  44. // Game loop
  45. while (!quit) {
  46. getmaxyx(stdscr, max_y, max_x);
  47. // Timer
  48. if (frame % (1000000 / sleep_time) == 0) {
  49. time++;
  50. }
  51. // Draw stats
  52. mvprintw(0, 0, "Hits: %d Misses: %d Streak: %d Best: %d Time: %d | Score left: %d Score right: %d | ",
  53. hits, misses, streak, best, time, left_score, right_score);
  54. // Draw controls
  55. mvprintw(max_y - 1, 0, "Controls: left up -> \',\' left down -> \'o\'; right up -> \'r\' right down -> \'n\'; speed up -> \'f\' slow down -> \'s\'; quit -> \'Q\'");
  56. // Draw borders
  57. attron(COLOR_PAIR(3));
  58. for (i = 0; i < max_x; i++) {
  59. mvprintw(1, i, BORDER);
  60. mvprintw(max_y - 2, i, BORDER);
  61. }
  62. attroff(COLOR_PAIR(3));
  63. // Clear old paddles
  64. for (i = 2; i < max_y - 2; i++) {
  65. mvprintw(i, paddle1.px, " ");
  66. mvprintw(i, paddle2.px, " ");
  67. }
  68. // Draw paddles
  69. attron(COLOR_PAIR(1));
  70. for (i = 0; i < paddle1.length; i++) {
  71. mvprintw(paddle1.py + i, paddle1.px, PADDLE);
  72. }
  73. for (i = 0; i < paddle2.length; i++) {
  74. mvprintw(paddle2.py + i, paddle2.px, PADDLE);
  75. }
  76. attroff(COLOR_PAIR(1));
  77. // Clear previous ball position
  78. mvprintw(ball.py, ball.px, " ");
  79. // Ball collisions
  80. if ((ball.py + ball.dy) < 2 || (ball.py + ball.dy) > max_y - 3) {
  81. ball.dy *= -1;
  82. }
  83. // Right paddle collision (Player 1)
  84. if ((ball.px + ball.dx == paddle1.px) &&
  85. (ball.py + ball.dy >= paddle1.py) &&
  86. (ball.py + ball.dy < paddle1.py + paddle1.length)) {
  87. hits++;
  88. streak++;
  89. if (streak > best) best = streak;
  90. ball.dx *= -1;
  91. }
  92. // Left paddle collision (Player 2)
  93. if ((ball.px + ball.dx == paddle2.px + 1) &&
  94. (ball.py + ball.dy >= paddle2.py) &&
  95. (ball.py + ball.dy < paddle2.py + paddle2.length)) {
  96. hits++;
  97. streak++;
  98. if (streak > best) best = streak;
  99. ball.dx *= -1;
  100. }
  101. // Ball goes past right paddle
  102. if (ball.px > max_x) {
  103. left_score++;
  104. misses++;
  105. streak = 0;
  106. ball.py = max_y / 2;
  107. ball.px = max_x / 2;
  108. ball.dy = rand() & 1 ? 1 : -1;
  109. ball.dx = rand() & 1 ? 1 : -1;
  110. }
  111. // Ball goes past Player 2's paddle (left side)
  112. if (ball.px < 1) {
  113. right_score++;
  114. misses++;
  115. streak = 0;
  116. ball.py = max_y / 2;
  117. ball.px = max_x / 2;
  118. ball.dy = rand() & 1 ? 1 : -1;
  119. ball.dx = rand() & 1 ? 1 : -1;
  120. }
  121. // Ball movement
  122. if (frame % 4 == 0) {
  123. ball.py += ball.dy;
  124. ball.px += ball.dx;
  125. }
  126. // Draw ball
  127. attron(COLOR_PAIR(2));
  128. mvprintw(ball.py, ball.px, BALL_SYMBOL);
  129. attroff(COLOR_PAIR(2));
  130. // Input
  131. switch (getch()) {
  132. case 'r': // Player 1 up
  133. if (paddle1.py > 2) paddle1.py -= 1;
  134. break;
  135. case 'n': // Player 1 down
  136. if (paddle1.py + paddle1.length < max_y - 2) paddle1.py += 1;
  137. break;
  138. case ',': // Player 2 up
  139. if (paddle2.py > 2) paddle2.py -= 1;
  140. break;
  141. case 'o': // Player 2 down
  142. if (paddle2.py + paddle2.length < max_y - 2) paddle2.py += 1;
  143. break;
  144. case 'f': // Speed up
  145. if (sleep_time > 1000) {
  146. sleep_time -= 1000;
  147. }
  148. break;
  149. case 's': // Slow down
  150. if (sleep_time < 30000) {
  151. sleep_time += 1000;
  152. }
  153. break;
  154. case 'Q':
  155. quit = 1;
  156. break;
  157. }
  158. frame++;
  159. usleep(sleep_time);
  160. }
  161. // Exit
  162. endwin();
  163. system("clear");
  164. return 0;
  165. }