Text Gaming
COP-3223H
Table of Contents
Non-canonical input
noncanon.c
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <termios.h> /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } int main (void) { char c; set_input_mode (); while (1) { read (STDIN_FILENO, &c, 1); if (c == '\004') /* C-d */ break; else write (STDOUT_FILENO, &c, 1); } return EXIT_SUCCESS; }
Example: rot13
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <termios.h> /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } int main (void) { char c; set_input_mode (); while (1) { read (STDIN_FILENO, &c, 1); if ('A' <= c && c <= 'Z') { c = (((c - 'A') + 13) % ('Z' - 'A' + 1)) + 'A'; } if ('a' <= c && c <= 'z') { c = (((c - 'a') + 13) % ('z' - 'a' + 1)) + 'a'; } if (c == '\004') /* C-d */ break; else write (STDOUT_FILENO, &c, 1); } return EXIT_SUCCESS; }
State machines
chase.c
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor int width = 40; int height = 20; // player data // 0 1 2 enum { vulnerable, invincible, dead }; int player_state = vulnerable; int player_x = width / 2; int player_y = height / 2; // enemy data int enemy_x = 1; int enemy_y = 1; enum { chasing, running, defeated }; int enemy_state = chasing; // potion data int potion_x = 29; int potion_y = 11; int random = 1; enum { available, using, done }; int potion_state = available; int potion_counter = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // 0 available // 1 using // 2 done // initial state is 0 // switch (potion_state) { // case 0: // } switch (potion_state) { case available: printf("\033[%d;%dH", potion_y, potion_x); printf("/\\"); printf("\033[%d;%dH", potion_y + 1, potion_x); printf("\\/"); break; case using: // intentionally empty break; } printf("\033[%d;%dH", enemy_y, enemy_x); switch (enemy_state) { case chasing: // case 0: putchar('@'); break; case running: // case 1: putchar('@'); break; case defeated: // case 2: putchar('X'); } printf("\033[%d;%dH", player_y, player_x); switch (player_state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } /* // debugging output */ /* printf("\033[%d;%dH", height + 1, 0); */ /* printf("player_y: %d\n", player_y); */ /* printf("player_x: %d\n", player_x); */ /* printf("enemy_y: %d\n", enemy_y); */ /* printf("enemy_x: %d\n", enemy_x); */ /* printf("potion_y: %d\n", potion_y); */ /* printf("potion_x: %d\n", potion_x); */ // read input int direction_x = 0; int direction_y = 0; bool valid = true; do { char c = '\0'; scanf("%c", &c); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: valid = false; break; } } while (! valid); switch(player_state) { case vulnerable: // case 0: player_x += direction_x; player_y += direction_y; break; case invincible: // case 1: player_x += direction_x; player_y += direction_y; if (enemy_x - 1 <= player_x && player_x <= enemy_x + 1 && enemy_y - 1 <= player_y && player_y <= enemy_y + 1) { player_state = vulnerable; enemy_state = defeated; potion_state = done; } break; } switch (enemy_state) { case chasing: // chasing if (player_x > enemy_x) { enemy_x += 1; } if (player_x < enemy_x) { enemy_x -= 1; } if (player_y > enemy_y) { enemy_y += 1; } if (player_y < enemy_y) { enemy_y -= 1; } if ((player_x == enemy_x || player_x == enemy_x + 1) && (player_y == enemy_y || player_y == enemy_y + 1)) { player_state = dead; } break; case running: if (player_x > enemy_x) { enemy_x -= 1; } if (player_x < enemy_x) { enemy_x += 1; } if (player_y > enemy_y) { enemy_y -= 1; } if (player_y < enemy_y) { enemy_y += 1; } if (enemy_x < 0) { enemy_x = 0; } if (enemy_x > width) { enemy_x = width; } if (enemy_y < 0) { enemy_y = 0; } if (enemy_y > height) { enemy_y = height; } break; } switch (potion_state) { case available: if ((player_x == potion_x || player_x == potion_x + 1) && (player_y == potion_y || player_y == potion_y + 1)) { player_state = invincible; enemy_state = running; potion_state = using; potion_counter = 10; } break; case using: potion_counter -= 1; if (potion_counter == 1) { player_state = vulnerable; enemy_state = chasing; potion_state = available; random = (random * 97) % 65533; potion_x = random % width; random = (random * 97) % 65533; potion_y = random % height; } break; } } }
term.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdbool.h> #include <termios.h> // https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } // https://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input bool kbhit() { struct timeval tv = { 0L, 0L }; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); if (select(1, &fds, NULL, NULL, &tv) == 1) { return true; } else { return false; } } int getch() { int r; unsigned char c; do { if ((r = read(0, &c, sizeof(c))) < 0) { return '\0'; // null character on error } } while (r < 1); // ensures read returns one character return c; }
Sprite Arrays
Example ascii art
/\ \/
Example array
int potion_sprite_width = 2; int potion_sprite_height = 2; char potion_sprite[2][2] = { { '/', '\\' }, { '\\', '/' } }
Another example array
int potion_sprite_width = 2; int potion_sprite_height = 3; char potion_sprite[3][2] = { { 'w', 'w' }, { '|', '|' }, { '/', '\\' } };
Drawing the array
for (int j = 0; j < potion_sprite_height; j++) { printf("\033[%d;%dH", potion_y + j, potion_x); for (int i = 0; i < potion_sprite_width; i++) { putchar(potion_sprite[j][i]); } }
In-class coding
/* int potion_sprite_width = 2; */ /* int potion_sprite_height = 2; */ /* // y x */ /* // 0 0 */ /* // 0 1 */ /* // 1 0 */ /* // 1 1 */ /* char potion_sprite[2][2] = { { '/', '\\' }, */ /* { '\\', '/' } }; */ int potion_sprite_width = 2; int potion_sprite_height = 3; char potion_sprite[3][2] = { { 'w', 'w' }, { '|', '|' }, { '/', '\\' } }; /* escape characters backlash is the escape character \n \0134 */ int sprite_x = 10; int sprite_y = 30; // how we move to y, x coordinates // j, i position within the array // y, x position on the screen // 0, 1 for (int j = 0; j < potion_sprite_height; j++) { // 0, 1 for (int i = 0; i < potion_sprite_width; i++) { int x = sprite_x + i; int y = sprite_y + j; // positioning the cursor printf("\033[%d;%dH", y, x); /* printing each y, x element of the array */ putchar(potion_sprite[j][i]); } } // y x // 1 1 // 1 2 // 2 1 // 2 2 printf("\n"); exit(1);
Chase
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor /* int potion_sprite_width = 2; */ /* int potion_sprite_height = 2; */ /* char potion_sprite[2][2] = { { '/', '\\' }, */ /* /* { '\\', '/' } }; *\/ */ /* int potion_sprite_width = 4; */ /* int potion_sprite_height = 3; */ /* char potion_sprite[4][3] = { { 0x6C, 0x6B }, */ /* { 0x6D, 0x6A } }; */ int potion_sprite_width = 2; int potion_sprite_height = 3; char potion_sprite[3][2] = { { 'w', 'w' }, { '|', '|' }, { '/', '\\' } }; int width = 40; int height = 20; // player data // 0 1 2 enum { vulnerable, invincible, dead }; int player_state = vulnerable; int player_x = width / 2; int player_y = height / 2; // enemy data int enemy_x = 1; int enemy_y = 1; enum { chasing, running, defeated }; int enemy_state = chasing; // potion data int potion_x = 29; int potion_y = 11; int random = 1; enum { available, using, done }; int potion_state = available; int potion_counter = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); switch (potion_state) { case available: /* printf("\e(0"); */ for (int j = 0; j < potion_sprite_height; j++) { printf("\033[%d;%dH", potion_y + j, potion_x); for (int i = 0; i < potion_sprite_width; i++) { putchar(potion_sprite[j][i]); } } /* printf("\e(B\n"); */ /* printf("\033[%d;%dH", potion_y, potion_x); */ /* printf("/\\"); */ /* printf("\033[%d;%dH", potion_y + 1, potion_x); */ /* printf("\\/"); */ break; case using: // intentionally empty break; } printf("\033[%d;%dH", enemy_y, enemy_x); switch (enemy_state) { case chasing: // case 0: putchar('@'); break; case running: // case 1: putchar('@'); break; case defeated: // case 2: putchar('X'); } printf("\033[%d;%dH", player_y, player_x); switch (player_state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } /* // debugging output */ /* printf("\033[%d;%dH", height + 1, 0); */ /* printf("player_y: %d\n", player_y); */ /* printf("player_x: %d\n", player_x); */ /* printf("enemy_y: %d\n", enemy_y); */ /* printf("enemy_x: %d\n", enemy_x); */ /* printf("potion_y: %d\n", potion_y); */ /* printf("potion_x: %d\n", potion_x); */ // read input int direction_x = 0; int direction_y = 0; bool valid = true; do { char c = '\0'; scanf("%c", &c); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: valid = false; break; } } while (! valid); switch(player_state) { case vulnerable: // case 0: player_x += direction_x; player_y += direction_y; break; case invincible: // case 1: player_x += direction_x; player_y += direction_y; if (enemy_x - 1 <= player_x && player_x <= enemy_x + 1 && enemy_y - 1 <= player_y && player_y <= enemy_y + 1) { player_state = vulnerable; enemy_state = defeated; potion_state = done; } break; } switch (enemy_state) { case chasing: // chasing if (player_x > enemy_x) { enemy_x += 1; } if (player_x < enemy_x) { enemy_x -= 1; } if (player_y > enemy_y) { enemy_y += 1; } if (player_y < enemy_y) { enemy_y -= 1; } if ((player_x == enemy_x || player_x == enemy_x + 1) && (player_y == enemy_y || player_y == enemy_y + 1)) { player_state = dead; } break; case running: if (player_x > enemy_x) { enemy_x -= 1; } if (player_x < enemy_x) { enemy_x += 1; } if (player_y > enemy_y) { enemy_y -= 1; } if (player_y < enemy_y) { enemy_y += 1; } if (enemy_x < 0) { enemy_x = 0; } if (enemy_x > width) { enemy_x = width; } if (enemy_y < 0) { enemy_y = 0; } if (enemy_y > height) { enemy_y = height; } break; } switch (potion_state) { case available: if ((player_x == potion_x || player_x == potion_x + 1) && (player_y == potion_y || player_y == potion_y + 1)) { player_state = invincible; enemy_state = running; potion_state = using; potion_counter = 10; } break; case using: potion_counter -= 1; if (potion_counter == 1) { player_state = vulnerable; enemy_state = chasing; potion_state = available; random = (random * 97) % 65533; potion_x = random % width; random = (random * 97) % 65533; potion_y = random % height; } break; } } }
Background Arrays
Same idea as sprite arrays
Plain text file to
.carray generator python script:wget https://www.cs.ucf.edu/~gazzillo/teaching/cop3223hspring26/livedemos/full_game/background.py python3 background.py < background.array > background.c
- Turn off word wrapping to make working with large background text files easier
- Press Alt-x, then type toggle-truncate-lines and hit Enter.
Example: larger screen
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor /* int potion_sprite_width = 2; */ /* int potion_sprite_height = 2; */ /* char potion_sprite[2][2] = { { '/', '\\' }, */ /* /* { '\\', '/' } }; *\/ */ /* int potion_sprite_width = 4; */ /* int potion_sprite_height = 3; */ /* char potion_sprite[4][3] = { { 0x6C, 0x6B }, */ /* { 0x6D, 0x6A } }; */ int potion_sprite_width = 2; int potion_sprite_height = 2; char potion_sprite[2][2] = { { 'w', 'w' }, { '\\', '/' } }; int width = 40; int height = 20; int background_rows = 21; int background_cols = 41; char background[21][41] = { { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',}, { ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '_', '_', '-', '-', '-', '-', '/', ' ', ' ', ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', ' ', '_', '-', '-', '/',}, { ' ', ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '/', ' ', ' ','\\', '-', '-', '/', ' ', ' ', ' ', ' ', ' ','\\', '_', '_', '/','\\', '-', '-', '_', '_', '/','\\', '/', ' ','\\', '/', ' ',}, { ' ', ' ', ' ','\\', '_', '_', '/','\\', '-', '-', '_', '_', '/', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '_', '/','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '/', '-', '-', '-','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '_', '_', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', '_', '_', '_', '_', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', '/', '-', '-', '-', '-','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ','\\', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', '|', '_', '_', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '_', '/','\\', ' ', ' ', ' ', ' ', ' ', '/','\\', '_', ' ', ' ', ' ', ' ',}, { ' ', '_', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '/', '-', '-', '-','\\', '_', '_', '_', '/', '-', '-', '-','\\', ' ', ' ', '_',}, { ' ', '-','\\', ' ', ' ', ' ', ' ', '_', '_', ' ', ' ', '/','\\', ' ', ' ', ' ', ' ', ' ', ' ', '/','\\', ' ', ' ', '_', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-','\\', '/', '-',}, { ' ', '-', '-','\\', ' ', ' ', '/', '-', '-','\\', '/', '-', '-','\\', ' ', ' ', ' ', ' ', '/', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { ' ', '-', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-','\\', ' ', ' ', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { ' ', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { ' ', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',}, }; // player data // 0 1 2 enum { vulnerable, invincible, dead }; int player_state = vulnerable; int player_x = width / 2; int player_y = height / 2; // enemy data int enemy_x = 2; int enemy_y = 2; enum { chasing, running, defeated }; int enemy_state = chasing; // potion data int potion_x = 29; int potion_y = 11; int random = 1; enum { available, using, done }; int potion_state = available; int potion_counter = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // draw background background_rows = 21; background_cols = 41; background[21][41]; for (int j = 1; j < background_rows; j++) { printf("\033[%d;%dH", j, 1); for (int i = 1; i < background_cols; i++) { putchar(background[j][i]); } } switch (potion_state) { case available: /* printf("\e(0"); */ for (int j = 0; j < potion_sprite_height; j++) { printf("\033[%d;%dH", potion_y + j, potion_x); for (int i = 0; i < potion_sprite_width; i++) { putchar(potion_sprite[j][i]); } } /* printf("\e(B\n"); */ /* printf("\033[%d;%dH", potion_y, potion_x); */ /* printf("/\\"); */ /* printf("\033[%d;%dH", potion_y + 1, potion_x); */ /* printf("\\/"); */ break; case using: // intentionally empty break; } printf("\033[%d;%dH", enemy_y, enemy_x); switch (enemy_state) { case chasing: // case 0: putchar('@'); break; case running: // case 1: putchar('@'); break; case defeated: // case 2: putchar('X'); } printf("\033[%d;%dH", player_y, player_x); switch (player_state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } /* // debugging output */ /* printf("\033[%d;%dH", height + 1, 0); */ /* printf("player_y: %d\n", player_y); */ /* printf("player_x: %d\n", player_x); */ /* printf("enemy_y: %d\n", enemy_y); */ /* printf("enemy_x: %d\n", enemy_x); */ /* printf("potion_y: %d\n", potion_y); */ /* printf("potion_x: %d\n", potion_x); */ // read input int direction_x = 0; int direction_y = 0; bool valid = true; do { char c = '\0'; scanf("%c", &c); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: valid = false; break; } } while (! valid); switch(player_state) { case vulnerable: // case 0: player_x += direction_x; player_y += direction_y; break; case invincible: // case 1: player_x += direction_x; player_y += direction_y; if (enemy_x - 1 <= player_x && player_x <= enemy_x + 1 && enemy_y - 1 <= player_y && player_y <= enemy_y + 1) { player_state = vulnerable; enemy_state = defeated; potion_state = done; } break; } switch (enemy_state) { case chasing: // chasing if (player_x > enemy_x) { enemy_x += 1; } if (player_x < enemy_x) { enemy_x -= 1; } if (player_y > enemy_y) { enemy_y += 1; } if (player_y < enemy_y) { enemy_y -= 1; } if ((player_x == enemy_x || player_x == enemy_x + 1) && (player_y == enemy_y || player_y == enemy_y + 1)) { player_state = dead; } break; case running: if (player_x > enemy_x) { enemy_x -= 1; } if (player_x < enemy_x) { enemy_x += 1; } if (player_y > enemy_y) { enemy_y -= 1; } if (player_y < enemy_y) { enemy_y += 1; } if (enemy_x < 0) { enemy_x = 0; } if (enemy_x > width) { enemy_x = width; } if (enemy_y < 0) { enemy_y = 0; } if (enemy_y > height) { enemy_y = height; } break; } switch (potion_state) { case available: if ((player_x == potion_x || player_x == potion_x + 1) && (player_y == potion_y || player_y == potion_y + 1)) { player_state = invincible; enemy_state = running; potion_state = using; potion_counter = 10; } break; case using: potion_counter -= 1; if (potion_counter == 1) { player_state = vulnerable; enemy_state = chasing; potion_state = available; random = (random * 97) % 65533; potion_x = random % width; random = (random * 97) % 65533; potion_y = random % height; } break; } } }
figlet
Use figlet to generate ascii art text banners.
See ls /usr/share/figlet for the names of fonts to pass to -f, e.g.,
figlet -f emboss hello
ASCII art to C array
wget https://www.cs.ucf.edu/~gazzillo/teaching/cop3223hspring26/livedemos/full_game/background.py python3 background.py < background.array > background.c
Side scrolling
Example: background scrolling
scroll_animate.c
#include <stdio.h> #include <stdbool.h> #include <unistd.h> int main(int argc, char **argv) { printf("\033[?25l"); // hide cursor #include "background.c" int scroll_x_offset = 0; int scroll_y_offset = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // draw background background_rows = 21; background_cols = 41; background[21][41]; for (int j = 1; j < background_rows; j++) { printf("\033[%d;%dH", j, 1); for (int i = 1; i < background_cols; i++) { // converting the character array position to an infinitely-sized screen int screen_y = (scroll_y_offset + j); int screen_x = (scroll_x_offset + i); // convert the screen position into a viewbox int viewbox_y = screen_y % background_rows; int viewbox_x = screen_x % background_cols; putchar(background[viewbox_y][viewbox_x]); } } scroll_x_offset = (scroll_x_offset + 1) % background_cols; fflush(stdout); usleep(80 * 1000); } }
#include <stdio.h> #include <stdbool.h> #include <unistd.h> int main(int argc, char **argv) { printf("\033[?25l"); // hide cursor #include "background.c" int scroll_x_offset = 0; int scroll_y_offset = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // draw background background_rows = 21; background_cols = 41; background[21][41]; for (int j = 1; j < background_rows; j++) { printf("\033[%d;%dH", j, 1); for (int i = 1; i < background_cols; i++) { putchar(background[(scroll_y_offset + j) % background_rows][(scroll_x_offset + i) % background_cols]); } } scroll_x_offset = (scroll_x_offset + 1) % background_cols; fflush(stdout); usleep(80 * 1000); } }
background.c
int background_rows = 21; int background_cols = 41; char background[21][41] = { { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',}, { ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '_', '_', '-', '-', '-', '-', '/', ' ', ' ', ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', ' ', '_', '-', '-', '/',}, { ' ', ' ','\\', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '/', ' ', ' ','\\', '-', '-', '/', ' ', ' ', ' ', ' ', ' ','\\', '_', '_', '/','\\', '-', '-', '_', '_', '/','\\', '/', ' ','\\', '/', ' ',}, { ' ', ' ', ' ','\\', '_', '_', '/','\\', '-', '-', '_', '_', '/', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '_', '/','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '/', '-', '-', '-','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ','\\', '_', '_', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', '_', '_', '_', '_', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', '/', '-', '-', '-', '-','\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ','\\', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', '|', '_', '_', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',}, { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '_', '/','\\', ' ', ' ', ' ', ' ', ' ', '/','\\', '_', ' ', ' ', ' ', ' ',}, { '_', '_', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '/', '-', '-', '-','\\', '_', '_', '_', '/', '-', '-', '-','\\', ' ', ' ', '_',}, { '-', '-','\\', ' ', ' ', ' ', ' ', '_', '_', ' ', ' ', '/','\\', ' ', ' ', ' ', ' ', ' ', ' ', '/','\\', ' ', ' ', '_', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-','\\', '/', '-',}, { '-', '-', '-','\\', ' ', ' ', '/', '-', '-','\\', '/', '-', '-','\\', ' ', ' ', ' ', ' ', '/', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { '-', '-', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-','\\', ' ', ' ', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-','\\', '/', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-',}, { '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',}, };
Asynchronous input
| Function | Description |
|---|---|
kbhit() |
Wait for keyboard input |
getch() |
Read the input |
Get term.c
From within your game source directory:
wget https://www.cs.ucf.edu/~gazzillo/teaching/cop3223hspring26/files/term.c
Waiting for input
Loop while there is no keyboard input
do { // draw screen, game logic, etc. } while (! kbhit());
Read the input
Read the character
c = getch();
Simple illustration
char c = 'a'; while (1) { do { // print a character until there is keyboard input putchar(c); fflush(stdout); usleep(80 * 1000); } while (! kbhit()); // until keyboard input // stop looping and read the character c = getch(); } // continue looping and printing the character
Full example
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); char c = 'a'; while (1) { do { putchar(c); fflush(stdout); usleep(80 * 1000); } while (! kbhit()); c = getch(); } }
Example: side scroller
term.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdbool.h> #include <termios.h> // https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example /* Use this variable to remember original terminal attributes. */ struct termios saved_attributes; void reset_input_mode (void) { tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); } void set_input_mode (void) { struct termios tattr; /* Make sure stdin is a terminal. */ if (!isatty (STDIN_FILENO)) { fprintf (stderr, "Not a terminal.\n"); exit (EXIT_FAILURE); } /* Save the terminal attributes so we can restore them later. */ tcgetattr (STDIN_FILENO, &saved_attributes); atexit (reset_input_mode); /* Set the funny terminal modes. */ tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr); } // https://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input bool kbhit() { struct timeval tv = { 0L, 0L }; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); if (select(1, &fds, NULL, NULL, &tv) == 1) { return true; } else { return false; } } int getch() { int r; unsigned char c; do { if ((r = read(0, &c, sizeof(c))) < 0) { return '\0'; // null character on error } } while (r < 1); // ensures read returns one character return c; }
Sprite collision detection
chase.c
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor int width = 40; int height = 20; // player data // 0 1 2 enum { vulnerable, invincible, dead }; int player_state = vulnerable; int player_x = width / 2; int player_y = height / 2; // enemy data int enemy_x = 1; int enemy_y = 1; enum { chasing, running, defeated }; int enemy_state = chasing; // potion data int potion_x = 29; int potion_y = 11; int random = 1; enum { available, using, done }; int potion_state = available; int potion_counter = 0; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // 0 available // 1 using // 2 done // initial state is 0 // switch (potion_state) { // case 0: // } switch (potion_state) { case available: printf("\033[%d;%dH", potion_y, potion_x); printf("/\\"); printf("\033[%d;%dH", potion_y + 1, potion_x); printf("\\/"); break; case using: // intentionally empty break; } printf("\033[%d;%dH", enemy_y, enemy_x); switch (enemy_state) { case chasing: // case 0: putchar('@'); break; case running: // case 1: putchar('@'); break; case defeated: // case 2: putchar('X'); } printf("\033[%d;%dH", player_y, player_x); switch (player_state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } // debugging output printf("\033[%d;%dH", height + 1, 0); printf("player_y: %d\n", player_y); printf("player_x: %d\n", player_x); printf("enemy_y: %d\n", enemy_y); printf("enemy_x: %d\n", enemy_x); printf("potion_y: %d\n", potion_y); printf("potion_x: %d\n", potion_x); // read input int direction_x = 0; int direction_y = 0; bool valid = true; do { char c = '\0'; scanf("%c", &c); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: valid = false; break; } } while (! valid); switch(player_state) { case vulnerable: // case 0: player_x += direction_x; player_y += direction_y; break; case invincible: // case 1: player_x += direction_x; player_y += direction_y; if (enemy_x - 1 <= player_x && player_x <= enemy_x + 1 && enemy_y - 1 <= player_y && player_y <= enemy_y + 1) { player_state = vulnerable; enemy_state = defeated; potion_state = done; } break; } switch (enemy_state) { case chasing: // chasing if (player_x > enemy_x) { enemy_x += 1; } if (player_x < enemy_x) { enemy_x -= 1; } if (player_y > enemy_y) { enemy_y += 1; } if (player_y < enemy_y) { enemy_y -= 1; } if ((player_x == enemy_x || player_x == enemy_x + 1) && (player_y == enemy_y || player_y == enemy_y + 1)) { player_state = dead; } break; case running: if (player_x > enemy_x) { enemy_x -= 1; } if (player_x < enemy_x) { enemy_x += 1; } if (player_y > enemy_y) { enemy_y -= 1; } if (player_y < enemy_y) { enemy_y += 1; } if (enemy_x < 0) { enemy_x = 0; } if (enemy_x > width) { enemy_x = width; } if (enemy_y < 0) { enemy_y = 0; } if (enemy_y > height) { enemy_y = height; } break; } switch (potion_state) { case available: if ((player_x == potion_x || player_x == potion_x + 1) && (player_y == potion_y || player_y == potion_y + 1)) { player_state = invincible; enemy_state = running; potion_state = using; potion_counter = 10; } break; case using: potion_counter -= 1; if (potion_counter == 1) { player_state = vulnerable; enemy_state = chasing; potion_state = available; random = (random * 97) % 65533; potion_x = random % width; random = (random * 97) % 65533; potion_y = random % height; } break; } } }
Background collision detection
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor int potion_sprite_width = 2; int potion_sprite_height = 2; char potion_sprite[2][2] = { { 'w', 'w' }, { '\\', '/' } }; int width = 40; int height = 20; #include "background.c" enum { vulnerable, invincible, dead }; int player_state = vulnerable; int player_x = width / 2; int player_y = height / 2; // enemy data int enemy_x = 2; int enemy_y = 2; enum { chasing, running, defeated }; int enemy_state = chasing; // potion data int potion_x = 29; int potion_y = 11; int random = 1; enum { available, using, done }; int potion_state = available; int potion_counter = 0; int scroll_x_offset = 0; int scroll_y_offset = 0; while (1) { do { printf("\x1b[2J"); printf("\x1b[H"); // draw background background_rows = 21; background_cols = 41; background[21][41]; for (int j = 1; j < background_rows; j++) { printf("\033[%d;%dH", j, 1); for (int i = 1; i < background_cols; i++) { putchar(background[(scroll_y_offset + j) % background_rows][(scroll_x_offset + i) % background_cols]); } } switch(player_state) { case vulnerable: if (' ' != background[scroll_y_offset + player_y][scroll_x_offset + player_x]) { player_state = dead; } // fall-through case invincible: scroll_x_offset = (scroll_x_offset + 1) % background_cols; break; case dead: break; } printf("\033[%d;%dH", player_y, player_x); switch (player_state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } fflush(stdout); usleep(80 * 1000); } while (! kbhit()); int direction_x = 0; int direction_y = 0; char c = getch(); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: break; } // do the actual movement in game loop and zero it out // make a ship-like sprite switch(player_state) { case vulnerable: // case 0: player_x += direction_x; player_y += direction_y; break; case invincible: // case 1: player_x += direction_x; player_y += direction_y; if (enemy_x - 1 <= player_x && player_x <= enemy_x + 1 && enemy_y - 1 <= player_y && player_y <= enemy_y + 1) { player_state = vulnerable; enemy_state = defeated; potion_state = done; } break; } } }
Gravity
gravity_bounce.c
#include <stdio.h> #include <unistd.h> int main(int argc, char **argv) { int height = 20; int width = 40; float y = 5; float vy = 0; float a = .05; float x = 0; float vx = .6; float loss = .98; while (1) { printf("\033[2J"); printf("\033[H"); /* printf("\033[%d;%dH", (int)y, (int)x); */ for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { if ((i == (int) x) && (j == (int) y)) { putchar('o'); } else { putchar(' '); } } putchar('|'); putchar('\n'); } for (int i = 0; i < width; i++) { putchar('^'); } putchar('\n'); /* printf("\033[%d;%dH", (int)y, (int)x); */ /* putchar('o'); */ if ((0 <= (x + vx)) && ((x + vx) < width)) { vx = vx; } else { vx = vx * -1; } x = x + vx; vy = vy + a; y = y + vy; if ((int) y > height) { vy = -1 * vy * loss; y = y + vy; } printf("\033[%d;%dH", height + 2, 0); printf("y: %f\n", y); printf("x: %f\n", x); printf("vy: %f\n", vy); printf("vx: %f\n", vx); usleep(25 * 1000); } return 0; }
Random numbers
random.c
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { /* srand(2); */ int seed = arc4random(); printf("seed = %d\n", seed); srand(seed); int r = rand(); printf("r = %d\n", r); int low = 10; // inclusive int high = 20; // exclusive int r_between = low + (r % (high - low)); printf("r_between [%d, %d) = %d\n", low, high, r_between); }
Random level generation
random_level.c
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> int main(int argc, char **argv) { printf("\033[?25l"); // hide cursor int seed = arc4random(); srand(seed); int width = 20; int height = 10; int background_x_offset = 0; int background_y_offset = 0; char cols = width + 2; char rows = height; char background[rows][cols]; for (int j = 0; j < rows; j++) { for (int i = 0; i < cols; i++) { background[j][i] = ' '; } } do { printf("\x1b[2J"); printf("\x1b[H"); // randomize the level offscreen int next_x = ((background_x_offset + width - 1) + 1) % cols; int y_offset = rand() % (rows / 2); printf("\033[%d;%dH", height + 1, 0); printf("%d\n", y_offset); printf("%d\n", next_x); for (int j = 0; j < rows; j++) { background[j][next_x] = ' '; } for (int j = rows - 1; j >= rows - y_offset; j--) { background[j][next_x] = '_'; } for (int j = 1; j <= height; j++) { for (int i = 1; i <= width; i++) { // convert screen position to background array int background_y = ((j - 1) + background_y_offset) % rows; int background_x = ((i - 1) + background_x_offset) % cols; printf("\033[%d;%dH", j, i); putchar(background[background_y][background_x]); } } background_x_offset = (background_x_offset + 1) % cols; fflush(stdout); usleep(80 * 1000); } while (1); }