"Master Mind" for Arduino v.02 with example in comments up.

Here is v0.1 for Arduino, the original: Mastermind (board game) - Wikipedia

I use a-f instead of 6 colors and show numbers of full + matches and half - matches.
I also use 6 instead of 4 letters/colors.
The commented-out debug prints can help with understanding the code, feel free to add more.

Just playing this seriously will help strengthen and sharpen most minds.
Any questions?

// codebreak 0.1

char player[ 4 ]; // initials
char secret[ 7 ], guess[ 7 ]; // 6 letters a-f
byte fullMatches, halfMatches, guesses, secretBits, guessBits;
enum gameState { prompt, id, precode, code, entry, clues, interact, win };
byte gamestate;

unsigned long t;
unsigned long seed;

byte i, j; // gp indexes
char chr;


void setup()
{
  Serial.begin( 115200 );
  for ( i = 0; i < 67; i++) Serial.write( '\n' );
  Serial.println( F( "code and guess are 6 letters, may be a to f" ));
  Serial.println( F( "clues are 2 numbers, complete and half matches\n" ));
}

void loop()
{
  switch ( gamestate )
  {
    case prompt :
      Serial.println( F( "enter your initials" ));
      for ( i = 0; i < 3; i++ )
      {
        player[ i ] = 0; // forced clear
      }
      i = guesses = 0; // counter in player
      gamestate = id;
      break;

    case id :
      if ( Serial.available())
      {
        chr = Serial.read();
//        Serial.write( chr );
//        Serial.write( 32 );
//        Serial.println( chr, DEC );
        if (( chr == ' ' || chr == '\n' || i > 2 ) && i != 0 )
        {
          Serial.println();
          Serial.flush();
          seed = micros() >> 2;
          randomSeed( seed );
          for ( i = 0; i < 6; i++ )
          {
            secret[ i ] = 0; // forced clear
          }
          i = 0; // counter in code
          gamestate = code;
        }
        else if (( chr | 0x20 ) >= 'a' && (( chr | 0x20 ) <= 'z' ))  // | 0x20 sets lowercase bit
        {
          player[ i++ ] = chr;
          Serial.write( chr );
        }
      }
      break;

    case code :
      secret[ i++ ] = 'a' + char( random( 0, 6 ));

      if ( i > 5 )
      {
        for ( i = 0; i < 6; i++ )
        {
          guess[ i ] = 0; // forced clear
        }

        i = 0; // counter in entry
        gamestate = entry;
//        Serial.println( secret );
        Serial.println(F( "\n****************" ));
      }
      break;

    case entry :
      if ( Serial.available())
      {
        chr = Serial.read();
        if (( chr | 0x20 ) >= 'a' && ( chr | 0x20 ) <= 'z' )  // | 0x20 sets lowercase bit
        {
          guess[ i++ ] = chr;
          Serial.write( chr );
        }
        else if ( chr == 8 && i > 0 ) // iirc 8 is backspace
        {
          i--;
        }

        if ( i > 5 )
        {
          Serial.print( "  " );
          Serial.flush();
          gamestate = clues;
          fullMatches = halfMatches = secretBits = guessBits = 0;
        }
      }
      break;

    case clues  :
      guesses++;
      
      for ( i = 0; i < 6; i++ )  // full matches
      {
        if ( secret[ i ] == guess[ i ] )
        {
          secretBits += 1 << i;
          guessBits += 1 << i;
          fullMatches++;
//          Serial.print( i, HEX );
//          Serial.write( ' ' );
        }
      }
      Serial.print( fullMatches );
      Serial.print( "+" );
//      Serial.write( ' ' );
//      Serial.print( secretBits, HEX );
      Serial.print( " | " );


      for ( i = 0; i < 6; i++ )  // half matches, only set matchBits for matches secret chars
      {
        if ( !(( 1 << i ) & secretBits ))  // make sure secret char is not already matched
        {
          for ( j = 0; j < 6; j++ )
          {
            if ( i != j )
            {
              if ( !((1 << j ) & guessBits ))  // make sure guess char is not already matched
              {
                if ( secret[ i ] == guess[ j ] )
                {
                  secretBits += 1 << i;
                  guessBits += 1 << j;
                  halfMatches++;
//                  Serial.print( j, HEX );
//                  Serial.write( ' ' );
                  break;
                }
              }
            }
          }
        }
      }
      Serial.print( halfMatches );
      Serial.println( "- " );
//      Serial.println( guessBits, HEX );

      if ( fullMatches == 6 )
      {
        Serial.println(F( "\n****************" ));
        Serial.print(F( "Solved in " ));
        Serial.print( guesses );
        Serial.println(F( " guesses\n" ));
        
        gamestate = prompt;
      }
      else
      {
        Serial.println(F( "----------------" ));
        i = 0; // counter in entry
        gamestate = entry;
      }
      break;

  }
}

