Thread: Creating a mastermind game

  1. #1
    Registered User
    Join Date
    Oct 2022
    Posts
    11

    Creating a mastermind game

    I have an assignment to create a mastermind game where the player has 10 attempts to find the secret code. After each input, the game indicates to the player the number of well placed pieces and the number of misplaced pieces.
    Pieces will be '0' '1' '2' '3' '4' '5' '6' '7' '8'.
    If the player finds the code, he wins, and the game stops. A misplaced piece is a piece that is present in the secret code but that is not in a good position.

    You must read the player's input from the standard input.
    and here is my code
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include "headers.h"
    
    #define false 0
    #define true 1
    
    char* input() {
        char* buffer = malloc(5);
        buffer[5] = '\0';
        fflush(stdout);
        read(0, buffer, 5);
        return buffer;
    }
    
    int main()
    {
        srand( time( NULL ) );
        int getRandom;
        int maxTries;
        int getAnswer;
        int printAnswer;
        int correctPlace=0;
        int run;
        int correctDigit=0;
        int secretCode[5];
        char* answer;
        int check[5];
    
        printf("\n Welcome to my mastermind");
    
        printf("\n Will you find the secret code?");
        printf("\t");
    
        for(getRandom = 0; getRandom < 5; getRandom++)
            secretCode[getRandom] = rand()%10;
        for(maxTries = 0; maxTries <= 10; maxTries++) {
            printf("\n Please enter a valid guess ");
            for (getAnswer = 0; getAnswer <=4; getAnswer++) {
                //scanf("%d", &answer[getAnswer]);
                answer = input();
    
            }
            printf("\n");
            for(printAnswer = 0; printAnswer <= 4; printAnswer++)
                printf("%d", answer[printAnswer]);
            printf("\t");
            check[getAnswer] = false;
            for (getAnswer = 0; getAnswer < 5; getAnswer++) {
                if (answer[getAnswer] == secretCode[getAnswer]) {
                    correctPlace++;
                    check[getAnswer] = true;
                }
            }
            for (getAnswer = 0; getAnswer < 5; getAnswer++) {
                for (run = 0; run < 5; run++){
                    if ((answer[getAnswer] == secretCode[run]) && (check[run] == false)){
                        correctDigit++;
                        check[run] = true;
                    }
                 }
            }
            if(correctPlace ==5){
                printf("\nCongratulations, you've won!\n");
                return 0;
            }
            for(; correctPlace >=0; correctPlace--)
                printf("*");
            for(; correctDigit >=0; correctDigit--)
                printf("0");
                printf("\n");
            if(maxTries==10)/*if maximum number of tries have passed, let them know*/{
                /*they didn't made it and end the game*/
                printf("\nUnfortunately you did not make it.\n");
                return 0;
            }
        }
        return 0;
    }
    Attached Files Attached Files
    Last edited by Salem; 10-17-2022 at 10:00 PM. Reason: Inlined code for convenience

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    There are many things wrong.

    > char* buffer = malloc(5);
    > buffer[5] = '\0';
    This is an array overrun, the \0 you place is outside the memory you allocated.

    The code is riddled with the magic numbers 4 and 5.
    How many actual code values are you trying to compare?

    Start by having
    #define MAX_CODE_LEN 5
    Then replace all the literal 4 & 5 with that symbol.

    > for(printAnswer = 0; printAnswer <= 4; printAnswer++)
    > for (getAnswer = 0; getAnswer < 5; getAnswer++)
    Both these loop the same number of times, but are written in two different ways.
    Both should be like
    for(printAnswer = 0; printAnswer < MAX_CODE_LEN ; printAnswer++)
    for (getAnswer = 0; getAnswer < MAX_CODE_LEN ; getAnswer++)



    > read(0, buffer, 5);
    Bear in mind that you'll end up storing the newline character at some point.
    Do you allow for this in your buffer length?

    > int correctPlace=0;
    > int correctDigit=0;
    These should surely be reset to zero on each attempt.

    > for (getAnswer = 0; getAnswer <=4; getAnswer++)
    > //scanf("%d", &answer[getAnswer]);
    > answer = input();
    You should stick with the scanf.


    Before you get to input and randomised secrets, you need to make sure you have a reliable function to check the answers.
    Here is an exercise for you.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX_CODE_LEN   5
    
    // This performs the following step
    // the game indicates to the player the number of well placed pieces and the number of misplaced pieces.
    void checkAnswer(char guess[], char secret[], int len, int *hits, int *miss) {
        *hits = 0;
        *miss = 0;
        for ( int i = 0 ; i < len ; i++ ) {
            if ( guess[i] == secret[i] )
            // over to you
        }
    }
    
    void testCheckAnswer(void) {
        char secret[MAX_CODE_LEN+1] = "32123";
        char tests[][MAX_CODE_LEN+1] = {
            "12345",  // 1 hit, 2 miss
            "54321",  // 1 hit, 2 miss
            "56789",  // 0 hit, 0 miss
            "32123",  // 5 hit, 0 miss - the winner
            "23312",  // 0 hit, 5 miss
            "11111",
            "22222",
            "33333",
            // add any other cases you can think of
            "" //!! end this with an empty string
        };
        // run tests until the empty string
        for ( int test = 0 ; tests[test][0] != '\0' ; test++ ) {
            int hit = 0, miss = 0;
            checkAnswer(tests[test], secret, MAX_CODE_LEN, &hit, &miss);
            printf("Guess=%s, secret=%s: hits=%d, miss=%d\n",
                    tests[test], secret, hit, miss);
        }
    }
    
    int main ( ) {
        testCheckAnswer();
    }
    Having done that, your first simple game main is very easy
    Code:
    int main ( ) {
        char secret[MAX_CODE_LEN+1] = "32123";
        char guess[MAX_CODE_LEN+1];
        bool won = false;
        for ( tries = 0 ; tries < 10 && !won ; tries++ ) {
            printf("Enter your guess of %d chars\n",MAX_CODE_LEN);
            scanf("%s",guess);
            int hit = 0, miss = 0;
            checkAnswer(guess, secret, MAX_CODE_LEN, &hit, &miss);
            printf("You have %d correct guesses and %d incorrect guesses\n",
                    hit, miss);
            won = hit == MAX_CODE_LEN;
        }
        if ( won ) {
            printf("Congratulations\n";
        } else {
            printf("Better luck next time\n");
        }
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Oct 2022
    Posts
    11
    Thanks for your reply but the reason i used the read is because i can't use the scanf function

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Is that "can't, because your assignment says so" or for some other reason?

    Regardless, you can develop with scanf up until the point you have something working, and then make a swap to using read and make sure everything still works.

    Whether you use read or scanf is a moot point, when the elephant in the room is the core implementation of the algorithm.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Oct 2022
    Posts
    11
    made some modifications and here is my code
    i'm having a little problem with the read format
    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<stddef.h>
    #include<string.h>
    #include<unistd.h>
    #include<time.h>
    #include<stdbool.h>
    
    _Bool isCorect(char ans[])
    {
      int i = 0;
      while (i < 4) {
        if (ans[i] > 57 || ans[i] < 48) {
          printf("Wrong input!\n");
          return 0;
        }
        i++;
      }
      return 0;
    };
    
    /*Prototypes */
    void intRandomCode(intcodeArray[]);
    void getGuess(intguessArray[]);
    int compare(intcodeArray[], intguessArray[], intprintAnswer[]);
    void showresults(intprintAnswer[]);
    void outputarray(intoutArray[]);
    
    /*main program input */
    int main()
    {
      intcodeArray[4], guessArray[4], printAnswer[4] = { 0, 0, 0, 0 };
      int tries = 10;
      int win = 0;
    
      printf("Welcome to MASTERMIND\n");
      printf("Will you find the secret code?\n");
    
      intRandomCode(codeArray);
    
      outputarray(codeArray);
    
      for (tries = 0; tries <= 10; tries++) {
        printf("Please enter a valid guess \n");
        getGuess(guessArray);
    
        win = compare(codeArray, guessArray, printAnswer);
    
        if (win == 4) {
          printf("Congratz! You did it!\n");
          printf("-----");
    
          break;
        }
        if (tries == 10 && win != 4) {
          printf("\nThat was TEN guesses, and you were unable to solve the "
                 "puzzle.\n");
        }
      }
      return 0;
    }
    
    void intRandomCode(int codeArray[])
    {
      int i = 0;
      srand(time(NULL));
      for (i = 0; i < 4; i++) {
        codeArray[i] = rand() % 9;
      }
    }
    
    void getGuess(int guessArray[])
    {
      int guess = 0;
      // scanf("%d", &guess);
      char *ans = (char *) malloc(5 * sizeof(char));
      int r = read(0, ans, 5);
      if (r == 0)
        return;
      while (!isCorect(ans)) {
        read(0, ans, 5);
      };
    
      guessArray[0] = guess / 1000;
      guess = guess % 1000;
      guessArray[1] = guess / 100;
      guess = guess % 100;
      guessArray[2] = guess / 10;
      guess = guess % 10;
      guessArray[3] = guess;
    }
    
    int compare(int codeArray[], int guessArray[], int printAnswer[])
    {
    
      int i = 0, outer = 0;
      int right = 0, almost = 0;
      for (i = 0; i < 4; i++) {
        if (codeArray[i] == guessArray[i]) {
          printAnswer[i] = 1;
          right++;
        }
      }
      for (outer = 0; outer < 4; outer++)
        for (i = 0; i < 4; i++) {
          if (codeArray[outer] == guessArray[i] && printAnswer[outer] == 0) {
            printAnswer[i] = 1;
            almost++;
          }
        }
      printf("Well placed pieces: %d , Misplaced pieces: %d\n", right, almost);
      return (right);
    }
    
    void outputarray(int outArray[])
    {
      int i = 0;
      for (i = 0; i < 4; i++) {
        printf("%d", outArray[i]);
      }
      printf("\n");
    }
    Last edited by Salem; 11-06-2022 at 12:11 AM. Reason: Removed crayola

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    First off, when posting code, make sure you do either "copy as text" from your IDE, or "paste as text" in your browser.
    Your whacky colour scheme makes a complete mess of the board formatting.

    From the question, it seems you want to replace
    > guessArray[0] = guess / 1000
    with
    Code:
    for ( i = 0 ; i < 4 ; i++ )
      guessArray[i] = ans[i] - '0';
    That is, if you're looking to convert a string "1234" into an array of integers 1,2,3,4
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Oct 2022
    Posts
    11
    I am having problems with the read function
    "Copy as text from vscode"
    Code:
    char* ans = (char*) malloc(5 * sizeof(char));
    int i = read(0, ans, 5);
    if (i == 0) return;
    while (!isCorect(ans))
        {
    read(0, ans, 5);
        };
    
    
    using this function the answer just keeps loading and loading without end after pressing enter key

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Try again with the posting of code.

    Compare the fuzzy washed out blob you posted with the fixed version above it.

    Use the post preview until you get it right.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Banned
    Join Date
    Jul 2022
    Posts
    112
    Code:
    char* ans = (char*) malloc(5 * sizeof(char));
    int i = read(0, ans, 5);
    Usually you have to set the null character after malloc().
    Every malloc() calls must end with free() at some point.
    Also avoid malloc() if you can.

    Don't use function() calls in a loop header.

    If you can't accomplish that, then trying to write a custom "printf" will be a nightmare..

  10. #10
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Quote Originally Posted by kodax View Post
    Usually you have to set the null character after malloc().
    Only if the memory will be used as a string. In this case, it's not used as a string, so it's not necessary to set a null character.

    Quote Originally Posted by kodax View Post
    Don't use function() calls in a loop header.
    I assume you mean using a function's return value in a loop condition.

    Why is that? Is there some obscure rule against it? It seems perfectly acceptable to me.

    It's a fairly common C idiom to do something like:

    Code:
    while (fgets(line, sizeof line, file) != NULL) {
      // do something with the line
    }
    It's succinct, and how it works should be pretty clear to anyone with a moderate amount (say, a year or more) of C experience, since it comes up fairly often.

  11. #11
    Banned
    Join Date
    Jul 2022
    Posts
    112
    I assume you mean using a function's return value in a loop condition.
    Why is that? Is there some obscure rule against it? It seems perfectly acceptable to me.
    Side effects are more likely to occur with these types of practices.

  12. #12
    Banned
    Join Date
    Jul 2022
    Posts
    112
    I assume you mean using a function's return value in a loop condition.
    Why is that? Is there some obscure rule against it? It seems perfectly acceptable to me.
    The problem here is not that you call a method inside the condition of the if block. The problem is that your function is not pure, i.e., it has a side effect. If you have a look at @Krayo's example, you'll see how two seemingly equivalent pieces of code can have different behavior: && does only execute the second expression, if the first expression evaluates to true. Analogous, || only executes the second expression, if the first is false.

    Have a look at the Command–query separation principle. It states that your methods should either compute and return a value, or they should change the state of an object, but not both.

    Edit: Also, have a look at the Uniform access principle. The semantics of your program should not depend on whether you obtain a value through storage or through computation. If your program behaves differently when accessing a field than when executing a method that computes the same value, then you should probably fix your method.

    Note:
    behavior and performance are two pairs of shoes: Accessing a field will be faster than calculating a value.

    answered Sep 28, 2014 at 20:18
    Kulu Limpa
    Is it bad practice to call a method inside an if/else condition? - Stack Overflow
    Last edited by kodax; 11-07-2022 at 01:08 PM.

  13. #13
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    The fgets() idiom I mentioned essentially follows the Command-query separation principle since it doesn't really return a value per se; it only returns whether the command succeeded or not (NULL means failure, any other value means success). It doesn't really make sense (at least in C) to have two separate functions, one to read a line and another to return whether reading the line succeeded. That would result in code that is more cumbersome and slightly more difficult to read and debug. Take this as example that does the same thing as my fgets() example but strictly follows the principle:

    Code:
    for (;;) { // forever
      fgets(line, sizeof line, file); // command
      if (feof(file) || ferror(file)) { // query
        break;
      }
      // do something with the line
    }
    Great, 6 lines to do the same thing as 2. Maybe some languages make the Command-query separation principle more transparent. For example, maybe a command method (like reading a line from a file) throws an exception if it fails? But in C it's concise and idiomatic to call an action method (like fgets()) and then immediately check whether it succeeded from its return value.

    On the other hand, the isCorect() function is essentially one that only returns a value. The printf() call is a side effect, and it should be moved to inside the loop, but that in itself doesn't seem to be a problem here.

  14. #14
    Banned
    Join Date
    Jul 2022
    Posts
    112
    Can I put a function name inside the IF statement in PHP? - Quora

    Darwin Santos
    Since 2002, from simple dynamic sites to full fledge ERP's

    Yes you can, but it is frowned upon. Depending on how many parameters you may need to pass to the function this can get the if statement cluttered and difficult to read.

    Pass the result of the function to a variable, then use the variable as often as you may need with the if statement. Your code will be way more readable and as a result easier to maintain as it grows.

    PHP’s flexibility is one the reasons for which some people find it to be a bad language, I personally love the freedom of choosing how I want to express my code but we must be responsible with what we deploy and stick to healthy practices.

    The fact that PHP lets you get away with certain things, does not mean you should.
    cluttered and difficult to read.
    Paragon of common sense. This guy knows his stuff.
    Yet I mentioned readable handwriting so many times..

    Common sense is something that everyone needs, few have, and none think they lack.
    Common sense without education, is better than education without common sense.
    Benjamin Franklin.
    Last edited by kodax; 11-07-2022 at 03:49 PM.

  15. #15
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    I wouldn't necessarily take some random person's online advice about PHP and apply it to C. For one, PHP itself is a fractal of bad design. It might look reasonable and readable at first glance, but it's really not.

    Second, what you quoted explicitly says "Depending on how many parameters you may need to pass to the function", implying it can look cluttered if you have to pass many arguments. Well, yeah, that goes without saying. But that's true even if the function call is on a line of its own (i.e., not inside an "if" statement) and you have to assign the return value to a variable that can be used in a following "if" statement. One thing you can do in either case is split the function call up across multiple lines, say one argument per line, and document what each argument is with a comment at the end of each line. That has basically nothing to do whether it's inside an "if" statement or not.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 10-04-2015, 11:00 AM
  2. c program for the mastermind game
    By College94 in forum C Programming
    Replies: 3
    Last Post: 04-14-2015, 12:09 PM
  3. Again, Mastermind Game Assistant Question
    By Jesterira in forum C Programming
    Replies: 8
    Last Post: 12-07-2012, 06:45 PM
  4. Problem with simple Mastermind game(beginner)
    By newbie2012 in forum Game Programming
    Replies: 1
    Last Post: 11-12-2012, 03:51 AM
  5. Finishing up Mastermind game program
    By Charak in forum C Programming
    Replies: 5
    Last Post: 02-17-2011, 02:49 AM

Tags for this Thread