Advertisement
Guest User

Untitled

a guest
May 24th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 3.81 KB | None | 0 0
  1. class BattlefieldBuilder
  2.   def initialize
  3.     @cells = 10.times.collect { 10.times.collect { false } }
  4.   end
  5.  
  6.   def add_segment(coordinate)
  7.     if !coordinate || self[coordinate] || !pre_validate_position(coordinate)
  8.       return false
  9.     end
  10.     self[coordinate] = true
  11.     true
  12.   end
  13.  
  14.   def collect_ships
  15.     @pointer = Coordinate.new(0, 0)
  16.     ships = []
  17.     while (ship = next_ship)
  18.       # deleting ship segments from the battlefield
  19.       ship.each { |segment| self[segment.coordinate] = false }
  20.       ships << ship
  21.     end
  22.     ships
  23.   end
  24.  
  25.   private
  26.  
  27.   def [](coordinate)
  28.     @cells[coordinate.row][coordinate.col]
  29.   end
  30.  
  31.   def []=(coordinate, value)
  32.     @cells[coordinate.row][coordinate.col] = value
  33.   end
  34.  
  35.   def pre_validate_position(coordinate)
  36.     neighbours = side_neighbouring_segments(coordinate)
  37.     angle_neighbouring_segments(coordinate).empty? &&
  38.         (neighbours.length < 2 ||
  39.             (neighbours.length == 2 &&
  40.                 ((neighbours[:top] && neighbours[:bottom]) ||
  41.                     (neighbours[:left] && neighbours[:right]))))
  42.   end
  43.  
  44.   def side_neighbouring_segments(coordinate)
  45.     result = {}
  46.     neighbours = coordinate.side_neighbours
  47.     result[:top] = true if neighbours[:top] && self[neighbours[:top]]
  48.     result[:bottom] = true if neighbours[:bottom] && self[neighbours[:bottom]]
  49.     result[:left] = true if neighbours[:left] && self[neighbours[:left]]
  50.     result[:right] = true if neighbours[:right] && self[neighbours[:right]]
  51.     result
  52.   end
  53.  
  54.   def angle_neighbouring_segments(coordinate)
  55.     result = {}
  56.     neighbours = coordinate.angle_neighbours
  57.     result[:top_left] = true if neighbours[:top_left] && self[neighbours[:top_left]]
  58.     result[:top_right] = true if neighbours[:top_right] && self[neighbours[:top_right]]
  59.     result[:bottom_left] = true if neighbours[:bottom_left] && self[neighbours[:bottom_left]]
  60.     result[:bottom_right] = true if neighbours[:bottom_right] && self[neighbours[:bottom_right]]
  61.     result
  62.   end
  63.  
  64.   def next_ship
  65.     coordinate = next_segment_coordinate
  66.     return nil unless coordinate
  67.  
  68.     ship = Ship.new([ShipSegment.new(coordinate)])
  69.     segments = get_segments_from(coordinate.side_neighbours[:right], true)
  70.     segments ||= get_segments_from(coordinate.side_neighbours[:bottom], false)
  71.     segments.each { |segment| ship << segment } if segments
  72.     ship
  73.   end
  74.  
  75.   def get_segments_from(coordinate, horizontal = true)
  76.     segments = []
  77.     while coordinate && self[coordinate]
  78.       segments << ShipSegment.new(coordinate)
  79.       coordinate = horizontal ?
  80.                        coordinate.right_neighbour :
  81.                        coordinate.bottom_neighbour
  82.     end
  83.     segments.empty? ? nil : segments
  84.   end
  85.  
  86.   def next_segment_coordinate
  87.     coordinate = nil
  88.     while @pointer && !coordinate
  89.       coordinate = @pointer if self[@pointer]
  90.       @pointer = @pointer.next
  91.     end
  92.     coordinate
  93.   end
  94. end
  95.  
  96. class ShipParser
  97.   def parse(ship_data)
  98.     return nil unless ship_data && ship_data.is_a?(String)
  99.     segments = ship_data.gsub(/[^A-Ja-j\d,]/, '').downcase.split(',')
  100.     return nil unless segments.length == 20
  101.  
  102.     battlefield = BattlefieldBuilder.new
  103.  
  104.     error = false
  105.     segments.each do |segment_coordinate|
  106.       unless battlefield.add_segment(Coordinate.parse(segment_coordinate))
  107.         error = true
  108.         break
  109.       end
  110.     end
  111.     return nil if error
  112.  
  113.     ships = battlefield.collect_ships
  114.     validate_ships(ships) ? Ships.new(ships) : nil
  115.   end
  116.  
  117.   private
  118.  
  119.   def validate_ships(ships)
  120.     ships.size == 10 &&
  121.         ships.select { |ship| ship.size == 1 }.size == 4 &&
  122.         ships.select { |ship| ship.size == 2 }.size == 3 &&
  123.         ships.select { |ship| ship.size == 3 }.size == 2 &&
  124.         ships.select { |ship| ship.size == 4 }.size == 1
  125.   end
  126. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement