# paulfioravanti's solution

## to Minesweeper in the Ruby Track

Published at May 23 2019 · 0 comments
Instructions
Test suite
Solution

Add the numbers to a minesweeper board.

Minesweeper is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square.

In this exercise you have to create some code that counts the number of mines adjacent to a square and transforms boards like this (where `*` indicates a mine):

``````+-----+
| * * |
|  *  |
|  *  |
|     |
+-----+
``````

into this:

``````+-----+
|1*3*1|
|13*31|
| 2*2 |
| 111 |
+-----+
``````

For installation and learning resources, refer to the Ruby resources page.

For running the tests provided, you will need the Minitest gem. Open a terminal window and run the following command to install minitest:

``````gem install minitest
``````

If you would like color output, you can `require 'minitest/pride'` in the test file, or note the alternative instruction, below, for running the test file.

Run the tests from the exercise directory using the following command:

``````ruby minesweeper_test.rb
``````

To include color from the command line:

``````ruby -r minitest/pride minesweeper_test.rb
``````

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### minesweeper_test.rb

``````require 'minitest/autorun'
require_relative 'minesweeper'

class MinesweeperTest < Minitest::Test
def test_transform1
inp = ['+------+', '| *  * |', '|  *   |', '|    * |', '|   * *|',
'| *  * |', '|      |', '+------+']
out = ['+------+', '|1*22*1|', '|12*322|', '| 123*2|', '|112*4*|',
'|1*22*2|', '|111111|', '+------+']
assert_equal out, Board.transform(inp)
end

def test_transform2
skip
inp = ['+-----+', '| * * |', '|     |', '|   * |', '|  * *|',
'| * * |', '+-----+']
out = ['+-----+', '|1*2*1|', '|11322|', '| 12*2|', '|12*4*|',
'|1*3*2|', '+-----+']
assert_equal out, Board.transform(inp)
end

def test_transform3
skip
inp = ['+-----+', '| * * |', '+-----+']
out = ['+-----+', '|1*2*1|', '+-----+']
assert_equal out, Board.transform(inp)
end

def test_transform4
skip
inp = ['+-+', '|*|', '| |', '|*|', '| |', '| |', '+-+']
out = ['+-+', '|*|', '|2|', '|*|', '|1|', '| |', '+-+']
assert_equal out, Board.transform(inp)
end

def test_transform5
skip
inp = ['+-+', '|*|', '+-+']
out = ['+-+', '|*|', '+-+']
assert_equal out, Board.transform(inp)
end

def test_transform6
skip
inp = ['+--+', '|**|', '|**|', '+--+']
out = ['+--+', '|**|', '|**|', '+--+']
assert_equal out, Board.transform(inp)
end

def test_transform7
skip
inp = ['+--+', '|**|', '|**|', '+--+']
out = ['+--+', '|**|', '|**|', '+--+']
assert_equal out, Board.transform(inp)
end

def test_transform8
skip
inp = ['+---+', '|***|', '|* *|', '|***|', '+---+']
out = ['+---+', '|***|', '|*8*|', '|***|', '+---+']
assert_equal out, Board.transform(inp)
end

def test_transform9
skip
inp = ['+-----+', '|     |', '|   * |', '|     |', '|     |',
'| *   |', '+-----+']
out = ['+-----+', '|  111|', '|  1*1|', '|  111|', '|111  |',
'|1*1  |', '+-----+']
assert_equal out, Board.transform(inp)
end

def test_different_len
skip
inp = ['+-+', '| |', '|*  |', '|  |', '+-+']
assert_raises(ArgumentError) do
Board.transform(inp)
end
end

def test_faulty_border
skip
inp = ['+-----+', '*   * |', '+-- --+']
assert_raises(ArgumentError) do
Board.transform(inp)
end
end

def test_invalid_char
skip
inp = ['+-----+', '|X  * |', '+-----+']
assert_raises(ArgumentError) do
Board.transform(inp)
end
end
end``````
``````# frozen_string_literal: true

module Board
ADJACENT_COORDINATES = lambda do |y_index, x_index|
[x_index - 1, x_index + 1, y_index - 1, y_index + 1]
end
BLANK = " "
private_constant :BLANK
MINE = "*"
private_constant :MINE
HORIZONTAL_BORDER_START = "+"
private_constant :HORIZONTAL_BORDER_START
VERTICAL_BORDER = "|"
private_constant :VERTICAL_BORDER

module_function

def transform(board)
raise ArgumentError unless all_lines_same_length?(board)

board
.each
.with_index
.with_object(board)
.map(&method(:transform_line))
end

def transform_line((line, y_index), board)
return line if line.start_with?(HORIZONTAL_BORDER_START)
raise ArgumentError unless line.start_with?(VERTICAL_BORDER)

line
.chars
.each
.with_index
.with_object([y_index, board])
.map(&method(:transform_character))
.join
end
private_class_method :transform_line

def transform_character((char, x_index), (y_index, board))
return char if board_element?(char)
raise ArgumentError unless char == BLANK

.each
.with_object(board)
.sum(&method(:sum_mine))
.then { |sum| sum.positive? ? sum : char }
end

def all_lines_same_length?(board)
board.map(&:length).uniq.one?
end
private_class_method :all_lines_same_length?

def board_element?(char)
[VERTICAL_BORDER, MINE].include?(char)
end
private_class_method :board_element?

left, right, above, below = ADJACENT_COORDINATES.call(y_index, x_index)
[[y_index, left], [y_index, right]].then do |coords|
board[above] &&
coords += [[above, left], [above, x_index], [above, right]]
board[below] &&
coords + [[below, left], [below, x_index], [below, right]]
end
end

def sum_mine(((y, x), board))
board[y][x] == MINE ? 1 : 0
end
private_class_method :sum_mine
end``````