Version 0.2 with a sample game output in the comments.

// codebreak 0.2 free to use by GoForSmoke at forum.arduino.cc
// rev 0.2 7/25/20 
// change it to learn the state of the machine!
// make it drive leds to change output? 
// retro-fy an old game controller to change input?
// even reduce the number of letters, IIRC the MB game had 4-6.
// add some processing, save lowest scores and initials to EEPROM!

// or just play it to sharpen your logical mind.

/*  sample game play

enter your initials
NNO

Let the Game Begin!

****************
abcdef  3+ | 1- 
------------------ 1
aaabbb  0+ | 1- 
------------------ 2
cccddd  2+ | 1- 
------------------ 3
eeefff  0+ | 2- 
------------------ 4
fffaaa  0+ | 0- 
------------------ 5
dddeee  3+ | 1- 
------------------ 6
bdcdee  2+ | 4- 
------------------ 7
bdcede  2+ | 4- 
------------------ 8
bdceed  4+ | 2- 
------------------ 9
dbceed  6+ | 0- 

****************
Solved in 10 guesses
 */

char player[ 4 ]; // initials
char secret[ 7 ], guess[ 7 ]; // 6 letters a-f
byte fullMatches, halfMatches, guesses, secretBits, guessBits;
enum gameState { prompt, id, precode, code, entry, clues, interact, win };
byte gamestate;

unsigned long t;
unsigned long seed;

byte i, j; // gp indexes
char chr;


void setup()
{
  Serial.begin( 115200 );
  for ( i = 0; i < 67; i++) Serial.write( '\n' );
  Serial.println( F( "codebreak v.0.2\n" ));
  Serial.println( F( "code and guess are 6 letters, may be a to f" ));
  Serial.println( F( "ex: secret code may be fbdaf" ));
  Serial.println( F( "code stays hidden until matched" ));
  Serial.println( F( "clues are 2 numbers, complete and half matches" ));
  Serial.println( F( "complete match is same letter and place" ));
  Serial.println( F( "half match is same letter, different place" ));
  Serial.println( F( "all matched letters can't match again" ));
  Serial.println( F( "there are only 6 matches of both kinds" ));
  Serial.println( F( "ex: 1st guess abcdef clues add to the" ));
  Serial.println( F( "number of different letters in the code" ));
  Serial.println( F( "strategize, make some guesses just to reveal" ));
  Serial.println();
}

