Mastermind: Difference between revisions

m
(Added Python example)
 
(38 intermediate revisions by 21 users not shown)
Line 1:
[[Category:Puzzles]]
 
{{task|Games}}
 
Create a simple version of the board game:   [https://en.wikipedia.org/wiki/Mastermind_(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 willcolors may be repeated colors in the code
 
<br>
The (computer program) game should display all the player guesses and the results of that guess.
 
Display (just an idea.):
:::::: {| class="wikitable" border="1"
|-
! Feature !! Graphic Version !! Text Version
Line 37 ⟶ 36:
|}
 
 
A text version example:
A text version example: &nbsp; &nbsp; &nbsp; <big> 1. &nbsp; ADEF &nbsp; - &nbsp; XXO- </big>
1: ADEF - XXO-
<br>Translates to:
<br>the first guess;
<br>the four colors (ADEF);
<br>result:
<br>result: two correct colors and spot, one correct color/wrong spot one color is not in the code.
:::: two correct colors and spot,
:::: one correct color/wrong spot, one color isn't in the code.
 
Happy coding!
Line 53 ⟶ 54:
* &nbsp; [[Guess the number/With Feedback]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F encode(correct, guess)
[String] output_arr
 
L(i) 0 .< correct.len
output_arr [+]= I guess[i] == correct[i] {‘X’} E I guess[i] C correct {‘O’} E ‘-’
 
R output_arr
 
F safe_int_input(prompt, min_val, max_val)
L
V user_input_str = input(prompt)
 
X.try
V user_input = Int(user_input_str)
I user_input C min_val .. max_val
R user_input
X.catch ValueError
L.continue
 
F play_game()
print(‘Welcome to Mastermind.’)
print(‘You will need to guess a random code.’)
print(‘For each guess, you will receive a hint.’)
print(‘In this hint, X denotes a correct letter, and O a letter in the original string but in a different position.’)
print()
 
V number_of_letters = safe_int_input(‘Select a number of possible letters for the code (2-20): ’, 2, 20)
V code_length = safe_int_input(‘Select a length for the code (4-10): ’, 4, 10)
 
V letters = ‘ABCDEFGHIJKLMNOPQRST’[0 .< number_of_letters]
V code = ‘’
L 0 .< code_length
code ‘’= random:choice(letters)
[String] guesses
 
L
print()
V guess = input(‘Enter a guess of length #. (#.): ’.format(code_length, letters)).uppercase()
 
I guess.len != code_length | any(guess.map(char -> char !C @letters))
L.continue
E I guess == code
print("\nYour guess "guess‘ was correct!’)
L.break
E
guesses.append(‘#.: #. => #.’.format(guesses.len + 1, Array(guess).join(‘ ’), encode(code, guess).join(‘ ’)))
 
L(i_guess) guesses
print(‘------------------------------------’)
print(i_guess)
print(‘------------------------------------’)
 
play_game()</syntaxhighlight>
 
{{out}}
<pre>
Welcome to Mastermind.
You will need to guess a random code.
For each guess, you will receive a hint.
In this hint, X denotes a correct letter, and O a letter in the original string but in a different position.
 
Select a number of possible letters for the code (2-20): 4
Select a length for the code (4-10): 4
 
Enter a guess of length 4 (ABCD): abcd
------------------------------------
1: A B C D => X X O O
------------------------------------
 
Enter a guess of length 4 (ABCD): abcc
------------------------------------
1: A B C D => X X O O
------------------------------------
2: A B C C => X X O X
------------------------------------
 
Enter a guess of length 4 (ABCD): abdc
 
Your guess ABDC was correct!
</pre>
 
=={{header|Action!}}==
<syntaxhighlight lang="action!">DEFINE MINCOLORS="2"
DEFINE MAXCOLORS="20"
DEFINE MINLENGTH="4"
DEFINE MAXLENGTH="10"
DEFINE MINGUESS="7"
DEFINE MAXGUESS="20"
TYPE Score=[BYTE spot,corr,err]
TYPE Settings=[BYTE colors,length,guesses,repeat]
 
PROC GetSettings(Settings POINTER s)
CHAR ARRAY tmp(10)
 
DO
PrintF("Enter number of colors (%B-%B):",MINCOLORS,MAXCOLORS)
s.colors=InputB()
UNTIL s.colors>=MINCOLORS AND s.colors<=MAXCOLORS
OD
DO
PrintF("Enter length of code (%B-%B):",MINLENGTH,MAXLENGTH)
s.length=InputB()
UNTIL s.length>=MINLENGTH AND s.length<=MAXLENGTH
OD
DO
PrintF("Enter max number of guesses (%B-%B):",MINGUESS,MAXGUESS)
s.guesses=InputB()
UNTIL s.guesses>=MINGUESS AND s.guesses<=MAXGUESS
OD
IF s.colors<s.length THEN
s.repeat=1
ELSE
DO
Print("Allow repeated colors (Y/N):")
InputS(tmp)
IF tmp(0)=1 THEN
IF tmp(1)='y OR tmp(1)='Y THEN
s.repeat=1 EXIT
ELSEIF tmp(1)='n OR tmp(1)='N THEN
s.repeat=0 EXIT
FI
FI
OD
FI
RETURN
 
PROC Generate(CHAR ARRAY code Settings POINTER s)
CHAR ARRAY col(MAXCOLORS)
BYTE i,j,d,tmp,count
 
FOR i=0 TO MAXCOLORS-1
DO
col(i)=i+'A
OD
code(0)=s.length
count=s.colors
FOR i=1 TO s.length
DO
d=Rand(count)
code(i)=col(d)
IF s.repeat=0 THEN
count==-1
col(d)=col(count)
FI
OD
RETURN
 
BYTE FUNC GetCount(CHAR ARRAY s CHAR c)
BYTE i,count
 
count=0
FOR i=1 TO s(0)
DO
IF s(i)=c THEN
count==+1
FI
OD
RETURN (count)
 
PROC CheckScore(CHAR ARRAY code,guess
Settings POINTER s Score POINTER res)
BYTE i,j,codeCount,guessCount
 
res.spot=0
res.corr=0
IF guess(0)#s.length THEN
res.err=1
RETURN
FI
res.err=0
 
FOR i=0 TO s.colors-1
DO
codeCount=GetCount(code,i+'A)
guessCount=GetCount(guess,i+'A)
IF codeCount<guessCount THEN
res.corr==+codeCount
ELSE
res.corr==+guessCount
FI
OD
FOR i=1 TO s.length
DO
IF guess(i)=code(i) THEN
res.spot==+1
res.corr==-1
FI
OD
RETURN
 
PROC ToUpper(CHAR ARRAY s)
BYTE i,c
 
IF s(0)=0 THEN RETURN FI
FOR i=1 TO s(0)
DO
c=s(i)
IF c>='a AND c<='z THEN
s(i)=c-'a+'A
FI
OD
RETURN
 
PROC PrintScore(Score POINTER res Settings POINTER s)
INT i
 
FOR i=1 TO res.spot
DO Put('X) OD
FOR i=1 TO res.corr
DO Put('O) OD
FOR i=1 TO s.length-res.spot-res.corr
DO Put('-) OD
RETURN
 
PROC Main()
CHAR ARRAY code(MAXLENGTH+1),guess(255)
Score res
Settings s
BYTE tries
 
PrintE("Mastermind") PutE()
GetSettings(s) PutE()
Generate(code,s)
tries=s.guesses
PrintF("Enter your guess (%B tries):%E",tries)
DO
InputS(guess) ToUpper(guess)
CheckScore(code,guess,s,res)
Put(28) ;cursor up
PrintF("%S -> ",guess)
IF res.err THEN
Print("Wrong input")
ELSE
PrintScore(res,s)
IF res.spot=s.length THEN
PutE() PutE()
PrintE("You won!")
EXIT
FI
tries==-1
IF tries=0 THEN
PutE() PutE()
PrintE("You lost!")
EXIT
FI
FI
PrintF(", try again (%B tries):%E",tries)
OD
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Mastermind.png Screenshot from Atari 8-bit computer]
<pre>
Mastermind
 
Enter number of colors (2-20):6
Enter length of code (4-10):5
Enter max number of guesses (7-20):20
Allow repeated colors (Y/N):Y
 
Enter your guess (20 tries):
AAAA -> Wrong input, try again (20 tries):
AAAAA -> -----, try again (19 tries):
BBBBB -> -----, try again (18 tries):
CCCCC -> -----, try again (17 tries):
DDDDD -> XX---, try again (16 tries):
EEEEE -> X----, try again (15 tries):
DDEFF -> XXXXX
 
You won!
</pre>
 
=={{header|Ada}}==
{{works with|Ada|Ada|2012}}
 
<syntaxhighlight lang="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;
-- Input will loop until a correct value is given by the user.
-- For each wrong input, the program will prompt the range of expected values.
 
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? ");
-- Not constant: if Color < Code_Size, we will have repetitions anyway.
 
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;
</syntaxhighlight>
{{out}}
<pre>How many colors? 9
How many guesses? 4
 
Invalid input!
Expected values in range: 7 .. 20
 
How many guesses? 20
Size of the code? 4
With repeats? False
> ABCD
--------------------------------------------
ABCD => XOO-
--------------------------------------------
 
> EFGH
--------------------------------------------
ABCD => XOO-
EFGH => O---
--------------------------------------------
 
> ABCE
--------------------------------------------
ABCD => XOO-
EFGH => O---
ABCE => XOO-
--------------------------------------------
 
> ABCF
--------------------------------------------
ABCD => XOO-
EFGH => O---
ABCE => XOO-
ABCF => XOO-
--------------------------------------------
 
> ABCG
--------------------------------------------
ABCD => XOO-
EFGH => O---
ABCE => XOO-
ABCF => XOO-
ABCG => XXOO
--------------------------------------------
 
> ACBG
You won, congratulations!
</pre>
 
=={{header|APL}}==
{{works with|GNU APL}}
 
<syntaxhighlight lang="apl">#!/usr/local/bin/apl -s -f --
 
⍝ Define the alphabet
A←'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
⍝ Make ASCII values upper case
∇n←AscUp c
n←c-32×(c≥97)∧(c≤122)
 
⍝ Does a list have repeated values?
∇r←Rpts l
r←(l⍳l)≢⍳⍴l
 
⍝ Keyboard input using ⎕ and ⍞ doesn't work well using GNU APL in script mode,
⍝ so you kind of have to write your own.
⍝ Read a line of text from the keyboard
∇l←ReadLine up;k;z;data
data←'' ⋄ csr←0 ⍝ Start out with empty string and cursor at 0
 
⍝⍝⍝ Keyboard input
in: k←1⎕fio[41]1 ⍝ Read byte from stdin
handle: →(k>127)/skip ⍝ Unicode is not supported (Wumpus doesn't need it)
→(k∊8 127)/back ⍝ Handle backspace
→(k=10)/done ⍝ Newline = Enter key pressed
→(k<32)/in ⍝ For simplicity, disregard terminal control entirely
 
k←(AscUp⍣up)k ⍝ Make key uppercase if necessary
z←k⎕fio[42]0 ⍝ Echo key to stdout
data←data,k ⍝ Insert key into data
→in ⍝ Go get next key
 
⍝⍝⍝ Skip UTF-8 input (read until byte ≤ 127)
skip: k←1⎕fio[41]1 ⋄ →(k>127)/skip ⋄ →handle
⍝⍝ Backspace
back: →(0=⍴data)/in ⍝ If already at beginning, ignore
z←k⎕fio[42]0 ⍝ Backspace to terminal
data←¯1↓data ⍝ Remove character
→in ⍝ Get next key
⍝⍝ We are done, return the line as text
done: l←⎕UCS data
 
⍝ Read a positive number from the keyboard in the range [min...max]
∇n←min ReadNum max;l;z
in: l←ReadLine 0
z←10⎕fio[42]0
→(~l∧.∊'0123456789')/no
→((min≤n)∧max≥n←⍎l)/0
no: ⍞←'Please enter a number between ',(⍕min),' and ',(⍕max),': '
→in
 
⍝ Ask a numeric question
∇n←q Question lim;min;max
(min max)←lim
⍞←q,' [',(⍕min),'..',(⍕max),']? '
n←min ReadNum max
 
⍝ Read a choice from the keyboard
∇c←Choice cs;ks;k;z
ks←AscUp ⎕UCS ↑¨cs ⍝ User should press first letter of choice
in: →(~(k←AscUp 1⎕fio[41]1)∊ks)/in ⍝ Wait for user to make choice
z←(c←⊃cs[↑ks⍳k])⎕fio[42]0 ⍝ Select and output correspoinding choice
 
⍝ Ask the user for game parameters
∇parms←InitGame;clrs;len;gss;rpts
⎕←'∘∘∘ MASTERMIND ∘∘∘' ⋄ ⎕←''
clrs←'How many colors' Question 2 20
len←'Code length' Question 4 10
gss←'Maximum amount of guesses' Question 7 20
⍞←'Allow repeated colors in code (Y/N)? '
rpts←'Yes'≡Choice 'Yes' 'No'
parms←clrs len gss rpts
 
⍝ Generate a code.
∇c←rpts MakeCode parms;clrs;len
(clrs len)←parms
c←A[(1+rpts)⊃(len?clrs)(?len/clrs)]
 
⍝ Let user make a guess and handle errors
∇g←parms Guess code;clrs;rpts;l;right;in
(clrs rpts num)←parms
guess: ⍞←'Guess ',(¯2↑⍕num),': ' ⋄ g←ReadLine 1 ⍝ Read a guess from the keyboard
⍝ Don't count obvously invalid input against the user
→((⍴code)≢⍴g)/len ⍝ Length is wrong
→(~g∧.∊A[⍳clrs])/inv ⍝ Invalid code in input
→((~rpts)∧Rpts g)/rpt ⍝ No repeats allowed
⍝ Give feedback
right←g=code ⍝ Colors in right position
in←g∊code ⍝ Colors not in right position
fb←(+/right)/'X' ⍝ X = amount of matching ones
fb←fb,(+/in∧~right)/'O' ⍝ O = amount of non-matching ones
fb←fb,(+/~in)/'-' ⍝ - = amount of colors not in code
⍞←' --→ ',fb,⎕UCS 10
→0
len: ⎕←'Invalid length.' ⋄ →guess
inv: ⎕←'Invalid color.' ⋄ →guess
rpt: ⎕←'No repeats allowed.' ⋄ →guess
 
⍝ Play the game
∇ Mastermind;clrs;len;gsmax;rpts;code;gs
⎕rl←(2*32)|×/⎕ts ⍝ initialize random seed
(clrs len gsmax rpts)←InitGame
code←rpts MakeCode clrs len
⎕←2 0⍴''
⎕←'The code consists of: ',A[⍳clrs]
gs←0
loop: gs←gs+1
→(gs>gsmax)/lose
→(code≢(clrs rpts gs)Guess code)/loop
⎕←'○○○ Congratulations! ○○○'
⎕←'You won in ',(⍕gs),' guesses.'
→0
lose: ⎕←'Alas, you are out of guesses.'
⎕←'The code was: ',code
 
Mastermind
)OFF</syntaxhighlight>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">w := h := 32, maxRows := 10, numPegs := 8
ww := floor(w/2-2), hh := floor(h/2-2)
grid := [], dx := w*4.5
gosub, Decode
 
Gui, Font, S18, Consolas
loop, 4
{
i := A_Index-1
Gui, add, button, % "x" (Mod(i, 4)?"+0":"30") " y"
. (Mod(i, 4)?"10" : "10") " w" w " h" h " vGoal" A_Index , ?
}
 
Gui, Add, Text, % "section x30 h1 0x1000 w" w*6
loop, % maxRows
{
Gui, Font, S18, consolas
row := maxRows - A_Index + 1
loop 4
{
col := A_Index, i:= col-1
Gui, add, button, % "x" (Mod(i, 4)?"+0":"s") " y" (Mod(i, 4)?"p":"+2")
. " w" w " h" h " vButton" row "_" col " gButton"
}
Gui, Font, S13, wingdings 2
loop 2
{
col := A_Index, i:= col-1
Gui, add, text, % "x" (Mod(i,2)?"+1":"s+" dx) " y" (Mod(i,2)?"p":"p+1")
. " w" ww " h" hh " vKeyPeg" row "_" col, % Chr(167)
}
loop 2
{
col := A_Index+2, i:= col-1
Gui, add, text, % "x" (Mod(i,2)?"+1":"s+" dx) " y" (Mod(i,2)?"p":"+1")
. " w" ww " h" hh " vKeyPeg" row "_" col, % Chr(167)
}
Gui, Add, Text, % "section xs h1 0x1000 w" w*6 " y+4"
}
Gui, Font, S12, consolas
Gui, add, Button, % "xs y+10 gSubmit w" W*2 , Submit
Gui, add, Button, % "x+0 gResetMM w" W*2, Reset
Gui, add, Checkbox, % "x+4 vNoDup", No`nDuplicates
Gui, Font, S18
for i, v in pegs
Gui, add, Radio, % "x" (!Mod(i-1, 4)?"10":"+10") " h" h " w" w+20 " vRadio" A_Index, % v
Gui, show
Row := 1
return
;-----------------------------------------------------------------------
GuiClose:
ExitApp
return
;-----------------------------------------------------------------------
Decode:
Gui, Submit, NoHide
pegs:=[], goal := [], usedPeg :=[]
pool := ["😺","🎃","🧨","⚽","😀","☠","👽","❄","🙉","💗"
,"💥","🖐","🏈","🎱","👁","🗨","🤙","👄","🐶","🐴"
,"🦢","🐍","🐞","💣","🐪","🐘","🐰","🐸","🌴","🏀"]
 
loop, % numPegs
{
Random, rnd, 1, % pool.count()
pegs[A_Index] := pool.RemoveAt(rnd)
}
i := 1
while (goal.count()<4)
{
Random, rnd, 1, % pegs.count()
if (NoDup && usedPeg[pegs[rnd]])
continue
goal[i++] := pegs[rnd]
usedPeg[pegs[rnd]] := true
}
return
;-----------------------------------------------------------------------
Button:
if GameEnd
return
 
Gui, Submit, NoHide
RegExMatch(A_GuiControl, "Button(\d+)_(\d+)", m)
if (m1 <> row)
{
thisPeg := Grid[m1, m2]
for i, v in pegs
if (v=thisPeg)
GuiControl,, Radio%i%, 1
GuiControl,, % "Button" row "_" m2, % thisPeg
Grid[row,m2] := thisPeg
}
else
{
loop, % pegs.count()
if Radio%A_Index%
GuiControl,, % A_GuiControl , % grid[m1, m2] := pegs[A_Index]
}
return
;-----------------------------------------------------------------------
Submit:
if (grid[row].count()<4) || GameEnd
return
 
Gui, submit, NoHide
Ans := [], FIP := [], inGoal := []
CIP := CNP := 0, KeyPeg := 1
 
for i, G in Goal
inGoal[G] := (inGoal[G] ? inGoal[G] : 0) +1 ; save inGoal
loop, 4
Ans[A_Index] := Grid[row, A_Index] ; save Ans
for i, A in Ans
if (goal[A_Index] = A)
CIP++, FIP.push(i), inGoal[A]:=inGoal[A] -1 ; Correct In Place, inGoal--
for i, v in FIP
Ans.RemoveAt(v-i+1) ; remove Correct In Place from Answers
for i, A in Ans
if (inGoal[A] > 0)
CNP++, inGoal[A] := inGoal[A] -1 ; Correct Not in Place
loop % CIP
GuiControl,, % "KeyPeg" row "_" KeyPeg++, % Chr(82) ; "✔"
loop % CNP
GuiControl,, % "KeyPeg" row "_" KeyPeg++, % Chr(83) ; "X"
 
if (CIP=4 || row=maxRows)
{
loop 4
GuiControl,, Goal%A_Index%, % Goal[A_Index]
MsgBox % CIP = 4 ? "You Win" : "You lose"
GameEnd := true
}
Row++
return
;-----------------------------------------------------------------------
LAlt:: ; peak at solution (for troubleshooting purposes only!)
loop 4
GuiControl,, Goal%A_Index%, % Goal[A_Index]
While GetKeyState("Lalt", "P")
continue
loop 4
GuiControl,, Goal%A_Index%, % "?"
return
;-----------------------------------------------------------------------
ResetMM:
Grid :=[], GameEnd:= false
loop, 4
{
Random, rnd, 1, % pegs.count()
goal[A_Index] := pegs[rnd]
GuiControl,, Goal%A_Index%, ?
}
 
loop, % maxRows
{
row := maxRows - A_Index + 1
loop 4
{
col := A_Index
GuiControl,, % "KeyPeg" row "_" col, % Chr(167) ; "O"
GuiControl,, % "Button" row "_" col
}
}
gosub Decode
loop, 8
GuiControl,, Radio%A_Index%, % pegs[A_Index]
return
;-----------------------------------------------------------------------</syntaxhighlight>
 
=={{header|BASIC}}==
==={{header|FreeBASIC}}===
<syntaxhighlight lang="freebasic">'--- Declaration of global variables ---
Dim As String colors(1 To 4) => {"A", "B", "C", "D"}
Dim Shared As Integer nr, ub', numlet=4, lencod=4
Dim Shared As String*4 master, pz
ub = Ubound(colors)
nr = 0
 
'--- SUBroutines and FUNCtions ---
Sub Encabezado
Dim As String dup
Color 11: Print "Welcome to Mastermind"
Print "=====================" + Chr(13) + Chr(10) : Color 15
Print "You will need to guess a random code."
Print "For each guess, you will receive a hint:"
Print "X - denotes a correct letter,"
Print "O - denotes a letter in the original"
Print " string but a different position."
Print "You have 12 attempts."
Print "Duplicates are not allowed." + Chr(10)
Print "Good luck!" + Chr(10) + Chr(10) : Color 7
End Sub
 
Sub showresult(test() As String, place1 As Byte, place2 As Byte, place3 As Byte)
Dim As Integer r, n1, n2, n3
Print Using "##: "; nr;
For r = 1 To Ubound(test)
Print test(r);
Next R
Print " : ";
For n1 = 1 To place1
Print "X"; " ";
Next N1
For n2 = 1 To place2
Print "O"; " ";
Next N2
For n3 = 1 To place3
Print "-"; " ";
Next N3
Print : Print
End Sub
 
Sub Inicio
Dim As Integer mind(ub), rands(ub)
Dim As Integer n, aleat
Dim As Boolean repeat = false
For n = 1 To ub
While true
aleat = (Rnd * (ub-1)) + 1
If rands(aleat) <> 1 Then
mind(n) = aleat
rands(aleat) = 1
Exit While
End If
Wend
Next n
For n = 1 To ub
Mid(master,n,1) = Chr(64 + mind(n))
pz &= Chr(64 + mind(n))
Next n
End Sub
 
 
'--- Main Program ---
Randomize Timer
Cls
Dim As Integer guesses = 12
Encabezado
Inicio
Color 15: Print pz : Color 7
Do
Dim As Integer n, p, d, x, posic
Dim As Integer places(1 To 2), place1, place2, place3
Dim As String*4 testbegin
Dim As String test(ub), mastertemp, tmp
Dim As Boolean flag = True
For p = 1 To Ubound(places)
places(p) = 0
Next p
nr += 1
Input "Your guess (ABCD)? " , testbegin
For d = 1 To Ubound(test)
test(d) = Mid(testbegin,d,1)
Next d
For n = 1 To Ubound(test)
If Ucase(test(n)) <> Mid(master,n,1) Then flag = False
Next n
If flag = True Then
Color 10: Print !"\nWell done! You guess correctly." : Sleep : Exit Do
Else
For x = 1 To Len(master)
If Ucase(test(x)) = Mid(master,x,1) Then places(1) += 1
Next x
mastertemp = master
For p = 1 To Ubound(test)
posic = Instr(mastertemp, Ucase(test(p)))
If posic > 0 Then
tmp = mastertemp
mastertemp = Left(tmp,posic-1) + Mid(tmp, posic+1, Len(tmp)-1)
places(2) += 1
End If
Next p
End If
place1 = places(1)
place2 = places(2) - place1
place3 = Len(master) - (place1 + place2)
showresult(test(), place1, place2, place3)
Loop Until nr = guesses
Color 14: Print "The correct combination was: "; pz
Color 7: Print !"\nEnd of game"
Sleep</syntaxhighlight>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <algorithm>
#include <ctime>
Line 203 ⟶ 1,114:
return 0;
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 232 ⟶ 1,143:
=={{header|EasyLang}}==
 
[https://easylang.onlinedev/apps/mastermind.html Run it]
 
<syntaxhighlight>
<lang>col[] = [ 922 990 171 229 950 808 ]
col[] = [ 802 990 171 229 950 808 ]
len code[] 4
len guess[] 4
#
subr init_vars
row = 70
.
funcproc draw_rate r black white . .
for j rangerange0 2
for c rangerange0 2
move c * 3.5 + 6771.5 r * 11.5 + 129.64 +- j * 3.5
if black > 0
color 000
circle 1.24
black -= 1
elif white > 0
color 999
circle 1.24
white -= 1
else
color 420310
circle 0.7
.
.
.
.
.
funcproc show_code . .
color 642531
move 2722 092
rect 46 8
for i rangeto 4
move i * 8 + 3320 397
color col[code[i]]
circle 2
.
.
funcproc next_rowdraw_guess . .
for ic rangeto 4
move c * 12 + 8 row * 11.5 + 7.5
guess[i] = -1
color col[guess[c]]
.
circle 3.8
for c range 4
.
move c * 9 + 32 row * 11 + 14
color 900
circle 2
color 420
circle 1.7
.
.
funcproc ratenext_row . .
color 420
test[] = code[]
linewidth 11
for i range 4
move if17 guess[i]row =* test[i]11.5 + 7.5
line 60 row black* 11.5 += 17.5
draw_guess
test[i] = -2
move 73.5 row guess[i]* =11.5 -1+ 7.5
color .310
circle 5.0
for icolor range 4753
move for71.5 jrow range* 411.5 + 5
textsize 7
if guess[i] = test[j]
text "✓"
white += 1
.
test[j] = -2
proc rate . .
guess[i] = -1
move 73.5 row * 11.5 + 7.5
color 531
circle 5.2
c[] = code[]
g[] = guess[]
for i to 4
if c[i] = g[i]
black += 1
c[i] = -1
g[i] = -2
.
.
for i to 4
.
move 64 row * 11for +j 11to 4
if c[i] = g[j]
color 642
white += 1
rect 9 6
c[i] = -1
#
g[j] = -2
call draw_rate row black white
row -= 1 .
if black = 4 .
row = -1.
draw_rate row black white
.
if rowcolor = -1531
linewidth 12
call show_code
move 17 row * 11.5 + 7.5
else
line 60 row * 11.5 + 7.5
call next_row
draw_guess
.
row += 1
if black = 4
row = 8
.
if row = 8
show_code
timer 2
else
next_row
.
.
on timer
func new . .
row = -2
call init_vars
.
for i range 4
proc new . .
code[i] = random 6
init_vars
.
for i to 4
color 642
code[i] = randint 6
move 15 0
rect 70 100.
color 420531
move 2710 010
rect 4670 880
move 35linewidth 210
move 5 95
color 864
line 5 5
text "Mastermind"
line 85 5
color 420
move 25line 1085 95
line 255 9495
move 75color 10310
line 75linewidth 947
for rmove range28 896.5
line for58 c range 496.5
move c * 9 + 32 r * 11 +30 1495
color circle 2864
textsize .4
text "Mastermind"
call draw_rate r 0 0
color 310
.
linewidth 0.5
call next_row
move 10 90
line 10 4
move 67 90
line 67 4
move 80 90
line 80 4
for r range0 8
for c range0 4
move c * 12 + 20 r * 11.5 + 7.5
circle 2
.
draw_rate r 0 0
.
guess[1] = 1
guess[2] = 1
guess[3] = 2
guess[4] = 2
next_row
.
proc do_move . .
#
c = (mouse_x - 15) div 12
func do_move . .
guess[c + 1] = truncguess[c + ((mouse_x1] -mod 27.5)6 /+ 9)1
draw_guess
move c * 9 + 32 row * 11 + 14
guess[c] = (guess[c] + 1) mod 6
color col[guess[c]]
circle 3.2
#
if guess[0] > -1 and guess[1] > -1 and guess[2] > -1 and guess[3] > -1
move 64 row * 11 + 11
color 900
rect 8.6 6
move 64.2 row * 11 + 11.2
color 642
rect 8.2 5.6
color 420
move 64.6 row * 11 + 11.6
text "OK"
.
.
on mouse_down
if row = -12
call new
elif mouse_y > row * 11.5 + 90.5 and mouse_y < row * 11.5 + 1910.5 and row < 8
if mouse_x > 2815 and mouse_x < 63.561
call do_move
elif mouse_x > 6567 and mouse_x < 7780
rate
if guess[0] > -1 and guess[1] > -1 and guess[2] > -1 and guess[3] > -1
call rate
.
.
.
.
new
textsize 5
</syntaxhighlight>
linewidth 0.8
call new</lang>
 
=={{header|Go}}==
 
<langsyntaxhighlight Golang="go">package main
 
import (
Line 569 ⟶ 1,496:
none := m.holes - black - white
return blacks[:black] + whites[:white] + nones[:none], black == m.holes
}</langsyntaxhighlight>
{{out|note=using Knuth's five-guess algorithm}}
<pre>
Line 589 ⟶ 1,516:
 
You found the code in 5 guesses.
</pre>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;
 
public final class MastermindTask {
 
public static void main(String[] aArgs) {
Mastermind mastermind = new Mastermind(4, 8, 12, false);
mastermind.play();
}
private static final class Mastermind {
public Mastermind(int aCodeLength, int aLetterCount, int aGuessCount, boolean aRepeatLetters) {
if ( aCodeLength < 4 ) {
aCodeLength = 4;
} else if ( aCodeLength > 10 ) {
aCodeLength = 10;
}
if ( aLetterCount < 2 ) {
aLetterCount = 2;
} else if ( aLetterCount > 20 ) {
aLetterCount = 20;
}
if ( aGuessCount < 7 ) {
aGuessCount = 7;
} else if ( aGuessCount > 20 ) {
aGuessCount = 20;
}
if ( ! aRepeatLetters && aLetterCount < aCodeLength ) {
aLetterCount = aCodeLength;
}
codeLength = aCodeLength;
letterCount = aLetterCount;
guessCount = aGuessCount;
repeatLetters = aRepeatLetters;
 
String validLetters = "ABCDEFGHIJKLMNOPQRST";
letters = "";
for ( int i = 0; i < letterCount; i++ ) {
letters += validLetters.charAt(i);
}
}
public void play() {
boolean playerWin = false;
goal = createGoal();
 
while ( guessCount > 0 && ! playerWin ) {
showBoard();
if ( checkUserInput(obtainUserGuess()) ) {
playerWin = true;
reader.close();
}
guessCount--;
}
if ( playerWin ) {
System.out.println(newLine + newLine + "--------------------------------" + newLine +
"Very well done! " + newLine + "You found the code: " + goal +
newLine + "--------------------------------" + newLine + newLine);
} else {
System.out.println(newLine + newLine + "--------------------------------" + newLine +
"I'm sorry, you couldn't make it! " + newLine + "The code was: " + goal +
newLine + "--------------------------------" + newLine + newLine);
}
}
private void showBoard() {
for ( int i = 0; i < guesses.size(); i++ ) {
System.out.print(newLine + "--------------------------------" + newLine);
System.out.print(( i + 1 ) + ": ");
for ( char ch : guesses.get(i) ) {
System.out.print(ch + " ");
}
 
System.out.print(" : ");
for ( char ch : results.get(i) ) {
System.out.print(ch + " ");
}
 
final int errorCount = codeLength - results.get(i).size();
for ( int j = 0; j < errorCount; j++ ) {
System.out.print("- ");
}
}
System.out.print(newLine + newLine);
}
private String obtainUserGuess() {
String result = "";
do {
System.out.print("Enter your guess (" + letters + "): ");
result = reader.nextLine().toUpperCase();
if ( result.length() != codeLength ) {
System.out.println("Please try again, your guess should have " + codeLength + " letters");
}
} while ( result.length() != codeLength );
return result;
}
private boolean checkUserInput(String aUserInput) {
List<Character> userInputCharacters = new ArrayList<Character>();
for ( char ch : aUserInput.toCharArray() ) {
userInputCharacters.add(ch);
}
guesses.add(userInputCharacters);
int xCount = 0;
int oCount = 0;
List<Boolean> fullMatches = new ArrayList<Boolean>(Collections.nCopies(codeLength, false));
List<Boolean> partialMatches = new ArrayList<Boolean>(Collections.nCopies(codeLength, false));
for ( int i = 0; i < codeLength; i++ ) {
if ( aUserInput.charAt(i) == goal.charAt(i) ) {
fullMatches.set(i, true);
partialMatches.set(i, true);
xCount++;
}
}
for ( int i = 0; i < codeLength; i++ ) {
if ( fullMatches.get(i) ) {
continue;
}
for ( int j = 0; j < codeLength; j++ ) {
if ( i == j || partialMatches.get(j) ) {
continue;
}
if ( aUserInput.charAt(i) == goal.charAt(j) ) {
partialMatches.set(j, true);
oCount++;
break;
}
}
}
List<Character> nextResult = new ArrayList<Character>();
for ( int i = 0; i < xCount; i++ ) {
nextResult.add('X');
}
for ( int i = 0; i < oCount; i++ ) {
nextResult.add('O');
}
results.add(nextResult);
 
return xCount == codeLength;
}
private String createGoal() {
String result = "";
String lettersCopy = letters;
 
for ( int i = 0; i < codeLength; i++ ) {
final int index = random.nextInt(lettersCopy.length());
result += lettersCopy.charAt(index);
if ( ! repeatLetters ) {
lettersCopy = lettersCopy.substring(0, index) + lettersCopy.substring(index + 1);
}
}
return result;
}
private int codeLength, letterCount, guessCount;
private String letters, goal;
private boolean repeatLetters;
private Scanner reader = new Scanner(System.in);
private List<List<Character>> guesses = new ArrayList<List<Character>>();
private List<List<Character>> results = new ArrayList<List<Character>>();
private final ThreadLocalRandom random = ThreadLocalRandom.current();
private final String newLine = System.lineSeparator();
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
Enter your guess (ABCDEFGH): abcd
 
--------------------------------
1: A B C D : X O O -
 
Enter your guess (ABCDEFGH): bcde
 
--------------------------------
1: A B C D : X O O -
--------------------------------
2: B C D E : O O O -
 
Enter your guess (ABCDEFGH): fbcd
 
--------------------------------
1: A B C D : X O O -
--------------------------------
2: B C D E : O O O -
--------------------------------
3: F B C D : X O O O
 
Enter your guess (ABCDEFGH): fbdc
 
--------------------------------
1: A B C D : X O O -
--------------------------------
2: B C D E : O O O -
--------------------------------
3: F B C D : X O O O
--------------------------------
4: F B D C : X X O O
 
Enter your guess (ABCDEFGH):
 
// continues ...
</pre>
 
Line 594 ⟶ 1,745:
You can try it [http://paulo-jorente.de/webgames/repos/mastermind/ here].
 
<langsyntaxhighlight lang="javascript">
class Mastermind {
constructor() {
Line 827 ⟶ 1,978:
mm.check()
});
</syntaxhighlight>
</lang>
 
To test you'll need a HTML file
Line 963 ⟶ 2,114:
=={{header|Julia}}==
GUI version, uses the Gtk toolkit.
<langsyntaxhighlight lang="julia">using Gtk, Colors, Cairo, Graphics
 
struct Guess
Line 978 ⟶ 2,129:
if i == j
hints[i] = colorant"black"
elseelseif hints[i] != colorant"black"
hints[i] = colorant"white"
end
Line 1,172 ⟶ 2,323:
 
mastermindapp()
</syntaxhighlight>
</lang>
 
 
 
=={{header|Kotlin}}==
{{trans|C++}}
<langsyntaxhighlight lang="scala">// version 1.2.51
 
import java.util.Random
Line 1,295 ⟶ 2,444:
val m = Mastermind(4, 8, 12, false)
m.play()
}</langsyntaxhighlight>
 
Sample input/output (showing last 2 guesses only):
Line 1,335 ⟶ 2,484:
=={{header|Lua}}==
Based on C++
<langsyntaxhighlight lang="lua">
math.randomseed( os.time() )
local black, white, none, code = "X", "O", "-"
Line 1,414 ⟶ 2,563:
if arg[4] ~= nil and arg[4] == "true" or arg[4] == "false" then rept = ( arg[4] == "true" ) end
play()
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,438 ⟶ 2,587:
Play again( Y/N )?
</pre>
 
=={{header|Nim}}==
{{trans|Python}}
<syntaxhighlight lang="nim">import random, sequtils, strformat, strutils
 
proc encode(correct, guess: string): string =
result.setlen(correct.len)
for i in 0..correct.high:
result[i] = if correct[i] == guess[i]: 'X' else: (if guess[i] in correct: 'O' else: '-')
result.join(" ")
 
proc safeIntInput(prompt: string; minVal, maxVal: Positive): int =
while true:
stdout.write prompt
let userInput = stdin.readLine()
result = try: parseInt(userInput)
except ValueError: continue
if result in minVal..maxVal:
return
 
 
proc playGame() =
 
echo "You will need to guess a random code."
echo "For each guess, you will receive a hint."
echo "In this hint, X denotes a correct letter, " &
"and O a letter in the original string but in a different position."
echo ""
 
let numLetters = safeIntInput("Select a number of possible letters for the code (2-20): ", 2, 20)
let codeLength = safeIntInput("Select a length for the code (4-10): ", 4, 10)
let letters = "ABCDEFGHIJKLMNOPQRST"[0..<numLetters]
let code = newSeqWith(codeLength, letters.sample()).join()
var guesses: seq[string]
 
while true:
echo ""
stdout.write &"Enter a guess of length {codeLength} ({letters}): "
let guess = stdin.readLine().toUpperAscii().strip()
if guess.len != codeLength or guess.anyIt(it notin letters):
continue
elif guess == code:
echo &"\nYour guess {guess} was correct!"
break
else:
guesses.add &"{guesses.len + 1}: {guess.join(\" \")} => {encode(code, guess)}"
for guess in guesses:
echo "------------------------------------"
echo guess
echo "------------------------------------"
 
 
randomize()
playGame()</syntaxhighlight>
 
{{out}}
<pre>You will need to guess a random code.
For each guess, you will receive a hint.
In this hint, X denotes a correct letter, and O a letter in the original string but in a different position.
 
Select a number of possible letters for the code (2-20): 4
Select a length for the code (4-10): 4
 
Enter a guess of length 4 (ABCD): ABCD
------------------------------------
1: A B C D => - O - X
------------------------------------
 
Enter a guess of length 4 (ABCD): BDBD
------------------------------------
1: A B C D => - O - X
------------------------------------
2: B D B D => X X O X
------------------------------------
 
Enter a guess of length 4 (ABCD): BDDD
 
Your guess BDDD was correct!</pre>
 
=={{header|Perl}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="perl">use List::Util qw(any);
 
print 'Enter pool size, puzzle size, attempts allowed: ';
Line 1,492 ⟶ 2,719:
 
sub lose { print 'Too bad, you ran out of guesses. The solution was: ' . join(' ',@puzzle) . "\n"; exit }
</syntaxhighlight>
</lang>
Sample output, omitting redundant instructions.
{{out}}
Line 1,511 ⟶ 2,738:
Your guess?: b d a c
You win! The correct answer is: B D A C</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|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;
 
my $black = '●';
my $white = '○';
 
loop {
clearscr();
say header();
printf " %{$length * 2}s :: %s\n", @guesses[$_][0], @guesses[$_][1] for ^@guesses;
say '';
lose() if @guesses == $guesses;
my $guess = get-guess();
next unless $guess.&is-valid;
my $score = score($puzzle, $guess);
win() if $score eq ($black xx $length).join: ' ';
@guesses.push: [$guess, $score];
}
 
sub header {
my $num = $guesses - @guesses;
qq:to/END/;
Valid letter, but wrong position: ○ - Correct letter and position: ●
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: $black;
}
elsif $puzzle[$_] eq any(@$guess) {
@score.push: $white;
}
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>
{{out|Sample output}}
<pre>Valid letter, but wrong position: ○ - Correct letter and position: ●
Guess the 4 element sequence containing the letters A B C D E F
Repeats are not allowed. You have 5 guesses remaining.
 
A B C D :: ○ ○ ○ -
C A B E :: ● ○ ○ -
D A E F :: ● ○ - -
B A E C :: ● ○ ○ -
D E B C :: ○ ○ ○ ○
 
Your guess?: cdeb
You Win! The correct answer is: (C D E B)</pre>
 
=={{header|Phix}}==
OTT GUI solution, fully configurable with solver.
<langsyntaxhighlight Phixlang="phix">-- demo/rosetta/mastermind.exw
constant SET_LIMIT = 1_000_000 -- above this, it uses random sampling.
 
Line 2,158 ⟶ 3,309:
IupClose()
end procedure
main()</langsyntaxhighlight>
 
=={{header|Prolog}}==
 
<syntaxhighlight lang="prolog">mastermind :- mastermind(7, 4, 8, no_duplicates).
 
mastermind(Colours, Length, Guesses, Duplicates) :-
between(2, 20, Colours),
between(4, 10, Length),
between(7, 20, Guesses),
member(Duplicates, [allow_duplicates, no_duplicates]),
 
create_board(Colours, Length, Duplicates, Board),
intro(Colours, Length, Duplicates),
play(board(Board, Length, Colours, Guesses), [], 0), !.
 
intro(Colours, Length, Duplicates) :-
format('Guess the code!~n'),
format('There are ~p character types, and ~p letters to guess~n',
[Colours, Length]),
Duplicates = allow_duplicates
-> format('Duplicates are allowed~n~n')
; format('Duplicates are not allowed~n~n').
 
/* Create the combination to be guessed */
create_board(Colours, Length, Duplicates, Board) :-
length(Board, Length),
valid_char_list(Colours, CharSet),
repeat,
maplist(random_alpha(CharSet), Board),
check_for_duplicates(Board, Duplicates).
 
check_for_duplicates(_, allow_dupicates).
check_for_duplicates(Board, no_duplicates) :- is_set(Board).
 
/* Main loop - get the player guess and print out status */
play(board(Board,_,_,MaxGuesses), _, MaxGuesses) :-
write('Sorry, You failed to guess in time...!\nThe code was : '),
maplist(write, Board),
nl.
play(BoardData, PrevGuesses, GuessNum) :-
BoardData = board(_, Length, Colours, MaxGuesses),
GuessNum < MaxGuesses,
ReportedGuess is GuessNum + 1,
format('Guess #~p of #~p: ', [ReportedGuess, MaxGuesses]),
get_player_guess(Length, Colours, Guess),
evaluate_and_print_result(BoardData, PrevGuesses, ReportedGuess, Guess).
 
evaluate_and_print_result(board(Board,_,_,_), _, _,Board) :-
format('Well done! You Guessed Correctly.~n').
evaluate_and_print_result(BoardData, PrevGuesses, NextGuessNum, Guess) :-
BoardData = board(Board, _, _, _),
dif(Board, Guess),
match_guess_to_board(Board, Guess, Diffs),
append(PrevGuesses, [guess(NextGuessNum, Guess, Diffs)], Guesses),
maplist(print_guess, Guesses),
play(BoardData, Guesses, NextGuessNum).
 
/* Get the player guess and validate that it matches the rules */
get_player_guess(Length, Colours, Guess) :-
repeat,
read_line_to_string(user_input, Line),
string_chars(Line, Guess),
 
% validate the correct number of items have been entered
length(Guess, Length),
 
% validate that all the characters are valid for the number of colours
valid_char_list(Colours, ValidCharSet),
subset(Guess, ValidCharSet).
 
/* Predicates to figure out how many places are correct */
match_guess_to_board(Board, Guess, Matches) :-
maplist(guess_differences(Board), Board, Guess, Differences),
sort(0, @>=, Differences, Matches).
 
% Same position, same type
guess_differences(_Board, B, B, 'X').
% Same type, different position
guess_differences(Board, B, G, 'O') :- dif(B, G), member(G, Board).
% Type not on board
guess_differences(Board, B, G, '-') :- dif(B, G), \+ member(G, Board).
 
/* Print out the current progress */
print_guess(guess(NextGuessNumber, Guess, Differences)) :-
format('~w: ', NextGuessNumber),
maplist(format('~w '), Guess),
format(' : '),
maplist(format('~w '), Differences),
nl.
 
/* Utils */
alpha_chars([a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]).
 
valid_char_list(Colours, CharSet) :-
alpha_chars(AllChars),
truncate_list(AllChars, Colours, CharSet).
 
random_alpha(AllChars, RandomMember) :- random_member(RandomMember, AllChars).
 
truncate_list(_, 0, []).
truncate_list([A|T], N, [A|R]) :-
N > 0,
N1 is N - 1,
truncate_list(T, N1, R).</syntaxhighlight>
{{out}}
<pre>
1 ?- mastermind.
Guess the code!
There are 7 character types, and 4 letters to guess
Duplicates are not allowed
 
Guess #1 of #8: abcd
1: a b c d : X O O -
Guess #2 of #8: acbe
1: a b c d : X O O -
2: a c b e : X O - -
Guess #3 of #8: fgab
1: a b c d : X O O -
2: a c b e : X O - -
3: f g a b : O O - -
Guess #4 of #8: cdfg
1: a b c d : X O O -
2: a c b e : X O - -
3: f g a b : O O - -
4: c d f g : X X O -
Guess #5 of #8: cdfb
1: a b c d : X O O -
2: a c b e : X O - -
3: f g a b : O O - -
4: c d f g : X X O -
5: c d f b : X X O -
Guess #6 of #8: cdaf
1: a b c d : X O O -
2: a c b e : X O - -
3: f g a b : O O - -
4: c d f g : X X O -
5: c d f b : X X O -
6: c d a f : X O O O
Guess #7 of #8: acdf
1: a b c d : X O O -
2: a c b e : X O - -
3: f g a b : O O - -
4: c d f g : X X O -
5: c d f b : X X O -
6: c d a f : X O O O
7: a c d f : X O O O
Guess #8 of #8: adfc
Well done! You Guess Correctly.
true.
</pre>
 
=={{header|Python}}==
{{works with|cpython|3.7.3}}
Tested in Python 3.7.3. Includes input verification.
<langsyntaxhighlight lang="python">
import random
 
Line 2,169 ⟶ 3,470:
def encode(correct, guess):
output_arr = [''] * len(correct)
correct_list = list(correct)
 
for i, (correct_char, guess_char) in enumerate(zip(correct, guess)):
output_arr[i] = 'X' if correct_charguess_char == correct_char else 'O' if guess_char: in correct else '-'
output_arr[i] = 'X'
correct_list.remove(guess_char)
 
for i, guess_char in enumerate(guess):
if output_arr[i] != '':
continue
elif guess_char in correct_list:
output_arr[i] = 'O'
correct_list.remove(guess_char)
else:
output_arr[i] = '-'
 
return ''.join(output_arr)
Line 2,205 ⟶ 3,494:
print("You will need to guess a random code.")
print("For each guess, you will receive a hint.")
print("In this hint, X denotes a correct letter, and O a letter in the original string but in a different position.")
print()
print("X's and O's will only be given for a letter as many times as that letter occurs in the code.")
print('')
 
number_of_letters = safe_int_input("Select a number of possible letters for the code (2-20): ", 2, 20)
Line 2,217 ⟶ 3,505:
 
while True:
print('')
guess = input(f"Enter a guess of length {code_length} ({letters}): ").upper().strip()
 
Line 2,237 ⟶ 3,525:
play_game()
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,244 ⟶ 3,532:
For each guess, you will receive a hint.
In this hint, X denotes a correct letter, and O a letter in the original string but a different position.
X's and O's will only be given for a letter as many times as that letter occurs in the code.
 
Select a number of possible letters for the code (2-20): 4
Line 2,251 ⟶ 3,538:
*omitted first guesses*
 
Enter a guess of length 4 (ABCD): ccddcdaa
------------------------------------
1: A A B B => O -O - -
------------------------------------
2: C C D DA A => O X X - XO
------------------------------------
 
Enter a guess of length 4 (ABCD): ccadddac
 
Your guess CCADDDAC was correct!
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|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.
<syntaxhighlight lang="raku" line>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;
 
my $black = '●';
my $white = '○';
 
loop {
clearscr();
say header();
printf " %{$length * 2}s :: %s\n", @guesses[$_][0], @guesses[$_][1] for ^@guesses;
say '';
lose() if @guesses == $guesses;
my $guess = get-guess();
next unless $guess.&is-valid;
my $score = score($puzzle, $guess);
win() if $score eq ($black xx $length).join: ' ';
@guesses.push: [$guess, $score];
}
 
sub header {
my $num = $guesses - @guesses;
qq:to/END/;
Valid letter, but wrong position: ○ - Correct letter and position: ●
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: $black;
}
elsif $puzzle[$_] eq any(@$guess) {
@score.push: $white;
}
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 }
}</syntaxhighlight>
{{out|Sample output}}
<pre>Valid letter, but wrong position: ○ - Correct letter and position: ●
Guess the 4 element sequence containing the letters A B C D E F
Repeats are not allowed. You have 5 guesses remaining.
 
A B C D :: ○ ○ ○ -
C A B E :: ● ○ ○ -
D A E F :: ● ○ - -
B A E C :: ● ○ ○ -
D E B C :: ○ ○ ○ ○
 
Your guess?: cdeb
You Win! The correct answer is: (C D E B)</pre>
 
=={{header|REXX}}==
More checks could have been added &nbsp; (for illegal inputs and illegal options).
<langsyntaxhighlight 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 " " " */
Line 2,342 ⟶ 3,706:
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</langsyntaxhighlight>
'''output'''
<pre>
Line 2,399 ⟶ 3,763:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Mastermind
 
Line 2,493 ⟶ 3,857:
next
see nl
</syntaxhighlight>
</lang>
Output:
<pre>
Line 2,505 ⟶ 3,869:
Well done!
End of game
</pre>
 
=={{header|Rust}}==
{{libheader|rand}}
<syntaxhighlight lang="rust">extern crate rand;
 
use rand::prelude::*;
use std::io;
 
fn main() {
let mut input_line = String::new();
let colors_n;
let code_len;
let guesses_max;
let colors_dup;
 
loop {
println!("Please enter the number of colors to be used in the game (2 - 20): ");
input_line.clear();
io::stdin()
.read_line(&mut input_line)
.expect("The read line failed.");
match (input_line.trim()).parse::<i32>() {
Ok(n) => {
if n >= 2 && n <= 20 {
colors_n = n;
break;
} else {
println!("Outside of range (2 - 20).");
}
}
Err(_) => println!("Invalid input."),
}
}
let colors = &"ABCDEFGHIJKLMNOPQRST"[..colors_n as usize];
 
println!("Playing with colors {}.\n", colors);
 
loop {
println!("Are duplicated colors allowed in the code? (Y/N): ");
input_line.clear();
io::stdin()
.read_line(&mut input_line)
.expect("The read line failed.");
if ["Y", "N"].contains(&&input_line.trim().to_uppercase()[..]) {
colors_dup = input_line.trim().to_uppercase() == "Y";
break;
} else {
println!("Invalid input.");
}
}
println!(
"Duplicated colors {}allowed.\n",
if colors_dup { "" } else { "not " }
);
loop {
let min_len = if colors_dup { 4 } else { 4.min(colors_n) };
let max_len = if colors_dup { 10 } else { 10.min(colors_n) };
println!(
"Please enter the length of the code ({} - {}): ",
min_len, max_len
);
input_line.clear();
io::stdin()
.read_line(&mut input_line)
.expect("The read line failed.");
match (input_line.trim()).parse::<i32>() {
Ok(n) => {
if n >= min_len && n <= max_len {
code_len = n;
break;
} else {
println!("Outside of range ({} - {}).", min_len, max_len);
}
}
Err(_) => println!("Invalid input."),
}
}
println!("Code of length {}.\n", code_len);
loop {
println!("Please enter the number of guesses allowed (7 - 20): ");
input_line.clear();
io::stdin()
.read_line(&mut input_line)
.expect("The read line failed.");
match (input_line.trim()).parse::<i32>() {
Ok(n) => {
if n >= 7 && n <= 20 {
guesses_max = n;
break;
} else {
println!("Outside of range (7 - 20).");
}
}
Err(_) => println!("Invalid input."),
}
}
println!("{} guesses allowed.\n", guesses_max);
 
let mut rng = rand::thread_rng();
let mut code;
if colors_dup {
code = (0..code_len)
.map(|_| ((65 + rng.gen_range(0, colors_n) as u8) as char))
.collect::<Vec<_>>();
} else {
code = colors.chars().collect::<Vec<_>>();
code.shuffle(&mut rng);
code = code[..code_len as usize].to_vec();
}
//code = vec!['J', 'A', 'R', 'D', 'A', 'N', 'I'];
//println!("Secret code: {:?}", code);
let mut guesses: Vec<(String, String)> = vec![];
let mut i = 1;
loop {
println!("Your guess ({}/{})?: ", i, guesses_max);
input_line.clear();
io::stdin()
.read_line(&mut input_line)
.expect("The read line failed.");
let mut guess = input_line.trim().to_uppercase();
if guess.len() as i32 > code_len {
guess = guess[..code_len as usize].to_string();
}
let guess_v = guess.chars().collect::<Vec<char>>();
let res = evaluate(&code, &guess_v);
guesses.push((guess, res.clone()));
let width = 8 + guesses_max.to_string().len() + code_len as usize * 2;
println!("{}", "-".repeat(width));
for (i, guess) in guesses.iter().enumerate() {
let line = format!(
" {:w1$} : {:w2$} : {:w2$} ",
i + 1,
guess.0,
guess.1,
w1 = guesses_max.to_string().len(),
w2 = code_len as usize
);
println!("{}", line);
}
println!("{}", "-".repeat(width));
if res == "X".repeat(code_len as usize) {
println!("You won! Code: {}", code.into_iter().collect::<String>());
break;
}
i += 1;
if i > guesses_max {
println!("You lost. Code: {}", code.into_iter().collect::<String>());
break;
}
}
}
 
fn evaluate(code: &[char], guess: &[char]) -> String {
let mut res: Vec<char> = vec![];
for i in 0..guess.len() {
if guess[i] == code[i] {
res.push('X');
} else if code.contains(&guess[i]) {
res.push('O');
} else {
res.push('-');
}
}
res.sort_by(|a, b| b.cmp(a));
res.into_iter().collect()
}</syntaxhighlight>
{{out}}
<pre>
Please enter the number of colors to be used in the game (2 - 20):
20
Playing with colors ABCDEFGHIJKLMNOPQRST.
 
Are duplicated colors allowed in the code? (Y/N):
n
Duplicated colors not allowed.
 
Please enter the length of the code (4 - 10):
10
Code of length 10.
 
Please enter the number of guesses allowed (7 - 20):
20
20 guesses allowed.
 
Your guess (1/20)?:
abcdefghi
------------------------------
1 : ABCDEFGHI : OOOOOO---
------------------------------
<...>
Your guess (20/20)?:
ipgecnmhdk
------------------------------
1 : ABCDEFGHI : OOOOOO---
2 : ABCDE : OOO--
3 : ABC : O--
4 : DEBF : OO--
5 : DEAG : OOO-
6 : DEAH : OOO-
7 : DEAGH : OOOO-
8 : DEGHI : XOOOO
9 : JKLMN : OOO--
10 : JKL : O--
11 : K : O
12 : DEGHIK : XOOOOO
13 : MN : OO
14 : OPQ : X--
15 : QRS : ---
16 : PT : O-
17 : PEGHIKCMND : XOOOOOOOOO
18 : HKMNICDPEG : OOOOOOOOOO
19 : EGNHKMPDCI : OOOOOOOOOO
20 : IPGECNMHDK : XXXXXXXXOO
------------------------------
You lost. Code: IPGECHMNDK
</pre>
 
=={{header|SQL}}==
<syntaxhighlight lang="sql">
-- Create Table
-- Distinct combination
--- R :Red, B :Blue, G: Green, V: Violet, O: Orange, Y: Yellow
DROP TYPE IF EXISTS color cascade;CREATE TYPE color AS ENUM ('R', 'B', 'G', 'V', 'O', 'Y');
 
DROP TABLE IF EXISTS guesses cascade ; CREATE TABLE guesses (
first color,
second color,
third color ,
fourth color
);
CREATE TABLE mastermind () inherits (guesses);
 
INSERT INTO mastermind values ('G', 'B', 'R', 'V');
 
 
INSERT INTO guesses values ('Y', 'Y', 'B', 'B');
INSERT INTO guesses values ('V', 'R', 'R', 'Y');
INSERT INTO guesses values ('G', 'V', 'G', 'Y');
INSERT INTO guesses values ('R', 'R', 'V', 'Y');
INSERT INTO guesses values ('B', 'R', 'G', 'V');
INSERT INTO guesses values ('G', 'B', 'R', 'V');
 
 
--- Matches Black
CREATE OR REPLACE FUNCTION check_black(guesses, mastermind) RETURNS integer AS $$
SELECT (
($1.first = $2.first)::int +
($1.second = $2.second)::int +
($1.third = $2.third)::int +
($1.fourth = $2.fourth)::int
);
$$ LANGUAGE SQL;
 
--- Matches White
CREATE OR REPLACE FUNCTION check_white(guesses, mastermind) RETURNS integer AS $$
SELECT (
case when ($1.first = $2.first) then 0 else 0 end +
case when ($1.second = $2.second) then 0 else 0 end +
case when ($1.third = $2.third) then 0 else 0 end +
case when ($1.fourth = $2.fourth) then 0 else 0 end +
case when ($1.first != $2.first) then (
$1.first = $2.second or
$1.first = $2.third or
$1.first = $2.fourth
)::int else 0 end +
case when ($1.second != $2.second) then (
$1.second = $2.first or
$1.second = $2.third or
$1.second = $2.fourth
)::int else 0 end +
case when ($1.third != $2.third) then (
$1.third = $2.first or
$1.third = $2.second or
$1.third = $2.fourth
)::int else 0 end +
case when ($1.fourth != $2.fourth) then (
$1.fourth = $2.first or
$1.fourth = $2.second or
$1.fourth = $2.third
)::int else 0 end
) from guesses
$$ LANGUAGE SQL;
 
 
 
SELECT guesses,
check_black(guesses.*, mastermind.*),
check_white(guesses.*, mastermind.*)
FROM guesses, mastermind
</syntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-ioutil}}
{{libheader|Wren-str}}
<syntaxhighlight lang="wren">import "random" for Random
import "./ioutil" for Input
import "./str" for Str
 
var Rand = Random.new()
 
class Mastermind {
construct new(codeLen, colorsCnt, guessCnt, repeatClr) {
var color = "ABCDEFGHIJKLMNOPQRST"
_codeLen = codeLen.clamp(4, 10)
var cl = colorsCnt
if (!repeatClr && cl < _codeLen) cl = _codeLen
_colorsCnt = cl.clamp(2, 20)
_guessCnt = guessCnt.clamp(7, 20)
_repeatClr = repeatClr
_colors = color.take(_colorsCnt).join()
_combo = ""
_guesses = []
_results = []
}
 
play() {
var win = false
_combo = getCombo_()
while (_guessCnt != 0) {
showBoard_()
if (checkInput_(getInput_())) {
win = true
break
}
_guessCnt = _guessCnt - 1
}
System.print("\n\n--------------------------------")
if (win) {
System.print("Very well done!\nYou found the code: %(_combo)")
} else {
System.print("I am sorry, you couldn't make it!\nThe code was: %(_combo)")
}
System.print("--------------------------------\n")
}
 
showBoard_() {
for (x in 0..._guesses.count) {
System.print("\n--------------------------------")
System.write("%(x + 1): ")
for (y in _guesses[x]) System.write("%(y) ")
System.write(" : ")
for (y in _results[x]) System.write("%(y) ")
var z = _codeLen - _results[x].count
if (z > 0) System.write("- " * z)
}
System.print("\n")
}
 
getInput_() {
while (true) {
var a = Str.upper(Input.text("Enter your guess (%(_colors)): ", 1)).take(_codeLen)
if (a.all { |c| _colors.contains(c) } ) return a.join()
}
}
 
checkInput_(a) {
_guesses.add(a.toList)
var black = 0
var white = 0
var gmatch = List.filled(_codeLen, false)
var cmatch = List.filled(_codeLen, false)
for (i in 0..._codeLen) {
if (a[i] == _combo[i]) {
gmatch[i] = true
cmatch[i] = true
black = black + 1
}
}
for (i in 0..._codeLen) {
if (gmatch[i]) continue
for (j in 0..._codeLen) {
if (i == j || cmatch[j]) continue
if (a[i] == _combo[j]) {
cmatch[j] = true
white = white + 1
break
}
}
}
var r = []
r.addAll(("X" * black).toList)
r.addAll(("O" * white).toList)
_results.add(r)
return black == _codeLen
}
 
getCombo_() {
var c = ""
var clr = _colors
for (s in 0..._codeLen) {
var z = Rand.int(clr.count)
c = c + clr[z]
if (!_repeatClr) Str.delete(clr, z)
}
return c
}
}
 
var m = Mastermind.new(4, 8, 12, false)
m.play()</syntaxhighlight>
 
{{out}}
Sample game:
<pre>
Enter your guess (ABCDEFGH): abcd
 
--------------------------------
1: A B C D : X - - -
 
Enter your guess (ABCDEFGH): efgh
 
--------------------------------
1: A B C D : X - - -
--------------------------------
2: E F G H : O O - -
 
Enter your guess (ABCDEFGH): aefa
 
--------------------------------
1: A B C D : X - - -
--------------------------------
2: E F G H : O O - -
--------------------------------
3: A E F A : X X - -
 
Enter your guess (ABCDEFGH): aagh
 
--------------------------------
1: A B C D : X - - -
--------------------------------
2: E F G H : O O - -
--------------------------------
3: A E F A : X X - -
--------------------------------
4: A A G H : X O O O
 
Enter your guess (ABCDEFGH): agah
 
--------------------------------
1: A B C D : X - - -
--------------------------------
2: E F G H : O O - -
--------------------------------
3: A E F A : X X - -
--------------------------------
4: A A G H : X O O O
--------------------------------
5: A G A H : X X O O
 
Enter your guess (ABCDEFGH): agha
 
 
--------------------------------
Very well done!
You found the code: AGHA
--------------------------------
</pre>
 
=={{header|zkl}}==
{{trans|C++}}
<langsyntaxhighlight lang="zkl">class MasterMind{
fcn init(code_len,guess_count){
var codeLen =code_len.max(4).min(10);
Line 2,555 ⟶ 4,377:
return(black==codeLen,"X"*black + "O"*white)
}
}(4,12).play();</langsyntaxhighlight>
{{out}}
<pre>
1,969

edits