solution.scm 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. ;; https://projecteuler.net/problem=33
  2. ;; Digit cancelling fractions
  3. ;; Problem 33
  4. ;; The fraction 49/98 is a curious fraction, as an
  5. ;; inexperienced mathematician in attempting to simplify it
  6. ;; may incorrectly believe that 49/98 = 4/8, which is
  7. ;; correct, is obtained by cancelling the 9s.
  8. ;; We shall consider fractions like, 30/50 = 3/5, to be
  9. ;; trivial examples.
  10. ;; There are exactly four non-trivial examples of this type
  11. ;; of fraction, less than one in value, and containing two
  12. ;; digits in the numerator and denominator.
  13. ;; If the product of these four fractions is given in its
  14. ;; lowest common terms, find the value of the denominator.
  15. (import
  16. (except (rnrs base) let-values map)
  17. (only (guile)
  18. lambda* λ)
  19. (ice-9 match)
  20. ;; (srfi srfi-69) ; hash tables
  21. (srfi srfi-1) ; reduce
  22. (contract)
  23. (lib math)
  24. (lib print-utils))
  25. (define-with-contract make-fraction
  26. (require (integer? numer)
  27. (integer? denom)
  28. (not (zero? denom)))
  29. (ensure (pair? <?>))
  30. (λ (numer denom)
  31. (cons numer denom)))
  32. (define fraction-numer
  33. (λ (frac)
  34. (car frac)))
  35. (define fraction-denom
  36. (λ (frac)
  37. (cdr frac)))
  38. (define fraction?
  39. (λ (frac)
  40. (pair? frac)))
  41. (define-with-contract fraction-reduce
  42. (require (fraction? frac))
  43. (ensure (fraction? frac))
  44. (λ (frac)
  45. (let ([reduced-fraction
  46. (/ (fraction-numer frac)
  47. (fraction-denom frac))])
  48. (make-fraction (numerator reduced-fraction)
  49. (denominator reduced-fraction)))))
  50. (define-with-contract common-digit-in-terms
  51. (require (fraction? frac))
  52. (ensure (or (integer? <?>)
  53. (boolean? <?>)))
  54. (λ (frac)
  55. "Get the first common digit of the numerator and denominator
  56. of a fraction."
  57. (let ([numer-digits (digits (fraction-numer frac))]
  58. [denom (fraction-denom frac)])
  59. (let iter ([digits° numer-digits])
  60. (cond
  61. [(null? digits°) #f]
  62. [(contains-digit? denom (car digits°)) (car digits°)]
  63. [else (iter (drop digits° 1))]))
  64. ;; any
  65. #;(reduce (λ (cur acc)
  66. (or acc cur))
  67. #f
  68. ;; check if contains digits
  69. (map (λ (digit)
  70. (contains-digit? denom digit))
  71. numer-digits)))))
  72. (define trivial?
  73. (λ (frac)
  74. (or
  75. (and (divides? 10 (fraction-numer frac))
  76. (divides? 10 (fraction-denom frac)))
  77. (= (fraction-numer frac)
  78. (fraction-denom frac)))))
  79. (define cancelling-fractions
  80. (let iter ([numer 10] [denom 10] [found-fractions '()])
  81. (cond
  82. [(> denom 99)
  83. found-fractions]
  84. [(> numer denom) ; avoid duplicates
  85. (iter 10 (+ denom 1) found-fractions)]
  86. [(> numer 99)
  87. (iter 10 (+ denom 1) found-fractions)]
  88. [(not (trivial? (make-fraction numer denom)))
  89. (let ([common-digit
  90. (common-digit-in-terms (make-fraction numer denom))])
  91. #;(print numer "and" denom
  92. "have the following digit in common:"
  93. common-digit)
  94. (cond
  95. [common-digit
  96. (cond
  97. [(zero? (remove-digit denom common-digit))
  98. (iter 10 (+ denom 1) found-fractions)]
  99. [else
  100. (let ([wrongly-simplified-fraction
  101. (make-fraction
  102. (remove-digit numer common-digit)
  103. (remove-digit denom common-digit))])
  104. (cond
  105. [(= (/ numer denom)
  106. (/ (remove-digit numer common-digit)
  107. (remove-digit denom common-digit)))
  108. (iter (+ numer 1)
  109. denom
  110. (cons (make-fraction numer denom)
  111. found-fractions))]
  112. [else
  113. (iter (+ numer 1)
  114. denom
  115. found-fractions)]))])]
  116. [else
  117. (iter (+ numer 1)
  118. denom
  119. found-fractions)]))]
  120. [else
  121. (iter (+ numer 1)
  122. denom
  123. found-fractions)])))
  124. (print cancelling-fractions)
  125. (print
  126. (let ([frac
  127. (reduce (λ (frac acc)
  128. (make-fraction (* (fraction-numer frac)
  129. (fraction-numer acc))
  130. (* (fraction-denom frac)
  131. (fraction-denom acc))))
  132. 1
  133. cancelling-fractions)])
  134. (/ (fraction-numer frac)
  135. (fraction-denom frac))))