6
\$\begingroup\$

For reference to the game of Mastermind: Solving Mastermind in 6 or less moves

In the version of Mastermind used in this problem, the operating string is a 4-digit number, from 0000 to 9999, represented as either numbers from 0 to 9999 or strings of consecutive digits "0000" to "9999" in input.

Your task is to build a function that will take two numbers/strings secret and guess as input, and return two numbers A and B, the number of red and white pegs respectively.

The shortest code in any language to do this wins.

\$\endgroup\$
  • 2
    \$\begingroup\$ I think this spec would be improved by not having people go read the actual specification of the game in another challenge. \$\endgroup\$ – Martin Ender Jan 20 '16 at 16:58
5
\$\begingroup\$

J: 40 26 29 22

=,&(+/)(~:#[)e.&~.~:#]
  • change: don't laminate, but work truly dyadically, eliminating need for explicit ranks ("1), lamination(,:) and between (/)
  • change: don't count duplicate characters twice
  • change: Strings are more efficient as they don't need parsing

This verb takes a left and right argument a string from '0000' to '9999'. It takes care of doubles and excludes exact matches from checking correct numbers but wrong place.

Test cases:

NB. Give the beast a name
mm=: =,&(+/)(~:#[)e.&~.~:#]
NB. make 6 by 4 arrays of the inputs
secret =: (, ;. _2) '1254 1234 5441 5441 5441 5441 '
guess  =: (, ;. _2) '1342 1111 1234 4531 4441 5441 '

NB. Apply the verb on each pair of secret/guess
'1111' mm '1231'
2 0

NB. A whole bunch of test cases with formatting and printing of the inputs:
secret ([,' ',(":@mm),' ',])"1 guess

NB. output:
1254 1 2 1342
1234 1 0 1111
5441 0 2 1234
5441 1 2 4531
5441 3 0 4441
5441 4 0 5441

A little bit of explanation, reading from right to left:

NB.   ExactMatch: checks where digits correspond:
ExactMatch =: =

NB.   GoodDigitWrongPlace: Copies non-matched numbers from both arguments (left and right
NB.   pairs of parentheses, and checks them for same elements(e.), after eliminating
NB.   doubles in both (&~.)
GoodDigitWrongPlace =: (~: # [) (e.&~.) (~: # ])

NB.   Piecing the conditions together, after summing the booleans:
mm =: ExactMatch ,&(+/) GoodDigitWrongPlace
\$\endgroup\$
  • \$\begingroup\$ I think the result of "5441" and "1234" should be 0,2 rather than 0,3. The duplicate 4's should only be counted once. Save for "5441","4531" \$\endgroup\$ – tmartin Sep 26 '13 at 10:00
  • \$\begingroup\$ Thanks, you are entirely right. Adds 3 characters ~.@ \$\endgroup\$ – jpjacobs Sep 27 '13 at 7:56
3
\$\begingroup\$

K, 41 36

{+/'(b;(in).(?x;y)@\:(!#x)@&~b:x=y)}

.

k)c1:("1254";"1234";"5441";"5441";"5441";"5441")
k)c2:("1342";"1111";"1234";"4531";"4441";"5441")
k){+/'(b;(in).(?x;y)@\:(!#x)@&~b:x=y)}'[c1;c2]
1 2
1 0
0 2
1 2
3 0
4 0
\$\endgroup\$
2
\$\begingroup\$

Ruby 2.0, 71 characters

f=->s,g{[x=(0..3).count{|n|s[n]==g[n]},g.chars.count{|e|s.sub!e,''}-x]}

This function actually modifies the first parameter, which is obviously a bit dodgy. Would be easy enough to fix if it's actually against the rules.

I'm sure there's something sneaky you could do with String#count but I couldn't think of a nice way to handle duplicates.

Example usage:

p f['1254', '1342'] #=> [1, 2]
p f['1234', '1111'] #=> [1, 0]
p f['5441', '1234'] #=> [0, 2]
p f['5441', '4531'] #=> [1, 2]
p f['5441', '4441'] #=> [3, 0]
p f['5441', '5441'] #=> [4, 0]
\$\endgroup\$
  • \$\begingroup\$ Modifying the parameters is fine (they're being passed by value, not by reference). \$\endgroup\$ – Joe Z. Sep 9 '13 at 5:28
  • \$\begingroup\$ @JoeZ. Why is this the accepted answer, when there are at least three other answers that are shorter? \$\endgroup\$ – user8777 Sep 9 '13 at 23:16
  • \$\begingroup\$ It was just one of the first to be posted. I'm sure he'll update it next time he checks :> \$\endgroup\$ – Paul Prestidge Sep 9 '13 at 23:52
  • \$\begingroup\$ @chron: Yup. ` ` \$\endgroup\$ – Joe Z. Sep 10 '13 at 0:31
1
\$\begingroup\$

GolfScript, 50 characters

{[[\].zip{1/~=},,\{$}/{1$?.)!!{)>0}*)},,\;1$-]}:M;

A similar solution to chron's answer written in GolfScript. Input must be provided as two strings on the stack, the result will be the array [A B].

Examples:

"1254" "1342" M p    # => [1 2]
"1234" "1111" M p    # => [1 0]
"5441" "1234" M p    # => [0 2]
"5441" "4531" M p    # => [1 2]
"5441" "4441" M p    # => [3 0]
"5441" "5441" M p    # => [4 0]
\$\endgroup\$
1
\$\begingroup\$

GolfScript (48 chars)

{[\]:&zip{1/~=},,.~)10,{{''+-,~5+}+&%.~>=+}/}:E;

E here stands for eval. I take a similar approach to Knuth's definition of the number of white pegs by calculating sum_{i=0}^{9} min(count(secret, i), count(guess, i)).

Online demo

\$\endgroup\$
0
\$\begingroup\$

Python - 93

I'm pretty sure this is right. But a few example input/outputs in the question would help.

def m(S,G):
 R = [(s,g) for s,g in zip(S,G) if s!=g];S,G=zip(*R);W=set(S)&set(G);return 4-len(R),len(W)

And calling it gives:

print m('1234','1231') 
>>> (3, 0)
print m('1234','1230') 
>>> (3, 0)
print m('1234','1243') 
>>> (2, 2)
print m('1234','4312') 
>>> (0, 4)
print m("0123","0131") 
>>> (2, 1)
print m("0123","0132") 
>>> (2, 2)
print m("0123","0123") 
>>> (4, 0)
print m("0123","4131") 
>>> (1, 1)
\$\endgroup\$
  • \$\begingroup\$ The use of set makes me suspect that it will give a wrong answer for m("0011", "1100") (should be (0,4)). \$\endgroup\$ – Peter Taylor Sep 9 '13 at 7:25
  • \$\begingroup\$ @PeterTaylor Probably, but the rules seemed really poorly defined. But I'll change my anaswer if its wrong. \$\endgroup\$ – user8777 Sep 9 '13 at 12:34
  • 1
    \$\begingroup\$ Knuth himself says that the rule for the number of white pegs "is somewhat difficult to state precisely and unambiguously, and the manufacturers have not succeeded in doing so on the directions they furnish with the game". \$\endgroup\$ – Peter Taylor Sep 9 '13 at 12:38
0
\$\begingroup\$

Here's a first draft in PowerShell: 168 characters.

function Test-Mastermind{param([char[]]$s,[char[]]$g)
4-($p=0..3|?{$s[$_]-ne$g[$_]}).Count
($p|%{$i=$_;$p|?{$s[$i]-eq$g[$_]-and0-ne$s[$i]}|%{($s[$i]=$g[$_]=0)}}).Count}

For the sake of illumination:

function Test-Mastermind {
    param([char[]]$s,[char[]]$g)
    4 - ($p = 0..3|?{ $s[$_] -ne $g[$_] }).count # count same  characters
    ( $p | % { $i = $_                           # ForEach $i in $p (char in secret)
        $p | ? {                                 # ForEach $_ in $p (char in guess) 
            $s[$i] -eq $g[$_] -and 0 -ne $s[$i]  # If they match and aren't 0
         } | % { ($s[$i]=$g[$_]=0) }             # 0 them out, output something we can count
    } ).Count
}
\$\endgroup\$
  • \$\begingroup\$ Zeroes are allowed, so "0" shouldn't be the padding character. \$\endgroup\$ – Joe Z. Sep 12 '13 at 17:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.