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 ...