void loop()
{
  switch ( gamestate )
  {
    case prompt :
      Serial.println( F( "enter your initials" ));
      for ( i = 0; i < 3; i++ )
      {
        player[ i ] = 0; // forced clear
      }
      i = guesses = 0; // counter in player
      gamestate = id;
      break;

    case id :
      if ( Serial.available())
      {
        chr = Serial.read();
//        Serial.write( chr );
//        Serial.write( 32 );
//        Serial.println( chr, DEC );
        if (( chr == ' ' || chr == '\n' || i > 2 ) && i != 0 )
        {
          Serial.println();
          Serial.flush();
          seed = micros() >> 2;
          randomSeed( seed );
          for ( i = 0; i < 6; i++ )
          {
            secret[ i ] = 0; // forced clear
          }
          i = 0; // counter in code
          gamestate = code;
        }
        else if (( chr | 0x20 ) >= 'a' && (( chr | 0x20 ) <= 'z' ))  // | 0x20 sets lowercase bit
        {
          player[ i++ ] = chr;
          Serial.write( chr );
        }
      }
      break;

    case code :
      secret[ i++ ] = 'a' + char( random( 0, 6 ));

      if ( i > 5 )
      {
        for ( i = 0; i < 6; i++ )
        {
          guess[ i ] = 0; // forced clear
        }

        i = 0; // counter in entry
        gamestate = entry;
//        Serial.println( secret );
        Serial.println(F( "\nLet the Game Begin!" ));
        Serial.println(F( "\n****************" ));
      }
      break;

    case entry :
      if ( Serial.available())
      {
        chr = Serial.read();
        if (( chr | 0x20 ) >= 'a' && ( chr | 0x20 ) <= 'z' )  // | 0x20 sets lowercase bit
        {
          guess[ i++ ] = chr;
          Serial.write( chr );
        }
        else if ( chr == 8 && i > 0 ) // iirc 8 is backspace
        {
          i--;
        }

        if ( i > 5 )
        {
          Serial.print( "  " );
          Serial.flush();
          gamestate = clues;
          fullMatches = halfMatches = secretBits = guessBits = 0;
        }
      }
      break;

    case clues  :
      guesses++;
      
      for ( i = 0; i < 6; i++ )  // full matches
      {
        if ( secret[ i ] == guess[ i ] )
        {
          secretBits += 1 << i;
          guessBits += 1 << i;
          fullMatches++;
//          Serial.print( i, HEX );
//          Serial.write( ' ' );
        }
      }
      Serial.print( fullMatches );
      Serial.print( "+" );
//      Serial.write( ' ' );
//      Serial.print( secretBits, HEX );
      Serial.print( " | " );


      for ( i = 0; i < 6; i++ )  // half matches, only set matchBits for matches secret chars
      {
        if ( !(( 1 << i ) & secretBits ))  // make sure secret char is not already matched
        {
          for ( j = 0; j < 6; j++ )
          {
            if ( i != j )
            {
              if ( !((1 << j ) & guessBits ))  // make sure guess char is not already matched
              {
                if ( secret[ i ] == guess[ j ] )
                {
                  secretBits += 1 << i;
                  guessBits += 1 << j;
                  halfMatches++;
//                  Serial.print( j, HEX );
//                  Serial.write( ' ' );
                  break;
                }
              }
            }
          }
        }
      }
      Serial.print( halfMatches );
      Serial.println( "- " );
//      Serial.println( guessBits, HEX );

      if ( fullMatches == 6 )
      {
        Serial.println(F( "\n****************" ));
        Serial.print(F( "Solved in " ));
        Serial.print( guesses );
        Serial.println(F( " guesses\n" ));
        
        gamestate = prompt;
      }
      else
      {
        Serial.print(F( "------------------ " ));
        Serial.println( guesses );
        i = 0; // counter in entry
        gamestate = entry;
      }
      break;

  }
}

You give it up to 3 initials to start a new game. Those are a hook to add score-keeping in EEPROM.

You enter guesses in Serial Monitor or a terminal emulator you connect via COM port. Terminal key strikes communicate immediately, Serial Monitor is line-entry.

Explanations below include why each choice was made.

This game is logical barbells for your mind.

/* sample game play copied from Serial Monitor

codebreak v.0.2

code and guess are 6 letters, may be a to f
ex: secret code may be fbdaf
code stays hidden until matched
clues are 2 numbers, complete and half matches
complete match is same letter and place
half match is same letter, different place
all matched letters can't match again
there are only 6 matches of both kinds
ex: 1st guess abcdef clues add to the
number of different letters in the code
strategize, make some guesses just to reveal

enter your initials
ABC

Let the Game Begin!


abcdef 3+ | 1-
------------------ 1
aaabbb 0+ | 1-
------------------ 2
cccddd 2+ | 1-
------------------ 3
eeefff 0+ | 2-
------------------ 4
fffaaa 0+ | 0-
------------------ 5
dddeee 3+ | 1-
------------------ 6
bdcdee 2+ | 4-
------------------ 7
bdcede 2+ | 4-
------------------ 8
bdceed 4+ | 2-
------------------ 9
dbceed 6+ | 0-


Solved in 10 guesses
*/

1st move I enter abcdef to find out how many letters are used/not used.

abcdef 3+ | 1-

4 letters used, 3 of those are in the right places

aaabbb 0+ | 1-

there is only 1 a or b, and it is on the opposite side of the guess

cccddd 2+ | 1-

means more later

eeefff 0+ | 2-

ditto

trying to catch a-or-b, I moved the aaa to the right side and swapped right side fff to the left

fffaaa 0+ | 0-

discovery: the unused letters are a and f!
that means there are 2 e's, both on the right side but gotta cover 3
that lets me count letter d's on the left.

dddeee 3+ | 1-

means 2 e's and 1 d on the right side, 1 d on the left side
that leaves 1 b and 1 c on the left with the d

bdcdee 2+ | 4-

the right side should be easier to get, limit change by keeping the left as is

bdcede 2+ | 4-

nope,

bdceed 4+ | 2-

got the right side and only 1 on the lef side is right, LOL!

dbceed 6+ | 0-

matched by luck on guess 10