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 db_hang_forall(Elf_Sym *sym, char *name, char *suff, int pre, void *varg) 79 { 80 struct db_hang_forall_arg *arg = varg; 81 82 if (arg->cnt-- == 0) 83 arg->sym = sym; 84 } 85 86 static __inline char * 87 db_randomsym(size_t *lenp) 88 { 89 int nsyms; 90 char *p, *q; 91 struct db_hang_forall_arg dfa; 92 93 dfa.cnt = 0; 94 db_elf_sym_forall(db_hang_forall, &dfa); 95 nsyms = -dfa.cnt; 96 97 if (nsyms == 0) 98 return (NULL); 99 100 dfa.cnt = arc4random_uniform(nsyms); 101 db_elf_sym_forall(db_hang_forall, &dfa); 102 103 db_symbol_values(dfa.sym, &q, 0); 104 105 /* strlen(q) && ignoring underscores and colons */ 106 for ((*lenp) = 0, p = q; *p; p++) 107 if (ISALPHA(*p)) 108 (*lenp)++; 109 110 return (q); 111 } 112 113 void 114 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 for (p = hangpic; *p; p++) 124 cnputc((*p >= '0' && *p <= '9') ? ((tries <= (*p) - '0') ? 125 substchar[(*p) - '0'] : ' ') : *p); 126 127 for (p = word; *p; p++) { 128 c = TOLOWER(*p); 129 cnputc(ISLOWALPHA(c) && ABC_ISCLR(c) ? '-' : *p); 130 } 131 132 #ifdef ABC_WRONGSTR 133 db_printf(" (%s)\r", ABC_WRONGSTR); 134 #else 135 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 for (i = 'a'; i <= 'z'; ++i) 144 if (ABC_ISWRONG(i)) 145 cnputc(i); 146 #endif 147 148 db_printf(")\r"); 149 #endif 150 } 151 152 void 153 db_hangman(db_expr_t addr, int haddr, db_expr_t count, char *modif) 154 { 155 char *word; 156 size_t tries; 157 size_t len; 158 struct _abc sabc[1]; 159 int skill; 160 161 if (modif[0] != 's' || (skill = modif[1] - '0') > 9U) 162 skill = 3; 163 word = NULL; 164 tries = 0; 165 for (;;) { 166 167 if (word == NULL) { 168 ABC_CLR(); 169 170 tries = skill + 1; 171 word = db_randomsym(&len); 172 if (word == NULL) 173 break; 174 175 db_plays++; 176 } 177 178 { 179 int c; 180 181 db_hang(tries, word, sabc); 182 c = cngetc(); 183 c = TOLOWER(c); 184 185 if (ISLOWALPHA(c) && ABC_ISCLR(c)) { 186 char *p; 187 size_t n; 188 189 /* strchr(word,c) */ 190 for (n = 0, p = word; *p ; p++) 191 if (TOLOWER(*p) == c) 192 n++; 193 194 if (n) { 195 ABC_SETRIGHT(c); 196 len -= n; 197 } else { 198 ABC_SETWRONG(c); 199 tries--; 200 } 201 } 202 } 203 204 if (tries && len) 205 continue; 206 207 if (!tries && skill > 2) { 208 char *p = word; 209 for (; *p; p++) 210 if (ISALPHA(*p)) 211 ABC_SETRIGHT(TOLOWER(*p)); 212 } 213 if (tries) 214 db_guesses++; 215 db_hang(tries, word, sabc); 216 db_printf("\nScore: %lu/%lu\n", db_plays, db_guesses); 217 word = NULL; 218 if (tries) 219 break; 220 } 221 } 222