Mastermind: Difference between revisions

m
m (added to the Puzzles category.)
 
(47 intermediate revisions by 22 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].
{{draft 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 230 ⟶ 1,141:
</pre>
 
=={{header|Easyprog.onlineEasyLang}}==
 
[https://easyprogeasylang.onlinedev/samplesapps/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 590 ⟶ 1,517:
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>
 
=={{header|Javascript}}==
You can try it [http://paulo-jorente.de/webgames/repos/mastermind/ here].
 
<syntaxhighlight lang="javascript">
class Mastermind {
constructor() {
this.colorsCnt;
this.rptColors;
this.codeLen;
this.guessCnt;
this.guesses;
this.code;
this.selected;
this.game_over;
this.clear = (el) => {
while (el.hasChildNodes()) {
el.removeChild(el.firstChild);
}
};
this.colors = ["🤡", "👹", "👺", "👻", "👽", "👾", "🤖", "🐵", "🐭",
"🐸", "🎃", "🤠", "☠️", "🦄", "🦇", "🛸", "🎅", "👿", "🐲", "🦋"
];
}
 
newGame() {
this.selected = null;
this.guessCnt = parseInt(document.getElementById("gssCnt").value);
this.colorsCnt = parseInt(document.getElementById("clrCnt").value);
this.codeLen = parseInt(document.getElementById("codeLen").value);
if (this.codeLen > this.colorsCnt) {
document.getElementById("rptClr").selectedIndex = 1;
}
this.rptColors = document.getElementById("rptClr").value === "yes";
this.guesses = 0;
this.game_over = false;
const go = document.getElementById("gameover");
go.innerText = "";
go.style.visibility = "hidden";
this.clear(document.getElementById("code"));
this.buildPalette();
this.buildPlayField();
}
 
buildPalette() {
const pal = document.getElementById("palette"),
z = this.colorsCnt / 5,
h = Math.floor(z) != z ? Math.floor(z) + 1 : z;
this.clear(pal);
pal.style.height = `${44 * h + 3 * h}px`;
const clrs = [];
for (let c = 0; c < this.colorsCnt; c++) {
clrs.push(c);
const b = document.createElement("div");
b.className = "bucket";
b.clr = c;
b.innerText = this.colors[c];
b.addEventListener("click", () => {
this.palClick(b);
});
pal.appendChild(b);
}
this.code = [];
while (this.code.length < this.codeLen) {
const r = Math.floor(Math.random() * clrs.length);
this.code.push(clrs[r]);
if (!this.rptColors) {
clrs.splice(r, 1);
}
}
}
 
buildPlayField() {
const brd = document.getElementById("board");
this.clear(brd);
const w = 49 * this.codeLen + 7 * this.codeLen + 5;
brd.active = 0;
brd.style.width = `${w}px`;
document.querySelector(".column").style.width = `${w + 20}px`;
this.addGuessLine(brd);
}
 
addGuessLine(brd) {
const z = document.createElement("div");
z.style.clear = "both";
brd.appendChild(z);
brd.active += 10;
for (let c = 0; c < this.codeLen; c++) {
const d = document.createElement("div");
d.className = "bucket";
d.id = `brd${brd.active+ c}`;
d.clr = -1;
d.addEventListener("click", () => {
this.playClick(d);
})
brd.appendChild(d);
}
}
 
palClick(bucket) {
if (this.game_over) return;
if (null === this.selected) {
bucket.classList.add("selected");
this.selected = bucket;
return;
}
if (this.selected !== bucket) {
this.selected.classList.remove("selected");
bucket.classList.add("selected");
this.selected = bucket;
return;
}
this.selected.classList.remove("selected");
this.selected = null;
}
 
vibrate() {
const brd = document.getElementById("board");
let timerCnt = 0;
const exp = setInterval(() => {
if ((timerCnt++) > 60) {
clearInterval(exp);
brd.style.top = "0px";
brd.style.left = "0px";
}
let x = Math.random() * 4,
y = Math.random() * 4;
if (Math.random() < .5) x = -x;
if (Math.random() < .5) y = -y;
brd.style.top = y + "px";
brd.style.left = x + "px";
}, 10);
}
 
playClick(bucket) {
if (this.game_over) return;
if (this.selected) {
bucket.innerText = this.selected.innerText;
bucket.clr = this.selected.clr;
} else {
this.vibrate();
}
}
 
check() {
if (this.game_over) return;
let code = [];
const brd = document.getElementById("board");
for (let b = 0; b < this.codeLen; b++) {
const h = document.getElementById(`brd${brd.active + b}`).clr;
if (h < 0) {
this.vibrate();
return;
}
code.push(h);
}
this.guesses++;
if (this.compareCode(code)) {
this.gameOver(true);
return;
}
if (this.guesses >= this.guessCnt) {
this.gameOver(false);
return;
}
this.addGuessLine(brd);
}
 
compareCode(code) {
let black = 0,
white = 0,
b_match = new Array(this.codeLen).fill(false),
w_match = new Array(this.codeLen).fill(false);
for (let i = 0; i < this.codeLen; i++) {
if (code[i] === this.code[i]) {
b_match[i] = true;
w_match[i] = true;
black++;
}
}
for (let i = 0; i < this.codeLen; i++) {
if (b_match[i]) continue;
for (let j = 0; j < this.codeLen; j++) {
if (i == j || w_match[j]) continue;
if (code[i] === this.code[j]) {
w_match[j] = true;
white++;
break;
}
}
}
const brd = document.getElementById("board");
let d;
for (let i = 0; i < black; i++) {
d = document.createElement("div");
d.className = "pin";
d.style.backgroundColor = "#a00";
brd.appendChild(d);
}
for (let i = 0; i < white; i++) {
d = document.createElement("div");
d.className = "pin";
d.style.backgroundColor = "#eee";
brd.appendChild(d);
}
return (black == this.codeLen);
}
 
gameOver(win) {
if (this.game_over) return;
this.game_over = true;
const cd = document.getElementById("code");
for (let c = 0; c < this.codeLen; c++) {
const d = document.createElement("div");
d.className = "bucket";
d.innerText = this.colors[this.code[c]];
cd.appendChild(d);
}
const go = document.getElementById("gameover");
go.style.visibility = "visible";
go.innerText = win ? "GREAT!" : "YOU FAILED!";
const i = setInterval(() => {
go.style.visibility = "hidden";
clearInterval(i);
}, 3000);
}
}
const mm = new Mastermind();
document.getElementById("newGame").addEventListener("click", () => {
mm.newGame()
});
document.getElementById("giveUp").addEventListener("click", () => {
mm.gameOver();
});
document.getElementById("check").addEventListener("click", () => {
mm.check()
});
</syntaxhighlight>
 
To test you'll need a HTML file
<pre>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./css/style.css" type="text/css">
<title>Mastermind</title>
</head>
<body>
<div id="gameover"></div>
<div class="column">
<div id="board" style="position: relative"></div>
<div style="clear: both"> </div>
<button id="check" style="margin-top:20px">Check!</button>
<button id="giveUp">Give up!</button>
<div id="code" style="margin-top: 40px"></div>
</div>
<div class="columnS">
<div id="ctrls">
<label for="clrCnt">Colors count:</label>
<input type="number" id="clrCnt" max="20" min="2" value="6"></input>
<br />
<label for="codeLen">Code length:</label>
<input type="number" id="codeLen" max="10" min="4" value="4"></input>
<br />
<label for="gssCnt">Guesses count:</label>
<input type="number" id="gssCnt" max="20" min="7" value="12"></input>
<br />
<label for="rptClr">Repeat colors:</label>
<select id="rptClr">
<option value="no">No</option>
<option value="yes">Yes</option>
</select>
<button id="newGame" style="width: 100%">New game</button>
</div>
<div id="palette"></div>
</div>
<script src="./src/index.js" type="module"></script>
</body>
</html>
</pre>
 
And a CSS file
<pre>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
background-color: #222;
text-align: left
}
button {
width: 101px;
height: 26px;
background-color: #444;
color: #ddd;
border: 1px solid #333;
border-radius: 4px;
}
input,
select {
float: right;
width: 60px;
height: 24px;
margin-top: 6px;
font-size: 20px;
}
#palette {
margin-top: 40px;
width: 233px;
border-radius: 5px;
border: 1px solid #fff;
}
#ctrls {
border-radius: 5px;
border: 1px solid #fff;
padding: 10px;
font-size: 20px;
width: 233px;
line-height: 36px;
color: #fff;
}
#gameover {
position: absolute;
top: 90px;
left: 0;
font-size: 100px;
text-align: center;
color: rgb(248, 143, 4);
background: rgba(34, 34, 34, .8);
padding: 10px;
z-index: 999;
}
.column,
.columnS {
float: left;
width: 249px;
margin: 30px;
}
.columnS {
width: 300px;
margin-left: 0;
}
.bucket {
float: left;
width: 42px;
height: 42px;
line-height: 40px;
font-size: 26px;
border: 2px solid #fff;
border-radius: 3px;
margin: 2px;
cursor: pointer;
}
.selected {
border: 2px solid #d00;
}
.pin {
float: left;
width: 14px;
height: 14px;
border-radius: 50%;
margin: 2px;
}
</pre>
 
=={{header|Julia}}==
GUI version, uses the Gtk toolkit.
<syntaxhighlight lang="julia">using Gtk, Colors, Cairo, Graphics
 
struct Guess
code::Vector{Color}
guess::Vector{Color}
hint::Vector{Color}
end
 
function Guess(code, guess)
len = length(code)
hints = fill(colorant"gray", len) # gray default
for (i, g) in enumerate(guess), (j, c) in enumerate(code)
if g == c
if i == j
hints[i] = colorant"black"
elseif hints[i] != colorant"black"
hints[i] = colorant"white"
end
end
end
g = Guess([c for c in code], [c for c in guess], [c for c in hints])
end
 
tovec(guess) = [x for x in [guess.code; guess.guess; guess.hint]]
 
function mastermindapp()
allu(s) = length(unique(s)) == length(s)
ccode(c, n, rok) = while true a = rand(c, n); if rok || allu(a) return a end end
 
numcolors, codelength, maxguesses, allowrep, gameover = 10, 4, 10, false, false
colors = distinguishable_colors(numcolors)
code = ccode(colors, numcolors, allowrep)
guesshistory = Vector{Guess}()
win = GtkWindow("Mastermind Game", 900, 750) |> (GtkFrame() |> (box = GtkBox(:v)))
settingsbox = GtkBox(:h)
playtoolbar = GtkToolbar()
 
