/*************************************************************** * Copyright notice * * (c) 2005-2006 Lukas Pitschl (lukas@25haday.com) && Thomas Klaida * All rights reserved * * This script can be redistributed and/or modified * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * * Description: the program is an implementation of master-mind * in C, using a number instead of colors * nothing but that, PERIOD! * * but..., it's using pipes and two process communicating. * the child process generates the number to guess. * the parent reads from stdin, passes the input to * the child. he processes it and checkes whether the number * matches the generated one or not. if not the number of * digits which were on the right place and the right numbers * are counted and marked as X. * all digits that are found in the generated number * are counted and marked as Points. * * a message is printed out and the game either * continues or stops. * ***************************************************************/ #include #include #include #include #include #include #include #include #include /* including header file containing all * funtion definitions and gloabl vars, * as well as structures, constants, preprocessor * directives... */ #include "mastermind.h" int main (int argc, char * argv[]) { pid_t pid; char buffer[PIPE_BUF]; int game_finish = 0; /* contains the id of the process itself */ pid = getpid(); #if DEBUG fprintf(stdout, "The process ID is %d\n", (int)pid); #endif /* resetting result */ result.x = result.points = result.solved = 0; fprintf(stdout, "MASTER MIND\n"); fprintf(stdout, "===========\n\n"); /* creating the pipe */ if(pipe(fd) < 0) { perror("pipe"); exit(EXIT_FAILURE); } /* creating second pipe */ if(pipe(fd2) < 0) { perror("pipe"); exit(EXIT_FAILURE); } /* creating a new process */ if((pid = fork()) < 0) { perror("fork"); exit(EXIT_FAILURE); } else if(pid > 0) { /* here comes all the code belonging to the parent process */ close(fd[0]); close(fd2[1]); /* opening pipe where the parent will write in the user input * the child will read this pipe. */ if((wpipe = fdopen(fd[1], "w")) == NULL) { fprintf(stderr, "line number %d\n", __LINE__); perror("Opening pipe in write mode failed"); exit(EXIT_FAILURE); } /* opening pipe to receive child's calculated result */ if((rpipe2 = fdopen(fd2[0], "r")) == NULL) { fprintf(stderr, "line number %d\n", __LINE__); perror("Opening pipe in read mode failed"); exit(EXIT_FAILURE); } /* loops till right result */ while(!game_finish) { /* asking for guess */ fprintf(stdout, "Guess my Number: "); fflush(stdout); /* reading guess number from stdin */ fgets(buffer, PIPE_BUF, stdin); /* checking on valid input */ if(!checkUserInput(buffer)) { fprintf(stdout, "\n"); continue; } /* writing input to pipe for child process */ fputs(buffer, wpipe); fflush(wpipe); /* reading result from child */ fgets(buffer, PIPE_BUF, rpipe2); /* checking on state and according to that, * printing the belonging message */ if(!strstr(buffer, "SOLVED")) { fprintf(stdout, "%s\n", buffer); fflush(stdout); } else { game_finish = 1; fprintf(stdout, "%sRight dude!! This was my number%s\n", green, normal); fflush(stdout); break; } } /* closing all pipes which are still left open */ fclose(wpipe); fclose(rpipe2); /* waiting for child process to die */ if ((waitpid (pid, NULL, 0)) < 0) { perror ("waitpid() failed for some reason!"); exit (EXIT_FAILURE); } } else { /* all tasks for the child process come here */ close(fd[1]); close(fd2[0]); /* if game_state is not set to NOT_SOLVED a new number is generated */ if(game_state != NOT_SOLVED) { guess_num = generateNumber(); } #if DEBUG fprintf(stdout, "Guess it: %s\n", guess_num.rand_num); fflush(stdout); #endif /* opening pipe for reading, to get the number input from parent */ if((rpipe = fdopen(fd[0], "r")) == NULL) { fprintf(stderr, "Couldn't open pipe for reading, %d\n", __LINE__); perror("fdopen"); exit(EXIT_FAILURE); } /* opening pipe for writing, to pass the result over to the parent process */ if((wpipe2 = fdopen(fd2[1], "w")) == NULL) { fprintf(stderr, "Couldn't open pipe for writing, %d\n", __LINE__); perror("fdopen"); exit(EXIT_FAILURE); } /* reading from pipe */ while(fgets(buffer, PIPE_BUF, rpipe) != NULL) { /* removing the newline-sequence */ ctrim(buffer); /* calculating the result */ result = calcGuess(guess_num, buffer); /* checking if the number was guessed right and telling the * parent about it */ if(result.solved) sprintf(buffer, "SOLVEDX = %d, Points = %d\n", result.x, result.points); else { sprintf(buffer, "X = %d, Points = %d\n", result.x, result.points); game_state = NOT_SOLVED; } /* writing result to the pipe the parent is reading, * and to assure it's not buffer, flush da bastard :-D */ fputs(buffer, wpipe2); fflush(wpipe2); } /* if the parent is closing the pipe the child is reading * the user input from, the while loop will stop. * * so here the child pipe-streams the child is reading from * and writing to are closed. */ fclose(rpipe); fclose(wpipe2); } exit(EXIT_SUCCESS); } /* implements a conditional trim * if last char of a string is the new-line-sequence * it's removed and 1 returned, else 0 */ int ctrim(char * string) { if(string[strlen(string)-1] == '\n') { string[strlen(string)-1] = '\0'; } return 0; } /* generateNumber() generates the random number * it generates real integers with rand() * and are then converted to a string, else * it'd be really hard to check per number. * * the string is then stored in a struct for easily * backpassing it to the calling function. */ gennum_t generateNumber() { int rand_num = 0; gennum_t guess_num; int i = 0; srand((unsigned)time(NULL)); for(i = 0; i < MAX_NUMS; i++) { rand_num = rand()%LETTER_RANGE+1; guess_num.rand_num[i] = (char)itoa(rand_num); } guess_num.rand_num[i+1] = '\0'; return guess_num; } /* calc Guess calculates the X's and Points and * stores them in a struct again. */ result_t calcGuess(gennum_t guess_num, char * string) { int i = 0; result_t result; int rand_code[LETTER_RANGE+1] = {0,0,0,0,0,0,0,0,0,0}; int tmp_i; /* initialize result var */ result.x = result.points = result.solved = 0; #if DEBUG fprintf(stdout, "Gen Num %s\n", guess_num.rand_num); #endif /* first check whether the number from input is equal to * the generated num or not. if so, all the calculation * is no longer needed, thus dismissed */ if(strcmp(guess_num.rand_num, string) == 0) { result.solved = 1; return result; } /* first calculating how often each number appears * in the generated number */ for(i = 0; i < (int)strlen(string); i++) { tmp_i = (int)guess_num.rand_num[i]-48; rand_code[tmp_i]++; } for(i = 0; i < (int)strlen(string); i++) { tmp_i = (int)string[i]-48; if(rand_code[tmp_i] > 0) { if(guess_num.rand_num[i] == string[i]) { ++result.x; rand_code[tmp_i]--; string[i] = 'x'; } } } for(i = 0; i < (int)strlen(string); i++) { tmp_i = (int)string[i]-48; if(rand_code[tmp_i] > 0) { if(string[i] == 'x') continue; else if(inArray(guess_num.rand_num, string[i])) { ++result.points; rand_code[tmp_i]--; } } } return result; } /* check whether a char is appearing in an char array */ int inArray(char * string, char c) { int i = 0; for(i = 0; i < (int)strlen(string); i++) { if(string[i] == c) return 1; } return 0; } /* returns the ASCII value matchin with the given integer */ int itoa(int i) { if(i < LETTER_FROM || i > LETTER_RANGE) return -1; else return i + 48; } /* check whether the user input is valid. * valid has to comply with the following conditions: * - must be no less than 4 digits * - must be no letters */ int checkUserInput(char * input) { #if DEBUG fprintf(stdout, "%d Nr.\n", (int)strlen(input)); #endif /* check if the input is less than 4 digits */ if(strlen(input) <= MAX_NUMS) { fprintf(stdout, "%sYou have to pass me exactly 4! numbers!%s\n", red, normal); return 0; } /* check if there are letters in the input. if so display error message */ if(!checkOnValidInt(input)) { fprintf(stdout, "%sC'mon, you can't pass me letters, as numbers are required!%s\n", red, normal); return 0; } return 1; } /* checks if there are letters in the input */ int checkOnValidInt(char * input) { int i = 0; for(i = 0; i < strlen(input); i++) { if(input[i] == '\n') continue; if(input[i]-48 < LETTER_FROM || input[i]-48 > LETTER_RANGE) return 0; } return 1; }