Line data Source code
1 : /* $OpenBSD: db_hangman.c,v 1.37 2017/05/30 15:39:05 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 1996 Theo de Raadt, Michael Shalayeff
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : *
27 : */
28 :
29 : #include <sys/param.h>
30 : #include <sys/systm.h>
31 :
32 : #include <machine/db_machdep.h>
33 :
34 : #include <ddb/db_sym.h>
35 : #include <ddb/db_output.h>
36 :
37 : #include <dev/cons.h>
38 :
39 : #define ABC_ISCLR(c) sabc->abc[(c)-'a']==0
40 : #define ABC_ISWRONG(c) sabc->abc[(c)-'a']=='_'
41 : #define ABC_SETWRONG(c) (sabc->abc[(c)-'a']='_')
42 : #define ABC_SETRIGHT(c) (sabc->abc[(c)-'a']='+')
43 : #define ABC_CLR() memset(sabc->abc,0,sizeof sabc->abc)
44 : struct _abc {
45 : char abc[26+2]; /* for int32 alignment */
46 : };
47 :
48 : #define TOLOWER(c) ((c)|0x20)
49 : #define ISLOWALPHA(c) ('a'<=(c) && (c)<='z')
50 : #define ISALPHA(c) ISLOWALPHA(TOLOWER(c))
51 :
52 : void db_hang(int, char *, struct _abc *);
53 :
54 : u_long db_plays, db_guesses;
55 :
56 : static const char hangpic[]=
57 : "\n88888\r\n"
58 : "9 7 6\r\n"
59 : "97 5\r\n"
60 : "9 423\r\n"
61 : "9 2\r\n"
62 : "9 1 0\r\n"
63 : "9\r\n"
64 : "9 ";
65 : static const char substchar[]="\\/|\\/O|/-|";
66 :
67 : struct db_hang_forall_arg {
68 : int cnt;
69 : Elf_Sym *sym;
70 : };
71 :
72 : /*
73 : * Horrible abuse of the forall function, but we're not in a hurry.
74 : */
75 : static void db_hang_forall(Elf_Sym *, char *, char *, int, void *);
76 :
77 : static void
78 0 : db_hang_forall(Elf_Sym *sym, char *name, char *suff, int pre, void *varg)
79 : {
80 0 : struct db_hang_forall_arg *arg = varg;
81 :
82 0 : if (arg->cnt-- == 0)
83 0 : arg->sym = sym;
84 0 : }
85 :
86 : static __inline char *
87 0 : db_randomsym(size_t *lenp)
88 : {
89 : int nsyms;
90 0 : char *p, *q;
91 0 : struct db_hang_forall_arg dfa;
92 :
93 0 : dfa.cnt = 0;
94 0 : db_elf_sym_forall(db_hang_forall, &dfa);
95 0 : nsyms = -dfa.cnt;
96 :
97 0 : if (nsyms == 0)
98 0 : return (NULL);
99 :
100 0 : dfa.cnt = arc4random_uniform(nsyms);
101 0 : db_elf_sym_forall(db_hang_forall, &dfa);
102 :
103 0 : db_symbol_values(dfa.sym, &q, 0);
104 :
105 : /* strlen(q) && ignoring underscores and colons */
106 0 : for ((*lenp) = 0, p = q; *p; p++)
107 0 : if (ISALPHA(*p))
108 0 : (*lenp)++;
109 :
110 0 : return (q);
111 0 : }
112 :
113 : void
114 0 : db_hang(int tries, char *word, struct _abc *sabc)
115 : {
116 : const char *p;
117 : int i;
118 : int c;
119 : #ifdef ABC_BITMASK
120 : int m;
121 : #endif
122 :
123 0 : for (p = hangpic; *p; p++)
124 0 : cnputc((*p >= '0' && *p <= '9') ? ((tries <= (*p) - '0') ?
125 0 : substchar[(*p) - '0'] : ' ') : *p);
126 :
127 0 : for (p = word; *p; p++) {
128 0 : c = TOLOWER(*p);
129 0 : cnputc(ISLOWALPHA(c) && ABC_ISCLR(c) ? '-' : *p);
130 : }
131 :
132 : #ifdef ABC_WRONGSTR
133 : db_printf(" (%s)\r", ABC_WRONGSTR);
134 : #else
135 0 : db_printf(" (");
136 :
137 : #ifdef ABC_BITMASK
138 : m = sabc->wrong;
139 : for (i = 'a'; i <= 'z'; ++i, m >>= 1)
140 : if (m&1)
141 : cnputc(i);
142 : #else
143 0 : for (i = 'a'; i <= 'z'; ++i)
144 0 : if (ABC_ISWRONG(i))
145 0 : cnputc(i);
146 : #endif
147 :
148 0 : db_printf(")\r");
149 : #endif
150 0 : }
151 :
152 : void
153 0 : db_hangman(db_expr_t addr, int haddr, db_expr_t count, char *modif)
154 : {
155 : char *word;
156 : size_t tries;
157 0 : size_t len;
158 0 : struct _abc sabc[1];
159 : int skill;
160 :
161 0 : if (modif[0] != 's' || (skill = modif[1] - '0') > 9U)
162 0 : skill = 3;
163 : word = NULL;
164 : tries = 0;
165 0 : for (;;) {
166 :
167 0 : if (word == NULL) {
168 0 : ABC_CLR();
169 :
170 0 : tries = skill + 1;
171 0 : word = db_randomsym(&len);
172 0 : if (word == NULL)
173 : break;
174 :
175 0 : db_plays++;
176 0 : }
177 :
178 : {
179 : int c;
180 :
181 0 : db_hang(tries, word, sabc);
182 0 : c = cngetc();
183 0 : c = TOLOWER(c);
184 :
185 0 : if (ISLOWALPHA(c) && ABC_ISCLR(c)) {
186 : char *p;
187 : size_t n;
188 :
189 : /* strchr(word,c) */
190 0 : for (n = 0, p = word; *p ; p++)
191 0 : if (TOLOWER(*p) == c)
192 0 : n++;
193 :
194 0 : if (n) {
195 0 : ABC_SETRIGHT(c);
196 0 : len -= n;
197 0 : } else {
198 0 : ABC_SETWRONG(c);
199 0 : tries--;
200 : }
201 0 : }
202 : }
203 :
204 0 : if (tries && len)
205 0 : continue;
206 :
207 0 : if (!tries && skill > 2) {
208 : char *p = word;
209 0 : for (; *p; p++)
210 0 : if (ISALPHA(*p))
211 0 : ABC_SETRIGHT(TOLOWER(*p));
212 0 : }
213 0 : if (tries)
214 0 : db_guesses++;
215 0 : db_hang(tries, word, sabc);
216 0 : db_printf("\nScore: %lu/%lu\n", db_plays, db_guesses);
217 : word = NULL;
218 0 : if (tries)
219 : break;
220 : }
221 0 : }
|