Backstory and Goal
Amelia is writing an article for a golf magazine about some of the most memorable winning rounds ever played by a handful of women golfers. Match each golfer to her score as well as the year and location of her victory.
Remember, as with all grid-based logic puzzles, no option in any category will ever be used more than once. If you get stuck or run into problems, try the "Clear Errors" button to remove any mistakes that might be present on the grid, or
the "Hint" button to see the next logical step in the puzzle.
Players = {Ethel Erwin, Freda Fritz, Inez, Leslie Lane, Tina Tuttle, Vickie Vern}
Scores = (59, 60, 61, 62, 64, 66}
Courses = {Amble Glen, Cowbush Cove, Juniper Hills, Pennyfoot, Scotch Pines, Willow Grove}
Years = {1920, 1921, 1922, 1923, 1924, 1925)
Clues:
1. Of the person who scored a 66 and the golfer who won at Scotch Pines, one won in 1924 and the other was Freda Fritz.
2. The woman who won at Pennyfoot won her tournament sometime after Freda Fritz.
3. The woman who won at Cowbush Cove won her tournament 2 years after the woman who scored a 62.
4. Vickie Vern shot a 66.
5. Tina Tuttle didn't win in 1925.
6. The six golfers were Freda Fritz, the woman who scored a 64, the person who won at Juniper Hills, the golfer who won at Willow Grove, the person who scored a 62 and the golfer who scored a 61.
7. The woman who won in 1923 shot a 59.
8. Ethel Erwin was either the person who scored a 61 or the person who scored a 60.
9. The person who won at Cowbush Cove didn't shoot a 64.
10. Leslie Lane didn't win at Juniper Hills.
11. The golfer who won at Scotch Pines won her tournament 2 years after Leslie Lane.
Python Code:
rel_classes = 6
types = 4
objects = rel_classes*types; print('objects = ' + str(objects))
print('types = ' + str(types))
print('rel_classes = ' + str(rel_classes))
print(str(objects^2) + ' Free Boolean Algebra generators: X0 = R[0,0], X1 = R[0,1], X2 = R[0,2],..., X' + str(objects^2-1) + ' = R[' + str(objects-1) + ',' + str(objects-1) + ']')
BPR = BooleanPolynomialRing(objects^2,'X',order='degneglex')
#X = BPR.gens()
KDELTA = lambda N, M: BPR(N == M)
NOT = lambda A: BPR(1) + A
XOR = lambda A, B: A + B
OR = lambda A, B: A + B + A*B
IF = lambda A, B: BPR(1) + A + A*B
IFF = lambda A, B: BPR(1) + A + B
AND = lambda A, B: A*B
NAND = lambda A, B: BPR(1) + A*B
NOR = lambda A, B: BPR(1) + A + B + A*B
ALT = lambda mylist: reduce(XOR,[reduce(AND,[[mylist[i]+NOT(KDELTA(i,j)) for i in range(len(mylist))] for j in range(len(mylist))][k]) for k in range(len(mylist))])
#REL = lambda i, j: X[i*objects + j]
R = matrix(BPR, objects, objects, BPR.gens())
relation = []
for i in range(0, objects): #reflexive
poly = R[i,i]
relation.append(poly + 1)
for i in range(0,objects): #symmentric
for j in range(i, objects):
#poly = IF(R[i,j],R[j,i])
poly = IFF(R[i,j],R[j,i])
if poly != 1:
relation.append(poly + 1) # don't append if poly+1=0 not really needed here but...
for j in range(0, objects): #transitive given symmetric and reflexive
for i in range(0, objects - 1):
for k in range(i + 1, objects):
poly = IF(AND(R[i,j],R[j,k]),R[i,k])
if poly != 1:
relation.append(poly + 1) # don't append if poly+1=0 IF(0,a)=1 always IF(a,1)=1 always IF(a,a)=1 always
for i in range(0, types): # distinct objects of the same type are not related
iobj = i*rel_classes
for j in range(0, rel_classes):
iobjj = iobj + j
for k in range(0, rel_classes):
if j!=k:
iobjk = iobj + k
poly = NOT(R[iobjj,iobjk])
if poly != 1:
relation.append(poly + 1) # not really needed here just append
#for i in range(types): # each object is related to exactly one oject of each other type
# for j in range(rel_classes):
# for k in range(types):
# if k != i:
# poly = ALT([R[i*rel_classes + j, k*rel_classes + l] for l in range(rel_classes)])
# if poly != 1:
# relation.append(poly + 1)
#for i in range(types-1): # another way to do the same but placing either here exceeds size limitations for quotient ring and groebner basis algorithms
# for j in range(rel_classes):
# for k in range(i+1,types):
# poly = ALT([R[i*rel_classes + j, k*rel_classes + l] for l in range(rel_classes)])
# if poly != 1:
# relation.append(poly + 1)
# poly = ALT([R[i*rel_classes + l, k*rel_classes + j] for l in range(rel_classes)])
# if poly != 1:
# relation.append(poly + 1)
relation.append(ALT([AND(R[11,22],R[16,1]), AND(R[11,1],R[16,22])]) + 1) # clue 1
relation.append(ALT([AND(R[1,18],R[15,19]), AND(R[1,18],R[15,20]), AND(R[1,18],R[15,21]), AND(R[1,18],R[15,22]), AND(R[1,18],R[15,23]), # clue 2
AND(R[1,19],R[15,20]), AND(R[1,19],R[15,21]), AND(R[1,19],R[15,22]), AND(R[1,19],R[15,23]),
AND(R[1,20],R[15,21]), AND(R[1,20],R[15,22]), AND(R[1,20],R[15,23]),
AND(R[1,21],R[15,22]), AND(R[1,21],R[15,23]),
AND(R[1,22],R[15,23])]) + 1)
relation.append(ALT([AND(R[13,23],R[9,21]), AND(R[13,22],R[9,20]), AND(R[13,21],R[9,19]), AND(R[13,20],R[9,18])]) + 1) # clue 3
relation.append(R[5,11] + 1) # clue 4
relation.append(NOT(R[4,23]) + 1) # clue 5
relation.append(NOT(R[1,10]) + 1) # clue 6.1
relation.append(NOT(R[1,14]) + 1) # clue 6.2
relation.append(NOT(R[1,17]) + 1) # clue 6.3
relation.append(NOT(R[1,9]) + 1) # clue 6.4
relation.append(NOT(R[1,8]) + 1) # clue 6.5
relation.append(NOT(R[10,14]) + 1) # clue 6.6
relation.append(NOT(R[10,17]) + 1) # clue 6.7
relation.append(NOT(R[14,9]) + 1) # clue 6.8
relation.append(NOT(R[14,8]) + 1) # clue 6.9
relation.append(NOT(R[17,9]) + 1) # clue 6.10
relation.append(NOT(R[17,8]) + 1) # clue 6.11
relation.append(R[21,6] + 1) # clue 7
relation.append(ALT([R[0,8], R[0,7]]) + 1) # clue 8
relation.append(NOT(R[13,10]) + 1) # clue 9
relation.append(NOT(R[3,14]) + 1) # clue 10
relation.append(ALT([AND(R[16,23],R[3,21]), AND(R[16,22],R[3,20]), AND(R[16,21],R[3,19]), AND(R[16,20],R[3,18])]) + 1) # clue 11
REI = ideal(relation); print('REI.gens() = ' + str(len(REI.gens())))
GB = REI.groebner_basis()
QR = BPR.quotient_ring(REI)
QRG = QR.gens()
quo = len(QRG) // objects
rem = len(QRG) % objects
if len(QRG) == objects^2:
A = matrix(BPR, objects, objects, 0)
for i in range(quo):
A[i,0:objects] = matrix(QRG[i*objects: (i + 1)*objects])
print('A 1st pass')
relation2 = []
for i in range(types-1): # more hidden assumptions -- each object is related to exactly one oject in each other type
for j in range(i+1,types):
A2=A[i*rel_classes:(i+1)*rel_classes,j*rel_classes:(j+1)*rel_classes]
print('type ' + str(i) + ' to type ' + str(j));print(A2);print(' ')
for k in range(rel_classes):
poly = BPR(ALT([A2[k,l] for l in range(rel_classes)]))
if poly != 1:
relation2.append(poly + 1)
poly = BPR(ALT([A2[l,k] for l in range(rel_classes)]))
if poly != 1:
relation2.append(poly + 1)
stuff=[relation2[l].variables() for l in range(len(relation2))]
stuff2 = set(stuff[0])
for i in range(1,len(stuff)):
stuff2 = stuff2.union(set(stuff[i]))
print('number of variables left to be determined: ' + str(len(stuff2)))
relation = relation + relation2
REI = ideal(relation); print('REI.gens() = ' + str(len(REI.gens())))
GB = REI.groebner_basis()
QR = BPR.quotient_ring(REI)
QRG = QR.gens()
quo = len(QRG) // objects
rem = len(QRG) % objects
if len(QRG) == objects^2:
A3 = matrix(BPR, objects, objects, 0)
for i in range(quo):
A3[i,0:objects] = matrix(QRG[i*objects: (i + 1)*objects])
print('A 2nd pass')
for i in range(types-1):
for j in range(i+1,types):
A2=A3[i*rel_classes:(i+1)*rel_classes,j*rel_classes:(j+1)*rel_classes]
print('type ' + str(i) + ' to type ' + str(j));print(A2);print(' ')
Sage Output:
load('Puzzle7.sage')
objects = 24 types = 4 rel_classes = 6 576 Free Boolean Algebra generators: X0 = R[0,0], X1 = R[0,1], X2 = R[0,2],..., X575 = R[23,23] REI.gens() = 6513 A 1st pass type 0 to type 1 [ 0 X7 X7 + 1 0 0 0] [ X30 X31 0 0 0 0] [ X54 X55 X56 X57 X58 0] [ 0 X79 X80 0 X82 0] [ X102 X103 X104 X105 X106 0] [ 0 0 0 0 0 1] type 0 to type 2 [ X12 X13 X14 X15 0 X17] [ 0 0 0 0 1 0] [ X60 X61 X62 X63 0 X65] [ X84 0 0 0 0 X89] [X108 X109 X110 0 0 X113] [X132 X133 X134 X135 0 X137] type 0 to type 3 [ X18 0 X13 0 0 X23] [ 0 0 X30 + 1 X30 0 0] [ X66 X67 X68 X54 0 X71] [X30 + 1 X30 0 0 0 0] [ X114 X115 X116 X102 0 0] [ 0 0 0 0 1 0] type 1 to type 2 [ 0 X30 + 1 0 0 X30 0] [ X180 X181 X182 X183 X31 X185] [ X204 X205 0 X207 0 0] [ X228 0 0 0 0 0] [ X252 0 0 X255 0 0] [ X132 X133 X134 X135 0 X137] type 1 to type 3 [ 0 0 0 1 0 0] [ X186 X187 X181 + X31 0 0 X191] [ X210 X211 X205 0 0 X215] [X133 + X30 X30 + 1 X133 0 0 0] [ X258 X259 0 0 0 X263] [ 0 0 0 0 1 0] type 2 to type 3 [ X306 X307 X308 0 X132 X311] [ 0 0 X133 + X30 X30 + 1 X133 0] [ X354 0 0 0 X134 X359] [ 0 0 0 0 X135 X135 + 1] [ 0 0 X30 + 1 X30 0 0] [ X426 X427 0 0 X137 X431] number of variables left to be determined: 75 REI.gens() = 6568 A 2nd pass type 0 to type 1 [0 0 1 0 0 0] [1 0 0 0 0 0] [0 0 0 0 1 0] [0 1 0 0 0 0] [0 0 0 1 0 0] [0 0 0 0 0 1] type 0 to type 2 [0 1 0 0 0 0] [0 0 0 0 1 0] [0 0 0 1 0 0] [0 0 0 0 0 1] [1 0 0 0 0 0] [0 0 1 0 0 0] type 0 to type 3 [0 0 1 0 0 0] [0 0 0 1 0 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 0 0 0 0] [0 0 0 0 1 0] type 1 to type 2 [0 0 0 0 1 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 0 0 0 0] [0 0 0 1 0 0] [0 0 1 0 0 0] type 1 to type 3 [0 0 0 1 0 0] [0 1 0 0 0 0] [0 0 1 0 0 0] [1 0 0 0 0 0] [0 0 0 0 0 1] [0 0 0 0 1 0] type 2 to type 3 [1 0 0 0 0 0] [0 0 1 0 0 0] [0 0 0 0 1 0] [0 0 0 0 0 1] [0 0 0 1 0 0] [0 1 0 0 0 0]