#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/time.h>/* C doesn't even have TRUE and FALSE, isn't C silly? */#define FALSE 0#define TRUE 1/* It's macros are fun though. Although people cry when you use them. */#define unless( x ) if ( ! ( x ) )#define until( x ) while( ! ( x ) )inline int answer_is_binary_nibble( const char *answer ) { char *ptr; if ( strlen( answer ) > 4 ) { return( FALSE ); } ptr = ( char * )answer; do { if ( *ptr != '1' && *ptr != '0' ) { return( FALSE ); } } while( *( ++ptr ) ); return( TRUE );}inline int answer_is_exit( const char *answer ) { return( !strcasecmp( answer, "exit" ) );}inline int answer_is_valid( const char *answer ) { return ( answer_is_binary_nibble( answer ) || answer_is_exit( answer ) );}char *strchomp( char string[] ) { char *ptr; ptr = string + strlen( string ) - 1; if ( *ptr == '\n' ) { *ptr = '\0'; } /* Perl also ditches \r but this isn't perl. */ return( string );}inline unsigned int convert_answer_to_number( const char *answer ) { char *ptr; int power; unsigned int result; unless ( answer_is_binary_nibble( answer ) ) { fputs( "It's usually good practice to perform sanity checks everywhere.\n", stderr ); fputs( "If you don't and make a mistake your program can be insecure!\n", stderr ); fputs( "This should never happen so we exit the program here.!\n", stderr ); exit( 255 ); } ptr = ( char * )answer; /* Another use of understanding how binary works */ power = 1 << ( strlen( answer ) - 1 ); result = 0; do { if ( *ptr == '1' ) { /* Here too */ result = result | power; } /* Here too */ power = power >> 1; } while( *( ++ptr ) ); return( result );}int main( int argc, char *argv[] ) { int stopped; unsigned int number; int valid_answer; int right_answer; unsigned int consecutive_right_answers; unsigned int total_right_answers; char answer[ 6 ]; unsigned int answer_as_a_number; struct timeval now; /* Pretend to be random */ gettimeofday( &now, NULL ); srand( now.tv_usec ); puts( "Puts there only are 10 kinds of people in the world:\nThose who grok binary, and those who do not.\n\nLearn binary by repetiton! Type exit to stop.\n" ); /* Some people say forever loops are bad form. Boohoo. */ consecutive_right_answers = 0; total_right_answers = 0; while ( TRUE ) { /* Another use of understanding how binary works */ number = ( unsigned int ) rand() & 0xF; printf( "Enter the following in binary: %X (%u).\n" , number, number ); right_answer = FALSE; until( right_answer ) { valid_answer = FALSE; until( valid_answer ) { fgets( answer, 6, stdin ); /* Some people do such silly things */ if ( feof( stdin ) || ferror( stderr ) ) { exit( 254 ); } /* This is a pearlism to ditch the linefeed */ strchomp( answer ); valid_answer = answer_is_valid( answer ); unless ( valid_answer ) { puts( "Not a valid answer. Enter a binary number up to 1111 or \"exit\".\nDo not enter more than 4 characters.\n" ); } } if ( answer_is_exit( answer ) ) { /* Exits forever loop */ return( 0 ); } answer_as_a_number = convert_answer_to_number( answer ); right_answer = answer_as_a_number == number; if ( right_answer ) { printf( "Correct! You have %u total right answers. Your current streak is %u.\n", ++total_right_answers, ++consecutive_right_answers ); } else { puts( "Haha! You fail! Try again!!!\n" ); consecutive_right_answers = 0; } } } return( FALSE );}