summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosias <justjosias@tutanota.com>2020-01-18 08:02:21 +0000
committerJosias <justjosias@tutanota.com>2020-01-18 08:02:21 +0000
commit568eca916cd47a9484152c222b09d4b899bac8eb (patch)
treefa480b73962cccf90e03d4f61d6d610da2a78a3c
Add basic program
-rw-r--r--Makefile2
-rw-r--r--blockbreak.c226
2 files changed, 228 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a1b8561
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+all:
+ $(CC) -std=c89 -lncurses -o blockbreak blockbreak.c
diff --git a/blockbreak.c b/blockbreak.c
new file mode 100644
index 0000000..58a053e
--- /dev/null
+++ b/blockbreak.c
@@ -0,0 +1,226 @@
+/*
+ * blockbreak - a simple ncurses game where you break blocks with a ball
+ *
+ */
+#include <ncurses.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+const int BLOCK_PADDING = 1;
+const int BLOCK_SIZE = 6;
+const int DELAY = 50000;
+const int PADDLE_SIZE = 10;
+const int PADDLE_SPEED = 10;
+
+struct block {
+ int size;
+ int x,y;
+};
+
+int kbhit()
+{
+ int ch = getch();
+
+ if (ch != ERR) {
+ ungetch(ch);
+ return 1;
+ } else
+ return 0;
+}
+
+void print_paddle(int size, int y, int x)
+{
+ int i;
+ for (i = 0; i < size; ++i)
+ mvprintw(y, x - i, "_");
+}
+
+void load_block(int size, int y, int x)
+{
+ int i;
+ for (i = 0; i < size; ++i) {
+ mvprintw(y, x - i, "=");
+ }
+}
+
+void decorations(int width, int height)
+{
+ int i;
+ for (i = 0; i < height; ++i)
+ mvprintw(i, 0, "|");
+ for (i = 0; i < height; ++i)
+ mvprintw(i, width - 1, "|");
+ for (i = 1; i + 1 < width; ++i)
+ mvprintw(0, i, "-");
+}
+
+/* Updates the panel of information */
+void refresh_score(int lives, int blocks, int y)
+{
+ char str_lives[3];
+ char str_blocks[3];
+
+ sprintf(str_lives, "%d", lives);
+ sprintf(str_blocks, "%d", blocks);
+ mvprintw(y, 1, "Lives:");
+ mvprintw(y, 9, str_lives);
+ mvprintw(y, 13, "Blocks:");
+ mvprintw(y, 25, str_blocks);
+}
+
+int main()
+{
+ int i,j,k;
+
+ srand(time(NULL));
+ int ball_next_x = 0, ball_next_y = 0;
+ int ball_direction_x = 0, ball_direction_y = 1;
+
+ int lives = 10;
+ int hits = 0;
+
+ initscr();
+ noecho();
+ nodelay(stdscr, TRUE);
+ curs_set(FALSE);
+
+ int max_y = 0, max_x = 0;
+ getmaxyx(stdscr, max_y, max_x);
+ int ball_x, paddle_x = max_x / 2 + PADDLE_SIZE / 2;
+ int ball_y = max_y - max_y / 4;
+
+ /* Generate blocks based on screen size */
+ int block_rows = max_y / 3;
+ int block_count = max_x / (BLOCK_SIZE + BLOCK_PADDING * 2);
+ const int BLOCKS = block_rows * block_count;
+ struct block blocks[BLOCKS];
+ k = 0;
+ for (i = 0; i < block_rows; ++i) {
+ for (j = 0; j < block_count; ++j) {
+ blocks[k].size = BLOCK_SIZE;
+ blocks[k].x = j * (BLOCK_SIZE + BLOCK_PADDING * 2) + 7;
+ blocks[k].y = i + 1;
+ k++;
+ }
+ }
+ int blocks_left = BLOCKS;
+
+ /* Main physics loop */
+ while (1) {
+ if (kbhit()) {
+ switch (getch()) {
+ case 'q':
+ endwin();
+ return 0;
+ case 'a':
+ if ((paddle_x - PADDLE_SPEED) > 0)
+ paddle_x -= PADDLE_SPEED;
+ else
+ paddle_x = PADDLE_SIZE;
+ break;
+ case 'd':
+ if ((paddle_x + PADDLE_SPEED) < max_x)
+ paddle_x += PADDLE_SPEED;
+ else
+ paddle_x = max_x - 1;
+ break;
+ }
+ }
+
+ clear();
+ decorations(max_x, max_y);
+ refresh_score(lives, blocks_left, max_y - 1);
+ print_paddle(PADDLE_SIZE, max_y - 2, paddle_x);
+ mvprintw(ball_y, ball_x, "o");
+ for (i = 0; i < BLOCKS; ++i)
+ if (blocks[i].size > 0)
+ load_block(BLOCK_SIZE, blocks[i].y, blocks[i].x);
+ refresh();
+
+ usleep(DELAY);
+
+ ball_next_x = ball_x + ball_direction_x;
+ ball_next_y = ball_y + ball_direction_y;
+
+ /* Check if the ball is going to hit the paddle */
+ if (ball_next_x > paddle_x - PADDLE_SIZE
+ && ball_next_x < paddle_x + 1
+ && ball_next_y >= max_y - 2) {
+ ball_direction_y *= -1;
+ ball_direction_x = rand() % 3 - 1;
+ hits++;
+ }
+
+ /* Check if the ball hits a block */
+ for (i = 0; i < BLOCKS; ++i) {
+ if (blocks[i].size == 0 || blocks[i].y != ball_next_y)
+ continue;
+ else if (ball_next_x > blocks[i].x || ball_next_x < blocks[i].x - BLOCK_SIZE)
+ continue;
+ else {
+ blocks[i].size = 0;
+ ball_direction_y *= -1;
+ blocks_left--;
+ break;
+ }
+ }
+
+ /* Check if the ball is going to hit an edge */
+ if (ball_next_x >= max_x - 1 || ball_next_x < 1)
+ ball_direction_x *= -1;
+ else
+ ball_x += ball_direction_x;
+
+ if (ball_next_y >= max_y - 1 || ball_next_y < 1)
+ ball_direction_y *= -1;
+ else
+ ball_y += ball_direction_y;
+
+ /* Check if the ball gets past the paddle */
+ if (ball_next_y > max_y - 2) {
+ lives -= 1;
+ sleep(1);
+ if (lives == 0)
+ break;
+ ball_x = max_x / 2;
+ ball_y = max_y - max_y / 4;
+ paddle_x = max_x / 2 + PADDLE_SIZE / 2;
+ ball_direction_y = 1;
+ ball_direction_x = 0;
+ }
+
+ /* Check if all the blocks are destroyed */
+ if (blocks_left == 0)
+ break;
+
+ /* Rescue ball if ball leaves board for some reason */
+ if (ball_y > max_y || ball_y < 0 || ball_x > max_x || ball_x < 0) {
+ ball_x = max_x / 2;
+ ball_y = max_y / 2;
+ paddle_x = max_x / 2 + PADDLE_SIZE / 2;
+ ball_direction_y = 1;
+ ball_direction_x = 0;
+ sleep(1);
+ }
+ }
+
+ int won;
+ if (blocks_left == 0) {
+ won = 1;
+ mvprintw(max_y / 2, max_x / 2 - 4, "YOU WIN!");
+ } else {
+ won = 0;
+ mvprintw(max_y / 2, max_x / 2 - 5, "GAME OVER!");
+ }
+ mvprintw(max_y / 2 + 1, max_x / 2 - 8, "press \'q\' to quit");
+ refresh();
+ while (getchar() != 'q');
+ endwin();
+ if (won)
+ printf("YOU WON! You broke all %d blocks!\n", BLOCKS);
+ else
+ printf("GAME OVER. You broke %d blocks!\n", BLOCKS - blocks_left);
+ return 0;
+}