From 49bad83cafbddbf17984eb82030824b4d1e5c3b4 Mon Sep 17 00:00:00 2001 From: kimth Date: Sun, 28 Oct 2012 04:38:59 +0000 Subject: [PATCH] Support for multiple rectangle hitboxes in imageresponse --- common/lib/capa/capa/responsetypes.py | 38 ++++++++++--------- .../capa/tests/test_files/imageresponse.xml | 8 +++- .../lib/capa/capa/tests/test_responsetypes.py | 12 +++++- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 427067d523..648fc9e861 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1717,7 +1717,7 @@ class ImageResponse(LoncapaResponse): """ Handle student response for image input: the input is a click on an image, which produces an [x,y] coordinate pair. The click is correct if it falls - within a region specified. This region is nominally a rectangle. + within a region specified. This region is a union of rectangles. Lon-CAPA requires that each has a inside it. That doesn't make sense to me (Ike). Instead, let's have it such that @@ -1727,6 +1727,7 @@ class ImageResponse(LoncapaResponse): snippets = [{'snippet': ''' + '''}] response_tag = 'imageresponse' @@ -1743,20 +1744,10 @@ class ImageResponse(LoncapaResponse): for aid in self.answer_ids: # loop through IDs of fields in our stanza given = student_answers[aid] # this should be a string of the form '[x,y]' + correct_map.set(aid, 'incorrect') if not given: # No answer to parse. Mark as incorrect and move on - correct_map.set(aid, 'incorrect') continue - # parse expected answer - # TODO: Compile regexp on file load - m = re.match('[\(\[]([0-9]+),([0-9]+)[\)\]]-[\(\[]([0-9]+),([0-9]+)[\)\]]', - expectedset[aid].strip().replace(' ', '')) - if not m: - msg = 'Error in problem specification! cannot parse rectangle in %s' % ( - etree.tostring(self.ielements[aid], pretty_print=True)) - raise Exception('[capamodule.capa.responsetypes.imageinput] ' + msg) - (llx, lly, urx, ury) = [int(x) for x in m.groups()] - # parse given answer m = re.match('\[([0-9]+),([0-9]+)]', given.strip().replace(' ', '')) if not m: @@ -1764,11 +1755,24 @@ class ImageResponse(LoncapaResponse): 'error grading %s (input=%s)' % (aid, given)) (gx, gy) = [int(x) for x in m.groups()] - # answer is correct if (x,y) is within the specified rectangle - if (llx <= gx <= urx) and (lly <= gy <= ury): - correct_map.set(aid, 'correct') - else: - correct_map.set(aid, 'incorrect') + # Check whether given point lies in any of the solution rectangles + solution_rectangles = expectedset[aid].split(';') + for solution_rectangle in solution_rectangles: + # parse expected answer + # TODO: Compile regexp on file load + m = re.match('[\(\[]([0-9]+),([0-9]+)[\)\]]-[\(\[]([0-9]+),([0-9]+)[\)\]]', + solution_rectangle.strip().replace(' ', '')) + if not m: + msg = 'Error in problem specification! cannot parse rectangle in %s' % ( + etree.tostring(self.ielements[aid], pretty_print=True)) + raise Exception('[capamodule.capa.responsetypes.imageinput] ' + msg) + (llx, lly, urx, ury) = [int(x) for x in m.groups()] + + # answer is correct if (x,y) is within the specified rectangle + if (llx <= gx <= urx) and (lly <= gy <= ury): + correct_map.set(aid, 'correct') + break + return correct_map def get_answers(self): diff --git a/common/lib/capa/capa/tests/test_files/imageresponse.xml b/common/lib/capa/capa/tests/test_files/imageresponse.xml index 72bf06401a..34dba37e3b 100644 --- a/common/lib/capa/capa/tests/test_files/imageresponse.xml +++ b/common/lib/capa/capa/tests/test_files/imageresponse.xml @@ -8,8 +8,14 @@ Hello

Click on the image where the top skier will stop momentarily if the top skier starts from rest. Click on the image where the lower skier will stop momentarily if the lower skier starts from rest. + +Click on either of the two positions as discussed previously. + +Click on either of the two positions as discussed previously. + +Click on either of the two positions as discussed previously.

Use conservation of energy.

- \ No newline at end of file + diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index f2fa873080..bcac555b5e 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -53,12 +53,22 @@ class ImageResponseTest(unittest.TestCase): imageresponse_file = os.path.dirname(__file__) + "/test_files/imageresponse.xml" test_lcp = lcp.LoncapaProblem(open(imageresponse_file).read(), '1', system=test_system) correct_answers = {'1_2_1': '(490,11)-(556,98)', - '1_2_2': '(242,202)-(296,276)'} + '1_2_2': '(242,202)-(296,276)', + '1_2_3': '(490,11)-(556,98);(242,202)-(296,276)', + '1_2_4': '(490,11)-(556,98);(242,202)-(296,276)', + '1_2_5': '(490,11)-(556,98);(242,202)-(296,276)', + } test_answers = {'1_2_1': '[500,20]', '1_2_2': '[250,300]', + '1_2_3': '[500,20]', + '1_2_4': '[250,250]', + '1_2_5': '[10,10]', } self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_1'), 'correct') self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_2'), 'incorrect') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_3'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_4'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_5'), 'incorrect') class SymbolicResponseTest(unittest.TestCase):