aboutsummaryrefslogtreecommitdiff
path: root/semestr-5/so/lista3/so21_lista_3/game.c
diff options
context:
space:
mode:
Diffstat (limited to 'semestr-5/so/lista3/so21_lista_3/game.c')
-rw-r--r--semestr-5/so/lista3/so21_lista_3/game.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/semestr-5/so/lista3/so21_lista_3/game.c b/semestr-5/so/lista3/so21_lista_3/game.c
new file mode 100644
index 0000000..87f8ef5
--- /dev/null
+++ b/semestr-5/so/lista3/so21_lista_3/game.c
@@ -0,0 +1,118 @@
+#include "csapp.h"
+#include "terminal.h"
+#include <string.h>
+#include <errno.h>
+
+#undef MAXLINE
+#define MAXLINE 120
+
+static sigjmp_buf env;
+
+static void signal_handler(int signo) {
+ siglongjmp(env, signo);
+}
+
+/* If interrupted by signal, returns signal number. Otherwise converts user
+ * provided string to number and saves it under num_p and returns zero. */
+static int readnum(int *num_p) {
+ char line[MAXLINE];
+ int n;
+ /* TODO: Something is missing here! Use Read() to get line from user. */
+ volatile static int ret_val;
+ ret_val = sigsetjmp(env, 1);
+ if (ret_val != 0) return ret_val;
+
+ alarm(1);
+ n = Read(STDIN_FILENO, line, MAXLINE - 1);
+
+ alarm(0);
+ line[n] = 0;
+ *num_p = atoi(line);
+ return 0;
+}
+
+static void game(void) {
+ int tty = tty_open();
+
+ int timeout = 0, num1 = 0, num2 = 0, sum;
+ int last_sig = 0;
+ int lives = 3;
+ int score = 0;
+
+ while (lives > 0) {
+ switch (last_sig) {
+ case 0:
+ timeout = 5;
+ num1 = random() % 100;
+ num2 = random() % 100;
+ printf("What is the sum of %d and %d?\n", num1, num2);
+ break;
+
+ case SIGINT:
+ printf(CHA(1) EL() "Bye bye!\n");
+ exit(EXIT_FAILURE);
+
+ case SIGALRM:
+ timeout--;
+ if (timeout < 0) {
+ last_sig = 0;
+ lives--;
+ printf(CHA(1) EL() "Answer was %d!\n", num1 + num2);
+ continue;
+ }
+ break;
+
+ default:
+ app_error("lastsig = %d not handled!\n", last_sig);
+ break;
+ }
+
+ /* Rewrite user prompt to show current number of lives and timeout. */
+ sigset_t set, oldset;
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGALRM);
+ Sigprocmask(SIG_BLOCK, &set, &oldset);
+
+ int x, y;
+ tty_curpos(tty, &x, &y);
+ dprintf(STDOUT_FILENO, CHA(1) "lives: %d timeout: %d > ", lives, timeout);
+ if (last_sig == SIGALRM)
+ dprintf(STDOUT_FILENO, CHA(%d), y);
+
+ Sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+ /* Read a number from user. */
+ last_sig = readnum(&sum);
+ if (last_sig)
+ continue;
+
+ /* Line contains user input (a number) terminated with '\0'. */
+ if (sum == num1 + num2) {
+ printf("Correct!\n");
+ score++;
+ } else {
+ printf("Incorrect!\n");
+ lives--;
+ }
+ }
+
+ Close(tty);
+
+ printf("Game over! Your score is %d.\n", score);
+}
+
+int main(void) {
+ /* Initialize PRNG seed. */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ srandom(tv.tv_usec);
+
+ /* SIGALRM is used for timeouts, SIGINT for graceful exit. */
+ Signal(SIGALRM, signal_handler);
+ Signal(SIGINT, signal_handler);
+
+ game();
+
+ return EXIT_SUCCESS;
+}