Thomascountz/battle_boats

View on GitHub
lib/battle_boats/board.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "battle_boats/cell"
require "battle_boats/fleet"

module BattleBoats
  class Board
    attr_reader :fleet, :board_size, :play_area, :status_report

    def initialize(fleet: BattleBoats::Fleet.new)
      @fleet = fleet
      @status_report = ""
      @board_size = 10
      @play_area = create_play_area
    end

    def place_ships_randomly
      @fleet.ships.each do |ship|
        until ship_deployed?(ship: ship)
          coordinate = get_random_coordinate
          orientation = %i[horizontal vertical].sample
          attempt_to_deploy_ship(ship: ship, coordinate: coordinate, orientation: orientation)
        end
      end
    end

    def ship_deployed?(ship:)
      play_area.flatten.map(&:occupant).include?(ship)
    end

    def attempt_to_deploy_ship(ship:, coordinate:, orientation:)
      cells = Array.new(ship.length) do |offset|
        if orientation == :horizontal
          next_coordinate = coordinate.right(offset: offset)
        elsif orientation == :vertical
          next_coordinate = coordinate.up(offset: offset)
        else
          return nil
        end
        cell_at(coordinate: next_coordinate)
      end

      if cells_occupiable?(cells: cells)
        cells.each do |cell|
          cell.occupant = ship
        end
      end
    end

    def strike_position(coordinate:)
      cell = cell_at(coordinate: coordinate)
      if cell.hit?
        @status_report = "That position has already been hit"
        false
      else
        cell.strike
        @status_report = cell.status_report
        true
      end
    end

    def game_over?
      fleet.ships.all?(&:sunk?)
    end

    def cell_at(coordinate:)
      if within_range?(coordinate: coordinate)
        @play_area[coordinate.row.to_i][coordinate.column.to_i]
      end
    end

    def get_random_coordinate
      BattleBoats::Coordinate.random(row: 0...board_size, column: 0...board_size)
    end

    private

    def create_play_area
      Array.new(board_size) do
        row = []
        board_size.times do
          row << BattleBoats::Cell.new
        end
        row
      end
    end

    def cells_occupiable?(cells:)
      cells.none?(&:nil?) && cells.none?(&:occupied?)
    end

    def within_range?(coordinate:)
      (0...board_size).cover?(coordinate.row) &&
        (0...board_size).cover?(coordinate.column)
    end
  end
end