/**************************************************************** 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 <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <limits.h>#include <fcntl.h>#include <time.h>/* 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;}