1 /* $OpenBSD: db_hangman.c,v 1.18 2001/06/29 05:28:18 mickey 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Michael Shalayeff. 18 * 4. The name of the authors may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/param.h> 35 36 #include <vm/vm.h> 37 38 #include <machine/db_machdep.h> 39 40 #include <ddb/db_sym.h> 41 #include <ddb/db_extern.h> 42 #include <ddb/db_output.h> 43 44 #include <dev/cons.h> 45 #include <dev/rndvar.h> 46 47 #define TOLOWER(c) (('A'<=(c)&&(c)<='Z')?(c)-'A'+'a':(c)) 48 #define ISALPHA(c) (('a'<=(c)&&(c)<='z')||('A'<=(c)&&(c)<='Z')) 49 50 void db_hang __P((int, char *, char *)); 51 52 static int skill; 53 u_long db_plays, db_guesses; 54 55 static __inline size_t 56 db_random(size_t mod) 57 { 58 return arc4random() % mod; 59 } 60 61 struct db_hang_forall_arg { 62 int cnt; 63 db_sym_t sym; 64 }; 65 66 /* 67 * Horrible abuse of the forall function, but we're not in a hurry. 68 */ 69 static void db_hang_forall __P((db_symtab_t *, db_sym_t, char *, char *, int, 70 void *)); 71 72 static void 73 db_hang_forall(stab, sym, name, suff, pre, varg) 74 db_symtab_t *stab; 75 db_sym_t sym; 76 char *name; 77 char *suff; 78 int pre; 79 void *varg; 80 { 81 struct db_hang_forall_arg *arg = (struct db_hang_forall_arg *)varg; 82 83 if (--arg->cnt == 0) 84 arg->sym = sym; 85 } 86 87 static __inline char * 88 db_randomsym(size_t *lenp) 89 { 90 extern db_symtab_t db_symtabs[]; 91 db_symtab_t *stab; 92 int nsymtabs, nsyms; 93 char *p, *q; 94 struct db_hang_forall_arg dfa; 95 96 for (nsymtabs = 0; db_symtabs[nsymtabs].name != NULL; nsymtabs++) 97 ; 98 99 if (nsymtabs == 0) 100 return (NULL); 101 102 stab = &db_symtabs[db_random(nsymtabs)]; 103 104 dfa.cnt = 1000000; 105 X_db_forall(stab, db_hang_forall, &dfa); 106 if (dfa.cnt <= 0) 107 return (NULL); 108 nsyms = 1000000 - dfa.cnt; 109 110 if (nsyms == 0) 111 return (NULL); 112 113 dfa.cnt = db_random(nsyms); 114 X_db_forall(stab, db_hang_forall, &dfa); 115 116 q = db_qualify(dfa.sym, stab->name); 117 118 /* don't show symtab name if there are less than 3 of 'em */ 119 if (nsymtabs < 3) 120 while(*q++ != ':'); 121 122 /* strlen(q) && ignoring underscores and colons */ 123 for ((*lenp) = 0, p = q; *p; p++) 124 if (ISALPHA(*p)) 125 (*lenp)++; 126 127 return (q); 128 } 129 130 static const char hangpic[]= 131 "\n88888 \r\n" 132 "9 7 6 \r\n" 133 "97 5 \r\n" 134 "9 423\r\n" 135 "9 2 \r\n" 136 "9 1 0\r\n" 137 "9\r\n" 138 "9 "; 139 static const char substchar[]="\\/|\\/O|/-|"; 140 141 void 142 db_hang(tries, word, abc) 143 int tries; 144 register char *word; 145 register char *abc; 146 { 147 register const char *p; 148 149 for(p = hangpic; *p; p++) 150 cnputc((*p >= '0' && *p <= '9') ? ((tries <= (*p) - '0') ? 151 substchar[(*p) - '0'] : ' ') : *p); 152 153 for (p = word; *p; p++) 154 cnputc(ISALPHA(*p) && abc[TOLOWER(*p) - 'a'] == '-'? '-' : *p); 155 156 db_printf(" ("); 157 158 for (p = abc; *p; p++) 159 if (*p == '_') 160 cnputc('a' + (p - abc)); 161 162 db_printf(")\r"); 163 } 164 165 166 static __inline int 167 db_hangon(void) 168 { 169 static size_t len; 170 static size_t tries; 171 static char *word = NULL; 172 static char abc[26+1]; /* for '\0' */ 173 174 if (word == NULL) { 175 register char *p; 176 177 for (p = abc; p < &abc[sizeof(abc)-1]; p++) 178 *p = '-'; 179 *p = '\0'; 180 181 tries = skill + 1; 182 word = db_randomsym(&len); 183 if (word == NULL) 184 return (0); 185 186 db_plays++; 187 } 188 189 { 190 register char c; 191 192 db_hang(tries, word, abc); 193 c = cngetc(); 194 c = TOLOWER(c); 195 196 if (ISALPHA(c) && abc[c - 'a'] == '-') { 197 register char *p; 198 register size_t n; 199 200 /* strchr(word,c) */ 201 for (n = 0, p = word; *p ; p++) 202 if (TOLOWER(*p) == c) 203 n++; 204 205 if (n) { 206 abc[c - 'a'] = c; 207 len -= n; 208 } else { 209 abc[c - 'a'] = '_'; 210 tries--; 211 } 212 } 213 } 214 215 if (tries && len) 216 return (1); 217 218 if (!tries && skill > 2) { 219 register char *p = word; 220 for (; *p; p++) 221 if (ISALPHA(*p)) 222 abc[TOLOWER(*p) - 'a'] = *p; 223 } 224 db_hang(tries, word, abc); 225 db_printf("\nScore: %lu/%lu\n", db_plays, ++db_guesses); 226 word = NULL; 227 228 return (!tries); 229 } 230 231 void 232 db_hangman(addr, haddr, count, modif) 233 db_expr_t addr; 234 int haddr; 235 db_expr_t count; 236 char *modif; 237 { 238 if (modif[0] == 's' && '0' <= modif[1] && modif[1] <= '9') 239 skill = modif[1] - '0'; 240 else 241 skill = 3; 242 243 while (db_hangon()); 244 } 245