Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution for balanced delimiter problem #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions balanced_delimiter/solutions/keppy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class ParseRules
# Rather than hardcoding each possible case into the StringParser,
# we abstract out the parsing rules into a class with one method for each
# allowed state. Then we can match on arbitrary parse tree values.
# The only restrictions to our language is that we assume each significant character is a delimiter,
# and that there are zero or more possible states 'in between' delimiters.
# There will never be a closing delimiter on the stack.

def initialize(tree)
# These rules dictate what can come next in the state machine
tree.each do |leaf|
self.class.send(:define_method, leaf[:state].to_sym) do |next_state, stack|
if leaf[:possible_states].include?(next_state)
stack.push(next_state)
elsif leaf[:close_this_state] == next_state
stack.pop()
else
return false
end
end
end
end

end


class StringParser
def initialize
@delimiters = "{[()]}"
@opening_delimiters = "{(["
@closing_delimiters = "}])"
@stack = []
@parse_tree = [
{:state => "[", :possible_states => ["{", "(", "["], :close_this_state => "]"},
{:state => "{", :possible_states => ["{", "(", "["], :close_this_state => "}"},
{:state => "(", :possible_states => ["{", "(", "["], :close_this_state => ")"}
]
@parser = ParseRules.new(@parse_tree)
end

def solve(character_set)
return false if character_set.length < 2
character_set.chars.each do |char|
if @stack.empty? && @closing_delimiters.include?(char)
return false
elsif @stack.empty? && @opening_delimiters.include?(char)
@stack.push(char)
elsif @delimiters.include?(char)
@parser.method(@stack[-1].to_sym).call(char, @stack)
end
end
@stack.empty? ? true : false
end
end
69 changes: 69 additions & 0 deletions balanced_delimiter/solutions/keppy_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

require 'minitest/autorun'

require_relative './keppy.rb'

class ParseRulesTest < MiniTest::Unit::TestCase
def setup
@parse_tree = [
{:state => "[", :possible_states => ["{", "(", "["], :close_this_state => "]"},
{:state => "{", :possible_states => ["{", "(", "["], :close_this_state => "}"},
{:state => "(", :possible_states => ["{", "(", "["], :close_this_state => ")"}
]
end

def test_parse_rules_with_existing_delim
# This is a stack that has seen an opening paren
stack = ["("]
parse_rules = ParseRules.new(@parse_tree)
parse_rules.method(:"(").call(")", stack)
assert_equal([], stack)
end

def test_parse_rules_with_wrong_match
stack = ["{"]
parse_rules = ParseRules.new(@parse_tree)
result = parse_rules.method(:"{").call(")", stack)
assert_equal(false, result)
end

def test_parse_rules_wrong_match_with_multiple_delims
stack = ["(", "{", "["]
parse_rules = ParseRules.new(@parse_tree)
result = parse_rules.method(:"[").call(")", stack)
assert_equal(false, result)
end

def test_parse_rules_correct_match_multiple_delims
stack = ["(", "{", "["]
expected_stack = ["(", "{"]
parse_rules = ParseRules.new(@parse_tree)
result = parse_rules.method(:"[").call("]", stack)
assert_equal(expected_stack, stack)
end

end

class StringParserTest < MiniTest::Unit::TestCase
def test_closing_delim
parser = StringParser.new
assert_equal(false, parser.solve("]"))
end

def test_open_delim
parser = StringParser.new
assert_equal(false, parser.solve("["))
end

def test_complicated_correct
parser = StringParser.new
chars = "()[]{}([{}])([]{})"
assert_equal(true, parser.solve(chars))
end

def test_complicated_incorrect
parser = StringParser.new
chars = "([)]([][])([})"
assert_equal(false, parser.solve(chars))
end
end