Class: Minehunter::Grid Private
- Inherits:
-
Object
- Object
- Minehunter::Grid
- Defined in:
- lib/minehunter/grid.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
A grid with fields representation
Instance Attribute Summary collapse
-
#flags_remaining ⇒ Integer
readonly
Track the number of flags remaining.
-
#unmined_fields_remaining ⇒ Integer
readonly
Track the number of unmined fields remaining.
Instance Method Summary collapse
-
#at(x, y) ⇒ Integer
Find field index at a given position.
-
#cleared? ⇒ Boolean
Check whether or not the grid is cleared.
-
#count_flags_next_to(x, y) ⇒ Integer
Total number of flags next to a given position.
-
#count_mines_next_to(x, y) ⇒ Integer
Total number of mines next to a given position.
-
#field_at(x, y) ⇒ Field
Find a field at a given position.
-
#fields_next_to(x, y) ⇒ Enumerator
Enumerate fields next to a given position.
-
#fill_with_mines(x, y, randomiser: DEFAULT_RANDOMISER) ⇒ Object
Fill grid with mines skipping the current position and nearby fields.
-
#flag(x, y) ⇒ Object
Add or remove a flag at a given position.
-
#flag?(x, y) ⇒ Boolean
Check whether or not there is a flag at a given position.
-
#initialize(width: nil, height: nil, mines_limit: nil) ⇒ Grid
constructor
Create a Grid instance.
-
#mine(x, y) ⇒ Object
Set a mine at a given position.
-
#mines ⇒ Array<Field>
All fields with mines.
-
#move_down(y) ⇒ Integer
Move down on the grid.
-
#move_left(x) ⇒ Integer
Move left on the grid.
-
#move_right(x) ⇒ Integer
Move right on the grid.
-
#move_up(y) ⇒ Integer
Move up on the grid.
-
#render(x, y, decorator: DEFAULT_DECORATOR) ⇒ String
Render grid.
-
#reset ⇒ Object
Reset all fields to defaults.
-
#uncover(x, y) ⇒ Boolean
Uncover fields surrounding the position.
-
#uncover_around(x, y) ⇒ Boolean
Uncover fields around numbered field matching flags count.
-
#uncover_mines ⇒ Object
Uncover all mines without a flag.
-
#within?(x, y) ⇒ Boolean
Check whether coordinates are within the grid.
Constructor Details
#initialize(width: nil, height: nil, mines_limit: nil) ⇒ Grid
Create a Grid instance
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/minehunter/grid.rb', line 34 def initialize(width: nil, height: nil, mines_limit: nil) if mines_limit >= width * height raise Error, "cannot have more mines than available fields" end @width = width @height = height @mines_limit = mines_limit @fields = [] reset end |
Instance Attribute Details
#flags_remaining ⇒ Integer (readonly)
Track the number of flags remaining
15 16 17 |
# File 'lib/minehunter/grid.rb', line 15 def flags_remaining @flags_remaining end |
#unmined_fields_remaining ⇒ Integer (readonly)
Track the number of unmined fields remaining
22 23 24 |
# File 'lib/minehunter/grid.rb', line 22 def unmined_fields_remaining @unmined_fields_remaining end |
Instance Method Details
#at(x, y) ⇒ Integer
Find field index at a given position
122 123 124 |
# File 'lib/minehunter/grid.rb', line 122 def at(x, y) y * @width + x end |
#cleared? ⇒ Boolean
Check whether or not the grid is cleared
63 64 65 |
# File 'lib/minehunter/grid.rb', line 63 def cleared? @unmined_fields_remaining.zero? end |
#count_flags_next_to(x, y) ⇒ Integer
Total number of flags next to a given position
270 271 272 273 274 |
# File 'lib/minehunter/grid.rb', line 270 def count_flags_next_to(x, y) fields_next_to(x, y).reduce(0) do |acc, cords| acc + (field_at(*cords).flag? ? 1 : 0) end end |
#count_mines_next_to(x, y) ⇒ Integer
Total number of mines next to a given position
254 255 256 257 258 |
# File 'lib/minehunter/grid.rb', line 254 def count_mines_next_to(x, y) fields_next_to(x, y).reduce(0) do |acc, cords| acc + (field_at(*cords).mine? ? 1 : 0) end end |
#field_at(x, y) ⇒ Field
Find a field at a given position
136 137 138 |
# File 'lib/minehunter/grid.rb', line 136 def field_at(x, y) @fields[at(x, y)] end |
#fields_next_to(x, y) ⇒ Enumerator
Enumerate fields next to a given position
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/minehunter/grid.rb', line 219 def fields_next_to(x, y) return to_enum(:fields_next_to, x, y) unless block_given? -1.upto(1) do |offset_x| -1.upto(1) do |offset_y| close_x = x + offset_x close_y = y + offset_y next if close_x == x && close_y == y next unless within?(close_x, close_y) yield(close_x, close_y) end end end |
#fill_with_mines(x, y, randomiser: DEFAULT_RANDOMISER) ⇒ Object
Fill grid with mines skipping the current position and nearby fields
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/minehunter/grid.rb', line 192 def fill_with_mines(x, y, randomiser: DEFAULT_RANDOMISER) limit = @mines_limit while limit > 0 mine_x = randomiser[@width] mine_y = randomiser[@height] next if mine_x == x && mine_y == y next if fields_next_to(x, y).include?([mine_x, mine_y]) field = field_at(mine_x, mine_y) next if field.mine? field.mine! limit -= 1 end end |
#flag(x, y) ⇒ Object
Add or remove a flag at a given position
160 161 162 163 164 165 166 |
# File 'lib/minehunter/grid.rb', line 160 def flag(x, y) field = field_at(x, y) return unless field.cover? @flags_remaining += field.flag? ? 1 : -1 field.flag end |
#flag?(x, y) ⇒ Boolean
Check whether or not there is a flag at a given position
178 179 180 |
# File 'lib/minehunter/grid.rb', line 178 def flag?(x, y) field_at(x, y).flag? end |
#mine(x, y) ⇒ Object
Set a mine at a given position
148 149 150 |
# File 'lib/minehunter/grid.rb', line 148 def mine(x, y) field_at(x, y).mine! end |
#mines ⇒ Array<Field>
All fields with mines
72 73 74 |
# File 'lib/minehunter/grid.rb', line 72 def mines @fields.select(&:mine?) end |
#move_down(y) ⇒ Integer
Move down on the grid
90 91 92 |
# File 'lib/minehunter/grid.rb', line 90 def move_down(y) y == @height - 1 ? 0 : y + 1 end |
#move_left(x) ⇒ Integer
Move left on the grid
99 100 101 |
# File 'lib/minehunter/grid.rb', line 99 def move_left(x) x.zero? ? @width - 1 : x - 1 end |
#move_right(x) ⇒ Integer
Move right on the grid
108 109 110 |
# File 'lib/minehunter/grid.rb', line 108 def move_right(x) x == @width - 1 ? 0 : x + 1 end |
#move_up(y) ⇒ Integer
Move up on the grid
81 82 83 |
# File 'lib/minehunter/grid.rb', line 81 def move_up(y) y.zero? ? @height - 1 : y - 1 end |
#render(x, y, decorator: DEFAULT_DECORATOR) ⇒ String
Render grid
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/minehunter/grid.rb', line 363 def render(x, y, decorator: DEFAULT_DECORATOR) out = [] @height.times do |field_y| @width.times do |field_x| field = field_at(field_x, field_y) rendered_field = field.render(decorator: decorator) if field_x == x && field_y == y && decorator bg_color = field.mine? && !field.cover? ? :on_red : :on_green rendered_field = decorator[rendered_field, bg_color] end out << rendered_field end out << "\n" end out.join end |
#reset ⇒ Object
Reset all fields to defaults
50 51 52 53 54 55 56 |
# File 'lib/minehunter/grid.rb', line 50 def reset (@width * @height).times do |i| @fields[i] = Field.new end @unmined_fields_remaining = @width * @height - @mines_limit @flags_remaining = @mines_limit end |
#uncover(x, y) ⇒ Boolean
Uncover fields surrounding the position
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/minehunter/grid.rb', line 287 def uncover(x, y) field = field_at(x, y) if field.mine? field.uncover uncover_mines return true end return uncover_around(x, y) unless field.cover? mine_count = count_mines_next_to(x, y) field.mine_count = mine_count flag(x, y) if field.flag? field.uncover @unmined_fields_remaining -= 1 if mine_count.zero? fields_next_to(x, y) do |close_x, close_y| close_field = field_at(close_x, close_y) next if !close_field.cover? || close_field.mine? uncover(close_x, close_y) end end false end |
#uncover_around(x, y) ⇒ Boolean
Uncover fields around numbered field matching flags count
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/minehunter/grid.rb', line 326 def uncover_around(x, y) field = field_at(x, y) uncovered_mine = false if count_flags_next_to(x, y) != field.mine_count return uncovered_mine end fields_next_to(x, y) do |close_x, close_y| close_field = field_at(close_x, close_y) next if !close_field.cover? || close_field.flag? uncover(close_x, close_y) uncovered_mine = true if close_field.mine? end uncovered_mine end |
#uncover_mines ⇒ Object
Uncover all mines without a flag
349 350 351 352 353 354 355 356 |
# File 'lib/minehunter/grid.rb', line 349 def uncover_mines @fields.each do |field| if field.mine? && !field.flag? || field.flag? && !field.mine? field.wrong if field.flag? field.uncover end end end |
#within?(x, y) ⇒ Boolean
Check whether coordinates are within the grid
return [Boolean]
240 241 242 |
# File 'lib/minehunter/grid.rb', line 240 def within?(x, y) x >= 0 && x < @width && y >= 0 && y < @height end |