Files
project_euler/58/main.ua
T
2025-09-15 12:07:14 +02:00

89 lines
2.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# rotate 90 deg
r ← ⍉≡⇌
# create spiral numbers with n rows and cols
# spiral ? n
s ← (
+1⇡ⁿ2 # create n^2 numbers
⊸(
⊸(-1×2√/↥) # t*2 - 1, where t = sqrt(max(range(n^2))) = n
⌈÷2↙ # create [1 1 2 2 3 ...] until sum is n^2
)
⊜□˜▽+1°⊏ # successively take 1, 1, 2, 2, 3, ... until all n^2 numbers taken
⇌/◇(˜⊂r)⍜⊢⍚¤ # combine all taken with rotating array to form spiral
)
# memoized recursive version of s
σ ← |1 memo(
⨬(⊂⊸(++1⇡∩/↥⊃△(⊢⊢)) r σ-1
| ⋅(¤[1]) # base-case
)⊸=1
)
# generates each diagonal of spiral array
Σ ← +1\+ +¤[2 4 6]×8 ⇡⌊÷2
# get numbers on diagonal
d ← ⊜°¤ ↥⊸r⊞=. °⊏
# is_prime(n) ? n
p ← =1⧻°/×
┌─╴test
p ↚ ⊜(⊜⋕⊸≠@\s)⊸≠@\n
⍤⤙≍ s 7 p $ 37 36 35 34 33 32 31
$ 38 17 16 15 14 13 30
$ 39 18 5 4 3 12 29
$ 40 19 6 1 2 11 28
$ 41 20 7 8 9 10 27
$ 42 21 22 23 24 25 26
$ 43 44 45 46 47 48 49
└─╴
Sol! ← +1×2⧻⍢(+2⟜(÷⊃⧻/+≡p ^0)|⋅(>0.1)) ⊙1
# Sol!(d s) 3 # too slow
# (σ -1×2) == s
# Sol!(d σ -1×2) 3 # too slow (too much memory usage)
# Sol!(⊂˜↯1÷2-1⟜(♭ Σ)) 3 # still too slow
# okay... let's do it mathematically from scratch:
# primes on diagonals/number of elements on diagonals
# Chance ← ÷-1×2⟜(
# ⊃((+5+∩×₄⊃×₂ⁿ₂)⇡
# | (+3+⊃×₆(×4ⁿ2))⇡
# | (+7+⊃×₁₀(×4ⁿ2))⇡
# ) ⌊÷2
# /+≡p⊂⊂
# )
#
# ⍢(+2|>0.1 Chance) 3
# that solved it in 4 minutes (with p memoized)... too slow!
NewP ← (
# get the next three prime candidates (lower right is odd square)
⊃((+5+∩×₄⊃×₂ⁿ₂)
| (+3+⊃×₆(×4ⁿ2))
| (+7+⊃×₁₀(×4ⁿ2))
)
++∩₃p # count how many are prime (0-3)
)
# initial values are:
# - 5: the amount of numbers so far; 1, 3, 5, 7, 9 (counter for diagonal)
# - NewP.: = 3, since 3, 5, 7 are prime (counter for primes on diagonal)
# - 0: current NewP generation. NewP 0 is 3 (see above)
5 NewP. 0
⍢(+4 ⊙+ ⊙⊙(⊸NewP+1) # add 4 for new corners, generate NewP(n+1)
| >0.1 ÷ # check prime ratio
)
# discard number of primes and diagonal values,
# scale generation up to side length
# newp gen 0 -> 0*2 + 3 = side length 3
# newp gen 1 -> 1*2 + 3 = side length 5, ...
⋅⋅(+3×2)
# that's a 240x speedup, from 4 minutes to 1 second. we can go faster...