setcolors = GtkScale(false, 4:20)
set_gtk_property!(setcolors, :hexpand, true)
adj = GtkAdjustment(setcolors)
set_gtk_property!(adj, :value, 10)
clabel = GtkLabel("Number of Colors")
 
setcodelength = GtkScale(false, 4:10)
set_gtk_property!(setcodelength, :hexpand, true)
adj = GtkAdjustment(setcodelength)
set_gtk_property!(adj, :value, 4)
slabel = GtkLabel("Code Length")
 
setnumguesses = GtkScale(false, 4:40)
set_gtk_property!(setnumguesses, :hexpand, true)
adj = GtkAdjustment(setnumguesses)
set_gtk_property!(adj, :value, 10)
nlabel = GtkLabel("Max Guesses")
 
allowrepeatcolor = GtkScale(false, 0:1)
set_gtk_property!(allowrepeatcolor, :hexpand, true)
rlabel = GtkLabel("Allow Repeated Colors (0 = No)")
 
newgame = GtkToolButton("New Game")
set_gtk_property!(newgame, :label, "New Game")
set_gtk_property!(newgame, :is_important, true)
 
tryguess = GtkToolButton("Submit Current Guess")
set_gtk_property!(tryguess, :label, "Submit Current Guess")
set_gtk_property!(tryguess, :is_important, true)
 
eraselast = GtkToolButton("Erase Last (Unsubmitted) Pick")
set_gtk_property!(eraselast, :label, "Erase Last (Unsubmitted) Pick")
set_gtk_property!(eraselast, :is_important, true)
 
map(w->push!(settingsbox, w),[clabel, setcolors, slabel, setcodelength,
nlabel, setnumguesses, rlabel, allowrepeatcolor])
map(w->push!(playtoolbar, w),[newgame, tryguess, eraselast])
scrwin = GtkScrolledWindow()
can = GtkCanvas()
set_gtk_property!(can, :expand, true)
map(w -> push!(box, w),[settingsbox, playtoolbar, scrwin])
push!(scrwin, can)
 
currentguess = RGB[]
guessesused = 0
colorpositions = Point[]
function newgame!(w)
empty!(guesshistory)
numcolors = Int(GAccessor.value(setcolors))
codelength = Int(GAccessor.value(setcodelength))
maxguesses = Int(GAccessor.value(setnumguesses))
allowrep = Int(GAccessor.value(allowrepeatcolor))
colors = distinguishable_colors(numcolors)
code = ccode(colors, codelength, allowrep == 1)
empty!(currentguess)
currentneeded = codelength
guessesused = 0
gameover = false
draw(can)
end
signal_connect(newgame!, newgame, :clicked)
function saywon!()
warn_dialog("You have WON the game!", win)
gameover = true
end
 
function outofguesses!()
warn_dialog("You have Run out of moves! Game over.", win)
gameover = true
end
can.mouse.button1press = @guarded (widget, event) -> begin
if !gameover && (i = findfirst(p ->
sqrt((p.x - event.x)^2 + (p.y - event.y)^2) < 20,
colorpositions)) != nothing
if length(currentguess) < codelength
if allowrep == 0 && !allu(currentguess)
warn_dialog("Please erase the duplicate color.", win)
else
push!(currentguess, colors[i])
draw(can)
end
else
warn_dialog("You need to submit this guess if ready.", win)
end
end
end
@guarded draw(can) do widget
ctx = Gtk.getgc(can)
select_font_face(ctx, "Courier", Cairo.FONT_SLANT_NORMAL, Cairo.FONT_WEIGHT_BOLD)
fontpointsize = 12
set_font_size(ctx, fontpointsize)
workcolor = colorant"black"
set_source(ctx, workcolor)
move_to(ctx, 0, fontpointsize)
show_text(ctx, "Color options: " * "-"^70)
stroke(ctx)
empty!(colorpositions)
for i in 1:numcolors
set_source(ctx, colors[i])
circle(ctx, i * 40, 40, 20)
push!(colorpositions, Point(i * 40, 40))
fill(ctx)
end
set_gtk_property!(can, :expand, false) # kludge for good text overwriting
move_to(ctx, 0, 80)
set_source(ctx, workcolor)
show_text(ctx, string(maxguesses - guessesused, pad = 2) * " moves remaining.")
stroke(ctx)
set_gtk_property!(can, :expand, true)
for i in 1:codelength
set_source(ctx, i > length(currentguess) ? colorant"lightgray" : currentguess[i])
circle(ctx, i * 40, 110, 20)
fill(ctx)
end
if length(guesshistory) > 0
move_to(ctx, 0, 155)
set_source(ctx, workcolor)
show_text(ctx, "Past Guesses: " * "-"^70)
for (i, g) in enumerate(guesshistory), (j, c) in enumerate(tovec(g)[codelength+1:end])
x = j * 40 + (j > codelength ? 20 : 0)
y = 150 + 40 * i
set_source(ctx, c)
circle(ctx, x, y, 20)
fill(ctx)
end
end
Gtk.showall(win)
end
 
