Class: Board
Overview
class Board describes game board
Constant Summary
Constants included from State
State::BROKEN, State::EMPTY, State::MISSED, State::SHIP
Constants included from Direction
Direction::EAST, Direction::NORTH, Direction::SOUTH, Direction::WEST
Instance Method Summary collapse
- #cell(col, row) ⇒ Object
- #display(str) ⇒ Object
- #generate(*list) ⇒ Object
-
#initialize(size_x = 10, size_y = 10, name = '') ⇒ Board
constructor
A new instance of Board.
- #is_ship_alive? ⇒ Boolean
- #put_ship(head_x, head_y, size, dir) ⇒ Object
- #shoot(x, y) ⇒ Object
Constructor Details
#initialize(size_x = 10, size_y = 10, name = '') ⇒ Board
Returns a new instance of Board.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/board.rb', line 14 def initialize(size_x = 10, size_y = 10, name = '') unless (1..20).include?(size_x) && (1..20).include?(size_y) fail BoardSizeError, 'size should be in (1..20) range' end @size_x, @size_y, @player_name = size_x, size_y, name @cells, @ships = [], [] @alphabet = ('A'..'Z').map { |a| a } 0.upto(size_x - 1) do |x| @cells[x] = [] 0.upto(size_y - 1) { |y| @cells[x][y] = Cell.new(x, y) } end end |
Instance Method Details
#cell(col, row) ⇒ Object
31 32 33 |
# File 'lib/board.rb', line 31 def cell(col, row) @cells[col][row] end |
#display(str) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/board.rb', line 118 def display(str) fail TypeError, 'str should be Fixnum' unless str.class == Fixnum offset = 2 res = '' case str when 0 res << @player_name.center(@size_x + 4) res << ' ' when 1, 1 + @size_y + 1 res << ' ' * 2 (@size_x).times { |i| res << @alphabet[i] } res << ' ' * 3 when (offset..@size_y - 1 + offset) res << (@size_y - 1 - (str - offset)).to_s res << '|' @size_x.times do |x| case @cells[x][@size_y - 1 - (str - offset)].state when SHIP then res << 'O' when BROKEN then res << 'X' when MISSED then res << '*' else res << ' ' end end res << '|' res << (@size_y - 1 - (str - offset)).to_s res << ' ' end res end |
#generate(*list) ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/board.rb', line 148 def generate(*list) 5.downto(1).each do |size| count = list[size - 1] count.times do 100.times do |try| begin head_x = rand(@size_x) head_y = rand(@size_y) dir = rand(4) put_ship head_x, head_y, size, dir break rescue NotRoomError raise NotRoomError, 'Too much ships' if try == 100 - 1 end end end end end |
#is_ship_alive? ⇒ Boolean
113 114 115 116 |
# File 'lib/board.rb', line 113 def is_ship_alive? @ships.each { |sh| return true if sh.alive? } false end |
#put_ship(head_x, head_y, size, dir) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/board.rb', line 35 def put_ship(head_x, head_y, size, dir) head_x, head_y = x_y_normalize head_x, head_y unless (1..5).include? size fail ShipSizeError, 'Ship size should be in range (1..5)' end # it makes list of cells which will be occupied by ship # and checks for board border crossing cell_list = [] x = head_x y = head_y size.times do |i| case dir when NORTH fail NotRoomError if y == 0 && i != size - 1 cell_list[i] = [x, y] y -= 1 when EAST fail NotRoomError if x == 0 && i != size - 1 cell_list[i] = [x, y] x -= 1 when SOUTH fail NotRoomError if y == @size_y - 1 && i != size - 1 cell_list[i] = [x, y] y += 1 when WEST fail NotRoomError if x == @size_x - 1 && i != size - 1 cell_list[i] = [x, y] x += 1 end end # it checks if the nearest cells have already been occupied # algorithm isn't optimal because some cells are being checked many times cell_list.each do |x, y| fail NotRoomError, 'Other ship is here' if cell(x, y).state != EMPTY if x != 0 if (cell(x - 1, y).state != EMPTY) || (y != 0 && cell(x - 1, y - 1).state != EMPTY) || (y != @size_y - 1 && cell(x - 1, y + 1).state != EMPTY) fail NotRoomError, "Other ship is near [#{x}:#{y}]" end end if (y != 0 && cell(x, y - 1).state != EMPTY) || (y != @size_y - 1 && cell(x, y + 1).state != EMPTY) fail NotRoomError, "Other ship is near [#{x}:#{y}]" end if x != @size_x - 1 if (cell(x + 1, y).state != EMPTY) || (y != 0 && cell(x + 1, y - 1).state != EMPTY) || (y != @size_y - 1 && cell(x + 1, y + 1).state != EMPTY) fail NotRoomError, 'Other ship is near [#{x}:#{y}]' end end end @ships << Ship.new(cell_list.map { |x, y| cell x, y }) end |
#shoot(x, y) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/board.rb', line 95 def shoot(x, y) # there is a posibility of using letters as X coordinate x, y = x_y_normalize x, y c = cell(x, y) case c.state when EMPTY c.state = MISSED return 'MISSED' when SHIP ship = @ships.find { |sh| sh.include? c } fail FatalError, 'Mismatch between cell and ship tables' if ship.nil? c. state = BROKEN ship.alive? ? (return 'INJURED') : (return 'KILLED') when MISSED, BROKEN return 'ALREADY SHOT' end end |