Skip to content

Instantly share code, notes, and snippets.

@futureperfect
Last active December 2, 2017 04:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save futureperfect/2998734987165bdb04817d70e93a284b to your computer and use it in GitHub Desktop.
Save futureperfect/2998734987165bdb04817d70e93a284b to your computer and use it in GitHub Desktop.
Minesweeper Code Kata - http://codingdojo.org/kata/Minesweeper/
source "https://rubygems.org"
gem "minitest"
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
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