main.scm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. ;; PSEUDO-CODE:
  2. ;; FUNCTION MoveTower(disk, source, dest, spare):
  3. ;; IF disk == 0, THEN:
  4. ;; move disk from source to dest
  5. ;; ELSE:
  6. ;; MoveTower(disk - 1, source, spare, dest) // Step 1 above
  7. ;; move disk from source to dest // Step 2 above
  8. ;; MoveTower(disk - 1, spare, dest, source) // Step 3 above
  9. ;; END IF
  10. ;; This solution for the Towers of Hanoi problem works without modifying any
  11. ;; (global) state. This means, that in-between results of steps must be used in
  12. ;; the next steps, instead of a globally available game state. This in turn
  13. ;; means simply having a reference to each tower from the arguments does not
  14. ;; work, because the references are switched around for some calls as well as
  15. ;; conceptually for solving the problem recursively. To avoid this problem the
  16. ;; solution makes use of tower ids, which are symbols, and finds towers by
  17. ;; symbol.
  18. ;; The code could be optimized for example by using hashtables for storing the
  19. ;; towers, so that a lookup of ids happens in O(1). However, the usual use cases
  20. ;; do not force this optimization.
  21. (use-modules (hanoi-model))
  22. (define move-disk
  23. (λ (hanoi source-id dest-id spare-id)
  24. (print-hanoi hanoi)
  25. (display (simple-format #f "moving disk from ~a to ~a\n" source-id dest-id))
  26. (let ([source-tower (find-tower-by-id hanoi source-id)]
  27. [dest-tower (find-tower-by-id hanoi dest-id)]
  28. [spare-tower (find-tower-by-id hanoi spare-id)])
  29. (create-hanoi
  30. ;; Remove one disk from the source, because we take it from there and put
  31. ;; it elsewhere.
  32. (remove-disk source-tower)
  33. ;; Since we are directly moving a disk, we do not need the spare, it
  34. ;; stays the same.
  35. spare-tower
  36. ;; Create a new destination tower, to put the disk there.
  37. (create-tower dest-id
  38. (stack-disks (first-of-disks (tower-disks source-tower))
  39. (tower-disks dest-tower)))))))
  40. (define move-tower-disks
  41. (λ (hanoi disk-size-to-move source-id dest-id spare-id)
  42. #;(print-hanoi hanoi)
  43. (cond
  44. ;; Disk size 1 is the smallest disk size. If we want to move a disk of
  45. ;; size 1, we can immediately move it, as it cannot be put onto a smaller
  46. ;; disk, as there exists no smaller disk.
  47. [(= disk-size-to-move 1)
  48. ;; To avoid modification, `move-disk` must return the updated hanoi.
  49. (move-disk hanoi #|so|# source-id #|de|# dest-id #|sp|# spare-id)]
  50. [else
  51. (call-with-values
  52. (λ ()
  53. ;; Do 2 preparational steps before moving the largest disk.
  54. (call-with-values
  55. (λ ()
  56. ;; CASE 1:
  57. ;; Move all disks except the lowest one to the spare tower, so
  58. ;; that we will be able to move the lowest (largest) disk to
  59. ;; the destination afterwards.
  60. (move-tower-disks hanoi
  61. (- disk-size-to-move 1)
  62. #|so|# source-id #|de|# spare-id #|sp|# dest-id))
  63. (λ (updated-hanoi)
  64. ;; CASE 2:
  65. ;; Move the largest disk now to the actual destination.
  66. (move-disk updated-hanoi
  67. #|so|# source-id #|de|# dest-id #|sp|# spare-id))))
  68. (λ (updated-hanoi)
  69. ;; CASE 3:
  70. ;; Now we need to move the remaining disks (all except the largest) to
  71. ;; the destination as well. The remaining disks are at the spare, so
  72. ;; spare becomes the source. The destination stays the same, so we
  73. ;; need to use source as spare.
  74. (move-tower-disks updated-hanoi
  75. (- disk-size-to-move 1)
  76. #|so|# spare-id #|de|# dest-id #|sp|# source-id)))])))
  77. (define solve-hanoi
  78. (λ (hanoi)
  79. (print-hanoi
  80. (move-tower-disks
  81. hanoi
  82. (find-largest-disk (first-of-towers hanoi))
  83. #|so|# (tower-id (first-tower hanoi))
  84. #|de|# (tower-id (third-tower hanoi))
  85. #|sp|# (tower-id (second-tower hanoi))))))
  86. (solve-hanoi
  87. (create-hanoi
  88. (create-tower 'SO '(1 2 3))
  89. (create-tower 'SP '())
  90. (create-tower 'DE '())))