summaryrefslogtreecommitdiff
path: root/games/quiz/quiz.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /games/quiz/quiz.c
initial import of NetBSD tree
Diffstat (limited to 'games/quiz/quiz.c')
-rw-r--r--games/quiz/quiz.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/games/quiz/quiz.c b/games/quiz/quiz.c
new file mode 100644
index 00000000000..6af648d2e53
--- /dev/null
+++ b/games/quiz/quiz.c
@@ -0,0 +1,362 @@
+/* $NetBSD: quiz.c,v 1.9 1995/04/22 10:16:58 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jim R. Oldroyd at The Instruction Set and Keith Gabryelski at
+ * Commodore Business Machines.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)quiz.c 8.2 (Berkeley) 1/3/94";
+#else
+static char rcsid[] = "$NetBSD: quiz.c,v 1.9 1995/04/22 10:16:58 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+#include "quiz.h"
+#include "pathnames.h"
+
+static QE qlist;
+static int catone, cattwo, tflag;
+static u_int qsize;
+
+char *appdstr __P((char *, char *, size_t));
+void downcase __P((char *));
+void get_cats __P((char *, char *));
+void get_file __P((char *));
+char *next_cat __P((char *));
+void quiz __P((void));
+void score __P((u_int, u_int, u_int));
+void show_index __P((void));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int ch;
+ char *indexfile;
+
+ indexfile = _PATH_QUIZIDX;
+ while ((ch = getopt(argc, argv, "i:t")) != EOF)
+ switch(ch) {
+ case 'i':
+ indexfile = optarg;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ get_file(indexfile);
+ show_index();
+ break;
+ case 2:
+ get_file(indexfile);
+ get_cats(argv[0], argv[1]);
+ quiz();
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+}
+
+void
+get_file(file)
+ char *file;
+{
+ register FILE *fp;
+ register QE *qp;
+ size_t len;
+ char *lp;
+
+ if ((fp = fopen(file, "r")) == NULL)
+ err(1, "%s", file);
+
+ /*
+ * XXX
+ * Should really free up space from any earlier read list
+ * but there are no reverse pointers to do so with.
+ */
+ qp = &qlist;
+ qsize = 0;
+ while ((lp = fgetln(fp, &len)) != NULL) {
+ lp[--len] = '\0';
+ if (qp->q_text && qp->q_text[strlen(qp->q_text) - 1] == '\\')
+ qp->q_text = appdstr(qp->q_text, lp, len);
+ else {
+ if ((qp->q_next = malloc(sizeof(QE))) == NULL)
+ err(1, NULL);
+ qp = qp->q_next;
+ if ((qp->q_text = strdup(lp)) == NULL)
+ err(1, NULL);
+ qp->q_asked = qp->q_answered = FALSE;
+ qp->q_next = NULL;
+ ++qsize;
+ }
+ }
+ (void)fclose(fp);
+}
+
+void
+show_index()
+{
+ register QE *qp;
+ register char *p, *s;
+ FILE *pf;
+
+ if ((pf = popen(_PATH_PAGER, "w")) == NULL)
+ err(1, "%s", _PATH_PAGER);
+ (void)fprintf(pf, "Subjects:\n\n");
+ for (qp = qlist.q_next; qp; qp = qp->q_next) {
+ for (s = next_cat(qp->q_text); s; s = next_cat(s)) {
+ if (!rxp_compile(s))
+ errx(1, "%s", rxperr);
+ if (p = rxp_expand())
+ (void)fprintf(pf, "%s ", p);
+ }
+ (void)fprintf(pf, "\n");
+ }
+ (void)fprintf(pf, "\n%s\n%s\n%s\n",
+"For example, \"quiz victim killer\" prints a victim's name and you reply",
+"with the killer, and \"quiz killer victim\" works the other way around.",
+"Type an empty line to get the correct answer.");
+ (void)pclose(pf);
+}
+
+void
+get_cats(cat1, cat2)
+ char *cat1, *cat2;
+{
+ register QE *qp;
+ int i;
+ char *s;
+
+ downcase(cat1);
+ downcase(cat2);
+ for (qp = qlist.q_next; qp; qp = qp->q_next) {
+ s = next_cat(qp->q_text);
+ catone = cattwo = i = 0;
+ while (s) {
+ if (!rxp_compile(s))
+ errx(1, "%s", rxperr);
+ i++;
+ if (rxp_match(cat1))
+ catone = i;
+ if (rxp_match(cat2))
+ cattwo = i;
+ s = next_cat(s);
+ }
+ if (catone && cattwo && catone != cattwo) {
+ if (!rxp_compile(qp->q_text))
+ errx(1, "%s", rxperr);
+ get_file(rxp_expand());
+ return;
+ }
+ }
+ errx(1, "invalid categories");
+}
+
+void
+quiz()
+{
+ register QE *qp;
+ register int i;
+ size_t len;
+ u_int guesses, rights, wrongs;
+ int next;
+ char *answer, *s, *t, question[LINE_SZ];
+
+ srandom(time(NULL));
+ guesses = rights = wrongs = 0;
+ for (;;) {
+ if (qsize == 0)
+ break;
+ next = random() % qsize;
+ qp = qlist.q_next;
+ for (i = 0; i < next; i++)
+ qp = qp->q_next;
+ while (qp && qp->q_answered)
+ qp = qp->q_next;
+ if (!qp) {
+ qsize = next;
+ continue;
+ }
+ if (tflag && random() % 100 > 20) {
+ /* repeat questions in tutorial mode */
+ while (qp && (!qp->q_asked || qp->q_answered))
+ qp = qp->q_next;
+ if (!qp)
+ continue;
+ }
+ s = qp->q_text;
+ for (i = 0; i < catone - 1; i++)
+ s = next_cat(s);
+ if (!rxp_compile(s))
+ errx(1, "%s", rxperr);
+ t = rxp_expand();
+ if (!t || *t == '\0') {
+ qp->q_answered = TRUE;
+ continue;
+ }
+ (void)strcpy(question, t);
+ s = qp->q_text;
+ for (i = 0; i < cattwo - 1; i++)
+ s = next_cat(s);
+ if (!rxp_compile(s))
+ errx(1, "%s", rxperr);
+ t = rxp_expand();
+ if (!t || *t == '\0') {
+ qp->q_answered = TRUE;
+ continue;
+ }
+ qp->q_asked = TRUE;
+ (void)printf("%s?\n", question);
+ for (;; ++guesses) {
+ if ((answer = fgetln(stdin, &len)) == NULL) {
+ score(rights, wrongs, guesses);
+ exit(0);
+ }
+ answer[len - 1] = '\0';
+ downcase(answer);
+ if (rxp_match(answer)) {
+ (void)printf("Right!\n");
+ ++rights;
+ qp->q_answered = TRUE;
+ break;
+ }
+ if (*answer == '\0') {
+ (void)printf("%s\n", t);
+ ++wrongs;
+ if (!tflag)
+ qp->q_answered = TRUE;
+ break;
+ }
+ (void)printf("What?\n");
+ }
+ }
+ score(rights, wrongs, guesses);
+}
+
+char *
+next_cat(s)
+ register char * s;
+{
+ for (;;)
+ switch (*s++) {
+ case '\0':
+ return (NULL);
+ case '\\':
+ break;
+ case ':':
+ return (s);
+ }
+ /* NOTREACHED */
+}
+
+char *
+appdstr(s, tp, len)
+ char *s;
+ register char *tp;
+ size_t len;
+{
+ register char *mp, *sp;
+ register int ch;
+ char *m;
+
+ if ((m = malloc(strlen(s) + len + 1)) == NULL)
+ err(1, NULL);
+ for (mp = m, sp = s; *mp++ = *sp++;);
+ --mp;
+ if (*(mp - 1) == '\\')
+ --mp;
+
+ while ((ch = *mp++ = *tp++) && ch != '\n');
+ *mp = '\0';
+
+ free(s);
+ return (m);
+}
+
+void
+score(r, w, g)
+ u_int r, w, g;
+{
+ (void)printf("Rights %d, wrongs %d,", r, w);
+ if (g)
+ (void)printf(" extra guesses %d,", g);
+ (void)printf(" score %d%%\n", (r + w + g) ? r * 100 / (r + w + g) : 0);
+}
+
+void
+downcase(p)
+ register char *p;
+{
+ register int ch;
+
+ for (; ch = *p; ++p)
+ if (isascii(ch) && isupper(ch))
+ *p = tolower(ch);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "quiz [-t] [-i file] category1 category2\n");
+ exit(1);
+}