Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
5
Task/Mastermind/00-META.yaml
Normal file
5
Task/Mastermind/00-META.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
category:
|
||||
- Puzzles
|
||||
from: http://rosettacode.org/wiki/Mastermind
|
||||
note: Games
|
||||
53
Task/Mastermind/00-TASK.txt
Normal file
53
Task/Mastermind/00-TASK.txt
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
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 colors may be repeated 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
|
||||
|-
|
||||
| Player guess
|
||||
| Colored circles
|
||||
| Alphabet letters
|
||||
|-
|
||||
|Correct color & position
|
||||
|Black circle
|
||||
|X
|
||||
|-
|
||||
|Correct color
|
||||
|White circle
|
||||
|O
|
||||
|-
|
||||
|None
|
||||
|Gray circle
|
||||
| -
|
||||
|-
|
||||
|}
|
||||
|
||||
|
||||
A text version example: <big> 1. ADEF - XXO- </big>
|
||||
<br>Translates to:
|
||||
<br>the first guess;
|
||||
<br>the four colors (ADEF);
|
||||
<br>result:
|
||||
:::: two correct colors and spot,
|
||||
:::: one correct color/wrong spot, one color isn't in the code.
|
||||
|
||||
Happy coding!
|
||||
|
||||
|
||||
;Related tasks:
|
||||
* [[Bulls and cows]]
|
||||
* [[Bulls and cows/Player]]
|
||||
* [[Guess the number]]
|
||||
* [[Guess the number/With Feedback]]
|
||||
<br><br>
|
||||
|
||||
53
Task/Mastermind/11l/mastermind.11l
Normal file
53
Task/Mastermind/11l/mastermind.11l
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
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()
|
||||
131
Task/Mastermind/APL/mastermind.apl
Normal file
131
Task/Mastermind/APL/mastermind.apl
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#!/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
|
||||
167
Task/Mastermind/Action-/mastermind.action
Normal file
167
Task/Mastermind/Action-/mastermind.action
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
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
|
||||
161
Task/Mastermind/Ada/mastermind.ada
Normal file
161
Task/Mastermind/Ada/mastermind.ada
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
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;
|
||||
168
Task/Mastermind/AutoHotkey/mastermind.ahk
Normal file
168
Task/Mastermind/AutoHotkey/mastermind.ahk
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
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
|
||||
;-----------------------------------------------------------------------
|
||||
148
Task/Mastermind/C++/mastermind.cpp
Normal file
148
Task/Mastermind/C++/mastermind.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<char> vecChar;
|
||||
|
||||
class master {
|
||||
public:
|
||||
master( size_t code_len, size_t clr_count, size_t guess_count, bool rpt ) {
|
||||
std::string color = "ABCDEFGHIJKLMNOPQRST";
|
||||
|
||||
if( code_len < 4 ) code_len = 4; else if( code_len > 10 ) code_len = 10;
|
||||
if( !rpt && clr_count < code_len ) clr_count = code_len;
|
||||
if( clr_count < 2 ) clr_count = 2; else if( clr_count > 20 ) clr_count = 20;
|
||||
if( guess_count < 7 ) guess_count = 7; else if( guess_count > 20 ) guess_count = 20;
|
||||
|
||||
codeLen = code_len; colorsCnt = clr_count; guessCnt = guess_count; repeatClr = rpt;
|
||||
|
||||
for( size_t s = 0; s < colorsCnt; s++ ) {
|
||||
colors.append( 1, color.at( s ) );
|
||||
}
|
||||
}
|
||||
void play() {
|
||||
bool win = false;
|
||||
combo = getCombo();
|
||||
|
||||
while( guessCnt ) {
|
||||
showBoard();
|
||||
if( checkInput( getInput() ) ) {
|
||||
win = true;
|
||||
break;
|
||||
}
|
||||
guessCnt--;
|
||||
}
|
||||
if( win ) {
|
||||
std::cout << "\n\n--------------------------------\n" <<
|
||||
"Very well done!\nYou found the code: " << combo <<
|
||||
"\n--------------------------------\n\n";
|
||||
} else {
|
||||
std::cout << "\n\n--------------------------------\n" <<
|
||||
"I am sorry, you couldn't make it!\nThe code was: " << combo <<
|
||||
"\n--------------------------------\n\n";
|
||||
}
|
||||
}
|
||||
private:
|
||||
void showBoard() {
|
||||
vecChar::iterator y;
|
||||
for( int x = 0; x < guesses.size(); x++ ) {
|
||||
std::cout << "\n--------------------------------\n";
|
||||
std::cout << x + 1 << ": ";
|
||||
for( y = guesses[x].begin(); y != guesses[x].end(); y++ ) {
|
||||
std::cout << *y << " ";
|
||||
}
|
||||
|
||||
std::cout << " : ";
|
||||
for( y = results[x].begin(); y != results[x].end(); y++ ) {
|
||||
std::cout << *y << " ";
|
||||
}
|
||||
|
||||
int z = codeLen - results[x].size();
|
||||
if( z > 0 ) {
|
||||
for( int x = 0; x < z; x++ ) std::cout << "- ";
|
||||
}
|
||||
}
|
||||
std::cout << "\n\n";
|
||||
}
|
||||
std::string getInput() {
|
||||
std::string a;
|
||||
while( true ) {
|
||||
std::cout << "Enter your guess (" << colors << "): ";
|
||||
a = ""; std::cin >> a;
|
||||
std::transform( a.begin(), a.end(), a.begin(), ::toupper );
|
||||
if( a.length() > codeLen ) a.erase( codeLen );
|
||||
bool r = true;
|
||||
for( std::string::iterator x = a.begin(); x != a.end(); x++ ) {
|
||||
if( colors.find( *x ) == std::string::npos ) {
|
||||
r = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( r ) break;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
bool checkInput( std::string a ) {
|
||||
vecChar g;
|
||||
for( std::string::iterator x = a.begin(); x != a.end(); x++ ) {
|
||||
g.push_back( *x );
|
||||
}
|
||||
guesses.push_back( g );
|
||||
|
||||
int black = 0, white = 0;
|
||||
std::vector<bool> gmatch( codeLen, false );
|
||||
std::vector<bool> cmatch( codeLen, false );
|
||||
|
||||
for( int i = 0; i < codeLen; i++ ) {
|
||||
if( a.at( i ) == combo.at( i ) ) {
|
||||
gmatch[i] = true;
|
||||
cmatch[i] = true;
|
||||
black++;
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < codeLen; i++ ) {
|
||||
if (gmatch[i]) continue;
|
||||
for( int j = 0; j < codeLen; j++ ) {
|
||||
if (i == j || cmatch[j]) continue;
|
||||
if( a.at( i ) == combo.at( j ) ) {
|
||||
cmatch[j] = true;
|
||||
white++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vecChar r;
|
||||
for( int b = 0; b < black; b++ ) r.push_back( 'X' );
|
||||
for( int w = 0; w < white; w++ ) r.push_back( 'O' );
|
||||
results.push_back( r );
|
||||
|
||||
return ( black == codeLen );
|
||||
}
|
||||
std::string getCombo() {
|
||||
std::string c, clr = colors;
|
||||
int l, z;
|
||||
|
||||
for( size_t s = 0; s < codeLen; s++ ) {
|
||||
z = rand() % ( int )clr.length();
|
||||
c.append( 1, clr[z] );
|
||||
if( !repeatClr ) clr.erase( z, 1 );
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t codeLen, colorsCnt, guessCnt;
|
||||
bool repeatClr;
|
||||
std::vector<vecChar> guesses, results;
|
||||
std::string colors, combo;
|
||||
};
|
||||
|
||||
int main( int argc, char* argv[] ) {
|
||||
srand( unsigned( time( 0 ) ) );
|
||||
master m( 4, 8, 12, false );
|
||||
m.play();
|
||||
return 0;
|
||||
}
|
||||
159
Task/Mastermind/EasyLang/mastermind.easy
Normal file
159
Task/Mastermind/EasyLang/mastermind.easy
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
col[] = [ 802 990 171 229 950 808 ]
|
||||
len code[] 4
|
||||
len guess[] 4
|
||||
#
|
||||
subr init_vars
|
||||
row = 0
|
||||
.
|
||||
proc draw_rate r black white . .
|
||||
for j range0 2
|
||||
for c range0 2
|
||||
move c * 3.5 + 71.5 r * 11.5 + 9.4 - j * 3.5
|
||||
if black > 0
|
||||
color 000
|
||||
circle 1.4
|
||||
black -= 1
|
||||
elif white > 0
|
||||
color 999
|
||||
circle 1.4
|
||||
white -= 1
|
||||
else
|
||||
color 310
|
||||
circle 0.7
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
proc show_code . .
|
||||
color 531
|
||||
move 22 92
|
||||
rect 46 8
|
||||
for i to 4
|
||||
move i * 8 + 20 97
|
||||
color col[code[i]]
|
||||
circle 2
|
||||
.
|
||||
.
|
||||
proc draw_guess . .
|
||||
for c to 4
|
||||
move c * 12 + 8 row * 11.5 + 7.5
|
||||
color col[guess[c]]
|
||||
circle 3.8
|
||||
.
|
||||
.
|
||||
proc next_row . .
|
||||
color 420
|
||||
linewidth 11
|
||||
move 17 row * 11.5 + 7.5
|
||||
line 60 row * 11.5 + 7.5
|
||||
call draw_guess
|
||||
move 73.5 row * 11.5 + 7.5
|
||||
color 310
|
||||
circle 5.0
|
||||
color 753
|
||||
move 71.5 row * 11.5 + 5
|
||||
textsize 7
|
||||
text "✓"
|
||||
.
|
||||
proc rate . .
|
||||
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
|
||||
for j to 4
|
||||
if c[i] = g[j]
|
||||
white += 1
|
||||
c[i] = -1
|
||||
g[j] = -2
|
||||
.
|
||||
.
|
||||
.
|
||||
call draw_rate row black white
|
||||
color 531
|
||||
linewidth 12
|
||||
move 17 row * 11.5 + 7.5
|
||||
line 60 row * 11.5 + 7.5
|
||||
call draw_guess
|
||||
row += 1
|
||||
if black = 4
|
||||
row = 8
|
||||
.
|
||||
if row = 8
|
||||
call show_code
|
||||
timer 2
|
||||
else
|
||||
call next_row
|
||||
.
|
||||
.
|
||||
on timer
|
||||
row = -2
|
||||
.
|
||||
proc new . .
|
||||
call init_vars
|
||||
for i to 4
|
||||
code[i] = random 6
|
||||
.
|
||||
color 531
|
||||
move 10 10
|
||||
rect 70 80
|
||||
linewidth 10
|
||||
move 5 95
|
||||
line 5 5
|
||||
line 85 5
|
||||
line 85 95
|
||||
line 5 95
|
||||
color 310
|
||||
linewidth 7
|
||||
move 28 96.5
|
||||
line 58 96.5
|
||||
move 30 95
|
||||
color 864
|
||||
textsize 4
|
||||
text "Mastermind"
|
||||
color 310
|
||||
linewidth 0.5
|
||||
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
|
||||
.
|
||||
call draw_rate r 0 0
|
||||
.
|
||||
guess[1] = 1
|
||||
guess[2] = 1
|
||||
guess[3] = 2
|
||||
guess[4] = 2
|
||||
call next_row
|
||||
.
|
||||
proc do_move . .
|
||||
c = (mouse_x - 15) div 12
|
||||
guess[c + 1] = guess[c + 1] mod 6 + 1
|
||||
call draw_guess
|
||||
.
|
||||
on mouse_down
|
||||
if row = -2
|
||||
call new
|
||||
elif mouse_y > row * 11.5 + 0.5 and mouse_y < row * 11.5 + 10.5 and row < 8
|
||||
if mouse_x > 15 and mouse_x < 61
|
||||
call do_move
|
||||
elif mouse_x > 67 and mouse_x < 80
|
||||
call rate
|
||||
.
|
||||
.
|
||||
.
|
||||
call new
|
||||
114
Task/Mastermind/FreeBASIC/mastermind.basic
Normal file
114
Task/Mastermind/FreeBASIC/mastermind.basic
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
'--- 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
|
||||
188
Task/Mastermind/Go/mastermind.go
Normal file
188
Task/Mastermind/Go/mastermind.go
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetPrefix("mastermind: ")
|
||||
log.SetFlags(0)
|
||||
colours := flag.Int("colours", 6, "number of colours to use (2-20)")
|
||||
flag.IntVar(colours, "colors", 6, "alias for colours")
|
||||
holes := flag.Int("holes", 4, "number of holes (the code length, 4-10)")
|
||||
guesses := flag.Int("guesses", 12, "number of guesses allowed (7-20)")
|
||||
unique := flag.Bool("unique", false, "disallow duplicate colours in the code")
|
||||
flag.Parse()
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
m, err := NewMastermind(*colours, *holes, *guesses, *unique)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = m.Play()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type mastermind struct {
|
||||
colours int
|
||||
holes int
|
||||
guesses int
|
||||
unique bool
|
||||
|
||||
code string
|
||||
past []string // history of guesses
|
||||
scores []string // history of scores
|
||||
}
|
||||
|
||||
func NewMastermind(colours, holes, guesses int, unique bool) (*mastermind, error) {
|
||||
if colours < 2 || colours > 20 {
|
||||
return nil, errors.New("colours must be between 2 and 20 inclusive")
|
||||
}
|
||||
if holes < 4 || holes > 10 {
|
||||
return nil, errors.New("holes must be between 4 and 10 inclusive")
|
||||
}
|
||||
if guesses < 7 || guesses > 20 {
|
||||
return nil, errors.New("guesses must be between 7 and 20 inclusive")
|
||||
}
|
||||
if unique && holes > colours {
|
||||
return nil, errors.New("holes must be > colours when using unique")
|
||||
}
|
||||
|
||||
return &mastermind{
|
||||
colours: colours,
|
||||
holes: holes,
|
||||
guesses: guesses,
|
||||
unique: unique,
|
||||
past: make([]string, 0, guesses),
|
||||
scores: make([]string, 0, guesses),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mastermind) Play() error {
|
||||
m.generateCode()
|
||||
fmt.Printf("A set of %s has been selected as the code.\n", m.describeCode(m.unique))
|
||||
fmt.Printf("You have %d guesses.\n", m.guesses)
|
||||
for len(m.past) < m.guesses {
|
||||
guess, err := m.inputGuess()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println()
|
||||
m.past = append(m.past, guess)
|
||||
str, won := m.scoreString(m.score(guess))
|
||||
if won {
|
||||
plural := "es"
|
||||
if len(m.past) == 1 {
|
||||
plural = ""
|
||||
}
|
||||
fmt.Printf("You found the code in %d guess%s.\n", len(m.past), plural)
|
||||
return nil
|
||||
}
|
||||
m.scores = append(m.scores, str)
|
||||
m.printHistory()
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Printf("You are out of guesses. The code was %s.\n", m.code)
|
||||
return nil
|
||||
}
|
||||
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const blacks = "XXXXXXXXXX"
|
||||
const whites = "OOOOOOOOOO"
|
||||
const nones = "----------"
|
||||
|
||||
func (m *mastermind) describeCode(unique bool) string {
|
||||
ustr := ""
|
||||
if unique {
|
||||
ustr = " unique"
|
||||
}
|
||||
return fmt.Sprintf("%d%s letters (from 'A' to %q)",
|
||||
m.holes, ustr, charset[m.colours-1],
|
||||
)
|
||||
}
|
||||
|
||||
func (m *mastermind) printHistory() {
|
||||
for i, g := range m.past {
|
||||
fmt.Printf("-----%s---%[1]s--\n", nones[:m.holes])
|
||||
fmt.Printf("%2d: %s : %s\n", i+1, g, m.scores[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mastermind) generateCode() {
|
||||
code := make([]byte, m.holes)
|
||||
if m.unique {
|
||||
p := rand.Perm(m.colours)
|
||||
for i := range code {
|
||||
code[i] = charset[p[i]]
|
||||
}
|
||||
} else {
|
||||
for i := range code {
|
||||
code[i] = charset[rand.Intn(m.colours)]
|
||||
}
|
||||
}
|
||||
m.code = string(code)
|
||||
//log.Printf("code is %q", m.code)
|
||||
}
|
||||
|
||||
func (m *mastermind) inputGuess() (string, error) {
|
||||
var input string
|
||||
for {
|
||||
fmt.Printf("Enter guess #%d: ", len(m.past)+1)
|
||||
if _, err := fmt.Scanln(&input); err != nil {
|
||||
return "", err
|
||||
}
|
||||
input = strings.ToUpper(strings.TrimSpace(input))
|
||||
if m.validGuess(input) {
|
||||
return input, nil
|
||||
}
|
||||
fmt.Printf("A guess must consist of %s.\n", m.describeCode(false))
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mastermind) validGuess(input string) bool {
|
||||
if len(input) != m.holes {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(input); i++ {
|
||||
c := input[i]
|
||||
if c < 'A' || c > charset[m.colours-1] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *mastermind) score(guess string) (black, white int) {
|
||||
scored := make([]bool, m.holes)
|
||||
for i := 0; i < len(guess); i++ {
|
||||
if guess[i] == m.code[i] {
|
||||
black++
|
||||
scored[i] = true
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(guess); i++ {
|
||||
if guess[i] == m.code[i] {
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(m.code); j++ {
|
||||
if i != j && !scored[j] && guess[i] == m.code[j] {
|
||||
white++
|
||||
scored[j] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *mastermind) scoreString(black, white int) (string, bool) {
|
||||
none := m.holes - black - white
|
||||
return blacks[:black] + whites[:white] + nones[:none], black == m.holes
|
||||
}
|
||||
232
Task/Mastermind/JavaScript/mastermind.js
Normal file
232
Task/Mastermind/JavaScript/mastermind.js
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
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()
|
||||
});
|
||||
209
Task/Mastermind/Julia/mastermind.julia
Normal file
209
Task/Mastermind/Julia/mastermind.julia
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
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()
|
||||
118
Task/Mastermind/Kotlin/mastermind.kotlin
Normal file
118
Task/Mastermind/Kotlin/mastermind.kotlin
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// version 1.2.51
|
||||
|
||||
import java.util.Random
|
||||
|
||||
val rand = Random()
|
||||
|
||||
class Mastermind {
|
||||
private val codeLen: Int
|
||||
private val colorsCnt: Int
|
||||
private var guessCnt = 0
|
||||
private val repeatClr: Boolean
|
||||
|
||||
private val colors: String
|
||||
private var combo = ""
|
||||
|
||||
private val guesses = mutableListOf<CharArray>()
|
||||
private val results = mutableListOf<CharArray>()
|
||||
|
||||
constructor(codeLen: Int, colorsCnt: Int, guessCnt: Int, repeatClr: Boolean) {
|
||||
val color = "ABCDEFGHIJKLMNOPQRST"
|
||||
this.codeLen = codeLen.coerceIn(4, 10)
|
||||
var cl = colorsCnt
|
||||
if (!repeatClr && cl < this.codeLen) cl = this.codeLen
|
||||
this.colorsCnt = cl.coerceIn(2, 20)
|
||||
this.guessCnt = guessCnt.coerceIn(7, 20)
|
||||
this.repeatClr = repeatClr
|
||||
this.colors = color.take(this.colorsCnt)
|
||||
}
|
||||
|
||||
fun play() {
|
||||
var win = false
|
||||
combo = getCombo()
|
||||
while (guessCnt != 0) {
|
||||
showBoard()
|
||||
if (checkInput(getInput())) {
|
||||
win = true
|
||||
break
|
||||
}
|
||||
guessCnt--
|
||||
}
|
||||
println("\n\n--------------------------------")
|
||||
if (win) {
|
||||
println("Very well done!\nYou found the code: $combo")
|
||||
}
|
||||
else {
|
||||
println("I am sorry, you couldn't make it!\nThe code was: $combo")
|
||||
}
|
||||
println("--------------------------------\n")
|
||||
}
|
||||
|
||||
private fun showBoard() {
|
||||
for (x in 0 until guesses.size) {
|
||||
println("\n--------------------------------")
|
||||
print("${x + 1}: ")
|
||||
for (y in guesses[x]) print("$y ")
|
||||
print(" : ")
|
||||
for (y in results[x]) print("$y ")
|
||||
val z = codeLen - results[x].size
|
||||
if (z > 0) print("- ".repeat(z))
|
||||
}
|
||||
println("\n")
|
||||
}
|
||||
|
||||
private fun getInput(): String {
|
||||
while (true) {
|
||||
print("Enter your guess ($colors): ")
|
||||
val a = readLine()!!.toUpperCase().take(codeLen)
|
||||
if (a.all { it in colors } ) return a
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkInput(a: String): Boolean {
|
||||
guesses.add(a.toCharArray())
|
||||
var black = 0
|
||||
var white = 0
|
||||
val gmatch = BooleanArray(codeLen)
|
||||
val cmatch = BooleanArray(codeLen)
|
||||
for (i in 0 until codeLen) {
|
||||
if (a[i] == combo[i]) {
|
||||
gmatch[i] = true
|
||||
cmatch[i] = true
|
||||
black++
|
||||
}
|
||||
}
|
||||
for (i in 0 until codeLen) {
|
||||
if (gmatch[i]) continue
|
||||
for (j in 0 until codeLen) {
|
||||
if (i == j || cmatch[j]) continue
|
||||
if (a[i] == combo[j]) {
|
||||
cmatch[j] = true
|
||||
white++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
val r = mutableListOf<Char>()
|
||||
r.addAll("X".repeat(black).toList())
|
||||
r.addAll("O".repeat(white).toList())
|
||||
results.add(r.toCharArray())
|
||||
return black == codeLen
|
||||
}
|
||||
|
||||
private fun getCombo(): String {
|
||||
val c = StringBuilder()
|
||||
val clr = StringBuilder(colors)
|
||||
for (s in 0 until codeLen) {
|
||||
val z = rand.nextInt(clr.length)
|
||||
c.append(clr[z])
|
||||
if (!repeatClr) clr.deleteCharAt(z)
|
||||
}
|
||||
return c.toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val m = Mastermind(4, 8, 12, false)
|
||||
m.play()
|
||||
}
|
||||
78
Task/Mastermind/Lua/mastermind.lua
Normal file
78
Task/Mastermind/Lua/mastermind.lua
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
math.randomseed( os.time() )
|
||||
local black, white, none, code = "X", "O", "-"
|
||||
local colors, codeLen, maxGuess, rept, alpha, opt = 6, 4, 10, false, "ABCDEFGHIJKLMNOPQRST", ""
|
||||
local guesses, results
|
||||
function createCode()
|
||||
code = ""
|
||||
local dic, a = ""
|
||||
for i = 1, colors do
|
||||
dic = dic .. alpha:sub( i, i )
|
||||
end
|
||||
for i = 1, codeLen do
|
||||
a = math.floor( math.random( 1, #dic ) )
|
||||
code = code .. dic:sub( a, a )
|
||||
if not rept then
|
||||
dic = dic:sub(1, a - 1 ) .. dic:sub( a + 1, #dic )
|
||||
end
|
||||
end
|
||||
end
|
||||
function checkInput( inp )
|
||||
table.insert( guesses, inp )
|
||||
local b, w, fnd, str = 0, 0, {}, ""
|
||||
for bl = 1, codeLen do
|
||||
if inp:sub( bl, bl ) == code:sub( bl, bl ) then
|
||||
b = b + 1; fnd[bl] = true
|
||||
else
|
||||
for wh = 1, codeLen do
|
||||
if nil == fnd[bl] and wh ~= bl and inp:sub( wh, wh ) == code:sub( bl, bl ) then
|
||||
w = w + 1; fnd[bl] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, b do str = str .. string.format( "%s ", black ) end
|
||||
for i = 1, w do str = str .. string.format( "%s ", white ) end
|
||||
for i = 1, 2 * codeLen - #str, 2 do str = str .. string.format( "%s ", none ) end
|
||||
table.insert( results, str )
|
||||
return b == codeLen
|
||||
end
|
||||
function play()
|
||||
local err, win, r = true, false;
|
||||
for j = 1, colors do opt = opt .. alpha:sub( j, j ) end
|
||||
while( true ) do
|
||||
createCode(); guesses, results = {}, {}
|
||||
for i = 1, maxGuess do
|
||||
err = true;
|
||||
while( err ) do
|
||||
io.write( string.format( "\n-------------------------------\nYour guess (%s)?", opt ) )
|
||||
inp = io.read():upper();
|
||||
if #inp == codeLen then
|
||||
err = false;
|
||||
for k = 1, #inp do
|
||||
if( nil == opt:find( inp:sub( k, k ) ) ) then
|
||||
err = true;
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if( checkInput( inp ) ) then win = true; break
|
||||
else
|
||||
for l = 1, #guesses do
|
||||
print( string.format( "%.2d: %s : %s", l, guesses[l], results[l] ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
if win then print( "\nWell done!" )
|
||||
else print( string.format( "\nSorry, you did not crack the code --> %s!", code ) )
|
||||
end
|
||||
io.write( "Play again( Y/N )? " ); r = io.read()
|
||||
if r ~= "Y" and r ~= "y" then break end
|
||||
end
|
||||
end
|
||||
--[[ entry point ]]---
|
||||
if arg[1] ~= nil and tonumber( arg[1] ) > 1 and tonumber( arg[1] ) < 21 then colors = tonumber( arg[1] ) end
|
||||
if arg[2] ~= nil and tonumber( arg[2] ) > 3 and tonumber( arg[2] ) < 11 then codeLen = tonumber( arg[2] ) end
|
||||
if arg[3] ~= nil and tonumber( arg[3] ) > 6 and tonumber( arg[3] ) < 21 then maxGuess = tonumber( arg[3] ) end
|
||||
if arg[4] ~= nil and arg[4] == "true" or arg[4] == "false" then rept = ( arg[4] == "true" ) end
|
||||
play()
|
||||
51
Task/Mastermind/Nim/mastermind.nim
Normal file
51
Task/Mastermind/Nim/mastermind.nim
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
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()
|
||||
51
Task/Mastermind/Perl/mastermind.pl
Normal file
51
Task/Mastermind/Perl/mastermind.pl
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use List::Util qw(any);
|
||||
|
||||
print 'Enter pool size, puzzle size, attempts allowed: ';
|
||||
($pool,$length,$tries) = split /\s+/, <>;
|
||||
$length = 4 if $length eq '' or $length < 3 or $length > 11;
|
||||
$pool = 6 if $pool eq '' or $pool < 2 or $pool > 21;
|
||||
$tries = 10 if $tries eq '' or $tries < 7 or $tries > 21;
|
||||
|
||||
@valid = sort { -1 + 2*int(rand 2) } ('A' .. 'T')[0..$pool-1];
|
||||
@puzzle = @valid[0..$length-1];
|
||||
|
||||
$black = '●';
|
||||
$white = '○';
|
||||
|
||||
while () {
|
||||
header();
|
||||
print "$_\n" for @guesses;
|
||||
lose() if @guesses == $tries;
|
||||
@guess = get_guess();
|
||||
next unless is_valid(@guess);
|
||||
$score = score(\@puzzle, \@guess);
|
||||
win() if $score eq join ' ', ($black) x $length;
|
||||
push @guesses, join(' ', @guess) . ' :: ' . $score;
|
||||
}
|
||||
|
||||
sub score {
|
||||
local *puzzle = shift;
|
||||
local *guess = shift;
|
||||
my @score;
|
||||
for $i (0..$length-1) {
|
||||
if ( $puzzle[$i] eq $guess[$i]) { push @score, $black }
|
||||
elsif (any {$puzzle[$i] eq $_} @guess) { push @score, $white }
|
||||
else { push @score, '-' }
|
||||
}
|
||||
join ' ', reverse sort @score;
|
||||
}
|
||||
|
||||
sub header {
|
||||
$num = $tries - @guesses;
|
||||
print "Valid letter, but wrong position: ○ - Correct letter and position: ●\n";
|
||||
print "Guess the $length element sequence containing the letters " . join(', ', sort @valid) . "\n";
|
||||
printf "Repeats are not allowed. You have $num guess%s remaining\n", $num > 1 ? 'es' : '';
|
||||
}
|
||||
|
||||
sub get_guess { print 'Your guess?: '; $g = <>; return split /\s*/, uc $g }
|
||||
|
||||
sub is_valid { $length == @_ }
|
||||
|
||||
sub win { print 'You win! The correct answer is: ' . join(' ',@puzzle) . "\n"; exit }
|
||||
|
||||
sub lose { print 'Too bad, you ran out of guesses. The solution was: ' . join(' ',@puzzle) . "\n"; exit }
|
||||
569
Task/Mastermind/Phix/mastermind.phix
Normal file
569
Task/Mastermind/Phix/mastermind.phix
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
-- 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()
|
||||
101
Task/Mastermind/Prolog/mastermind.pro
Normal file
101
Task/Mastermind/Prolog/mastermind.pro
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
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).
|
||||
59
Task/Mastermind/Python/mastermind.py
Normal file
59
Task/Mastermind/Python/mastermind.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
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()
|
||||
78
Task/Mastermind/REXX/mastermind.rexx
Normal file
78
Task/Mastermind/REXX/mastermind.rexx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*REXX pgm scores mastermind game with a human or CBLFs (Carbon Based Life Forms). */
|
||||
parse arg let wid mxG oRep seed _ /*obtain optional arguments from the CL*/
|
||||
arg . . . rep . /*get uppercase 4th argument " " " */
|
||||
if let=='' | let=="," then let= 20 /*Not specified? Then use the default.*/
|
||||
if wid=='' | wid=="," then wid= 4 /* " " " " " " */
|
||||
if mxG=='' | mxG=="," then mxG= 20 /* " " " " " " */
|
||||
if rep=='' | rep=="," then rep= 0 /* " " " " " " */
|
||||
if datatype(seed,'W') then call random ,,seed /*use a seed for random repeatability. */
|
||||
if abbrev( 'REPEATSALLOWED',rep,3) then rep=1 /*allow an abbreviated option for REP. */
|
||||
if abbrev('NOREPEATSALLOWED',rep,3) then rep=0 /* " " " " " " */
|
||||
call vet arg(), 'args' /*Vet the number of arguments entered. */ /*◄■■■■■■ optional vetting.*/
|
||||
call vet let, 'letters', 2, 20 /* " " " " letters in the code*/ /*◄■■■■■■ optional vetting.*/
|
||||
call vet wid, 'width', 4, 10 /* " " " " the width of code. */ /*◄■■■■■■ optional vetting.*/
|
||||
call vet mxG, 'maxGuess', 7, 20 /* " " " " maximum guesses. */ /*◄■■■■■■ optional vetting.*/
|
||||
call vet rep, 'REP', 0, 1e8 /* " " value if repeats are allowed*/ /*◄■■■■■■ optional vetting.*/
|
||||
call gen; yourG= 'Your guess must be exactly '
|
||||
youve= "You've already tried that guess "
|
||||
do prompt=0 by 0 until xx==wid; say /*play until guessed or QUIT is entered*/
|
||||
say id 'Please enter a guess with ' wid ' letters [or Quit]:'
|
||||
pull g; g=space(g,0); L=length(g); if abbrev('QUIT',g,1) then exit 0
|
||||
if L\==wid then do; say id '***error***' yourG wid " letters."; iterate; end
|
||||
call dups /*look through the history log for dups*/
|
||||
q=?; XX=0; OO=0; try=try+1 /*initialize some REXX vars; bump TRY.*/
|
||||
|
||||
do j=1 for L; if substr(g,j,1) \== substr(q,j,1) then iterate /*hit? */
|
||||
xx=xx+1; q=overlay('▒', q, j) /*bump the XX correct count. */
|
||||
end /*j*/ /* [↑] XX correct count; scrub guess.*/
|
||||
|
||||
do k=1 for L; _=substr(g, k, 1) /*process the count for "spots". */
|
||||
if pos(_, q)==0 then iterate /*is this (spot) letter in the code? */
|
||||
oo=oo+1; q=translate(q, , _) /*bump the OO spot count. */
|
||||
end /*k*/ /* [↑] OO spot count; & scrub guess.*/
|
||||
say
|
||||
@.try=id right('guess' try, 11) ' ('mxG "is the max):" g '──►' ,
|
||||
copies('X', xx)copies("O", oo)copies('-', wid-xx-oo)
|
||||
call hist
|
||||
if try==mxG then do; say; say id "you've used the maximum guesses:" mxG
|
||||
say; say id "The code was: " ?; say; exit 1
|
||||
end
|
||||
end /*prompt*/
|
||||
say; say " ┌─────────────────────────────────────────┐"
|
||||
say " │ │"
|
||||
say " │ Congratulations, you've guessed it !! │"
|
||||
say " │ │"
|
||||
say " └─────────────────────────────────────────┘"
|
||||
exit 0 /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
dups: do h=1 for try; if g\=word(@.h, 8) then iterate /*any duplicated guesses? */
|
||||
say; say id youve " (guess number" h').'; iterate prompt; end /*h*/; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
gen: if rep==0 then reps= 'no' /*create a literal for the prompt msg. */
|
||||
else reps=
|
||||
@abc= 'QWERTYUIOPASDFGHJKLZXCVBNM' /*capital letters used for random code.*/
|
||||
id='────────'; try=0; L@abc=length(@abc) /*identifier in front of msg from here.*/
|
||||
?=
|
||||
do until length(?)==wid /*gen random codes 'til there's enough.*/
|
||||
r=substr(@abc, random(1, L@abc), 1) /*generate a random letter, 1 at a time*/
|
||||
if \rep & pos(r, ?)\==0 then iterate /*maybe don't allow a repeated digit.*/
|
||||
?=? || r; if ?=='QUIT'&let==4 then ?= /*append random letter; ··· except this*/
|
||||
end /*until*/ /* [↑] builds a unique N-letter code.*/
|
||||
say
|
||||
say id 'A random code of ' wid "letters (out of a possible " let ' letters) '
|
||||
say id 'has been generated (with' reps "repeats)."
|
||||
return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
hist: do hist=1 for try; say @.hist; end; return /*show "guess" history.*/
|
||||
s: if arg(1)==1 then return ''; return "s" /*a simpler pluraizer. */
|
||||
ser: say; say; say '***error***' arg(1); say; say; exit 13
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/ /*◄■■■■■■ optional vetting.*/
|
||||
vet: parse arg val,?,mn,mx /*vet (validate) a specified argument. */ /*◄■■■■■■ optional vetting.*/
|
||||
if ?=="args" & (val>1 | _\='') then call ser "Too many arguments specified. " _ /*◄■■■■■■ optional vetting.*/
|
||||
if ?=="args" then return /*◄■■■■■■ optional vetting.*/
|
||||
if \datatype(val, 'N') then call ser ? "isn't numeric: " val /*◄■■■■■■ optional vetting.*/
|
||||
if \datatype(val, 'W') then call ser ? "isn't an integer: " val /*◄■■■■■■ optional vetting.*/
|
||||
if val < mn then call ser ? "has a value less than " mn /*◄■■■■■■ optional vetting.*/
|
||||
if val > mx then call ser ? "has a value greater than " mx /*◄■■■■■■ optional vetting.*/
|
||||
if ?=='REP' & \datatype(val,W) then call ser "Value for REPEATS isn't valid: " oRep /*◄■■■■■■ optional vetting.*/
|
||||
return 1
|
||||
59
Task/Mastermind/Raku/mastermind.raku
Normal file
59
Task/Mastermind/Raku/mastermind.raku
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
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 }
|
||||
}
|
||||
93
Task/Mastermind/Ring/mastermind.ring
Normal file
93
Task/Mastermind/Ring/mastermind.ring
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Project : Mastermind
|
||||
|
||||
colors = ["A", "B", "C", "D"]
|
||||
places = list(2)
|
||||
mind = list(len(colors))
|
||||
rands = list(len(colors))
|
||||
master = list(len(colors))
|
||||
test = list(len(colors))
|
||||
guesses = 7
|
||||
repeat = false
|
||||
nr = 0
|
||||
|
||||
if repeat
|
||||
for n = 1 to len(colors)
|
||||
while true
|
||||
rnd = random(len(colors)-1) + 1
|
||||
if rands[rnd] != 1
|
||||
mind[n] = rnd
|
||||
rands[rnd] = 1
|
||||
exit
|
||||
ok
|
||||
end
|
||||
next
|
||||
else
|
||||
for n = 1 to len(colors)
|
||||
rnd = random(len(colors)-1) + 1
|
||||
mind[n] = rnd
|
||||
next
|
||||
ok
|
||||
|
||||
for n = 1 to len(colors)
|
||||
master[n] = char(64+mind[n])
|
||||
next
|
||||
while true
|
||||
for p = 1 to len(places)
|
||||
places[p] = 0
|
||||
next
|
||||
nr = nr + 1
|
||||
see "Your guess (ABCD)? "
|
||||
give testbegin
|
||||
for d = 1 to len(test)
|
||||
test[d] = testbegin[d]
|
||||
next
|
||||
flag = 1
|
||||
for n = 1 to len(test)
|
||||
if upper(test[n]) != master[n]
|
||||
flag = 0
|
||||
ok
|
||||
next
|
||||
if flag = 1
|
||||
exit
|
||||
else
|
||||
for x = 1 to len(master)
|
||||
if upper(test[x]) = master[x]
|
||||
places[1] = places[1] + 1
|
||||
ok
|
||||
next
|
||||
mastertemp = master
|
||||
for p = 1 to len(test)
|
||||
pos = find(mastertemp, upper(test[p]))
|
||||
if pos > 0
|
||||
del(mastertemp, pos)
|
||||
places[2] = places[2] + 1
|
||||
ok
|
||||
next
|
||||
ok
|
||||
place1 = places[1]
|
||||
place2 = places[2] - place1
|
||||
place3 = len(master) - (place1 + place2)
|
||||
showresult(test, place1, place2, place3)
|
||||
if nr = guesses
|
||||
exit
|
||||
ok
|
||||
end
|
||||
see "Well done!" + nl
|
||||
see "End of game" + nl
|
||||
|
||||
func showresult(test, place1, place2, place3)
|
||||
see "" + nr + " : "
|
||||
for r = 1 to len(test)
|
||||
see test[r]
|
||||
next
|
||||
see " : "
|
||||
for n1 = 1 to place1
|
||||
see "X" + " "
|
||||
next
|
||||
for n2 = 1 to place2
|
||||
see "O" + " "
|
||||
next
|
||||
for n3 = 1 to place3
|
||||
see "-" + " "
|
||||
next
|
||||
see nl
|
||||
163
Task/Mastermind/Rust/mastermind.rust
Normal file
163
Task/Mastermind/Rust/mastermind.rust
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
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()
|
||||
}
|
||||
70
Task/Mastermind/SQL/mastermind.sql
Normal file
70
Task/Mastermind/SQL/mastermind.sql
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
-- 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
|
||||
106
Task/Mastermind/Wren/mastermind.wren
Normal file
106
Task/Mastermind/Wren/mastermind.wren
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
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()
|
||||
47
Task/Mastermind/Zkl/mastermind.zkl
Normal file
47
Task/Mastermind/Zkl/mastermind.zkl
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
class MasterMind{
|
||||
fcn init(code_len,guess_count){
|
||||
var codeLen =code_len.max(4).min(10);
|
||||
var guessCnt=guess_count.max(7).min(20);
|
||||
var colors ="ABCDEFGHIJKLMNOPQRST"[0,codeLen];
|
||||
}
|
||||
fcn play{
|
||||
guesses,win,blackWhite:=List(),False,Void;
|
||||
code:=codeLen.pump(String,'wrap(_){ colors[(0).random(codeLen)] });
|
||||
do(guessCnt){
|
||||
str:=getInput();
|
||||
win,blackWhite = checkInput(str,code);
|
||||
guesses.append(T(str,blackWhite));
|
||||
showBoard(guesses);
|
||||
if(win) break;
|
||||
}
|
||||
if(win) println("--------------------------------\n",
|
||||
"Very well done!\nYou found the code: ",code);
|
||||
else println("--------------------------------\n",
|
||||
"I am sorry, you didn't discover the code!\nThe code was: ",code);
|
||||
}
|
||||
fcn [private] showBoard(guesses){
|
||||
foreach n,gbw in ([1..].zip(guesses)){
|
||||
guess,blackWhite := gbw;
|
||||
println("%2d: %s :% s %s".fmt(n,
|
||||
guess.split("").concat(" "), blackWhite.split("").concat(" "),
|
||||
"- "*(codeLen - blackWhite.len())));
|
||||
}
|
||||
}
|
||||
fcn [private] getInput{
|
||||
while(True){
|
||||
a:=ask("Enter your guess (" + colors + "): ").toUpper()[0,codeLen];
|
||||
if(not (a-colors) and a.len()>=codeLen) return(a);
|
||||
}
|
||||
}
|
||||
fcn [private] checkInput(guess,code){
|
||||
// black: guess is correct in both color and position
|
||||
// white: correct color, wrong position
|
||||
matched,black := guess.split("").zipWith('==,code), matched.sum(0);
|
||||
// remove black from code, prepend null to make counting easy
|
||||
code = L("-").extend(matched.zipWith('wrap(m,peg){ m and "-" or peg },code));
|
||||
white:=0; foreach m,p in (matched.zip(guess)){
|
||||
if(not m and (z:=code.find(p))){ white+=1; code[z]="-"; }
|
||||
}
|
||||
return(black==codeLen,"X"*black + "O"*white)
|
||||
}
|
||||
}(4,12).play();
|
||||
Loading…
Add table
Add a link
Reference in a new issue