Task: Mastermind


C++: #include <iostream>
#include <algorithm>
#include <ctime>
#include <string>
#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> gmatch( codeLen, false );
        std::vector<bool> cmatch( codeLen, false );
 
        for( int i = 0; i < codeLen; i++ ) {
            if( a.at( i ) == combo.at( i ) ) {
                gmatch[i] = true;
                cmatch[i] = true;
                black++;
            }
        }
 
        for( int i = 0; i < codeLen; i++ ) {
            if (gmatch[i]) continue;
            for( int j = 0; j < codeLen; j++ ) {
                if (i == j || cmatch[j]) continue;
                if( a.at( i ) == combo.at( j ) ) {
                    cmatch[j] = true;
                    white++;
                    break;
                }
            }
        }
       
        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;
}










Ada: with Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
with Ada.Strings.Fixed;
with Ada.Containers.Ordered_Sets;

use Ada.Strings.Fixed;

procedure MasterMind
is
   subtype Color_Number is Positive range 2 .. 20;
   subtype Code_Size is Positive range 4 .. 10;
   subtype Guesses_Number is Positive range 7 .. 20;
   subtype Color is Character range 'A' .. 'T';

   function Hint(correct, guess : in String) return String
   is
      Xs : Natural := 0;
      Os : Natural := 0;
      to_display : String(1 .. correct'Length) := (others => '-');
   begin
      for I in guess'Range loop
         if guess(I) = correct(I) then
            Xs := Xs + 1;
            to_display(I) := 'X';
         end if;
      end loop;
      for I in guess'Range loop
         if to_display(I) = '-' then
            for J in correct'Range loop
               if J /= I and to_display(J) /= 'X' and correct(J) = guess(I) then
                  Os := Os + 1;
                  exit;
               end if;
            end loop;
         end if;
      end loop;
      return Xs * 'X' & Os * 'O' & (guess'Length - Xs - Os) * '-';
   end Hint;

   generic
      type Data is (<>);
   function Input(message : in String) return Data;
   
   

   function Input(message : in String) return Data is
   begin
      loop
         Ada.Text_IO.Put(message);
         declare
            S : constant String := Ada.Text_IO.Get_Line;
         begin
            return Data'Value(S);
         exception
            when Constraint_Error =>
               Ada.Text_IO.New_Line;
               Ada.Text_IO.Put_Line("Invalid input!");
               Ada.Text_IO.Put_Line
                 ("Expected values in range:"
                  & Data'First'Img & " .." & Data'Last'Img);
               Ada.Text_IO.New_Line;
         end;
      end loop;
   end;

   function Input_Color_Number is new Input(Color_Number);
   function Input_Code_Size is new Input(Code_Size);
   function Input_Guesses_Number is new Input(Guesses_Number);
   function Input_Boolean is new Input(Boolean);

   CN : constant Color_Number := Input_Color_Number("How many colors? ");
   GN : constant Guesses_Number := Input_Guesses_Number("How many guesses? ");
   CS : constant Code_Size := Input_Code_Size("Size of the code? ");
   repeats : Boolean := Input_Boolean("With repeats? ");
   

   subtype Actual_Colors is Color range Color'First .. Color'Val(Color'Pos(Color'First) + CN - 1);
   package Actual_Colors_Sets is new Ada.Containers.Ordered_Sets(Element_Type => Actual_Colors);

   package Color_Random is new Ada.Numerics.Discrete_Random(Result_Subtype => Actual_Colors);
   generator : Color_Random.Generator;

   function Random return String
   is
      C : String(1 .. CS);
      seen : Actual_Colors_Sets.Set;
   begin
      for I in C'Range loop
         C(I) := Color_Random.Random(generator);
         while (not repeats) and seen.Contains(C(I)) loop
            C(I) := Color_Random.Random(generator);
         end loop;
         seen.Include(C(I));
      end loop;
      return C;
   end Random;

   function Get_Code return String is
   begin
      loop
         Ada.Text_IO.Put("> ");
         declare
            input : constant String := Ada.Text_IO.Get_Line;
         begin
            if input'Length /= CS then
               raise Constraint_Error;
            end if;
            for C of input loop
               if C not in Actual_Colors then
                  raise Constraint_Error;
               end if;
            end loop;
            return input;
         exception
            when Constraint_Error =>
               Ada.Text_IO.New_Line;
               Ada.Text_IO.Put_Line("Invalid input!");
               Ada.Text_IO.New_Line;
         end;
      end loop;
   end Get_Code;

   found : Boolean := False;
begin
   if (not repeats) and (CN < CS) then
      Ada.Text_IO.Put_Line("Not enough colors! Using repeats anyway.");
      repeats := True;
   end if;

   Color_Random.Reset(generator);

   declare
      answer : constant String := Random;
      previous : array(1 .. GN) of String(1 .. CS*2);
   begin
      for I in 1 .. GN loop
         declare
            guess : constant String := Get_Code;
         begin
            if guess = answer then
               Ada.Text_IO.Put_Line("You won, congratulations!");
               found := True;
            else
               previous(I) := guess & Hint(answer, guess);
               Ada.Text_IO.Put_Line(44 * '-');
               for J in 1 .. I loop
                  Ada.Text_IO.Put_Line
                    (previous(J)(1 .. CS)
                     & " => " & previous(J)(CS+1 .. previous(J)'Last));
               end loop;
               Ada.Text_IO.Put_Line(44 * '-');
               Ada.Text_IO.New_Line;
            end if;
         end;
         exit when found;
      end loop;
      if not found then
         Ada.Text_IO.Put_Line("You lost, sorry! The answer was: " & answer);
      end if;
   end;
end MasterMind;