Mastermind: Difference between revisions

From Rosetta Code
Content added Content deleted
m (added another Related task.)
m (added whitespace to the task's preamble.)
Line 9: Line 9:
* choose whether or not will be repeated colors in the code
* choose whether or not will be repeated colors in the code


<br>
The game should display all the player guesses and the results of that guess.
The game should display all the player guesses and the results of that guess.



Revision as of 11:19, 31 January 2017

Mastermind is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Create a simple version of the board game: Mastermind.

It must be possible to:

  • choose the number of colors will be used in the game(2 - 20)
  • choose the color code length(4 - 10)
  • choose the maximum number of guesses the player has (7 - 20)
  • choose whether or not will be repeated colors in the code


The game should display all the player guesses and the results of that guess.

Display(just an idea.):

Feature Graphic Version Text Version
Player guess Colored circles Alphabet letters
Correct color & position Black circle X
Correct color White circle O
None Gray circle -

A text version example: 1: ADEF - XXO-
Translates to:
first guess;
the four colors(ADEF);
result: two correct colors and spot, one correct color/wrong spot one color is not in the code.

Happy coding!


Related tasks



C++

<lang cpp>

  1. include <iostream>
  2. include <algorithm>
  3. include <ctime>
  4. include <string>
  5. include <vector>

typedef std::vector<char> vecChar;

class master { public:

   master( size_t code_len, size_t clr_count, size_t guess_count, bool rpt ) {
       std::string color = "ABCDEFGHIJKLMNOPQRST";
       if( code_len < 4 ) code_len = 4; else if( code_len > 10 ) code_len = 10;
       if( !rpt && clr_count < code_len ) clr_count = code_len; 
       if( clr_count < 2 ) clr_count = 2; else if( clr_count > 20 ) clr_count = 20;
       if( guess_count < 7 ) guess_count = 7; else if( guess_count > 20 ) guess_count = 20;
       
       codeLen = code_len; colorsCnt = clr_count; guessCnt = guess_count; repeatClr = rpt;
       for( size_t s = 0; s < colorsCnt; s++ ) {
           colors.append( 1, color.at( s ) );
       }
   }
   void play() {
       bool win = false;
       combo = getCombo();
       while( guessCnt ) {
           showBoard();
           if( checkInput( getInput() ) ) {
               win = true;
               break;
           }
           guessCnt--;
       }
       if( win ) {
           std::cout << "\n\n--------------------------------\n" <<
               "Very well done!\nYou found the code: " << combo <<
               "\n--------------------------------\n\n";
       } else {
           std::cout << "\n\n--------------------------------\n" <<
               "I am sorry, you couldn't make it!\nThe code was: " << combo <<
               "\n--------------------------------\n\n";
       }
   }

private:

   void showBoard() {
       vecChar::iterator y;
       for( int x = 0; x < guesses.size(); x++ ) {
           std::cout << "\n--------------------------------\n";
           std::cout << x + 1 << ": ";
           for( y = guesses[x].begin(); y != guesses[x].end(); y++ ) {
               std::cout << *y << " ";
           }
           std::cout << " :  ";
           for( y = results[x].begin(); y != results[x].end(); y++ ) {
               std::cout << *y << " ";
           }
           int z = codeLen - results[x].size();
           if( z > 0 ) {
               for( int x = 0; x < z; x++ ) std::cout << "- ";
           }
       }
       std::cout << "\n\n";
   }
   std::string getInput() {
       std::string a;
       while( true ) {
           std::cout << "Enter your guess (" << colors << "): ";
           a = ""; std::cin >> a;
           std::transform( a.begin(), a.end(), a.begin(), ::toupper );
           if( a.length() > codeLen ) a.erase( codeLen );
           bool r = true;
           for( std::string::iterator x = a.begin(); x != a.end(); x++ ) {
               if( colors.find( *x ) == std::string.npos ) {
                   r = false;
                   break;
               }
           }
           if( r ) break;
       }
       return a;
   }
   bool checkInput( std::string a ) {
       vecChar g;
       for( std::string::iterator x = a.begin(); x != a.end(); x++ ) {
           g.push_back( *x );
       }
       guesses.push_back( g );
       
       int black = 0, white = 0;
       std::vector<bool> match( codeLen, false );
       for( int b = 0; b < codeLen; b++ ) {
           if( a.at( b ) == combo.at( b ) ) {
               match[b] = true;
               black++;
               continue;
           }
           for( int w = 0; w < codeLen; w++ ) {
               if( !match[b] && w != b && a.at( w ) == combo.at( b ) ) {
                   match[b] = true;
                   white++;
                   continue;
               }
           }
       }
       
       vecChar r;
       for( int b = 0; b < black; b++ ) r.push_back( 'X' );
       for( int w = 0; w < white; w++ ) r.push_back( 'O' );
       results.push_back( r );
       return ( black == codeLen );
   }
   std::string getCombo() {
       std::string c, clr = colors;
       int l, z;
       for( size_t s = 0; s < codeLen; s++ ) {
           z = rand() % ( int )clr.length();
           c.append( 1, clr[z] );
           if( !repeatClr ) clr.erase( z, 1 );
       }
       return c;
   }
   size_t codeLen, colorsCnt, guessCnt;
   bool repeatClr;
   std::vector<vecChar> guesses, results;
   std::string colors, combo;

};

int main( int argc, char* argv[] ) {

   srand( unsigned( time( 0 ) ) );
   master m( 4, 8, 12, false );
   m.play();
   return 0;

} </lang>

Output:
Enter your guess (ABCDEFGH): gbda

--------------------------------
1: A B C D  :  X O O -
--------------------------------
2: A A A E  :  O - - -
--------------------------------
3: E E E E  :  - - - -
--------------------------------
4: B B B C  :  X - - -
--------------------------------
5: D B A F  :  X O O -
--------------------------------
6: G B D A  :  X X X -

Enter your guess (ABCDEFGH): hbda


--------------------------------
Very well done!
You found the code: HBDA
--------------------------------

Perl 6

Works with: Rakudo version 2017.01

By default, plays classic Mastermind using letters in place of colors. ( 4 chosen from 6, no repeats, 10 guess limit. ) Pass in parameters to modify the game. Enter a string of --length (default 4) letters with or without spaces. Guesses accept lower or upper case. <lang perl6>sub MAIN (

   Int :$colors  where 1 < * < 21 = 6,  Int :$length  where 3 < * < 11 = 4,
   Int :$guesses where 7 < * < 21 = 10, Bool :$repeat = False
 ) {
   my @valid = ('A' .. 'T')[^$colors];
   my $puzzle = $repeat ?? @valid.roll($length) !! @valid.pick($length);
   my @guesses;
   loop {
       clearscr();
       say header();
       printf " %{$length * 2}s :: %s\n", @guesses[$_][0], @guesses[$_][1] for ^@guesses;
       lose() if @guesses == $guesses;
       my $guess = get-guess();
       next unless $guess.&is-valid;
       my $score = score($puzzle, $guess);
       win() if $score eq ('X' xx $length).join: ' ';
       @guesses.push: [$guess, $score];
   }
   sub header {
       my $num = $guesses - @guesses;
       qq:to/END/;
       Guess the {$length} element sequence containing the letters {@valid}
       Repeats are {$repeat ??  !! 'not '}allowed. You have $num guess{ $num == 1 ??  !! 'es'} remaining.
       END
   }
   sub score ($puzzle, $guess) {
       my @score;
       for ^$length {
           if $puzzle[$_] eq $guess[$_] {
               @score.push: 'X';
           }
           elsif $puzzle[$_] eq any(@$guess) {
               @score.push: 'O';
           }
           else {
               @score.push('-');
           }
       }
       @score.sort.reverse.join: ' ';
   }
   sub clearscr { $*KERNEL ~~ /'win32'/ ?? run('cls') !! run('clear') }
   sub get-guess { (uc prompt 'Your guess?: ').comb(/@valid/) }
   sub is-valid (@guess) { so $length == @guess }
   sub win  { say 'You Win! The correct answer is: ', $puzzle; exit }
   sub lose { say 'Too bad, you ran out of guesses. The solution was: ', $puzzle; exit }

}</lang>

Sample output:
Guess the 4 element sequence containing the letters A B C D E F
Repeats are not allowed. You have 4 guesses remaining.

  A B C D :: X O O -
  B A C E :: O O - -
  D F E A :: X O O -
  C E F D :: O O - -
  F B D A :: X O O O
  D B A F :: O O O O
Your guess?: afdb
You Win! The correct answer is: (A F D B)

REXX

More checks could have been added   (for illegal inputs and illegal optoins). <lang rexx>/*REXX pgm scores mastermind game with a human or CBLFs (Carbon Based Life Forms). */ parse arg let wid mxG oRep seed _ /*obtain optional arguments from the CL*/

     arg  .   .   .   rep .                     /*get uppercase 4th argument  "   "  " */

if let== | let=="," then let= 20 /*Not specified? Then use the default.*/ if wid== | wid=="," then wid= 4 /* " " " " " " */ if mxG== | mxG=="," then mxG= 20 /* " " " " " " */ if rep== | rep=="," then rep= 0 /* " " " " " " */ if datatype(seed,'W') then call random ,,seed /*use a seed for random repeatability. */ @abc= 'QWERTYUIOPASDFGHJKLZXCVBNM' /*capital letters used for random code.*/ if abbrev( 'REPEATSALLOWED',rep,3) then rep=1 /*allow an abbreviated option for REP. */ if abbrev('NOREPEATSALLOWED',rep,3) then rep=0 /* " " " " " " */ call vet arg(), 'args' /*Vet the number of arguments entered. */ /*◄■■■■■■ optional vetting.*/ call vet let, 'letters', 2, 20 /* " " " " letters in the code*/ /*◄■■■■■■ optional vetting.*/ call vet wid, 'width', 4, 10 /* " " " " the width of code. */ /*◄■■■■■■ optional vetting.*/ call vet mxG, 'maxGuess', 7, 20 /* " " " " maximum guesses. */ /*◄■■■■■■ optional vetting.*/ call vet rep, 'REP', 0, 1e8 /* " " value if repeats are allowed*/ /*◄■■■■■■ optional vetting.*/ call gen yourG= 'Your guess must be exactly '

       do  until  xx==wid;      say             /*play until guessed or QUIT is entered*/
       say id 'Please enter a guess with '   wid  ' letters                   [or Quit]:'
       pull g;   g=space(g,0);  L=length(g);     if abbrev('QUIT',g,1)  then exit
       if L\==wid  then do;  say id '***error***'  yourG wid  " letters.";  iterate;  end
       q=?;    XX=0;    OO=0;   try=try+1       /*initialize some REXX variables.      */
            do j=1  for L;  if substr(g,j,1) \== substr(q,j,1)  then iterate    /*hit? */
            xx=xx+1;    q=overlay('▒', q, j)    /*bump the  XX  correct   count.       */
            end   /*j*/                         /* [↑]  XX  correct count; scrub guess.*/
            do k=1  for L;  _=substr(g, k, 1);  if pos(_, q)==0  then iterate   /*spot?*/
            oo=oo+1;    q=translate(q, , _)     /*bump the  OO  spot count.            */
            end   /*k*/                         /* [↑]  OO  spot count;  & scrub guess.*/
       say
       @.try=id   right(try, 9)    '(out of' mxG"):"    g   '──►' ,
                                        copies('X',xx)copies("O",oo)copies('-',wid-xx-oo)
           do hist=1  for try;    say @.hist    /*show all previous and current guesses*/
           end   /*hist*/
       if try==mxG  then do;   say id   "you've used the maximum guesses:"   mxG
                               say id   "The code was: "   ?;    exit 1
                         end
       end   /*until XX ···*/

say; say " ┌─────────────────────────────────────────┐"

                              say "          │                                         │"
                              say "          │  Congratulations, you've guessed it !!  │"
                              say "          │                                         │"
                              say "          └─────────────────────────────────────────┘"

exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ gen: if rep==0 then reps= 'no'

                else reps=
     id='────────';  try=0;  L@abc=length(@abc) /*identifier in front of msg from here.*/
     ?=
         do  until  length(?)==wid              /*gen random codes 'til there's enough.*/
         r=substr(@abc, random(1, L@abc), 1)    /*generate a random letter, 1 at a time*/
         if \rep & pos(r, ?)\==0  then iterate  /*maybe don't allow a repeated digit.  */
         ?=? || r; if ?=='QUIT'&let==4  then ?= /*append random letter; ··· except this*/
         end   /*until*/                        /* [↑]  builds a unique  N-letter code.*/
     say
     say id 'A random code of '   wid   "letters  (out of a possible "  let  ' letters) '
     say id 'has been generated   (with'    reps    "repeats)."
     return

/*──────────────────────────────────────────────────────────────────────────────────────*/ s: if arg(1)==1 then return ; return "s" /*a simpler pluraizer. */ ser: say; say; say '***error***' arg(1); say; say; exit 13 /*──────────────────────────────────────────────────────────────────────────────────────*/ vet: parse arg val,?,mn,mx /*vet (validate) a specified argument. */ /*◄■■■■■■ optional vetting.*/

     if ?=="args" & (val>1 | _\=)  then call ser "Too many arguments specified. "  _     /*◄■■■■■■ optional vetting.*/
     if ?=="args"       then return                                                        /*◄■■■■■■ optional vetting.*/
     if \datatype(val, 'N')          then call ser ? "isn't numeric: "               val   /*◄■■■■■■ optional vetting.*/
     if \datatype(val, 'W')          then call ser ? "isn't an integer: "            val   /*◄■■■■■■ optional vetting.*/
     if val < mn                     then call ser ? "has a value less than "        mn    /*◄■■■■■■ optional vetting.*/
     if val > mx                     then call ser ? "has a value greater than "     mx    /*◄■■■■■■ optional vetting.*/
     if ?=='REP' & \datatype(val,W)  then call ser "Value for REPEATS isn't valid: " oRep  /*◄■■■■■■ optional vetting.*/
     return 1</lang>

output

──────── A random code of  4 letters  (out of a possible  20  letters)
──────── has been generated   (with no repeats).

──────── Please enter a guess with  4  letters                   [or Quit]:
abcd                  ◄■■■■■■ user input

────────     guess 1   (20 is the max): ABCD ──► ----

──────── Please enter a guess with  4  letters                   [or Quit]:
efgh                  ◄■■■■■■ user input

────────     guess 1   (20 is the max): ABCD ──► ----
────────     guess 2   (20 is the max): EFGH ──► ----

──────── Please enter a guess with  4  letters                   [or Quit]:
ijkl                  ◄■■■■■■ user input

────────     guess 1   (20 is the max): ABCD ──► ----
────────     guess 2   (20 is the max): EFGH ──► ----
────────     guess 3   (20 is the max): IJKL ──► O---

──────── Please enter a guess with  4  letters                   [or Quit]:
mnop                  ◄■■■■■■ user input

     ···············································
     ·    (Some of the output has been elided.)    ·
     ···············································

──────── Please enter a guess with  4  letters                   [or Quit]:
yinp                  ◄■■■■■■ user input

────────     guess 1   (20 is the max): ABCD ──► ----
────────     guess 2   (20 is the max): EFGH ──► ----
────────     guess 3   (20 is the max): IJKL ──► O---
────────     guess 4   (20 is the max): MNOP ──► XO--
────────     guess 5   (20 is the max): WXYZ ──► O---
────────     guess 6   (20 is the max): LKHI ──► O---
────────     guess 7   (20 is the max): PONM ──► XO--
────────     guess 8   (20 is the max): ZYXW ──► O---
────────     guess 9   (20 is the max): YZWX ──► X---
────────    guess 10   (20 is the max): MOPN ──► OO--
────────    guess 11   (20 is the max): OMPN ──► OO--
────────    guess 12   (20 is the max): LKJI ──► O---
────────    guess 13   (20 is the max): JILK ──► X---
────────    guess 14   (20 is the max): YINP ──► XXXX

          ┌─────────────────────────────────────────┐
          │                                         │
          │  Congratulations, you've guessed it !!  │
          │                                         │
          └─────────────────────────────────────────┘

zkl

Translation of: C++

<lang zkl>class MasterMind{

  fcn init(code_len,guess_count){
     var codeLen =code_len.max(4).min(10);
     var guessCnt=guess_count.max(7).min(20);
     var colors  ="ABCDEFGHIJKLMNOPQRST"[0,codeLen];
  }
  fcn play{
     guesses,win,blackWhite:=List(),False,Void;
     code:=codeLen.pump(String,'wrap(_){ colors[(0).random(codeLen)] });
     do(guessCnt){

str:=getInput(); win,blackWhite = checkInput(str,code); guesses.append(T(str,blackWhite)); showBoard(guesses); if(win) break;

     }
     if(win) println("--------------------------------\n",

"Very well done!\nYou found the code: ",code);

      else println("--------------------------------\n",

"I am sorry, you didn't discover the code!\nThe code was: ",code);

   }
   fcn [private] showBoard(guesses){
      foreach n,gbw in ([1..].zip(guesses)){
         guess,blackWhite := gbw;
         println("%2d: %s :% s %s".fmt(n,

guess.split("").concat(" "), blackWhite.split("").concat(" "), "- "*(codeLen - blackWhite.len())));

      }
   }
   fcn [private] getInput{
      while(True){

a:=ask("Enter your guess (" + colors + "): ").toUpper()[0,codeLen]; if(not (a-colors) and a.len()>=codeLen) return(a);

      }
   }
   fcn [private] checkInput(guess,code){

// black: guess is correct in both color and position

       // white: correct color, wrong position

matched,black := guess.split("").zipWith('==,code), matched.sum(0); // remove black from code, prepend null to make counting easy code = L("-").extend(matched.zipWith('wrap(m,peg){ m and "-" or peg },code)); white:=0; foreach m,p in (matched.zip(guess)){ if(not m and (z:=code.find(p))){ white+=1; code[z]="-"; } } return(black==codeLen,"X"*black + "O"*white)

   }

}(4,12).play();</lang>

Output:
Enter your guess (ABCD): abcd
 1: A B C D : X O O - 
Enter your guess (ABCD): abcc
 1: A B C D : X O O - 
 2: A B C C : O O - - 
Enter your guess (ABCD): aaad
 1: A B C D : X O O - 
 2: A B C C : O O - - 
 3: A A A D : X - - - 
Enter your guess (ABCD): bccd
 1: A B C D : X O O - 
 2: A B C C : O O - - 
 3: A A A D : X - - - 
 4: B C C D : X X O - 
Enter your guess (ABCD): dcbd
 1: A B C D : X O O - 
 2: A B C C : O O - - 
 3: A A A D : X - - - 
 4: B C C D : X X O - 
 5: D C B D : X X X X 
--------------------------------
Very well done!
You found the code: DCBD