Guest User

Untitled

a guest
Feb 20th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.91 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2.  
  3. # Helper class
  4.  
  5. class Tile
  6. attr_reader :x, :y
  7. protected :x, :y
  8.  
  9. def initialize(x, y)
  10. @x, @y = x, y
  11. end
  12.  
  13. def Tile.named(s)
  14. Tile.new(s.downcase[0] - ?a, s[1] - ?1)
  15. end
  16.  
  17. def valid?
  18. (0...8) === @x and (0...8) === @y
  19. end
  20.  
  21. def to_s
  22. to_str
  23. end
  24.  
  25. def to_str
  26. %w(a b c d e f g h)[@x] + %w(1 2 3 4 5 6 7 8)[@y] if valid?
  27. end
  28.  
  29. def ==(c)
  30. @x == c.x and @y == c.y
  31. end
  32.  
  33. def adjacent?(c)
  34. dx = (@x - c.x).abs
  35. dy = (@y - c.y).abs
  36. valid? and c.valid? and (dx == 1 && dy == 2 or dx == 2 && dy == 1)
  37. end
  38. end
  39.  
  40.  
  41.  
  42. def knights_trip(start, finish, *forbidden)
  43. # First, build big bucket o' tiles.
  44. board = (0...64).collect { |n| Tile.new(n % 8, n / 8) }
  45.  
  46. # Second, pull out forbidden tiles.
  47. board.reject! { |t| forbidden.include?(t) }
  48.  
  49. # Third, prepare a hash, where layer 0 is just the start.
  50. # Remove start from the board.
  51. x = 0
  52. flood = { x => [start] }
  53. board.delete(start)
  54.  
  55. # Fourth, perform a "flood fill" step, finding all board tiles
  56. # adjacent to the previous step.
  57. until flood[x].empty? or flood[x].include?(finish) do
  58. x += 1
  59. flood[x] = flood[x-1].inject([]) do |mem, obj|
  60. mem.concat(board.find_all { |t| t.adjacent?(obj) })
  61. end
  62.  
  63. # Remove those found from the board.
  64. board.reject! { |t| flood[x].include?(t) }
  65. end
  66.  
  67. # Finally, determine whether we found a way to the finish and, if so,
  68. # build a path.
  69. if not flood[x].empty?
  70. # We found a way. Time to build the path. This is built
  71. # backwards, so finish goes in first.
  72. path = [finish]
  73.  
  74. # Since we got to finish in X steps, we know there must be
  75. # at least one adjacent to finish at X-1 steps, and so on.
  76. until x == 0
  77. x -= 1
  78.  
  79. # Find in flood[x] a tile adjacent to the head of our
  80. # path. Doesn't matter which one. Make it the new head
  81. # of our path.
  82. jumps = flood[x].find_all { |t| t.adjacent?(path.first) }
  83. path[0,0] = jumps.sort_by { rand }.first
  84. end
  85.  
  86. # Tada!
  87. path
  88. end
  89. end
  90.  
  91.  
  92.  
  93. def build_output(trip, forbidden)
  94. y = 17
  95. until y == 0
  96. unless (y % 2) == 0
  97. puts "+---" * 8 + "+"
  98. else
  99. x = 0
  100. until x == 17
  101. if (x % 2) == 0
  102. print "|"
  103. else
  104. test = Tile.new(x/2, y/2-1)
  105. tile = trip.include? test
  106. if tile
  107. print " #{trip.index test} "
  108. elsif forbidden.include? test
  109. print " X "
  110. else
  111. print " "
  112. end
  113. end
  114. x += 1
  115. end
  116. print "\n"
  117. end
  118. y -= 1
  119. end
  120. end
  121.  
  122.  
  123.  
  124. # main
  125. args = ARGV.collect { |arg| Tile.named(arg) }
  126. if args.any? { |c| not c.valid? }
  127. puts "Invalid argument(s)!"
  128. else
  129. trip = knights_trip(*args)
  130. if trip
  131. #puts "Knight's trip: ", trip
  132. build_output(trip, args[2..-1])
  133. else
  134. puts "No route available!"
  135. end
  136. end
Add Comment
Please, Sign In to add comment