function submitguess!(w)
if length(currentguess) == length(code)
g = Guess(code, currentguess)
push!(guesshistory, g)
empty!(currentguess)
guessesused += 1
draw(can)
if all(i -> g.code[i] == g.guess[i], 1:length(code))
saywon!()
elseif guessesused > maxguesses
outofguesses!()
end
end
end
signal_connect(submitguess!, tryguess, :clicked)
 
function undolast!(w)
if length(currentguess) > 0
pop!(currentguess)
draw(can)
end
end
signal_connect(undolast!, eraselast, :clicked)
 
newgame!(win)
Gtk.showall(win)
condition = Condition()
endit(w) = notify(condition)
signal_connect(endit, win, :destroy)
showall(win)
wait(condition)
end
 
mastermindapp()
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|C++}}
<langsyntaxhighlight lang="scala">// version 1.2.51
 
import java.util.Random
Line 710 ⟶ 2,444:
val m = Mastermind(4, 8, 12, false)
m.play()
}</langsyntaxhighlight>
 
Sample input/output (showing last 2 guesses only):
Line 750 ⟶ 2,484:
=={{header|Lua}}==
Based on C++
<langsyntaxhighlight lang="lua">
math.randomseed( os.time() )
local black, white, none, code = "X", "O", "-"
Line 829 ⟶ 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 853 ⟶ 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 907 ⟶ 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 927 ⟶ 2,739:
You win! The correct answer is: B D A C</pre>
 
=={{header|Perl 6Phix}}==
OTT GUI solution, fully configurable with solver.
<syntaxhighlight lang="phix">-- demo/rosetta/mastermind.exw
constant SET_LIMIT = 1_000_000 -- above this, it uses random sampling.
 
constant help_text = """
The game of mastermind, with a Knuth solver.
 
Specify the number of colours (1..20), the code length (1..10), the
number of guesses allowed (1-20), and whether colours can be repeated
(auto-ticked & greyed-out inactive when length>colours).
 
Note that at the highest settings there are 10,240,000,000,000 possible
answers: the (order n squared) analysis of that is simply not practical,
as indeed is simply building the initial list of all possible answers,
and therefore a fixed limit of 1,000,000 has been applied, which also
just about manages to keep the program responsive. Obviously, should the
actual answer not be among those samples, it cannot possibly find it,
and it will tell you in plain english when that occurs. You can always
trim the search space back to something more reasonable at any time, and
still play the game when that limit is breached, with weaker hints.
 
Conversely the lowest settings do not make for an interesting game, but
proved quite useful when ironing out some bugs, so were left in.
 
The Use button (disabled until something useful found) allows you to
take the best found (so far), displayed at the top of the colours frame.
Obviously "1/1 (100%)" means that it has deduced the correct answer.
Below that the colours frame shows all available colours, which can be
individually clicked in any order.
 
Press Delete or click on the last peg (in the left-hand game frame)
to remove it, before the last one is placed, however once full your
turn is immediately scored and cannot be undone.
 
New Game, Help, and Exit buttons are assumed to be self-explanatory.
Changing the option settings implicitly triggers a new game, except
for the number of permitted guesses, pre-game-over. Reducing the
number of guesses can also be used as a means of conceding.
 
When a correct guess is entered or all guesses have been used the hint
and colours are replaced with "GAME OVER - YOU WIN/LOSE" under the
actual answer.
"""
include pGUI.e
 
Ihandle dlg, colours, codelen, maxgoes, repeats, progress,
usehint, game_canvas, colour_canvas
integer ncolours, ncodelen, nmaxgoes
bool brepeats
 
sequence secret = {},
hint = {},
guesses = {{}},
scores = {}
--
-- note: while the game is ongoing, length(guesses) should always be
-- length(scores)+1; equal lengths is equivalent to game over.
--
 
function get_score(sequence guess, goal)
integer blacks = 0, -- (right colour & place)
whites = 0 -- ("" but wrong place)
for i=1 to length(guess) do
if guess[i]=goal[i] then
blacks += 1
guess[i] = ' '
goal[i] = ' '
end if
end for
for i=1 to length(guess) do
if guess[i]!=' ' then
integer k = find(guess[i],goal)
if k then
whites += 1
goal[k] = ' '
end if
end if
end for
return {blacks, whites}
end function
 
function random_set()
-- create the secret code, and/or (when rqd) a SET_LIMIT random sample
sequence cset = tagset(ncolours),
res = repeat(0,ncodelen)
for i=1 to ncodelen do
integer c = rand(length(cset))
res[i] = cset[c]
if not brepeats then
cset[c..c] = {}
end if
end for
return res
end function
 
