Skip to content

Instantly share code, notes, and snippets.

@jrosskopf
Created November 23, 2011 16:14
Show Gist options
  • Save jrosskopf/1389091 to your computer and use it in GitHub Desktop.
Save jrosskopf/1389091 to your computer and use it in GitHub Desktop.
08_hangman
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define TO_CHAR(_x) ((unsigned char)_x)
#define MAX_LINE_LENGTH 1024
#define MAX_TOKEN_COUNT 2
#define TOKEN_DELIMITER "\t"
#define IDX_HINT 0
#define IDX_NAME 1
#define MAX_CHARS ('z' - 'a')
void remove_trailing_newline(char *line) {
if (line == NULL)
return;
int n = strlen(line);
if (line[n - 1] == '\n')
line[n - 1] = '\0';
}
char* read_random_line_from_file(char *file_name) {
char line_buffer[MAX_LINE_LENGTH] = { 0 };
char reservoir_buffer[MAX_LINE_LENGTH] = { 0 };
FILE *file = fopen(file_name, "r");
if (file == NULL)
return NULL;
srand(time(NULL));
for(double i = 1.0; fgets(line_buffer, sizeof(line_buffer), file) != NULL; i++) {
if ((double)rand() / (double)RAND_MAX * i < 1.0) {
remove_trailing_newline(line_buffer);
strncpy(reservoir_buffer, line_buffer, MAX_LINE_LENGTH);
}
}
fclose(file);
return strdup(reservoir_buffer);
}
int split(char **retv, char *str, char *delimiter, int max_token_count) {
char *t_start;
int i;
for (i = 0, t_start = NULL; (t_start = strsep(&str, delimiter)) != NULL && i < max_token_count; i++) {
retv[i] = t_start;
}
return i;
}
int get_char_in_array(char c, char requested_chars[]) {
for (int i = 0; i < MAX_CHARS; i++) {
if (tolower(c) == requested_chars[i])
return i;
}
return -1;
}
int insert_char_in_array(char c, char requested_chars[]) {
int idx = -1;
if ((idx = get_char_in_array(c, requested_chars)) >= 0)
return idx;
for (int i = 0; i < MAX_CHARS; i++) {
if (requested_chars[i] == 0) {
requested_chars[i] = c;
return i;
}
}
return idx;
}
int get_unknown_char_count(char *name, char requested_chars[]) {
int n = strlen(name);
for (int i = n; i > 0; i--) {
if (get_char_in_array(name[i], requested_chars) >= 0)
n--;
}
return n - 1;
}
void mask_current_line(char *masked_name, char requested_chars[]) {
for (int i = 0; i < strlen(masked_name); i++) {
if (masked_name[i] == ' ')
continue;
if (get_char_in_array(masked_name[i], requested_chars) >= 0)
continue;
masked_name[i] = '_';
}
}
void print_current_state_line(char *name, char requested_chars[]) {
char format[MAX_LINE_LENGTH] = { 0 };
char *masked_name = strdup(name);
mask_current_line(masked_name, requested_chars);
snprintf(format, MAX_LINE_LENGTH, "%%%dd\t%%-%ds\t%%%ds\n", 2, MAX_CHARS, (unsigned int)strlen(name));
printf(format, get_unknown_char_count(name, requested_chars),
requested_chars,
masked_name);
free(masked_name);
}
void read_input_chars_from_user(char requested_chars[]) {
int input = 0;
for (int i = 0; (input = getchar()) != EOF;) {
char c = tolower(TO_CHAR(input));
if (c == '\n')
break;
if (c < 'a' || c > 'z') {
printf("**Warning** '%c' is no character, ignoring;\n", c);
continue;
}
insert_char_in_array(c, requested_chars);
if (++i >= MAX_CHARS)
break;
}
}
int main(int argc, char *argv[]) {
char *line = read_random_line_from_file("./Ulm.hm");
if (line == NULL) {
fprintf(stderr, "**Error** while reading line from file;\n");
return 1;
}
char *tokens[2] = {"", ""};
if (split(tokens, line, TOKEN_DELIMITER, MAX_TOKEN_COUNT) != MAX_TOKEN_COUNT) {
fprintf(stderr, "**Error** while tokenizing line '%s';\n", line);
return 2;
}
printf("Hint: %s\n", tokens[IDX_HINT]);
char requested_chars[MAX_CHARS] = { 0 };
while(get_unknown_char_count(tokens[IDX_NAME], requested_chars) > 0) {
read_input_chars_from_user(requested_chars);
print_current_state_line(tokens[IDX_NAME], requested_chars);
}
printf("Congratulations!\n");
free(line);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment