How to solve this problem in Mathematica?

Let's say we have some 4-character strings:

fxhg
eagc
aceh
chbe
beca


From those strings we want to get the correct passcode. Each of the string contains two correct passcode characters but not in the correct position. How can we get the correct 4-character passcode?

• I ask myself, provided this problem has the solution, is it really right to help anyone to get it? The question looks quite close to be criminal. I vote to close it. – Alexei Boulbitch Dec 20 '16 at 8:59
• Oh no @AlexeiBoulbitch, it has nothing to do with criminal! It's simply a math problem. I can do it manually to find the correct answer. I just want to know how to do it in Mathematica. Purely out of curiosity! – Just a learner Dec 20 '16 at 9:02
• I'm so sorry giving you the feeling. I swear to God, it's just a math problem. I found this problem on a picture posted by someone on the web. – Just a learner Dec 20 '16 at 9:04
• I have no suspects personally against you. The problem, however, seems me to have such a potential in itself, and may be used by others. – Alexei Boulbitch Dec 20 '16 at 9:06
• Is there any serious application that is still using four-letter passcodes? – J. M. will be back soon Dec 20 '16 at 12:02

1 Answer

Start with the given words as strings. Separate the letters into character sets with Characters[]. Find the universal set of all characters with Union[]. Find the 4-character subsets of the universal set with Subsets[]. These trials are the passwords character sets to try.

s = {"fxhg", "eagc", "aceh", "chbe", "beca"}
chsets = Characters /@ s;
univ = Union@Flatten[chsets];
trials = Subsets[univ, {4}];


Define a function test[] that will test each of trials to make sure it has exactly 2 characters in each of the 5 strings. Use the test[] function to select sets from trials that meet the 2 character requirement. Find all permutations of each of the sets. These are possible passwords.

test[word_] := And @@ (
(Length[Intersection[word, chsets[[#]]]] == 2) & /@ Range[5])
poss = Flatten[Permutations[#] & /@ Select[trials, test[#] &], 1]


Define a function compare[] that compares each possible password to the given strings. We know 2 characters will be the same. This comparison is to see if any of the same characters occur in the same position in any of the 5 given strings. We select from the possible words only those for which the comparison is false. That is, only for possible passwords that have no letters in the same position as in the given strings.

compare[word_] := Or @@ ((Or @@ MapThread[Equal,
{word, chsets[[#]]}]) & /@ Range[5])
Select[poss, Not[compare[#]] &]


And the answer is ...