Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
edx-platform
Commits
7ab13256
Commit
7ab13256
authored
Jan 02, 2013
by
Alexander Kryklia
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
extended grader
parent
744b7947
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
184 additions
and
48 deletions
+184
-48
common/lib/capa/capa/graders/draganddrop.py
+184
-48
No files found.
common/lib/capa/capa/graders/draganddrop.py
View file @
7ab13256
...
...
@@ -28,74 +28,210 @@ values are (x,y) coordinates of centers of dragged images.
"""
import
json
from
collections
import
OrderedDict
def
grade
(
user_input
,
correct_answer
):
'''
Grade drag and drop problem.
If use_targets is True - checks if image placed on proper target.
If use_targets is False - checks if image placed on proper coordinates,
with setted radius of forgiveness (default is 10)
Args:
user_input, correct_answer: json. Format:
class
PositionsCompare
(
list
):
"""Inputs are: "abc" - target
[10, 20] - list of integers
[[10,20], 200] list of list and integer
user_input: see module docstring
"""
def
__eq__
(
self
,
other
):
# Default lists behaviour is convers "abc" to ["a", "b", "c"].
# We will use that.
# import ipdb; ipdb.set_trace()
correct_answer:
if use_targets is True:
{'1': 't1', 'name_with_icon': 't2'}
else:
{'1': '[10, 10]', 'name_with_icon': '[[10, 10], 20]'}
#check if self or other is not empty list (empty lists = false)
if
not
self
or
not
other
:
return
False
Returns:
True or False.
'''
# check correct input types
if
(
not
isinstance
(
self
[
0
],
(
str
,
unicode
,
list
,
int
))
or
not
isinstance
(
other
[
0
],
(
str
,
unicode
,
list
,
int
))):
print
'Incorrect input type'
return
False
user_answer
=
json
.
loads
(
user_input
)
if
(
isinstance
(
self
[
0
],
(
list
,
int
))
and
isinstance
(
other
[
0
],
(
list
,
int
))):
print
'Numerical position compare'
return
self
.
coordinate_positions_compare
(
other
)
elif
(
isinstance
(
self
[
0
],
(
unicode
,
str
))
and
isinstance
(
other
[
0
],
(
unicode
,
str
))):
print
'Targets compare'
return
''
.
join
(
self
)
==
''
.
join
(
other
)
else
:
# we do not have ints or lists of lists or two string/unicode lists
# on both sides
print
type
(
self
[
0
]),
type
(
other
[
0
]),
"not correct"
return
False
if
len
(
correct_answer
.
keys
())
!=
len
(
user_answer
[
'draggables'
]
):
return
False
def
__ne__
(
self
,
other
):
return
not
self
.
__eq__
(
other
)
def
is_equal
(
user_answer
,
correct_answer
):
""" Checks if
user_answer is equal to correct_answer
inside radius
def
coordinate_positions_compare
(
self
,
other
,
r
=
10
):
""" Checks if
pos1 is equal to pos2
inside radius
of forgiveness (default 10 px).
Args:
user_answer: [x, y] - list of floats;
correct_answer: [x, y] or [[x, y], r], where
r is radius of forgiveness;
self, other: [x, y] or [[x, y], r], where
r is radius of forgiveness;
x, y, r: int
Returns: bool.
"""
if
not
isinstance
(
correct_answer
,
list
)
or
isinstance
(
user_answer
,
list
):
print
'I am called'
,
self
,
other
# get max radius of forgiveness
if
isinstance
(
self
[
0
],
list
):
# [(x, y), r] case
r
=
max
(
self
[
1
],
r
)
x1
,
y1
=
self
[
0
]
else
:
x1
,
y1
=
self
if
isinstance
(
other
[
0
],
list
):
# [(x, y), r] case
r
=
max
(
other
[
1
],
r
)
x2
,
y2
=
other
[
0
]
else
:
x2
,
y2
=
other
if
(
x2
-
x1
)
**
2
+
(
y2
-
y1
)
**
2
>
r
*
r
:
return
False
r
=
10
if
isinstance
(
correct_answer
[
0
],
list
):
# [(x, y), r] case
r
=
correct_answer
[
1
]
corr_x
=
correct_answer
[
0
][
0
]
corr_y
=
correct_answer
[
0
][
1
]
else
:
# (x, y) case
corr_x
=
correct_answer
[
0
]
corr_y
=
correct_answer
[
1
]
if
((
user_answer
[
0
]
-
corr_x
)
**
2
+
(
user_answer
[
1
]
-
corr_y
)
**
2
)
>
r
*
r
:
return
True
class
DragAndDrop
(
object
):
def
__init__
(
self
):
self
.
correct_groups
=
OrderedDict
()
# groups
self
.
correct_positions
=
OrderedDict
()
# positions of comparing
self
.
user_groups
=
OrderedDict
()
self
.
user_positions
=
OrderedDict
()
def
grade
(
self
):
'''
Grade drag and drop problem.
If use_targets is True - checks if image placed on proper target.
If use_targets is False - checks if image placed on proper coordinates,
with setted radius of forgiveness (default is 10)
Args:
user_input, correct_answer: json. Format:
user_input: see module docstring
correct_answer:
if use_targets is True:
{'1': 't1', 'name_with_icon': 't2'}
else:
{'1': '[10, 10]', 'name_with_icon': '[[10, 10], 20]'}
Returns:
True or False.
'''
if
sorted
(
self
.
correct_groups
.
keys
())
!=
sorted
(
self
.
user_groups
.
keys
()):
return
False
return
True
for
groupname
,
draggable_ids
in
self
.
correct_groups
.
items
():
if
sorted
(
draggable_ids
)
!=
sorted
(
self
.
user_groups
[
groupname
]):
return
False
# from now self.groups and self.user_groups are equal
assert
self
.
correct_groups
==
self
.
user_groups
if
user_answer
[
"use_targets"
]:
is_equal
=
lambda
user
,
correct
:
user
==
correct
if
(
isinstance
(
user
,
unicode
)
and
isinstance
(
correct
,
str
))
else
False
# Check fo every group that positions of every group element are equal
# with positions
for
draggable
in
user_answer
[
'draggables'
]:
user_img_location
=
draggable
.
values
()[
0
]
corr_img_location
=
correct_answer
.
get
(
draggable
.
keys
()[
0
],
None
)
if
not
corr_img_location
:
# 'denied' rule
# import ipdb; ipdb.set_trace()
denied_positions
=
[
self
.
correct_positions
[
g
]
.
get
(
'denied'
,
[])
for
g
in
self
.
correct_groups
.
keys
()]
all_user_positions
=
[
self
.
user_positions
[
g
][
'user'
]
for
g
in
self
.
correct_groups
.
keys
()]
if
not
self
.
compare_positions
(
denied_positions
,
all_user_positions
,
flag
=
'denied'
):
return
False
if
not
is_equal
(
user_img_location
,
corr_img_location
):
no_exact
,
no_allowed
=
False
,
False
# 'exact' rule
for
groupname
in
self
.
correct_groups
:
if
self
.
correct_positions
[
groupname
]
.
get
(
'exact'
,
[]):
if
not
self
.
compare_positions
(
self
.
correct_positions
[
groupname
][
'exact'
],
self
.
user_positions
[
groupname
][
'user'
],
flag
=
'exact'
):
return
False
else
:
no_exact
=
True
# 'allowed' rule
for
groupname
in
self
.
correct_groups
:
if
self
.
correct_positions
[
groupname
]
.
get
(
'allowed'
,
[]):
if
not
self
.
compare_positions
(
self
.
correct_positions
[
groupname
][
'allowed'
],
self
.
user_positions
[
groupname
][
'user'
],
flag
=
'allowed'
):
return
False
else
:
no_allowed
=
True
if
no_allowed
and
no_exact
:
return
False
return
True
return
True
def
compare_positions
(
self
,
list1
,
list2
,
flag
):
# import ipdb; ipdb.set_trace()
if
flag
==
'denied'
:
for
el1
in
list1
:
for
el2
in
list2
:
if
PositionsCompare
(
el1
)
==
PositionsCompare
(
el2
):
return
False
if
flag
==
'allowed'
:
for
el1
,
el2
in
zip
(
sorted
(
list1
),
sorted
(
list2
)):
if
PositionsCompare
(
el1
)
!=
PositionsCompare
(
el2
):
return
False
if
flag
==
'exact'
:
for
el1
,
el2
in
zip
(
list1
,
list2
):
if
PositionsCompare
(
el1
)
!=
PositionsCompare
(
el2
):
return
False
return
True
def
populate
(
self
,
correct_answer
,
user_answer
):
""" """
if
isinstance
(
correct_answer
,
dict
):
for
key
,
value
in
correct_answer
.
items
():
self
.
correct_groups
[
key
]
=
[
key
]
self
.
correct_positions
[
key
]
=
{
'exact'
:
[
value
]}
user_answer
=
json
.
loads
(
user_answer
)
self
.
use_targets
=
user_answer
.
get
(
'use_targets'
)
# create identical data structures
# user groups must mirror correct_groups
# and positions must reflect order in groups
for
groupname
in
self
.
correct_groups
:
self
.
user_groups
[
groupname
]
=
[]
self
.
user_positions
[
groupname
]
=
{
'user'
:
[]}
for
draggable_dict
in
user_answer
[
'draggables'
]:
# draggable_dict is 1-to-1 {draggable_name: position}
draggable_name
=
draggable_dict
.
keys
()[
0
]
if
draggable_name
in
self
.
correct_groups
[
groupname
]:
self
.
user_groups
[
groupname
]
.
append
(
draggable_name
)
self
.
user_positions
[
groupname
][
'user'
]
.
append
(
draggable_dict
[
draggable_name
])
# import ipdb; ipdb.set_trace()
def
grade
(
user_input
,
correct_answer
):
""" Support 2 interfaces"""
if
isinstance
(
correct_answer
,
dict
):
dnd
=
DragAndDrop
()
dnd
.
populate
(
correct_answer
=
correct_answer
,
user_answer
=
user_input
)
return
dnd
.
grade
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment