083.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. ;; Path sum: four ways
  2. ;; Using dijkstras algorithm to find shortest path from top left to bottom right
  3. (use-modules (ice-9 receive)
  4. (rnrs io ports)
  5. (srfi srfi-1))
  6. (define (dijkstras graph start directions)
  7. (define min-path-array (make-array #f (array-length graph) (array-length graph)))
  8. (define direction-proc-lst (filter-map (lambda (yes? dir-proc)
  9. (if yes? dir-proc #f))
  10. directions
  11. base-dir-procs))
  12. (define (vertex-loop vertices)
  13. (if (null? vertices) min-path-array
  14. (vertex-loop (update-path-array vertices))))
  15. (define (update-path-array perimeter-vertices)
  16. (receive (min-vertex rest) (get-min-vertex perimeter-vertices)
  17. (for-each
  18. (lambda (neighbor)
  19. (array-set!
  20. min-path-array
  21. (let* ((neighbor-val (array-ref min-path-array
  22. (car neighbor) (cadr neighbor)))
  23. (min-v-val (array-ref min-path-array
  24. (car min-vertex) (cadr min-vertex)))
  25. (min-v->neigh-val (array-ref graph
  26. (car neighbor) (cadr neighbor))))
  27. (if (and neighbor-val min-v-val (< neighbor-val (+ min-v-val min-v->neigh-val)))
  28. neighbor-val (if min-v-val (+ min-v-val min-v->neigh-val) 0)))
  29. (car neighbor) (cadr neighbor)))
  30. (get-neighbors graph direction-proc-lst min-vertex))
  31. rest))
  32. (define (get-min-vertex perimeter-vertices)
  33. (define vert-array (list->array 1 perimeter-vertices))
  34. (let loop ((i 1)
  35. (min-vert (array-ref vert-array 0))
  36. (rest '()))
  37. (if (>= i (array-length vert-array))
  38. (values min-vert rest)
  39. (let* ((curr-vert (array-ref vert-array i))
  40. (curr-val (array-ref min-path-array (car curr-vert) (cadr curr-vert)))
  41. (min-val (array-ref min-path-array (car min-vert) (cadr min-vert))))
  42. (cond
  43. ((not curr-val) (loop (1+ i) min-vert (cons curr-vert rest)))
  44. ((not min-val) (loop (1+ i) curr-vert (cons min-vert rest)))
  45. ((<= curr-val min-val) (loop (1+ i) curr-vert (cons min-vert rest)))
  46. (else (loop (1+ i) min-vert (cons curr-vert rest))))))))
  47. (begin
  48. (array-set! min-path-array
  49. (array-ref graph (car start) (cadr start))
  50. (car start) (cadr start))
  51. (vertex-loop (get-index-list graph))))
  52. (define (get-index-list array)
  53. (define length (array-length array))
  54. (let loop ((i 0) (j 0) (acc '()))
  55. (cond
  56. ((>= i length) acc)
  57. ((>= j length) (loop (1+ i) 0 acc))
  58. (else (loop i (1+ j) (cons (list i j) acc))))))
  59. (define (get-l-neighbor graph point)
  60. (neighbor? graph (1- (car point)) (cadr point)))
  61. (define (get-r-neighbor graph point)
  62. (neighbor? graph (1+ (car point)) (cadr point)))
  63. (define (get-u-neighbor graph point)
  64. (neighbor? graph (car point) (1+ (cadr point))))
  65. (define (get-d-neighbor graph point)
  66. (neighbor? graph (car point) (1- (cadr point))))
  67. (define (neighbor? graph x y)
  68. (if (array-in-bounds? graph x y) (list x y) #f))
  69. (define base-dir-procs (list get-l-neighbor
  70. get-r-neighbor
  71. get-u-neighbor
  72. get-d-neighbor))
  73. (define (get-neighbors graph direction-proc-lst point)
  74. (filter-map (lambda (dir-proc)
  75. (dir-proc graph point))
  76. direction-proc-lst))
  77. (define default-array
  78. (list->array 2
  79. (list
  80. (list 131 673 234 103 18)
  81. (list 201 96 342 965 150)
  82. (list 630 803 746 422 111)
  83. (list 537 699 497 121 956)
  84. (list 805 732 524 37 331))))
  85. (define (make-matrix-from-file file)
  86. (let ((port (open-input-file file)))
  87. (let loop ((line (get-line port)) (lst '()))
  88. (if (eof-object? line) (list->array 2 (reverse lst))
  89. (loop (get-line port) (cons (line->number-list line) lst))))))
  90. (define (line->number-list line)
  91. (map string->number (string-split line #\,)))
  92. (define (print-array array)
  93. (for-each (lambda (row)
  94. (display row) (newline))
  95. (array->list array)))
  96. (print-array (dijkstras default-array '(0 0) '(#t #t #t #t)))
  97. (newline)
  98. (display
  99. (let ((min-path-matrix (dijkstras default-array ;(make-matrix-from-file "../input/p083.txt")
  100. '(0 0)
  101. '(#t #t #t #t))))
  102. (array-ref min-path-matrix
  103. (1- (array-length min-path-matrix))
  104. (1- (array-length min-path-matrix)))))
  105. (newline)
  106. ;; Note this is for problem 083, but still needs work
  107. (display
  108. (let ((matrix default-array))
  109. (reduce (lambda (val acc)
  110. (if (< val acc) val acc))
  111. 0
  112. (append-map
  113. (lambda (start)
  114. (let ((min-path-matrix
  115. (dijkstras matrix
  116. start
  117. '(#f #t #t #t))))
  118. (print-array min-path-matrix)
  119. (newline)
  120. (map (lambda (i)
  121. (array-ref min-path-matrix (1- (array-length min-path-matrix)) i))
  122. (iota (array-length min-path-matrix)))))
  123. (map (lambda (i) (list i 0))
  124. (iota (array-length matrix)))))))
  125. (newline)