source: trunk/minix/commands/advent/english.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 17.1 KB
Line 
1/* program ENGLISH.C */
2
3
4#include <stdio.h>
5#include <string.h>
6#include <ctype.h>
7#include <stdlib.h>
8#include "advent.h"
9#include "advdec.h"
10
11#define ALL 109
12
13#define ENTER 3
14#define CRAWL 17
15#define JUMP 39
16#define CLIMB 56
17#define XYZZY 62
18#define PLUGH 65
19#define PLOVER 71
20#define PHUCE 82
21
22_PROTOTYPE(static void getwords, (void));
23_PROTOTYPE(static void clrlin, (void));
24_PROTOTYPE(static void doobj, (int *));
25_PROTOTYPE(static boolean doiobj, (void));
26_PROTOTYPE(static boolean do_scoop_up, (void));
27_PROTOTYPE(static boolean check_next, (void));
28
29static char buffer[INPUTBUFLEN] = {'\0', '\0', '\0', '\0'};
30static char *txt[MAXWORDS] = {buffer, buffer, buffer, buffer};
31static char *cindex = buffer;
32static boolean pflag;
33static int vrbkey, words[MAXWORDS] = {0, 0, 0, 0}, word, wdx = 0;
34static int takdir[20] = {2, 6, 9, 10, 11, 13, 14, 17, 23, 25,
35 33, 34, 36, 37, 39, 78, 79, 80, 89, -1};
36
37static int vkey[60] = {
38 0, 199, 9, 0, 130, 0, 197, 0, 0, 243,
39 0, 0, 89, 140, 0, 5, 0, 227, 0, 0,
40 0, 31, 42, 0, 0, 0, 0, 172, 1, 0,
41 0, 0, 254, 0, 69, 0, 0, 92, 0, 0,
42 138, 137, 149, 239, 45, 74, 183, 0, 0, 112,
43 241, 0, 114, 0, 30, 0, 0, 0, 0, 0
44};
45
46static int ptab[260] = {
47 0, 3028, 3065, 3009, -3005, 5071, 5070, 5058, -5020, 19055,
48 19108, 19038, 19020, 19071, 19070, 19058, 19004, 19048, 19091, 19094,
49 19112, 19002, 19118, 2062, 2066, 2047, 2067, 2053, 2065, -2010,
50 -3114, 4034, 4011, 4101, 4035, 4099, 4098, 4017, 4104, 4014,
51 4015, -4087, 3083, 3085, -3081, 5055, 5108, 5020, 5071, 5070,
52 5058, 5004, 5048, 5091, 5112, 5099, 5118, 19055, 19108, 19020,
53 19071, 19070, 19058, 19004, 19048, 19091, 19112, 19099,-19118, 3028,
54 3065, 3009, 3005, -3018, 19055, 19108, 19038, 19020, 19071, 19070,
55 19058, 19004, 19004, 19048, 19091, 19094, 19112, 19002,-19118, 3028,
56 3065, -3018, 19055, 19108, 19038, 19020, 19071, 19070, 19058, 19004,
57 19048, 19091, 19094, 19112, 19118, 2062, 2066, 2047, 2067, 2053,
58 2065, -2010, 3102, -3090, 19055, 19108, 19020, 19071, 19070, 19058,
59 19004, 19048, 19091, 19014, 19015, 19112, 19118, 19120, 19120, -9999,
60 3090, 3102, 3028, 3057, 3065, 3009, -3005,-29999, 2052, -2068,
61 2024, 2065, 2091, 2042, 2073, 5071, 5070, 5058, -5020, 30999,
62 2062, 2066, 2047, 2067, 2053, 2065, 2010, 2073, 19055, 19108,
63 19038, 19020, 19071, 19070, 19058, 19004, 19048, 19091, 19094, 19112,
64 19002,-19118, 2014, 2015, 2013, 2999, 5014, 5015, 5013, 5999,
65 5110, 5113, -5999, 5055, 5108, 5020, 5071, 5070, 5058, 5004,
66 5048, 5091, 5014, 5015, 5112, 5099, -5118, 3102, -3090, 6066,
67 6047, 6067, 6053, 6072, 6073, 5055, 5108, 5020, 5071, 5070,
68 5004, 5004, 5048, 5091, 5112, 5099, 5118, 19055, 19108, 19020,
69 19071, 19070, 19058, 19004, 19048, 19091,-19118, 4034, 4011, 4101,
70 4035, 4099, 4098, 4017, 4104, 4027, 4087, 9999,-30999, 2002,
71 -6002, 3102, -3090, 9999, 4034, 4011, 4101, 4035, 4099, 4087,
72 4098, 4017, 4104, -4027, -5999, 0, 0, 0, 0, 0,
73};
74
75static int adjkey[40] = {
76 0, 15, 38, 64, 4, 63, 1, 61, 62, 67,
77 9, 27, 53, 46, 47, 60, 31, 39, 40, 6,
78 43, 26, 32, 28, 34, 50, 49, 45, 44, 10,
79 20, 25, 21, 36, 37, 30, 33, 0, 0, 0
80};
81
82static int adjtab[70] = {
83 0, 5, 98, -83, 2, -90, 66, 41, -90, -39,
84 41, 14, 15, 50, -11, 50, 64, 56, 72, -74,
85 -19, 119, 59, 73, -118, -119, -70, -41, 95, -118,
86 -118, -58, -71, -120, 110, -108, -120, -73, -62, -60,
87 110, 54, -63, -67, -41, -27, -47, 52, -75, -69,
88 65, 112, -3, 41, 72, 90, 20, 101, 107, -118,
89 -55, -10, -38, -4, 48, 9, -71, -39, 0, 0
90};
91
92/*
93 Analyze a two word sentence
94*/
95int english()
96{
97
98 char *ch_ptr, *word1, *word2;
99 int type, val, type2, val2, adj, k, kk;
100 static int iwest = 0;
101
102 if (!(words[++wdx])) {
103 getwords();
104 wdx = 0;
105 }
106 pflag = FALSE;
107 word = words[wdx];
108 if (word < 0) { /* check first word */
109 printf("I didn't understand the word \"%s\"\n", txt[wdx]);
110 words[wdx+1] = 0;
111 return (FALSE); /* didn't know it */
112 }
113 type2 = val2 = -1;
114 type = CLASS(word);
115 clrlin();
116 val = VAL(word);
117 if (words[wdx + 1] && CLASS(words[wdx + 1]) != CONJUNCTION) {
118
119 /* 'SAY' or 'CALL'. If no next word, pass on to higher powers. */
120 if (type == ACTION && (val == SAY || val == YELL)) {
121 word = words[++wdx];
122 if (!(word == XYZZY || word == PLUGH
123 || word == PLOVER || word == PHUCE)) {
124 if (val == SAY)
125 printf("Okay, \"%s\".\n", txt[wdx]);
126 else {
127 for (ch_ptr = txt[wdx]; *ch_ptr; ch_ptr++)
128 if (islower(*ch_ptr))
129 *ch_ptr = toupper(*ch_ptr);
130 printf("Okay, \"%s\"!!!!!\n", txt[wdx]);
131 }
132 return (FALSE);
133 }
134 } else {
135 word1 = txt[wdx];
136 word2 = txt[wdx + 1];
137
138 /* Special stuff for 'ENTER'. Can't go into water. 'ENTER
139 BOAT' means 'TAKE BOAT' */
140 if (word == ENTER) {
141 if (CLASS(words[wdx + 1]) == NOUN && VAL(words[wdx + 1]) == BOAT)
142 word = TAKE + 2000;
143 else if ((strcmp(word2, "stream") == 0)
144 || (strcmp(word2, "water") == 0)
145 || (strcmp(word2, "reservoir") == 0)
146 || (strcmp(word2, "ocean") == 0)
147 || (strcmp(word2, "sea") == 0)
148 || (strcmp(word2, "pool") == 0)) {
149 rspeak(liqloc(g.loc) == WATER ? 70 : 43);
150 wdx++;
151 return (FALSE);
152 }
153 } else {
154 type2 = CLASS(words[wdx + 1]);
155 val2 = VAL(words[wdx + 1]);
156
157 /* 'LEAVE' is motion verb, unsless leaving an object.
158 E.G., 'LEAVE BOAT' or 'LEAVE BOTTLE'. BUt make sure
159 to leave ('DROP') only totable objects. */
160 if (strcmp(word1, "leave") == 0 && type2 == NOUN) {
161 if (!hinged(val2) || g.fixed[val2])
162 word = LEAVE + 2000;
163
164 /* IF 'LIGHT LAMP', Light must be taken as an
165 action verb, not a noun. */
166 } else if (strcmp(word1, "light") == 0
167 && VAL(words[wdx + 1]) == LAMP) {
168 word = ON + 2000;
169
170 /* 'WATER PLANT' becomes 'POUR WATER', If we are at
171 plant. 'OIL DOOR' becomes 'POUR OIL', etc., etc. */
172 } else if ((strcmp(word1, "water") == 0 || strcmp(word1, "oil") == 0)
173 && (strcmp(word2, "plant") == 0 || strcmp(word2, "door") == 0
174 || strcmp(word2, "sword") == 0 || strcmp(word2, "anvil") == 0)
175 && at(val2)) {
176 words[wdx + 1] = word;
177 txt[wdx + 1] = txt[wdx];
178 word = POUR + 2000;
179 }
180 }
181 }
182
183 }
184 /* This is the 'inner' loop. Dispatching of all word in a clause
185 after the first comes through here. */
186 do {
187 switch (CLASS(word)) {
188 case MOTION:
189 {
190 boolean do_part2;
191 int i;
192
193 do_part2 = FALSE;
194 type = CLASS(verbs[vrbx]);
195 val = VAL(verbs[vrbx]);
196 if (!vrbx)
197 do_part2 = TRUE;
198 else {
199 if (type > ACTION) {
200 rspeak(confuz());
201 return (FALSE);
202 }
203 }
204 if (type == ACTION) {
205 if (val == GO)
206 do_part2 = TRUE;
207 else {
208 if (val == TAKE) {
209 for (i = 0; i < 20; i++)
210 if (takdir[i] == val)
211 do_part2 = TRUE;
212 }
213 if (!do_part2) {
214 word = vocab(txt[wdx], 1);
215 if (word)
216 words[wdx--] = word;
217 }
218 }
219 } else if (type != CRAWL && type != JUMP
220 && type != CLIMB)
221 do_part2 = TRUE;
222 if (do_part2) {
223 verbs[1] = word;
224 vrbx = 1;
225 if (strcmp(txt[wdx], "west") == 0) {
226 iwest++;
227 if (iwest == 10)
228 rspeak(17);
229 }
230 }
231 break;
232 }
233 case NOUN:
234 if (pflag) {
235 if (!doiobj())
236 return (FALSE);
237 } else {
238 word = VAL(word);
239 if (word == ALL) {
240 if (!do_scoop_up())
241 return (FALSE);
242 } else {
243 doobj(&word);
244 if (word > 0) {
245 objs[++objx] = word;
246 otxt[objx] = txt[wdx];
247 } else {
248 clrlin();
249 pflag = FALSE;
250 wdx++;
251 while (words[wdx]) {
252 if (CLASS(words[wdx]) == CONJUNCTION)
253 break;
254 wdx++;
255 }
256 if (words[wdx] == 0)
257 return (FALSE);
258 }
259 }
260 }
261 break;
262 case ACTION:
263 if (vrbx == 0)
264 vrbx++;
265 else {
266 if (VAL(verbs[vrbx]) == TAKE) {
267 val = VAL(word);
268 if (val == DRINK || val == INVENTORY
269 || val == SCORE || val == NOTHING
270 || val == LOOK);
271 else if (val == GO && (
272 strcmp(txt[wdx], "walk") == 0
273 || strcmp(txt[wdx], "run") == 0
274 || strcmp(txt[wdx], "hike") == 0));
275 else {
276 rspeak(confuz());
277 return (FALSE);
278 }
279 } else if (objx || CLASS(words[wdx - 1]) == CONJUNCTION) {
280 rspeak(confuz());
281 return (FALSE);
282 }
283 }
284 verbs[vrbx] = word;
285 vtxt[vrbx] = txt[wdx];
286 break;
287 case MISC:
288 if (vrbx) {
289 rspeak(confuz());
290 return (FALSE);
291 }
292 verbs[1] = word;
293 vrbx = 1;
294 break;
295 case PREPOSITION:
296 if (CLASS(verbs[vrbx]) != ACTION || iobx) {
297 rspeak(confuz());
298 return (FALSE);
299 }
300 vrbkey = vkey[VAL(verbs[vrbx])];
301 if (!vrbkey) {
302 rspeak(confuz());
303 return (FALSE);
304 }
305 prep = VAL(word);
306 pflag = TRUE;
307 break;
308 case ADJACTIVE:
309 /* Adjective handler. Scarf the next word, make sure it is
310 a valid object for this object. Then call getobj to see
311 if it is really there, Then link into object code. */
312 adj = VAL(word);
313 if (!check_next())
314 return (FALSE);
315 else if (CLASS(word) == CONJUNCTION) {
316 printf("%s what?\n", txt[wdx - 1]);
317 return (FALSE);
318 } else {
319 if (CLASS(word) != NOUN)
320 word = vocab(txt[wdx], NOUN);
321 if (word == -1 || CLASS(word) != NOUN || VAL(word) == ALL) {
322 rspeak(confuz());
323 return (FALSE);
324 }
325 words[wdx] = word;
326 kk = VAL(word);
327 for (k = adjkey[adj]; adjtab[k] >= 0; k++) {
328 if (kk == abs(adjtab[k]))
329 break;
330 }
331 if (adjtab[k] < 0) {
332 rspeak(confuz());
333 return (FALSE);
334 }
335 }
336 break;
337 case CONJUNCTION:
338 if (!check_next())
339 return (FALSE);
340 switch (CLASS(word)) {
341 case MOTION:
342 case ACTION:
343 case MISC:
344 words[wdx--] = 0;
345 break;
346 case NOUN:
347 case ADJACTIVE:
348 break;
349 case PREPOSITION:
350 case CONJUNCTION:
351 rspeak(confuz());
352 return (FALSE);
353 default:
354 bug(33);
355 }
356 break;
357 default:
358 bug(33);
359 }
360 word = words[++wdx];
361 if (word < 0) {
362 if (pct(50))
363 printf("I don't understand the word %s?\n", txt[wdx]);
364 else
365 printf("Mumble ? %s\n", txt[wdx]);
366
367 words[wdx+1] = 0;
368 return (FALSE);
369 }
370 type = CLASS(word);
371 if (type == NOUN) {
372 /* It's not the first: Make sure he included a comma or
373 'and'. Differenctiate between direct & indirect objects.
374 Check for special case of multiple ofjects: 'feed bear
375 honey' or 'throw troll nugget'. */
376 if ((pflag ? iobx : objx)
377 && CLASS(words[wdx - 1]) != CONJUNCTION) {
378 val = VAL(verbs[vrbx]);
379 if (!living(objs[objx]) || (val != THROW && val != FEED)) {
380 rspeak(confuz());
381 return (FALSE);
382 }
383 iobx++;
384 iobjs[iobx] = objs[objx];
385 objs[objx] = 0;
386 objx++;
387 }
388 }
389 } while (word);
390
391 if (verbs[1] == 0) {
392 if (objs[1] == 0) {
393 rspeak(confuz());
394 clrlin();
395 } else if (objs[2])
396 printf("What do you want to do with them?\n");
397 else
398 printf("What do you want to do with %s?\n", otxt[1]);
399 return (FALSE);
400 } else if (objx > 1 && iobx > 1) {
401 rspeak(confuz());
402 return (FALSE);
403 }
404 return (TRUE);
405
406}
407
408/*
409 retrieve input line (max INPUTBUFLEN chars), convert to lower case
410 & rescan for first two words (max. WORDSIZE-1 chars).
411*/
412static void getwords()
413{
414 static int wdx = 0;
415 int i, term_loc;
416 char terminator;
417
418 if (*cindex == '\0') {
419 while (!*ask("\n> ", buffer, sizeof(buffer))) ;
420 for (cindex = buffer; *cindex; cindex++)
421 if (isupper(*cindex))
422 *cindex = tolower(*cindex);
423 cindex = buffer;
424 }
425 wdx = 0;
426 buffer[sizeof(buffer)-1] = '\0';
427 for (i = 0; i < MAXWORDS; i++) {
428 txt[i] = &buffer[sizeof(buffer)-1];
429 words[i] = 0;
430 }
431 do {
432 while (*cindex == ' ')
433 cindex++;
434 txt[wdx] = cindex;
435 term_loc = strcspn(cindex, " ,.;\n");
436 cindex += term_loc;
437 terminator = *cindex;
438 *cindex++ = '\0';
439 if ((strcmp(txt[wdx], "a") != 0)
440 && (strcmp(txt[wdx], "the") != 0)
441 && (strcmp(txt[wdx], "an") != 0)) {
442 words[wdx] = vocab(txt[wdx], 0);
443 wdx++;
444 }
445 if (terminator == ',') {
446 txt[wdx] = "and";
447 words[wdx] = vocab(txt[wdx], 0);
448 wdx++;
449 }
450 }
451 while ((terminator != ';') && (terminator != '.')
452 && (terminator != '\0') && (terminator != '\n'));
453 if (terminator == '\0')
454 cindex--;
455 return;
456}
457
458/* CLRIN, clears out all surrent syntax args in preparation for
459 * new input line
460 */
461
462static void clrlin()
463{
464 int i;
465
466 for (i = 0; i < MAXWORDS; i++) {
467 verbs[i] = 0;
468 vtxt[i] = &buffer[sizeof(buffer)-1];
469 }
470
471 for (i = 0; i < MAXITEMS; i++) {
472 objs[i] = 0;
473 otxt[i] = &buffer[sizeof(buffer)-1];
474 iobjs[i] = 0;
475 iotxt[i] = &buffer[sizeof(buffer)-1];
476 }
477 vrbx = 0;
478 objx = 0;
479 iobx = 0;
480 prep = 0;
481}
482
483/*
484 Routine to process an object.
485*/
486static void doobj(object)
487int *object;
488{
489 int msg;
490
491 if (holding(*object))
492 return;
493 if (blind()) {
494 printf("I see no %s here.\n", txt[wdx]);
495 *object = 0;
496 return;
497 }
498 /* Is object here? if so, transitive */
499 if (g.fixed[*object] == g.loc || athand(*object))
500 return;
501 else if (here(*object)) {
502 msg = plural(*object) ? 373 : 335;
503 *object = 0;
504 rspeak(msg);
505 }
506 /* Did he give grate as destination? */
507 else if (*object == GRATE) {
508 if (g.loc == 1 || g.loc == 4 || g.loc == 7) {
509 verbs[1] = DEPRESSION;
510 vrbx = 1;
511 return;
512 } else if (g.loc > 9 && g.loc < 15) {
513 verbs[1] = ENTRANCE;
514 vrbx = 1;
515 return;
516 }
517 }
518 /* Is it a dwarf he is after? */
519 else if (dcheck() && g.dflag >= 2) {
520 *object = DWARF;
521 }
522 /* Is he trying to get/use a liquid? */
523 else if (liqloc(g.loc) == *object
524 || (liq(BOTTLE) == *object && athand(BOTTLE))
525 || (liq(CASK) == *object && athand(CASK)));
526 else if (*object == PLANT && at(PLANT2) &&
527 g.prop[PLANT2] == 0) {
528 *object = PLANT2;
529 } else if (*object == ROCKS && at(CARVNG)) {
530 *object = CARVNG;
531 }
532 /* Is he trying to grab a knife? */
533 else if (*object == KNIFE && g.knfloc == g.loc) {
534 rspeak(116);
535 g.knfloc = -1;
536 }
537 /* Is he trying to get at dynamite? */
538 else if (*object == ROD && athand(ROD2)) {
539 *object = ROD2;
540 } else if (*object == DOOR && (at(SAFE) || at(TDOOR)
541 || at(TDOOR2) || at(PDOOR))) {
542 if (at(TDOOR2))
543 *object = TDOOR2;
544 else if (at(PDOOR))
545 *object = PDOOR;
546 else if (at(SAFE))
547 *object = SAFE;
548 else
549 *object = TDOOR;
550 } else if (*object == BOOK && athand(BOOK2)) {
551 *object = BOOK2;
552 } else if (!(verbs[vrbx] == FIND || verbs[vrbx] == INVENTORY)) {
553 *object = 0;
554 printf("I see no %s here.\n", txt[wdx]);
555 }
556 return;
557}
558
559static boolean doiobj()
560{
561 char dk[INPUTBUFLEN], dkk[INPUTBUFLEN];
562 int kk;
563 boolean ok;
564
565 /* checks object is valid for this preposition */
566 ok = TRUE;
567 word = VAL(word);
568 if (word != ALL) {
569 doobj(&word);
570 if (word > 0) {
571 iobjs[++iobx] = word;
572 iotxt[iobx] = txt[wdx];
573 } else
574 ok = FALSE;
575 }
576 kk = abs(ptab[vrbkey]) / 1000;
577 if (kk == prep) {
578 /* preprosition is valid with this verb now check object of
579 preprosition */
580
581 if (word == 0 || CLASS(word) == CONJUNCTION) {
582 /* no object following prepresition: check special cases */
583
584 pflag = FALSE;
585 strcpy(dk, txt[--wdx]);
586 strcpy(dkk, vtxt[vrbx]);
587 ok = FALSE;
588 if ((strcmp(dk, "on") == 0
589 || strcmp(dk, "off") == 0)
590 && (strcmp(dkk, "turn") == 0
591 || objs[objx] == LAMP))
592 ok = TRUE;
593 if (strcmp(dkk, "take") == 0
594 || strcmp(dkk, "put") == 0)
595 ok = TRUE;
596 if (strcmp(dk, "up") == 0
597 && strcmp(dkk, "pick") == 0)
598 ok = TRUE;
599 if (strcmp(dk, "down") == 0
600 && (strcmp(dkk, "put") == 0 || verbs[vrbx] == THROW) )
601 ok = TRUE;
602 } else {
603 /* object follows preposition See if it's plausible. */
604
605 kk = abs(ptab[vrbkey]) % 1000;
606 if (kk == word && kk == ALL) {
607 if (!do_scoop_up())
608 return (FALSE);
609 } else if (!(kk == word || kk == 999)) {
610 vrbkey++;
611 ok = ptab[vrbkey - 1] < 0 ? FALSE : TRUE;
612 }
613 }
614 }
615 return (ok);
616}
617
618static boolean do_scoop_up()
619{
620 int i, val;
621
622 val = VAL(verbs[vrbx]);
623 if (val == DROP || val == PUT || val == LEAVE) {
624 for (i = 1; i < MAXOBJ; i++) {
625 if (!athand(i) || g.fixed[i])
626 continue;
627 if (i > WATER && i <= WINE + 1)
628 continue;
629 if (toting(i)) {
630 objs[++objx] = i;
631 otxt[objx] = "BUG???";
632 if (objx >= 44)
633 break;
634 }
635 }
636 }
637 if (val == TAKE || val == PICK || val == GET) {
638 if (blind()) {
639 rspeak(357);
640 return (FALSE);
641 } else {
642 for (i = 1; i < MAXOBJ; i++) {
643 if (!athand(i) || g.fixed[i])
644 continue;
645 if (i > WATER && i <= WINE + 1)
646 continue;
647 if (!toting(i)) {
648 objs[++objx] = i;
649 otxt[objx] = "BUG???";
650 if (objx >= 44)
651 break;
652 }
653 }
654 }
655 }
656 return (TRUE);
657}
658
659static boolean check_next()
660{
661
662 word = words[wdx + 1];
663 if (word > 0)
664 return (TRUE);
665 else if (word == 0)
666 rspeak(confuz());
667 else {
668 if (pct(50))
669 printf("I don't understand the word %s?\n", txt[wdx]);
670 else
671 printf("Mumble ? %s\n", txt[wdx]);
672 words[wdx+1] = 0;
673 }
674
675 return (FALSE);
676}
Note: See TracBrowser for help on using the repository browser.