sequence initial_set
atom is_len, -- logically length(initial_set), except when > SET_LIMIT.
excluded -- initialset[1..excluded-1], are not, [excluded..$] are.
 
procedure create_initial_set()
is_len = iff(brepeats?power(ncolours,ncodelen):k_perm(ncolours,ncodelen))
if is_len<=SET_LIMIT then
--
-- generate the full set
--
initial_set = repeat(0,is_len)
excluded = is_len+1 -- (ie none)
sequence next = iff(brepeats?repeat(1,ncodelen):tagset(ncodelen))
for i=1 to is_len do
initial_set[i] = next
for ndx=length(next) to 1 by -1 do
integer n = next[ndx]
while n<=ncolours do
n += 1
if brepeats
-- or not find(n,next[1..ndx-1]) then
or not find(n,next) then --(see below)
exit
end if
end while
next[ndx] = n
if n<=ncolours then
if not brepeats then
--
-- Fill in the rest lowest-first, eg
-- in the 4 colours and 4 holes case:
-- (start) (above) (this)
-- {1,2,3,4} --> {1,2,4,_} --> {1,2,4,3}
-- {1,2,4,3} --> {1,3,_,_} --> {1,3,2,4}
-- ... (20 other cases omitted)
-- {4,3,1,2} --> {4,3,2,_} --> {4,3,2,1}
--
-- (probably sub-optimal, but insignificant
-- vs. the o(n^2) analysis which follows.)
--
for j=ndx+1 to length(next) do
for k=1 to ncolours do
-- if not find(k,next[1..j-1]) then
if not find(k,next) then --(see below)
next[j] = k
exit
end if
end for
end for
end if
exit
end if
--
-- technical note: if not brepeats, we are going to
-- replace all next[ndx..$] later/above anyway, but
-- replacing with 0 means we can avoid those slices.
-- The next three all work: 1 is perfect for the
-- brepeats=true case, but brepeats=false needs the
-- above slices, while the 2nd & 3rd are equivalent
-- the latter is obviously somewhat faster, at the
-- cost of a wtf?!, without a comment such as this.
--
-- next[ndx] = 1
-- next[ndx] = iff(brepeats?1:0)
next[ndx] = brepeats -- (equivalent)
end for
end for
else
--
-- generate SET_LIMIT random codes
-- note that if (as is quite likely) the actual answer is
-- not present in initial_set, then obviously it cannot
-- possibly find it!
--
initial_set = repeat(0,SET_LIMIT)
excluded = SET_LIMIT+1 -- (ie none)
for i=1 to SET_LIMIT do
initial_set[i] = random_set()
end for
end if
end procedure
 
atom done, is_done, best
 
function idle_action()
atom to_do = excluded-1,
t1 = time()+1
string samp = iff(is_len=length(initial_set)?"":sprintf(" samples of %,d",{is_len}))
for i=1 to 100000 do -- reasonable slice of work
done += 1
is_done += (done<excluded)
sequence guest = initial_set[done],
scores = {}, counts = {}
if not find(guest,guesses) then
for j=1 to excluded-1 do
sequence s = get_score(guest,initial_set[j])
integer k = find(s,scores)
if k=0 then
scores = append(scores,s)
counts = append(counts,1)
else
counts[k] += 1
end if
end for
if length(counts)=0 then
IupSetStrAttribute(progress,"TITLE","[answer not in %,d%s]",{SET_LIMIT,samp})
return IUP_IGNORE -- (stop idle)
end if
integer k = largest(counts,return_index:=true),
ck = counts[k]
if ck<best then
best = ck
hint = guest
IupSetInt(usehint,"ACTIVE",true)
IupUpdate(colour_canvas)
end if
end if
if done=length(initial_set) then
IupSetStrAttribute(progress,"TITLE","%,d/%,d%s (100%%)",{is_done,to_do,samp})
return IUP_IGNORE -- (stop idle)
end if
if time()>t1 then exit end if
end for
IupSetStrAttribute(progress,"TITLE","%,d/%,d%s (%d%%)",{is_done,to_do,samp,100*(is_done/to_do)})
return IUP_DEFAULT
end function
constant idle_action_cb = Icallback("idle_action")
 
procedure start_idle()
done = 0
is_done = 0
best = length(initial_set)+1
IupSetGlobalFunction("IDLE_ACTION",idle_action_cb)
end procedure
 
procedure new_game()
ncolours = IupGetInt(colours,"VALUE")
ncodelen = IupGetInt(codelen,"VALUE")
nmaxgoes = IupGetInt(maxgoes,"VALUE")
brepeats = IupGetInt(repeats,"VALUE")
secret = random_set()
guesses = {{}}
scores = {}
hint = {}
create_initial_set()
start_idle()
end procedure
 
constant colour_table = {#e6194b, -- Red
#3cb44b, -- Green
#ffe119, -- Yellow
#4363d8, -- Blue
#f58231, -- Orange
#911eb4, -- Purple
#42d4f4, -- Cyan
#f032e6, -- Magenta
#bfef45, -- Lime
#fabebe, -- Pink
#469990, -- Teal
#e6beff, -- Lavender
#9A6324, -- Brown
#fffac8, -- Beige
#800000, -- Maroon
#aaffc3, -- Mint
#808000, -- Olive
#ffd8b1, -- Apricot
#000075, -- Navy
#a9a9a9} -- Grey
 
-- saved in redraw_cb(), for click testing in button_cb():
sequence last_guess = {},
colour_centres = {}
integer guess_r2 = 0,
colour_r2 = 0
 
function redraw_cb(Ihandle ih, integer /*posx*/, integer /*posy*/)
Ihandle frame = IupGetParent(ih)
string title = IupGetAttribute(ih,"TITLE")
if not find(title,{"Game","Colours"}) then ?9/0 end if
integer {cw,ch} = IupGetIntInt(ih, "DRAWSIZE")
cdCanvas cddbuffer = IupGetAttributePtr(ih,"DBUFFER")
IupGLMakeCurrent(ih)
cdCanvasActivate(cddbuffer)
cdCanvasClear(cddbuffer)
 
if title="Game" then
integer mx = min(floor(cw/(ncodelen*1.5+0.5)),floor(ch/(nmaxgoes+1))),
diameter = floor(mx/2),
px = floor((cw-(ncodelen*1.5+0.5)*mx)/2), -- (set margin)
cy = ch, cx, c, r
last_guess = {}
for g=1 to length(guesses) do
cy -= mx
cx = px+floor(mx/2)
for i=1 to 2*ncodelen+1 do
if i!=ncodelen+1 then
if i<=ncodelen then
if i<=length(guesses[g]) then
c = colour_table[guesses[g][i]]
if g=length(guesses) then
last_guess = {{cx,ch-cy}}
end if
else
c = CD_GREY
end if
r = diameter
else
c = CD_GREY
if g<=length(scores) then
integer k = i-ncodelen-1,
{b,w} = scores[g]
c = iff(k<=b ? CD_BLACK : iff(k<=b+w ? CD_WHITE : CD_GREY))
end if
r = floor(diameter*0.5)
end if
cdCanvasSetForeground(cddbuffer,c)
cdCanvasSector(cddbuffer, cx, cy, r, r, 0, 360)
cdCanvasSetForeground(cddbuffer,CD_DARK_GREY)
cdCanvasCircle(cddbuffer, cx, cy, r)
end if
cx += iff(i<ncodelen?mx:floor(mx/2))
end for
end for
guess_r2 = floor(diameter*diameter/4)
elsif title="Colours" then
integer mx = min(floor(cw/ncodelen),floor(ch/2)),
r = floor(mx/2),
px = floor((cw-ncodelen*mx)/2), -- (set margin)
cy = ch-r, cx, c
cx = px+floor(mx/2)
bool active = length(hint)>0
if length(scores)=nmaxgoes then
hint = secret
active = true
end if
for i=1 to ncodelen do
c = iff(active?colour_table[hint[i]]:CD_GREY)
cdCanvasSetForeground(cddbuffer,c)
cdCanvasSector(cddbuffer, cx, cy, r, r, 0, 360)
cdCanvasSetForeground(cddbuffer,CD_DARK_GREY)
cdCanvasCircle(cddbuffer, cx, cy, r)
cx += mx
end for
if length(scores)=nmaxgoes
or guesses[$]=secret then
ch -= floor(mx/2)
{} = cdCanvasTextAlignment(cddbuffer, CD_CENTER)
string wl = iff(guesses[$]=secret?"WIN":"LOSE"),
msg = sprintf("GAME OVER - YOU %s",{wl})
cdCanvasText(cddbuffer, cw/2, ch/2, msg)
else
integer ch0 = ch
ch -= mx
--
-- calculate the best nw*nh way to fit all the colours in:
-- (if nw ends up = ncodelen there is no clear separation
-- between the hint and the colour table; the start with
-- ncodelen+1 solves that and looks pretty good to me.)
--
integer nw = ncodelen+1, -- (as above)
nh = 1
while nw*nh<ncolours do
if (cw/(nw+1))>(ch/(nh+1)) then
nw += 1
else
nh += 1
end if
end while
--
-- now draw all the colours
--
mx = min(floor(cw/nw),floor(ch/nh))
r = floor(mx/2)
px = floor((cw-nw*mx)/2)
cx = px+floor(mx/2)
cy = ch-r
integer this_row = 0
colour_centres = repeat(0,ncolours)
colour_r2 = floor(r*r/4)
for i=1 to ncolours do
colour_centres[i] = {cx,ch0-cy}
c = colour_table[i]
cdCanvasSetForeground(cddbuffer,c)
cdCanvasSector(cddbuffer, cx, cy, r, r, 0, 360)
cdCanvasSetForeground(cddbuffer,CD_DARK_GREY)
cdCanvasCircle(cddbuffer, cx, cy, r)
cx += mx
this_row += 1
if this_row>=nw then
this_row = 0
cx = px + floor(mx/2)
cy -= mx
end if
end for
end if
end if
cdCanvasFlush(cddbuffer)
return IUP_DEFAULT
end function
 
function map_cb(Ihandle ih)
IupGLMakeCurrent(ih)
atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
cdCanvas cddbuffer = cdCreateCanvas(CD_GL, "10x10 %g", {res})
IupSetAttributePtr(ih,"DBUFFER",cddbuffer)
cdCanvasSetBackground(cddbuffer, CD_PARCHMENT)
return IUP_DEFAULT
end function
 
function canvas_resize_cb(Ihandle canvas)
cdCanvas cddbuffer = IupGetAttributePtr(canvas,"DBUFFER")
integer {canvas_width, canvas_height} = IupGetIntInt(canvas, "DRAWSIZE")
atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
cdCanvasSetAttribute(cddbuffer, "SIZE", "%dx%d %g", {canvas_width, canvas_height, res})
return IUP_DEFAULT
end function
 
procedure redraw_all()
IupUpdate({game_canvas,colour_canvas})
end procedure
 
procedure undo_move()
-- Called from button_cb and from K_DEL, but latter may be invalid.
if length(guesses[$])!=0 then
guesses[$] = guesses[$][1..$-1]
redraw_all()
end if
end procedure
 
procedure add_move(integer i)
if i!=0 then
guesses[$] &= i
end if
if length(guesses[$])=ncodelen then
sequence guest = guesses[$],
score = get_score(guest,secret)
scores = append(scores,score)
if score!={ncodelen,0} -- (not all black==game over)
and length(guesses)<nmaxgoes then
for i=excluded-1 to 1 by -1 do
sequence isi = initial_set[i]
if get_score(guest,isi)!=score then
excluded -= 1
if excluded!=i then
initial_set[i] = initial_set[excluded]
initial_set[excluded] = isi -- (swap)
end if
end if
end for
guesses = append(guesses,{})
hint = {}
IupSetAttribute(progress,"TITLE","-")
IupSetInt(usehint,"ACTIVE",false)
start_idle()
end if
end if
redraw_all()
end procedure
 
function usehint_cb(Ihandle /*usehint*/)
guesses[$] = hint
add_move(0)
return IUP_DEFAULT
end function
 
function button_cb(Ihandle canvas, integer button, pressed, x, y, atom /*pStatus*/)
Ihandle frame = IupGetParent(canvas)
string title = IupGetAttribute(frame,"TITLE")
if not find(title,{"Game","Colours"}) then ?9/0 end if
if button=IUP_BUTTON1 and not pressed then -- (left button released)
{sequence centres, integer r2} = iff(title="Game"?{last_guess,guess_r2}
:{colour_centres,colour_r2})
for i=1 to length(centres) do
integer {cx,cy} = sq_sub(centres[i],{x,y})
if (cx*cx+cy*cy)<=r2 then
if title="Game" then
undo_move()
else
add_move(i)
end if
exit
end if
end for
end if
return IUP_CONTINUE
end function
 
function new_game_cb(Ihandle /*ih*/)
new_game()
redraw_all()
return IUP_DEFAULT
end function
 
function exit_cb(Ihandle /*ih*/)
return IUP_CLOSE
end function
constant cb_exit = Icallback("exit_cb")
 
function help_cb(Ihandln /*ih*/)
IupMessage("Mastermind",help_text)
return IUP_DEFAULT
end function
 
function key_cb(Ihandle /*dlg*/, atom c)
if c=K_ESC then return IUP_CLOSE end if
if c=K_F1 then return help_cb(NULL) end if
if find(c,{K_DEL,K_BS}) then undo_move() end if
return IUP_CONTINUE
end function
 
function valuechanged_cb(Ihandle ih)
ncolours = IupGetInt(colours,"VALUE")
ncodelen = IupGetInt(codelen,"VALUE")
nmaxgoes = IupGetInt(maxgoes,"VALUE")
IupSetInt(repeats,"ACTIVE",ncodelen<=ncolours)
if ncodelen>ncolours then
IupSetInt(repeats,"VALUE",true)
end if
brepeats = IupGetInt(repeats,"VALUE")
if ih!=maxgoes
or length(scores)=length(guesses) then -- (game over)
new_game()
elsif nmaxgoes<=length(scores) then
-- (signal/force game over state)
guesses = guesses[1..length(scores)]
end if
redraw_all()
return IUP_DEFAULT
end function
constant cb_valuechanged = Icallback("valuechanged_cb")
 
procedure main()
IupOpen()
colours = IupText("SPIN=Yes, SPINMIN=1, SPINMAX=20, VALUE=6, RASTERSIZE=34x")
codelen = IupText("SPIN=Yes, SPINMIN=1, SPINMAX=10, VALUE=4, RASTERSIZE=34x")
maxgoes = IupText("SPIN=Yes, SPINMIN=1, SPINMAX=20, VALUE=7, RASTERSIZE=34x")
repeats = IupToggle("Repeatable?","VALUE=YES, RIGHTBUTTON=YES, PADDING=5x4")
progress = IupLabel("-","EXPAND=HORIZONTAL, PADDING=5x4")
usehint = IupButton("Use",Icallback("usehint_cb"),"PADDING=5x4, ACTIVE=NO")
game_canvas = IupGLCanvas("RASTERSIZE=200x")
colour_canvas = IupGLCanvas("RASTERSIZE=x200")
Ihandle newgame = IupButton("New Game",Icallback("new_game_cb"),"PADDING=5x4"),
help = IupButton("Help (F1)",Icallback("help_cb"),"PADDING=5x4"),
quit = IupButton("E&xit",Icallback("exit_cb"),"PADDING=5x4"),
vbox = IupVbox({IupHbox({IupLabel("Colours (1-20)","PADDING=5x4"),colours}),
IupHbox({IupLabel("Code Length (1-10)","PADDING=5x4"),codelen}),
IupHbox({IupLabel("Guesses (1-20)","PADDING=5x4"),maxgoes}),
IupHbox({repeats},"MARGIN=10x5"),
IupHbox({progress}),
IupHbox({usehint,newgame,help,quit})},"MARGIN=5x5"),
game_frame = IupFrame(IupHbox({game_canvas},"MARGIN=3x3"),"TITLE=Game"),
option_frame = IupFrame(vbox,"TITLE=Options"),
colour_frame = IupFrame(colour_canvas,"TITLE=Colours"),
full = IupHbox({game_frame,IupVbox({option_frame,colour_frame})})
IupSetCallbacks({colours,codelen,maxgoes,repeats}, {"VALUECHANGED_CB", cb_valuechanged})
IupSetCallbacks({game_canvas,colour_canvas}, {"ACTION", Icallback("redraw_cb"),
"MAP_CB", Icallback("map_cb"),
"RESIZE_CB", Icallback("canvas_resize_cb"),
"BUTTON_CB", Icallback("button_cb")})
dlg = IupDialog(IupHbox({full},"MARGIN=3x3"),"TITLE=Mastermind")
IupSetCallback(dlg, "K_ANY", Icallback("key_cb"))
IupSetAttributeHandle(dlg,"DEFAULTENTER", usehint)
 
new_game()
 
IupShowXY(dlg,IUP_CENTER,IUP_CENTER)
IupSetAttribute(dlg, "RASTERSIZE", NULL)
IupSetStrAttribute(dlg, "MINSIZE", IupGetAttribute(dlg,"RASTERSIZE"))
IupMainLoop()
IupClose()
end procedure
main()</syntaxhighlight>
 
=={{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.
<syntaxhighlight lang="python">
import random
 
 
def encode(correct, guess):
output_arr = [''] * len(correct)
 
for i, (correct_char, guess_char) in enumerate(zip(correct, guess)):
output_arr[i] = 'X' if guess_char == correct_char else 'O' if guess_char in correct else '-'
 
return ''.join(output_arr)
 
 
def safe_int_input(prompt, min_val, max_val):
while True:
user_input = input(prompt)
 
try:
user_input = int(user_input)
except ValueError:
continue
 
if min_val <= user_input <= max_val:
return user_input
 
 
def 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()
 
number_of_letters = safe_int_input("Select a number of possible letters for the code (2-20): ", 2, 20)
code_length = safe_int_input("Select a length for the code (4-10): ", 4, 10)
 
letters = 'ABCDEFGHIJKLMNOPQRST'[:number_of_letters]
code = ''.join(random.choices(letters, k=code_length))
guesses = []
 
while True:
print()
guess = input(f"Enter a guess of length {code_length} ({letters}): ").upper().strip()
 
if len(guess) != code_length or any([char not in letters for char in guess]):
continue
elif guess == code:
print(f"\nYour guess {guess} was correct!")
break
else:
guesses.append(f"{len(guesses)+1}: {' '.join(guess)} => {' '.join(encode(code, guess))}")
 
for i_guess in guesses:
print("------------------------------------")
print(i_guess)
print("------------------------------------")
 
 
if __name__ == '__main__':
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 a different position.
 
Select a number of possible letters for the code (2-20): 4
Select a length for the code (4-10): 4
 
*omitted first guesses*
 
Enter a guess of length 4 (ABCD): cdaa
------------------------------------
1: A A B B => O O - -
------------------------------------
2: C D A A => O X X O
------------------------------------
 
Enter a guess of length 4 (ABCD): ddac
 
Your guess DDAC 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" perl6line>sub MAIN (
Int :$colors where 1 < * < 21 = 6, Int :$length where 3 < * < 11 = 4,
Int :$guesses where 7 < * < 21 = 10, Bool :$repeat = False
Line 988 ⟶ 3,612:
 
sub lose { say 'Too bad, you ran out of guesses. The solution was: ', $puzzle; exit }
}</langsyntaxhighlight>
{{out|Sample output}}
<pre>Valid letter, but wrong position: ○ - Correct letter and position: ●
Line 1,005 ⟶ 3,629:
=={{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 1,082 ⟶ 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 1,139 ⟶ 3,763:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Mastermind
 
Line 1,233 ⟶ 3,857:
next
see nl
</syntaxhighlight>
</lang>
Output:
<pre>
Line 1,245 ⟶ 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 1,295 ⟶ 4,377:
return(black==codeLen,"X"*black + "O"*white)
}
}(4,12).play();</langsyntaxhighlight>
{{out}}
<pre>
1,969

edits