Skip to content

Commit

Permalink
Rectangles: sync expected test results and input data with problem-sp…
Browse files Browse the repository at this point in the history
…ecifications. (#1819)
  • Loading branch information
BethanyG authored and cmccandless committed Jun 11, 2019
1 parent 0aac011 commit 0a52d8e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 113 deletions.
108 changes: 53 additions & 55 deletions exercises/rectangles/example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import itertools


class corners(object):
class Corners(object):
def __init__(self, i, j):
# i, j are position of corner
self.i = i
Expand All @@ -13,38 +13,34 @@ def __str__(self):

# return corner on the same line
def same_line(index, list):
for c in list:
if c.i == index:
return c
for corner in list:
if corner.i == index:
return corner


# return corner on the same column
def same_col(index, list):
for c in list:
if c.j == index:
return c
for corner in list:
if corner.j == index:
return corner


def search_corners(input):
corner_list = []
for i in range(0, len(input)):
for j in range(0, len(input[i])):
if (input[i][j] == "+"):
corner_list.append(corners(i, j))
return corner_list

return [Corners(item, element) for item in range(len(input))
for element in range(len(input[item]))
if (input[item][element] == "+")]

# validate that 4 points form a
# rectangle by comparing distance to
# centroid of the rectangle for all corners

# validate that 4 points form a rectangle by
# comparing distance to centroid of the rectangle for all corners
def possible_rect(quartet):
mid_x = 0
mid_y = 0

# centroid
for c in quartet:
mid_x = mid_x + c.i / 4.0
mid_y = mid_y + c.j / 4.0
for centroid in quartet:
mid_x = mid_x + centroid.i / 4.0
mid_y = mid_y + centroid.j / 4.0

# reference distance using first corner
dx = abs(quartet[0].i - mid_x)
Expand All @@ -58,54 +54,56 @@ def possible_rect(quartet):


# validate path between two corners
def path(c1, c2, input):
if c1.i == c2.i:
for j in range(min(c1.j + 1, c2.j + 1), max(c1.j, c2.j)):
if input[c1.i][j] != "-" and input[c1.i][j] != "+":
def path(corner1, corner2, input):
if corner1.i == corner2.i:
for j in range(min(corner1.j + 1, corner2.j + 1),
max(corner1.j, corner2.j)):
if input[corner1.i][j] != "-" and input[corner1.i][j] != "+":
return False
return True
elif c1.j == c2.j:
for i in range(min(c1.i + 1, c2.i + 1), max(c1.i, c2.i)):
if input[i][c1.j] != "|" and input[i][c1.j] != "+":

elif corner1.j == corner2.j:
for i in range(min(corner1.i + 1, corner2.i + 1),
max(corner1.i, corner2.i)):
if input[i][corner1.j] != "|" and input[i][corner1.j] != "+":
return False
return True


# validate path of rectangle
def validate_rect(rect, input):
def validate_rect(rectangle, input):
# validate connection at every corner
# with neighbours on the same line and col
for i in range(0, len(rect)):
line = same_line(rect[i].i, rect[0:i] + rect[i + 1:])
column = same_col(rect[i].j, rect[0:i] + rect[i + 1:])
if not path(rect[i], line, input) or not path(rect[i], column, input):
for i in range(0, len(rectangle)):
line = same_line(rectangle[i].i, rectangle[0:i] + rectangle[i + 1:])
column = same_col(rectangle[i].j, rectangle[0:i] + rectangle[i + 1:])

if ((not path(rectangle[i], line, input)) or
(not path(rectangle[i], column, input))):
return False

return True


# count number of rectangles
# inside ASCII in input lines
def count(lines=""):
nb_rect = 0
# count number of rectangles inside ASCII in input lines
def rectangles(strings=""):
rectangle_total = 0
# test empty str
if lines == "":
return nb_rect
if not strings:
return rectangle_total

corners = search_corners(strings)

corners = search_corners(lines)
# no corners in str
if len(corners) == 0:
return nb_rect

# now let the magic begins
# all combinations of 4 corners (python ftw)
q = list(itertools.combinations(corners, r=4))
rectangles = []
for el in q:
if (possible_rect(el)):
rectangles.append(el)

# validate path in found rectangles
for rect in rectangles:
if (validate_rect(rect, lines)):
nb_rect = nb_rect + 1
return nb_rect
if not len(corners):
return rectangle_total

# all combinations of 4 corners
quartets = list(itertools.combinations(corners, r=4))
paths = (quartet for quartet in quartets if possible_rect(quartet))

# validate paths
for path in paths:
if validate_rect(path, strings):
rectangle_total += 1
return rectangle_total
2 changes: 1 addition & 1 deletion exercises/rectangles/rectangles.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
def count(ascii_diagram):
def rectangles(strings):
pass
114 changes: 57 additions & 57 deletions exercises/rectangles/rectangles_test.py
Original file line number Diff line number Diff line change
@@ -1,92 +1,92 @@
import unittest

from rectangles import count
from rectangles import rectangles


# Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0

class RectanglesTest(unittest.TestCase):
def test_no_rows(self):
self.assertEqual(count([]), 0)
self.assertEqual(rectangles([]), 0)

def test_no_columns(self):
self.assertEqual(count(['']), 0)
self.assertEqual(rectangles(['']), 0)

def test_no_rectangles(self):
self.assertEqual(count([' ']), 0)
self.assertEqual(rectangles([' ']), 0)

def test_one_rectangle(self):
lines = ['+-+',
'| |',
'+-+']
self.assertEqual(count(lines), 1)
strings = ['+-+',
'| |',
'+-+']
self.assertEqual(rectangles(strings), 1)

def test_two_rectangles_without_shared_parts(self):
lines = [' +-+',
' | |',
'+-+-+',
'| | ',
'+-+ ']
self.assertEqual(count(lines), 2)
strings = [' +-+',
' | |',
'+-+-+',
'| | ',
'+-+ ']
self.assertEqual(rectangles(strings), 2)

def test_five_rectangles_with_shared_parts(self):
lines = [' +-+',
' | |',
'+-+-+',
'| | |',
'+-+-+']
self.assertEqual(count(lines), 5)
strings = [' +-+',
' | |',
'+-+-+',
'| | |',
'+-+-+']
self.assertEqual(rectangles(strings), 5)

def test_rectangle_of_height_1_is_counted(self):
lines = ['+--+',
'+--+']
self.assertEqual(count(lines), 1)
strings = ['+--+',
'+--+']
self.assertEqual(rectangles(strings), 1)

def test_rectangle_of_width_1_is_counted(self):
lines = ['++',
'||',
'++']
self.assertEqual(count(lines), 1)
strings = ['++',
'||',
'++']
self.assertEqual(rectangles(strings), 1)

def test_1x1_square_is_counted(self):
lines = ['++',
'++']
self.assertEqual(count(lines), 1)
strings = ['++',
'++']
self.assertEqual(rectangles(strings), 1)

def test_only_complete_rectangles_are_counted(self):
lines = [' +-+',
' |',
'+-+-+',
'| | -',
'+-+-+']
self.assertEqual(count(lines), 1)
strings = [' +-+',
' |',
'+-+-+',
'| | -',
'+-+-+']
self.assertEqual(rectangles(strings), 1)

def test_rectangles_can_be_of_different_sizes(self):
lines = ['+------+----+',
'| | |',
'+---+--+ |',
'| | |',
'+---+-------+']
self.assertEqual(count(lines), 3)
strings = ['+------+----+',
'| | |',
'+---+--+ |',
'| | |',
'+---+-------+']
self.assertEqual(rectangles(strings), 3)

def test_corner_is_required_for_a_rectangle_to_be_complete(self):
lines = ['+------+----+',
'| | |',
'+------+ |',
'| | |',
'+---+-------+']
self.assertEqual(count(lines), 2)
strings = ['+------+----+',
'| | |',
'+------+ |',
'| | |',
'+---+-------+']
self.assertEqual(rectangles(strings), 2)

def test_large_input_with_many_rectangles(self):
lines = ['+---+--+----+',
'| +--+----+',
'+---+--+ |',
'| +--+----+',
'+---+--+--+-+',
'+---+--+--+-+',
'+------+ | |',
' +-+']
self.assertEqual(count(lines), 60)
strings = ['+---+--+----+',
'| +--+----+',
'+---+--+ |',
'| +--+----+',
'+---+--+--+-+',
'+---+--+--+-+',
'+------+ | |',
' +-+']
self.assertEqual(rectangles(strings), 60)


if __name__ == '__main__':
Expand Down

0 comments on commit 0a52d8e

Please sign in to comment.