In [8]:
given = """
C	C	C	D	D	A	A
E	E	E	C	C	C	E
D	E	D	D	E	D	E
E	A	E	E	D	B	A
A	A	A	E	A	C	A
C	A	E	C	A	B	A
D	E	D	B	C	B	D
C	B	C	C	B	C	B
C	C	D	D	E	A	C
C	C	D	D	A	E	C
B	D	B	B	D	B	D
D	A	E	C	A	D	C
B	D	B	A	D	B	B
D	C	D	D	C	D	C
C	B	A	B	D	A	B
E	C	E	E	A	E	B
E	A	E	E	A	E	A
B	D	D	E	C	C	D
A	B	A	A	B	A	B
A	A	C	A	C	C	C
D	D	A	D	D	D	A
"""

answer_to_idx = {answer: i for i, answer in enumerate('ABCDE')}
idx_to_answer = {v: k for k, v in answer_to_idx.items()}

expected_scores = [
  5, 6, 5, 9, 8, 5, 10,
]

In [3]:
people = [[], [], [], [], [], [], []]
for line in given.strip('\n').split('\n'):
  guesses = line.split('\t')
  for person, guess in zip(people, guesses):
    person.append(guess)

In [57]:
import Numberjack

grid = Numberjack.Matrix(22, 5, 0, 1, 'answers')
model = Numberjack.Model()

# One correct solution per row.
for question in range(0, 21):
  model.add(
    sum([grid[question][i] for i in range(0, 5)]) == 1
  )

for person_idx, expected_score in enumerate(expected_scores):
  person_guessed_correct = []
  for question in range(0, 21):
    person_guessed_correct.append(
      grid[question][answer_to_idx[people[person_idx][question]]])
  model.add(
    sum(person_guessed_correct) == expected_score
  )

solver = model.load('Mistral')
print('Solution is...')
solver.solve()
for row in range(0, 21):
  print(grid[row])

print('Nodes:', solver.getNodes(), ' Time:', solver.getTime())


Solution is...
[0, 0, 0, 0, 1]
[0, 0, 1, 0, 0]
[0, 0, 0, 0, 1]
[0, 0, 0, 0, 1]
[0, 0, 0, 0, 1]
[0, 0, 1, 0, 0]
[1, 0, 0, 0, 0]
[0, 1, 0, 0, 0]
[0, 0, 0, 0, 1]
[0, 0, 1, 0, 0]
[0, 0, 0, 1, 0]
[0, 0, 1, 0, 0]
[1, 0, 0, 0, 0]
[0, 0, 0, 1, 0]
[0, 1, 0, 0, 0]
[0, 1, 0, 0, 0]
[0, 0, 0, 0, 1]
[0, 0, 1, 0, 0]
[0, 1, 0, 0, 0]
[0, 0, 1, 0, 0]
[1, 0, 0, 0, 0]
Nodes: 130787598  Time: 157.68

In [4]:
finished = [
  [0, 0, 0, 0, 1],
  [0, 0, 1, 0, 0],
  [0, 0, 0, 0, 1],
  [0, 0, 0, 0, 1],
  [0, 0, 0, 0, 1],
  [0, 0, 1, 0, 0],
  [1, 0, 0, 0, 0],
  [0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1],
  [0, 0, 1, 0, 0],
  [0, 0, 0, 1, 0],
  [0, 0, 1, 0, 0],
  [1, 0, 0, 0, 0],
  [0, 0, 0, 1, 0],
  [0, 1, 0, 0, 0],
  [0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1],
  [0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0],
  [0, 0, 1, 0, 0],
  [1, 0, 0, 0, 0],
]

In [5]:
n_to_letter = []

for row in finished:
  print(int(''.join(map(str, row)), 2))


1
4
1
1
1
4
16
8
1
4
2
4
16
2
8
8
1
4
8
4
16

In [37]:
import Numberjack


questions = Numberjack.VarArray(21, 5, 'answers')
model = Numberjack.Model()

for person_idx, expected_score in enumerate(expected_scores):
  person_guessed_correct = []
  for question in range(0, 21):
    person_guessed_correct.append(
      questions[question] == answer_to_idx[people[person_idx][question]])
  model.add(
    sum(person_guessed_correct) == expected_score
  )

