Last active
December 2, 2017 04:49
-
-
Save futureperfect/2998734987165bdb04817d70e93a284b to your computer and use it in GitHub Desktop.
Minesweeper Code Kata - http://codingdojo.org/kata/Minesweeper/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2.4.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source "https://rubygems.org" | |
gem "minitest" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MinefieldParser | |
def self.parse input | |
new.read_text input | |
end | |
def read_text input | |
input.split("\n").to_enum.slice_before(/\d+ \d+/).collect do |f| | |
Minefield.new(f) | |
end | |
end | |
end | |
class Minefield | |
attr_reader :rows, :columns, :mines | |
def initialize body | |
@rows, @columns = find_size(body) | |
@mines = detect_mines(body.drop(1)) | |
end | |
def mine_at?(c) | |
mines.include? c | |
end | |
def mines_near(c) | |
adjacent_mines = mines.select do |b| | |
((b[0] - c[0]).abs < 2) && ((b[1] - c[1]).abs < 2) | |
end | |
adjacent_mines - c | |
end | |
private | |
def detect_mines field_array | |
mines = [] | |
field_array.each_with_index do |val, row_idx| | |
val.split("").each_with_index do |v, col_idx| | |
mines << [row_idx, col_idx] if v == "*" | |
end | |
end | |
mines | |
end | |
def find_size body | |
body.first.split(" ").map(&:to_i) | |
end | |
end | |
class MinefieldJournal | |
def initialize minefields | |
@minefields = minefields | |
end | |
def self.for(minefields) | |
new(minefields).journal | |
end | |
def journal | |
entries = [] | |
@minefields.each_with_index do |m, index| | |
entries << <<~JOURNAL | |
Field ##{index + 1}: | |
#{ HintedMinefield.new(m).hinted_text} | |
JOURNAL | |
end | |
entries.join("") | |
end | |
end | |
class HintedMinefield < SimpleDelegator | |
def initialize(minefield) | |
super(minefield) | |
end | |
def hint_at(c) | |
if mine_at?(c) | |
"*" | |
else | |
mines_near(c).count.to_s | |
end | |
end | |
def hinted_text | |
row_strings = (0...rows).collect do |i| | |
c = (0...columns).collect { |j| hint_at([i,j]) } | |
c.join("") | |
end | |
row_strings.join("\n") | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "minitest/autorun" | |
require "./minesweeper.rb" | |
class MinesweeperTest < Minitest::Test | |
def test_read_field | |
input = <<~INPUT | |
1 5 | |
*... | |
INPUT | |
minefields = MinefieldParser.parse input | |
assert_equal 1, minefields.count | |
end | |
def test_read_two_fields | |
input = <<~INPUT | |
2 2 | |
.. | |
** | |
3 5 | |
..... | |
*.... | |
....* | |
INPUT | |
minefields = MinefieldParser.parse input | |
assert_equal 2, minefields.count | |
end | |
end | |
class MinefieldTest < Minitest::Test | |
def test_constructor | |
m = Minefield.new empty_field | |
assert_instance_of Minefield, m | |
end | |
def test_size | |
m = Minefield.new empty_field | |
assert_equal 2, m.columns | |
assert_equal 2, m.rows | |
end | |
def test_nonzero_size | |
m = Minefield.new two_by_three_field | |
assert_equal 2, m.rows | |
assert_equal 3, m.columns | |
end | |
def test_has_no_mines | |
m = Minefield.new empty_field | |
assert_equal 0, m.mines.count | |
end | |
def test_has_a_mine | |
m = Minefield.new two_by_three_field | |
assert_equal [[0, 1]], m.mines | |
end | |
def test_many_mines | |
m = Minefield.new multiple_field | |
assert_equal 4, m.mines.count | |
end | |
def test_mine_count_near | |
m = Minefield.new empty_field | |
assert_equal 0, m.mines_near([0, 0]).count | |
end | |
def test_single_mine_nearby | |
m = Minefield.new two_by_three_field | |
assert_equal 1, m.mines_near([0, 0]).count | |
end | |
def test_multiple_mines_nearby | |
m = Minefield.new multiple_field | |
assert_equal 2, m.mines_near([0, 0]).count | |
end | |
def empty_field | |
["2 2", | |
"..", | |
".."] | |
end | |
def two_by_three_field | |
["2 3", | |
".*.", | |
"..."] | |
end | |
def multiple_field | |
["4 4", | |
".*..", | |
"*..*", | |
"....", | |
"...*"] | |
end | |
end | |
class MinefieldJournalTest < Minitest::Test | |
def test_single_minefield_journal | |
input = <<~INPUT | |
1 1 | |
. | |
INPUT | |
single_entry_journal = <<~JOURNAL | |
Field #1: | |
0 | |
JOURNAL | |
minefields = MinefieldParser.parse input | |
assert_equal single_entry_journal, MinefieldJournal.for(minefields) | |
end | |
def test_larger_single_minefield | |
input = <<~INPUT | |
3 3 | |
..* | |
... | |
*.. | |
INPUT | |
journal = <<~JOURNAL | |
Field #1: | |
01* | |
121 | |
*10 | |
JOURNAL | |
minefields = MinefieldParser.parse input | |
assert_equal journal, MinefieldJournal.for(minefields) | |
end | |
def test_multiple_minefield_journal | |
input = <<~INPUT | |
2 2 | |
.. | |
.* | |
3 3 | |
... | |
.*. | |
... | |
INPUT | |
journal = <<~JOURNAL | |
Field #1: | |
11 | |
1* | |
Field #2: | |
111 | |
1*1 | |
111 | |
JOURNAL | |
minefields = MinefieldParser.parse input | |
assert_equal journal, MinefieldJournal.for(minefields) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment