Teaser 3258: On grid
From The Sunday Times, 2nd March 2025 [link] [link]
Using all the digits 1 to 9 in a 3 by 3 grid, I have devised a game. In this grid, if each of the three rows, three columns and two diagonals are read both forwards and backwards, there are 16 three-digit numbers.
Points are awarded to each of these three-digit numbers; with 1 point awarded if it’s a prime number, 3 points if it’s a perfect square, 6 points if a perfect cube; with the points being cumulative if more than one applies.
What is the highest number of points that can be awarded?
[teaser3258]
Jim Randell 1:27 am on 2 March 2025 Permalink |
Here’s a brute force solution.
It runs in 177ms (using PyPy).
from enigma import ( defaultdict, Accumulator, primes, powers, nsplit, irange, subsets, rev, printf ) # points for 3-digit primes, squares, cubes cats = [ (primes.between(100, 999), 1), # prime -> +1 (powers(10, 31, 2), 3), # square -> +3 (powers(5, 9, 3), 6), # cube -> +6 ] # collect points for 3-digit sequences, in both directions pts = defaultdict(int) for (ns, p) in cats: for n in ns: ds = nsplit(n) if len(set(ds)) < len(ds): continue pts[ds] += p pts[rev(ds)] += p # find maximal grids r = Accumulator(fn=max, collect=1) for ss in subsets(irange(1, 9), size=len, select='P'): (A, B, C, D, E, F, G, H, I) = ss # eliminate repeated solutions if not (A < C and A < G and A < I and B < D): continue # score this grid p = sum(pts.get(k, 0) for k in [ (A, B, C), (D, E, F), (G, H, I), # rows (A, D, G), (B, E, H), (C, F, I), # columns (A, E, I), (C, E, G), # diagonals ]) r.accumulate_data(p, ss) # output solution(s) printf("max points = {r.value} [from {r.count} grids]") for (A, B, C, D, E, F, G, H, I) in r.data: printf("-> [ {A} {B} {C} | {D} {E} {F} | {G} {H} {I} ]")Solution: The maximum possible points total is: 27.
Here is a grid that scores 27:
The scoring numbers are:
As the numbers are read in both directions this grid can be rotated and reflected to give 7 additional grids using the same numbers.
These can be seen by removing the check at line 25 from the program.
LikeLike
Frits 1:22 pm on 2 March 2025 Permalink |
from enigma import SubstitutedExpression from itertools import permutations # determine valid primes 123 - 987 P = {3, 5, 7} P |= {n for n in range(11, 100, 2) if all(n % p for p in P)} P = {n for n in range(123, 988, 2) if all(n % p for p in P) and len(set(str(n))) == 3} sqs = {sq for n in range(10, 32) if len(set(str(sq := n * n))) == 3} cbs = {cb for n in range(5, 10) if len(set(str(cb := n * n * n))) == 3} # make dictionary of points per number d = {(n := int(''.join(p))): 1 if n in P else 3 if n in sqs else 6 if n in cbs else 0 for p in permutations("123456789", 3)} # check numbers both square and cube for c in cbs: if c in sqs: d[c] = 9 # return points for number <n> pts = lambda n: d[n] rows = "ABC DEF GHI".split() cols = list(''.join(x) for x in zip(*rows)) diags = ["AEI", "CEG"] vars = rows + cols + diags vars += [v[::-1] for v in vars] ans = ' + '.join(f"pts({v})" for v in vars) exprs = [] # avoid rotations, reflections etc exprs.append("A < C") exprs.append("A < G") exprs.append("A < I") exprs.append("B < D") # calculate one of the variables exprs.append("45 - (A + B + C + D + E + F + G + I) = H") # the alphametic puzzle p = SubstitutedExpression( exprs, answer="@ans, (ABC, DEF, GHI)", macro=dict([("ans", ans)]), d2i=dict([(1, "CDGI")] + [(k, "A") for k in range(7, 9)] + [(9, "AB")]), env=dict(pts=pts), digits=range(1, 10), verbose=0, # use 256 to see the generated code ) mx, sols = 0, [] # collect answers for t, m in sorted(p.answers(), reverse=True): if mx and t != mx: break sols.append(m) mx = t print("answer:", mx) print() print("Example(s):") # print examples for s in sols: print() print('\n'.join(str(x) for x in s))LikeLike
Ruud 7:41 pm on 2 March 2025 Permalink |
Even more brute force:
import istr def is_square(n): square_root = int(n) ** (1.0 / 2.0) return round(square_root) ** 2 == n def is_cube(n): cube_root = int(n) ** (1.0 / 3.0) return round(cube_root) ** 3 == n max_score = 0 for a, b, c, d, e, f, g, h, i in istr.permutations(istr.digits("1-9")): total = 0 for n in (a | b | c, d | e | f, g | h | i, a | d | g, b | e | h, c | f | i, a | e | i, c | e | g): for m in n, n[::-1]: total += m.is_prime() + 3 * is_square(m) + 6 * is_cube(m) max_score = max(max_score, total) print(max_score)LikeLiked by 1 person
Frits 6:11 am on 4 March 2025 Permalink |
Using Jim’s trick of also storing the points of the reversed entry.
from itertools import permutations # determine valid primes 123 - 987 P = {3, 5, 7} P |= {n for n in range(11, 100, 2) if all(n % p for p in P)} P = {str(n) for n in range(123, 988, 2) if all(n % p for p in P)} sqs = {str(n * n) for n in range(10, 32)} cbs = {str(n * n * n) for n in range(5, 10)} # make dictionary of points per three-digits tuple d = {tuple(int(x) for x in p): 1 if (s := ''.join(p)) in P else 3 if s in sqs else 6 if s in cbs else 0 for p in permutations("123456789", 3)} # check numbers both square and cube for c in cbs: if c in sqs: d[tuple(int(x) for x in c)] = 9 # let every entry also contain the points of the reversed entry d = {k: v + d[k[::-1]] for k, v in d.items()} # return points for sequence of three digits <s> pts = lambda s: d[s] alldgts = set(range(1, 10)) sols, mx = [], 0 # A B C # D E F # G H I for A in range(1, 7): # eliminate repeated solutions for C, G, I in permutations(range(A + 1, 10), 3): r5 = alldgts - {A, C, G, I} for B in r5 - {9}: # B < D r4 = r5 - {B} p4 = pts((A, B, C)) for D in [x for x in r4 if x > B]: p3 = p4 + pts((A, D, G)) for E, F, H in permutations(r4 - {D}): p0 = (p3 + pts((D, E, F)) + pts((G, H, I)) + pts((B, E, H)) + pts((C, F, I)) + pts((A, E, I)) + pts((C, E, G))) if p0 >= mx: if p0 > mx: sols = [] mx = p0 sols.append([(A, B, C), (D, E, F), (G, H, I)]) print("answer:", mx) print() print("Example(s):") # print examples for s in sols: print() print('\n'.join(str(x) for x in s))LikeLike