132 lines
4.5 KiB
APL
132 lines
4.5 KiB
APL
|
|
#!/usr/local/bin/apl -s -f --
|
|||
|
|
|
|||
|
|
⍝ Define the alphabet
|
|||
|
|
A←'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|||
|
|
|
|||
|
|
⍝ Make ASCII values upper case
|
|||
|
|
∇n←AscUp c
|
|||
|
|
n←c-32×(c≥97)∧(c≤122)
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Does a list have repeated values?
|
|||
|
|
∇r←Rpts l
|
|||
|
|
r←(l⍳l)≢⍳⍴l
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Keyboard input using ⎕ and ⍞ doesn't work well using GNU APL in script mode,
|
|||
|
|
⍝ so you kind of have to write your own.
|
|||
|
|
⍝ Read a line of text from the keyboard
|
|||
|
|
∇l←ReadLine up;k;z;data
|
|||
|
|
data←'' ⋄ csr←0 ⍝ Start out with empty string and cursor at 0
|
|||
|
|
|
|||
|
|
⍝⍝⍝ Keyboard input
|
|||
|
|
in: k←1⎕fio[41]1 ⍝ Read byte from stdin
|
|||
|
|
handle: →(k>127)/skip ⍝ Unicode is not supported (Wumpus doesn't need it)
|
|||
|
|
→(k∊8 127)/back ⍝ Handle backspace
|
|||
|
|
→(k=10)/done ⍝ Newline = Enter key pressed
|
|||
|
|
→(k<32)/in ⍝ For simplicity, disregard terminal control entirely
|
|||
|
|
|
|||
|
|
k←(AscUp⍣up)k ⍝ Make key uppercase if necessary
|
|||
|
|
z←k⎕fio[42]0 ⍝ Echo key to stdout
|
|||
|
|
data←data,k ⍝ Insert key into data
|
|||
|
|
→in ⍝ Go get next key
|
|||
|
|
|
|||
|
|
⍝⍝⍝ Skip UTF-8 input (read until byte ≤ 127)
|
|||
|
|
skip: k←1⎕fio[41]1 ⋄ →(k>127)/skip ⋄ →handle
|
|||
|
|
|
|||
|
|
⍝⍝ Backspace
|
|||
|
|
back: →(0=⍴data)/in ⍝ If already at beginning, ignore
|
|||
|
|
z←k⎕fio[42]0 ⍝ Backspace to terminal
|
|||
|
|
data←¯1↓data ⍝ Remove character
|
|||
|
|
→in ⍝ Get next key
|
|||
|
|
|
|||
|
|
⍝⍝ We are done, return the line as text
|
|||
|
|
done: l←⎕UCS data
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Read a positive number from the keyboard in the range [min...max]
|
|||
|
|
∇n←min ReadNum max;l;z
|
|||
|
|
in: l←ReadLine 0
|
|||
|
|
z←10⎕fio[42]0
|
|||
|
|
→(~l∧.∊'0123456789')/no
|
|||
|
|
→((min≤n)∧max≥n←⍎l)/0
|
|||
|
|
no: ⍞←'Please enter a number between ',(⍕min),' and ',(⍕max),': '
|
|||
|
|
→in
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Ask a numeric question
|
|||
|
|
∇n←q Question lim;min;max
|
|||
|
|
(min max)←lim
|
|||
|
|
⍞←q,' [',(⍕min),'..',(⍕max),']? '
|
|||
|
|
n←min ReadNum max
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Read a choice from the keyboard
|
|||
|
|
∇c←Choice cs;ks;k;z
|
|||
|
|
ks←AscUp ⎕UCS ↑¨cs ⍝ User should press first letter of choice
|
|||
|
|
in: →(~(k←AscUp 1⎕fio[41]1)∊ks)/in ⍝ Wait for user to make choice
|
|||
|
|
z←(c←⊃cs[↑ks⍳k])⎕fio[42]0 ⍝ Select and output correspoinding choice
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Ask the user for game parameters
|
|||
|
|
∇parms←InitGame;clrs;len;gss;rpts
|
|||
|
|
⎕←'∘∘∘ MASTERMIND ∘∘∘' ⋄ ⎕←''
|
|||
|
|
clrs←'How many colors' Question 2 20
|
|||
|
|
len←'Code length' Question 4 10
|
|||
|
|
gss←'Maximum amount of guesses' Question 7 20
|
|||
|
|
⍞←'Allow repeated colors in code (Y/N)? '
|
|||
|
|
rpts←'Yes'≡Choice 'Yes' 'No'
|
|||
|
|
parms←clrs len gss rpts
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Generate a code.
|
|||
|
|
∇c←rpts MakeCode parms;clrs;len
|
|||
|
|
(clrs len)←parms
|
|||
|
|
c←A[(1+rpts)⊃(len?clrs)(?len/clrs)]
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Let user make a guess and handle errors
|
|||
|
|
∇g←parms Guess code;clrs;rpts;l;right;in
|
|||
|
|
(clrs rpts num)←parms
|
|||
|
|
|
|||
|
|
guess: ⍞←'Guess ',(¯2↑⍕num),': ' ⋄ g←ReadLine 1 ⍝ Read a guess from the keyboard
|
|||
|
|
|
|||
|
|
⍝ Don't count obvously invalid input against the user
|
|||
|
|
→((⍴code)≢⍴g)/len ⍝ Length is wrong
|
|||
|
|
→(~g∧.∊A[⍳clrs])/inv ⍝ Invalid code in input
|
|||
|
|
→((~rpts)∧Rpts g)/rpt ⍝ No repeats allowed
|
|||
|
|
|
|||
|
|
⍝ Give feedback
|
|||
|
|
right←g=code ⍝ Colors in right position
|
|||
|
|
in←g∊code ⍝ Colors not in right position
|
|||
|
|
fb←(+/right)/'X' ⍝ X = amount of matching ones
|
|||
|
|
fb←fb,(+/in∧~right)/'O' ⍝ O = amount of non-matching ones
|
|||
|
|
fb←fb,(+/~in)/'-' ⍝ - = amount of colors not in code
|
|||
|
|
⍞←' --→ ',fb,⎕UCS 10
|
|||
|
|
→0
|
|||
|
|
len: ⎕←'Invalid length.' ⋄ →guess
|
|||
|
|
inv: ⎕←'Invalid color.' ⋄ →guess
|
|||
|
|
rpt: ⎕←'No repeats allowed.' ⋄ →guess
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
⍝ Play the game
|
|||
|
|
∇ Mastermind;clrs;len;gsmax;rpts;code;gs
|
|||
|
|
⎕rl←(2*32)|×/⎕ts ⍝ initialize random seed
|
|||
|
|
(clrs len gsmax rpts)←InitGame
|
|||
|
|
code←rpts MakeCode clrs len
|
|||
|
|
⎕←2 0⍴''
|
|||
|
|
⎕←'The code consists of: ',A[⍳clrs]
|
|||
|
|
gs←0
|
|||
|
|
loop: gs←gs+1
|
|||
|
|
→(gs>gsmax)/lose
|
|||
|
|
→(code≢(clrs rpts gs)Guess code)/loop
|
|||
|
|
⎕←'○○○ Congratulations! ○○○'
|
|||
|
|
⎕←'You won in ',(⍕gs),' guesses.'
|
|||
|
|
→0
|
|||
|
|
lose: ⎕←'Alas, you are out of guesses.'
|
|||
|
|
⎕←'The code was: ',code
|
|||
|
|
∇
|
|||
|
|
|
|||
|
|
Mastermind
|
|||
|
|
)OFF
|