PasteRack.org
Paste # 48140
2025-05-01 22:13:10

Fork as a new paste.

Paste viewed 313 times.


Embed:

numeric core

  1. #lang racket
  2. ; numeric core
  3. ; given a number with 4 or more digits, split digits into 4 numbers without changing the order
  4. ; apply operators - * / in the order that produces the smallest whole (natural?) result
  5. ; if result has more than 3 digits, repeat from the top
  6. ; final number with less than four digits is the numeric core of the larger number
  7. ;
  8. ; e.g. 86455
  9. ; becomes 8 6 45 5
  10. ; becomes 8, -6, *45, /5
  11. ; core = 18
  12. ;
  13. ; e.g. 45292
  14. ; becomes 45 2 9 2
  15. ; becomes 45, *2, /9, -2
  16. ; core = 8
  17. (define (numeric-core n)
  18.   (let* ([digits (number->digits n)]
  19.          [core (case (length digits)
  20.                  [(1 2 3) n]
  21.                  #;[(4) (apply split-core digits)]
  22.                  #;[(5) (apply five-digit-core digits)]
  23.                  [else (n-digit-core digits)])])
  24.     ; if core has more than 3 digits, recalculate with resulting core as new start
  25.     (if (< core 1000) core
  26.         (numeric-core core))))
  27. #;(numeric-core 86455) ; => 18
  28. #;(numeric-core 45292) ; => 8
  29.  
  30. ; minimum value in finite sequence of numbers or '() for empty sequence
  31. (define (sequence-minimum seq)
  32.   (sequence-fold (λ (a b) (if (null? a) b (min a b))) null seq))
  33.  
  34. ; given a character in range #\0 to #\9, convert to number represented by character
  35. (define (char-digit->integer c)
  36.   (- (char->integer c) (char->integer #\0)))
  37. #;(char-digit->integer #\3) ; => 3
  38. #;(char-digit->integer #\6) ; => 6
  39.  
  40. ; split a natural number into its digits
  41. (define (number->digits n)
  42.   (let ([chars (string->list (number->string n))])
  43.     (map char-digit->integer chars)))
  44. #;(number->digits 4) ; => '(4)
  45. #;(number->digits 12) ; => '(1 2)
  46. #;(number->digits 123) ; => '(1 2 3)
  47.  
  48. ; combine a list of single digit numbers into one number containing digits in given order
  49. (define (digits->number digits)
  50.   (foldl (λ (n acc) (+ (* acc 10) n)) 0 digits))
  51. #;(digits->number '(1 2 3)) ; => 123
  52.  
  53. ; merge two natural numbers into one resulting number by appending their digits
  54. (define (merge-digits a b)
  55.   (digits->number (append (number->digits a)
  56.                           (number->digits b))))
  57. #;(merge 1 2) ; => 12
  58. #;(merge 12 3) ; => 123
  59. #;(merge 1 23) ; => 123
  60.  
  61. ; remove repeats from given list
  62. (define (uniqify lst)
  63.   (let loop ([seen (set)]
  64.              [lst lst]
  65.              [acc '()])
  66.     (if (empty? lst) (reverse acc)
  67.         (let ([a (first lst)])
  68.           (loop (set-add seen a)
  69.                 (rest lst)
  70.                 (if (set-member? seen a) acc
  71.                     (cons a acc)))))))
  72.  
  73. ; smallest natural result from applying math to 4 given numbers
  74. ; #false if no natural core exists for given numbers
  75. (define (split-core a b c d)
  76.   (define ops (list - * /)) ; plus is implied
  77.   (define (compute ops)
  78.     (match ops
  79.       [(list o1 o2 o3)
  80.        (o3 (o2 (o1 a b) c) d)]))
  81.   (let* ([computed-results (sequence-map compute (in-permutations ops))]
  82.          [potential-cores (sequence-filter natural? computed-results)]
  83.          [core (sequence-minimum potential-cores)])
  84.     (if (number? core) core #false)))
  85. #;(split-core 8 6 45 5) ; => 18
  86. #;(split-core 45 2 9 2) ; => 8
  87.  
  88. ; initial idea exploring how to find 4 number candidates in a 5 digit input
  89. ; replaced with n-digit-core below
  90. #;(define (five-digit-core a b c d e)
  91.     (let* ([candidates (list (list (merge-digits a b) c d e)
  92.                              (list a (merge-digits b c) d e)
  93.                              (list a b (merge-digits c d) e)
  94.                              (list a b c (merge-digits d e)))]
  95.            [potential-cores (filter-map (curry apply split-core) candidates)])
  96.       (if (empty? potential-cores)
  97.           #false
  98.           (apply min potential-cores))))
  99. #;(five-digit-core 8 6 4 5 5) ; => 18
  100.  
  101. ; merge numbers until there are 4 numbers (filters output to only return unique results
  102. ; resulting candidate list's length will correspond to https://oeis.org/A000292 Tetrahedral numbers
  103. ; if input is 4 or fewer digits, output will have 1 candidate
  104. ; if input is 5 digits, output will have 4 candidates
  105. ; if input is 6 digits, output will have 10 candidates
  106. (define (potential-merges digits)
  107.   (case (length digits)
  108.     [(1 2 3 4) (list digits)]
  109.     [else
  110.      (uniqify
  111.       (append-map potential-merges
  112.                   (let loop ([head '()]
  113.                              [tail digits]
  114.                              [acc '()])
  115.                     (match tail
  116.                       [(list-rest a b rest)
  117.                        (loop (append head (list a))
  118.                              (cons b rest)
  119.                              (cons (append head
  120.                                            (list (merge-digits a b))
  121.                                            rest)
  122.                                    acc))]
  123.                       [_ (reverse acc)]))))]))
  124. #;(potential-merges '(1 2)) ; => '((1 2))
  125. #;(potential-merges '(1 2 3 4)) ; => '((1 2 3 4))
  126. #;(potential-merges '(1 2 3 4 5)) ; => '((12 3 4 5) (1 23 4 5) (1 2 34 5) (1 2 3 45))
  127. #;(potential-merges '(1 2 3 4 5 6))
  128. ; => '((123 4 5 6) (12 34 5 6) (12 3 45 6) (12 3 4 56) (1 234 5 6)
  129. ;      (1 23 45 6) (1 23 4 56) (1 2 345 6) (1 2 34 56) (1 2 3 456))
  130.  
  131. ;
  132. (define (n-digit-core digits)
  133.   (let* ([candidates (potential-merges digits)]
  134.          [potential-cores (filter-map (curry apply split-core) candidates)])
  135.     (if (empty? potential-cores)
  136.         #false
  137.         (apply min potential-cores))))
  138. #;(n-digit-core '(8 6 4 5 5)) ; => 18
  139.  
  140. (define (display-core n)
  141.   (displayln (~a "Numeric core of " n " is " (numeric-core n))))
  142. (display-core 86455)
  143. (display-core 45292)

=>

Numeric core of 86455 is 18

Numeric core of 45292 is 8