correct = """
A
E
D
B
A
C
D
B
E
D
D
E
A
D
A
E
A
C
B
C
A
"""
# Attempt to constrain != correct solution.
correct = """
A
E
D
B
A
C
D
B
E
D
D
E
A
D
A
E
A
C
B
"""
for question, answer in enumerate(correct.strip('\n').split('\n')):
  print('#%s != %s' % (question, answer))
  model.add(
    questions[question] != answer_to_idx[answer]
  )

solver = model.load('Mistral')
print('Solution is...')
solver.solve()

possibilities = [set() for _ in range(21)]

for row in range(0, 21):
  print(idx_to_answer[questions[row].get_value()])

print('Nodes:', solver.getNodes(), ' Time:', solver.getTime())

n_solutions = 1
while solver.getNextSolution() and n_solutions < 1000:
  n_solutions += 1
  for row in range(0, 21):
    # print(idx_to_answer[questions[row].get_value()])
    possibilities[row].add(idx_to_answer[questions[row].get_value()])
  print('Nodes:', solver.getNodes(), ' Time:', solver.getTime())

print(n_solutions)
print(possibilities)


#0 != A
#1 != E
#2 != D
#3 != B
#4 != A
#5 != C
#6 != D
#7 != B
#8 != E
#9 != D
#10 != D
#11 != E
#12 != A
#13 != D
#14 != A
#15 != E
#16 != A
#17 != C
#18 != B
Solution is...
D
C
E
D
E
A
C
A
C
C
B
C
C
C
B
B
E
E
A
C
A
Nodes: 181  Time: 0.010000000000001563
Nodes: 182  Time: 0.010000000000001563
Nodes: 182  Time: 0.010000000000001563
Nodes: 183  Time: 0.010000000000001563
Nodes: 184  Time: 0.010000000000001563
Nodes: 184  Time: 0.010000000000001563
Nodes: 1171  Time: 0.010000000000001563
Nodes: 1172  Time: 0.010000000000001563
Nodes: 1172  Time: 0.010000000000001563
Nodes: 1209  Time: 0.019999999999999574
Nodes: 1210  Time: 0.019999999999999574
Nodes: 1210  Time: 0.019999999999999574
Nodes: 1418  Time: 0.019999999999999574
Nodes: 1419  Time: 0.019999999999999574
Nodes: 1419  Time: 0.019999999999999574
Nodes: 1420  Time: 0.019999999999999574
Nodes: 1421  Time: 0.019999999999999574
Nodes: 1421  Time: 0.019999999999999574
Nodes: 1423  Time: 0.019999999999999574
Nodes: 1424  Time: 0.030000000000001137
Nodes: 1424  Time: 0.030000000000001137
Nodes: 1425  Time: 0.030000000000001137
Nodes: 1426  Time: 0.030000000000001137
Nodes: 1426  Time: 0.030000000000001137
24
[{'D'}, {'C'}, {'E'}, {'D'}, {'E'}, {'A'}, {'C'}, {'D', 'E', 'C', 'A'}, {'C'}, {'C'}, {'B', 'A', 'E', 'C'}, {'C'}, {'E', 'C'}, {'C'}, {'B'}, {'B'}, {'D', 'B', 'E', 'C'}, {'E'}, {'D', 'A', 'E', 'C'}, {'C'}, {'A'}]

In [20]:
possibilities


Out[20]:
[{'D'},
 {'A', 'B', 'C', 'D'},
 {'A', 'B', 'C', 'D', 'E'},
 {'A', 'C', 'D'},
 {'B', 'D', 'E'},
 {'A', 'D', 'E'},
 {'A', 'B', 'C'},
 {'A', 'B', 'D', 'E'},
 {'B', 'C', 'D', 'E'},
 {'A', 'B', 'C', 'D'},
 {'A', 'B', 'C', 'D', 'E'},
 {'C'},
 {'A', 'B', 'C', 'E'},
 {'A', 'B', 'C', 'D', 'E'},
 {'B', 'C', 'D', 'E'},
 {'B'},
 {'A', 'B', 'C', 'D', 'E'},
 {'A', 'B', 'E'},
 {'A', 'B', 'C', 'D', 'E'},
 {'B', 'C', 'D', 'E'},
 {'A'}]

In [ ]: