the source code for the best KDL game ever (yet), hangman.

WIP, doesn't compile atm, must be changed to a module


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17658 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol 2006-05-30 20:09:07 +00:00
parent 8be1739f45
commit 7e6e175b9e
2 changed files with 412 additions and 0 deletions

View File

@ -0,0 +1,11 @@
SubDir HAIKU_TOP src add-ons kernel debugger ;
SetSubDirSupportedPlatformsBeOSCompatible ;
# UsePrivateHeaders drivers ;
# UsePrivateHeaders kernel ;
KernelAddon <kdebug>hangman : kernel debugger :
hangman.c
;

View File

@ -0,0 +1,401 @@
#ifdef _KERNEL_MODE
#include <Drivers.h>
#include <KernelExport.h>
#endif
#include <OS.h>
#include <image.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
/* do we reboot on loose ? */
//#define FAIL_IN_BSOD_CAUSE_REBOOT
/* shortcut to be able to exit (and take a screenshot) */
#define CAN_EXIT_ON_HYPHEN
#define MAX_FAILS_BEFORE_BSOD 0
#define FORTUNE_FILE "/etc/fortunes/default"
#define DEV_ENTRY "misc/hangman"
#define KERNEL_IMAGE_ID 1
#define MIN_LETTERS 3
#define MAX_LETTERS 10
#define MAX_CACHED_WORDS 5
char words[MAX_CACHED_WORDS][MAX_LETTERS+1];
/* design ripped off from http://www.latms.berkeley.k12.ca.us/perl/node30.html :) */
static char hungman[] = \
" ____ \n" \
" | | \n" \
" | %c \n" \
" | %c%c%c \n" \
" | %c %c \n" \
" | \n";
/* some colors */
static char hungman_ansi[] = \
" ____ \n" \
" | | \n" \
" | \033[36m%c\033[0m \n" \
" | \033[35m%c%c%c\033[0m \n" \
" | \033[35m%c %c\033[0m \n" \
" | \n";
// for gets,
#define BIGBUFFSZ 128
char bigbuffer[BIGBUFFSZ];
#define BIT_FROM_LETTER(l) (0x1 << (l - 'a'))
status_t init_words(char *from);
#ifdef _KERNEL_MODE
# ifdef __HAIKU__
extern int kgets(char *buf, int len);
# define PRINTF kprintf
# define GETS(a) ({kprintf("hangman> "); kgets(a, sizeof(a));})
# define HIDDEN_LETTER '_'
# define HUNGMAN hungman_ansi
# else
/* BeOS R5 version, needs some R5 kernel privates... */
/* the kernel pointer to the bsod_gets */
static char *(*bsod_gets)(char *, char *, int);
extern char *(*bsod_kgets)(char *, char *, int);
//extern char *bsod_gets(char *);
/* saved here before panic()ing */
char *(*bsod_saved_kgets)(char *, char *, int);
# define PRINTF kprintf
# define GETS(a) ((*bsod_kgets)?(*bsod_kgets):(*bsod_gets))("hangman> ", a, sizeof(a))
# define HIDDEN_LETTER '_'
# define HUNGMAN hungman
# endif
#else
/* userland version */
# define PRINTF printf
# define GETS(a) gets(a)
# define dprintf printf
# define HIDDEN_LETTER '.'
# define HUNGMAN hungman_ansi
#endif /* !_KERNEL_MODE */
status_t init_words(char *from)
{
int fd;
size_t sz, got;
int current, beg, end, i;
struct stat st;
memset((void *)words, 0, sizeof(words));
fd = open(from, O_RDONLY);
if (fd < B_OK)
return fd;
/* lseek() seems to always return 0 from the kernel ??? */
if (fstat(fd, &st))
return B_ERROR;
sz = (size_t)st.st_size;
// sz = (size_t)lseek(fd, 0, SEEK_END);
// dprintf("khangman: lseek(): %ld\n", sz);
if (sz < 30) {
dprintf("khangman: fortune file too small\n");
return B_ERROR;
}
// lseek(fd, 0, SEEK_SET);
//srand((unsigned int)(system_time() + (system_time() >> 32) + find_thread(NULL)));
srand((unsigned int)(system_time() & 0x0ffffffff));
for (current = 0; current < MAX_CACHED_WORDS; current++) {
off_t offset = (rand() % (sz - MAX_LETTERS));
// dprintf("current %d, offset %ld\n", current, (long)offset);
lseek(fd, offset, SEEK_SET);
got = read(fd, bigbuffer, BIGBUFFSZ - 2);
// dprintf("--------------buff(%d):\n%20s\n", current, bigbuffer);
for (beg = 0; beg < got && isalpha(bigbuffer[beg]); beg++);
for (; beg < got && !isalpha(bigbuffer[beg]); beg++);
if (beg + 1 < got && isalpha(bigbuffer[beg])) {
for (end = beg; end < got && isalpha(bigbuffer[end]); end++);
if (end < got && !isalpha(bigbuffer[end]) && beg + MIN_LETTERS < end) {
/* got one */
/* tolower */
for (i = beg; i < end; i++)
bigbuffer[i] = tolower(bigbuffer[i]);
strncpy(&(words[current][0]), &(bigbuffer[beg]), end - beg);
} else
current--;
} else
current--;
}
close(fd);
/*
for (current = 0; current < MAX_CACHED_WORDS; current++)
dprintf("%s\n", words[current]);
*/
return B_OK;
}
void print_hangman(int fails)
{
PRINTF(HUNGMAN,
(fails > 0)?'O':' ',
(fails > 2)?'/':' ',
(fails > 1)?'|':' ',
(fails > 3)?'\\':' ',
(fails > 4)?'/':' ',
(fails > 5)?'\\':' ');
}
void display_word(int current, uint32 tried_letters)
{
int i = 0;
PRINTF("word> ");
while (words[current][i]) {
PRINTF("%c", (BIT_FROM_LETTER(words[current][i]) & tried_letters)?(words[current][i]):HIDDEN_LETTER);
i++;
}
PRINTF("\n");
}
int play_hangman(void)
{
int current;
int score = 0;
int bad_guesses;
uint32 tried_letters;
char *str;
char try;
int gotit, gotone;
for (current = 0; current < MAX_CACHED_WORDS; current++) {
tried_letters = 0;
gotit = 0;
for (bad_guesses = 0; bad_guesses < 6; bad_guesses++) {
do {
gotit = 0;
gotone = 1;
display_word(current, tried_letters);
str = GETS(bigbuffer);
if (!str) {
str = bigbuffer;
PRINTF("buffer:%s\n", str);
}
#ifdef CAN_EXIT_ON_HYPHEN
if (str[0] == '-') /* emergency exit */
return 0;
#endif
if (!isalpha(str[0])) {
PRINTF("not a letter\n");
} else {
try = tolower(str[0]);
if (BIT_FROM_LETTER(try) & tried_letters) {
PRINTF("%c already tried\n", try);
} else {
// REUSE
str = words[current];
gotit = 1;
gotone = 0;
tried_letters |= BIT_FROM_LETTER(try);
while (*str) {
if (!(BIT_FROM_LETTER(*str) & tried_letters))
gotit=0;
if (*str == try) {
gotone = 1;
}
str++;
}
}
}
//PRINTF("gotone:%d, gotit:%d, tried_letters:%08lx\n", gotone, gotit, tried_letters);
} while(tried_letters != 0x03ffffff && !gotit && gotone);
if (gotit)
break;
print_hangman(bad_guesses+1);
}
if (bad_guesses < 6) {
display_word(current, 0x03ffffff);
if (strlen(words[current]) < 5)
PRINTF("That was easy :-P\n");
else if (strlen(words[current]) < 7)
PRINTF("Good one !\n");
else
PRINTF("You got this hard one ! :-)\n");
score ++;
}
/**/
else return score;
/**/
}
return score;
}
#ifdef _KERNEL_MODE /* driver parts */
typedef struct {
int dummy;
} cookie_t;
#ifndef __HAIKU__ /* BeOS intimacy revealed */
//char *bsod_wrapper_gets(char *p, int len)
//char *bsod_wrapper_gets(int len, char *p)
char *bsod_wrapper_gets(char *prompt, char *p, int len)
{
/* fall back to the normal gets() */
bsod_kgets = bsod_saved_kgets;
// if (!bsod_kgets)
// bsod_kgets = bsod_gets;
/* and fake some typing */
strcpy(p, fake_typed);
return p;
}
#else
#endif
int kdlhangman(int argc, char **argv)
{
int score;
score = play_hangman();
PRINTF("score %d\n", score);
if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) {
PRINTF("Congrats !\n");
}
if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) {
#ifdef FAIL_IN_BSOD_CAUSE_REBOOT
PRINTF("Hmmm, sorry, need to trash your hdd... Ok, just a reboot then\n");
fake_typed = "reboot";
bsod_kgets = bsod_wrapper_gets;
return 1;
#else
PRINTF("Hmmm, sorry, need to trash your hdd... Well, I'll be nice this time\n");
#endif
}
//return B_KDEBUG_CONT;
return B_KDEBUG_QUIT;
}
const char * device_names[]={DEV_ENTRY, NULL};
status_t init_hardware(void) {
return B_OK;
}
status_t init_driver(void) {
if (init_words(FORTUNE_FILE) < B_OK) {
dprintf("error reading fortune file\n");
return B_ERROR;
}
get_image_symbol(KERNEL_IMAGE_ID, "bsod_gets", B_SYMBOL_TYPE_ANY, (void **)&bsod_gets);
add_debugger_command("kdlhangman", kdlhangman, "A funny KDL hangman game :-)");
return B_OK;
}
void uninit_driver(void) {
remove_debugger_command("kdlhangman", kdlhangman);
}
const char **publish_devices() {
return device_names;
}
status_t khangman_open(const char *name, uint32 flags, cookie_t **cookie) {
(void)name; (void)flags;
*cookie = (void*)malloc(sizeof(cookie_t));
if (*cookie == NULL) {
dprintf("khangman_open : error allocating cookie\n");
goto err0;
}
memset(*cookie, 0, sizeof(cookie_t));
return B_OK;
err0:
return B_ERROR;
}
status_t khangman_close(void *cookie) {
(void)cookie;
return B_OK;
}
status_t khangman_free(cookie_t *cookie) {
free(cookie);
return B_OK;
}
status_t khangman_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) {
*numbytes = 0;
return B_NOT_ALLOWED;
}
status_t khangman_write(void *cookie, off_t position, const void *data, size_t *numbytes) {
(void)cookie; (void)position; (void)data; (void)numbytes;
//*numbytes = 0;
/* here we get to kdlhangman */
fake_typed = "kdlhangman";
bsod_saved_kgets = bsod_kgets;
bsod_kgets = bsod_wrapper_gets;
kernel_debugger("So much more fun in KDL...");
return B_OK;
}
device_hooks khangman_hooks={
(device_open_hook)khangman_open,
khangman_close,
(device_free_hook)khangman_free,
NULL,
(device_read_hook)khangman_read,
khangman_write,
NULL,
NULL,
NULL,
NULL
};
device_hooks *find_device(const char *name) {
(void)name;
return &khangman_hooks;
}
#else
void kdl_trip(void)
{
int fd;
fd = open("/dev/misc/hangman", O_WRONLY);
if (fd < B_OK) {
puts("hey, you're pissing me off, no /dev/"DEV_ENTRY" !!!");
system("/bin/alert --stop 'It would work better with the hangman driver enabled...\nyou really deserves a forced reboot :P'");
return;
}
write(fd, "hangme!", 7);
close(fd);
}
int main(int argc, char *argv)
{
int score; /* how many correct guesses ? */
/* init */
if (init_words(FORTUNE_FILE) < B_OK) {
fprintf(stderr, "error reading fortune file\n");
return 1;
}
score = play_hangman();
PRINTF("score %d\n", score);
if (score > (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) {
PRINTF("Congrats !\n");
}
if (score < (MAX_CACHED_WORDS - MAX_FAILS_BEFORE_BSOD)) {
/* too many fails... gonna kick :p */
kdl_trip();
}
return 0;
}
#endif