15-112 Spring 2016 Homework 10 (the last!)
Due never
Read these instructions first!
-
This hw is not submitted. We will review solutions in
lecture and/or recitation and/or midterm review sessions.
The material can appear on midterm2 or the final.
-
If you know what itertools are, don't use them to get around using recursion. If you don't know what itertools are, you may safely ignore this item.
-
Do not use global variables! Do use test functions! Do use helper functions!
-
You may use iteration (for + while loops) to solve rectangula, but only if you use recursion meaningfully.
- solveRectangula(board) [60 pts] [manually graded]
Background: first, watch this short video on how to play
the game of Rectangula:
Now, your task is to write the function solveRectangula(board).
This function takes a board which is a 2d list of integers
corresponding to the board you see in the video, where blank
cells contain 0's. Your function should return a solution
to that board, which consists of a list of rectangles (in any
order) such that:
- Every rectangle in your solution is on the board.
- No two rectangles in your solution overlap.
- Every non-zero number on the board is inside exactly one rectangle in your solution, and the area of that rectangle matches the number.
- And every rectangle in your solution contains exactly one number on the board.
One oddity is that your rectangles must be of the form (row0, col0, width, height), where (row0, col0) marks the top-left of the
rectangle (remember, rows increase vertically, cols increase horizontally), and
width is the total number of columns, and height is the total number
of rows (so width*height is the area of the rectangle).
If there is no possible solution, your function should return None.
We have provided a lot of code for you. This code is in the file
hw10_rectangula_tester.py.
You should place that code next to your hw10.py file. Do not include any code from rectangula-tester.py in your hw10.py file! Instead, include these lines in your hw10.py file, below the #ignore_rest line:
###############################################
# ignore_rest
###############################################
# Place these imports in hw10.py below the ignore_rest line!
from hw10_rectangula_tester import testSolveRectangula
from hw10_rectangula_tester import playRectangula
testSolveRectangula(solveRectangula)
playRectangula(solveRectangula)
Then, when you run your hw10.py file, you'll run the testSolveRectangula function and the playRectangula function
in rectangula-tester.py.
Remember: Do not include any code from rectangula-tester.py in your hw10.py file!
Now, how should you solve a Rectangula puzzle? You may do this any way you wish, so long as you use backtracking meaningfully. That said, here are some hints about how we did this in our sample solution:
Have fun!!!
- Gate class and subclasses [20 pts] [autograded]
Write the classes required to make the following test function work properly.
import types
def getLocalMethods(clss):
# This is a helper function for the test function below.
# It returns a sorted list of the names of the methods
# defined in a class.
result = [ ]
for var in clss.__dict__:
val = clss.__dict__[var]
if (isinstance(val, types.FunctionType)):
result.append(var)
return sorted(result)
def testGateClasses():
print("Testing Gate Classes... ", end="")
# require methods be written in appropriate classes
assert(getLocalMethods(Gate) == ['__init__', '__str__',
'numberOfInputs', 'setInput'])
assert(getLocalMethods(AndGate) == ['getOutput'])
assert(getLocalMethods(OrGate) == ['getOutput'])
assert(getLocalMethods(NotGate) == ['getOutput', 'numberOfInputs'])
# make a simple And gate
and1 = AndGate()
assert(type(and1) == AndGate)
assert(isinstance(and1, Gate) == True)
assert(and1.numberOfInputs() == 2)
and1.setInput(0, True)
and1.setInput(1, False)
# Hint: to get the name of the class given an object obj,
# you can do this: type(obj).__name__
# You might do this in the Gate.__str__ method...
assert(str(and1) == "And(True,False)")
assert(and1.getOutput() == False)
and1.setInput(1, True) # now both inputs are True
assert(and1.getOutput() == True)
assert(str(and1) == "And(True,True)")
# make a simple Or gate
or1 = OrGate()
assert(type(or1) == OrGate)
assert(isinstance(or1, Gate) == True)
assert(or1.numberOfInputs() == 2)
or1.setInput(0, False)
or1.setInput(1, False)
assert(or1.getOutput() == False)
assert(str(or1) == "Or(False,False)")
or1.setInput(1, True)
assert(or1.getOutput() == True)
assert(str(or1) == "Or(False,True)")
# make a simple Not gate
not1 = NotGate()
assert(type(not1) == NotGate)
assert(isinstance(not1, Gate) == True)
assert(not1.numberOfInputs() == 1)
not1.setInput(0, False)
assert(not1.getOutput() == True)
assert(str(not1) == "Not(False)")
not1.setInput(0, True)
assert(not1.getOutput() == False)
assert(str(not1) == "Not(True)")
print("Passed!")
testGateClasses()
- ComplexNumber class [20 pts] [autograded]
Write the ComplexNumber class to make the following test function work properly. Do not use the builtin complex numbers in Python, but rather only use integers.
def testComplexNumberClass():
print("Testing ComplexNumber class... ", end="")
# Do not use the builtin complex numbers in Python!
# Only use integers!
c1 = ComplexNumber(1, 2)
assert(str(c1) == "1+2i")
assert(c1.realPart() == 1)
assert(c1.imaginaryPart() == 2)
c2 = ComplexNumber(3)
assert(str(c2) == "3+0i") # default imaginary part is 0
assert(c2.realPart() == 3)
assert(c2.imaginaryPart() == 0)
c3 = ComplexNumber()
assert(str(c3) == "0+0i") # default real part is also 0
assert(c3.realPart() == 0)
assert(c3.imaginaryPart() == 0)
# Here we see that the constructor for a ComplexNumber
# can take another ComplexNumber, which it duplicates
c4 = ComplexNumber(c1)
assert(str(c4) == "1+2i")
assert(c4.realPart() == 1)
assert(c4.imaginaryPart() == 2)
assert((c1 == c4) == True)
assert((c1 == c2) == False)
assert((c1 == "Yikes!") == False) # don't crash here
assert((c2 == 3) == True)
s = set()
assert(c1 not in s)
s.add(c1)
assert(c1 in s)
assert(c4 in s)
assert(c2 not in s)
assert(ComplexNumber.getZero() == 0)
assert(isinstance(ComplexNumber.getZero(), ComplexNumber))
assert(ComplexNumber.getZero() == ComplexNumber())
# This next one is the tricky part -- there should be one and
# only one instance of ComplexNumber that is ever returned
# every time you call ComplexNumber.getZero():
assert(ComplexNumber.getZero() is ComplexNumber.getZero())
# Hint: you might want to store the singleton instance
# of the zero in a class attribute (which you should
# initialize to None in the class definition, and then
# update the first time you call getZero()).
print("Passed!")
testComplexNumberClass()
- No bonus!
Note that there is no bonus on hw10. This is to leave you plenty of time to study for midterm2 and to make some solid progres on your term projects. We hope this helps!