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
edx
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.
...
@@ -28,74 +28,210 @@ values are (x,y) coordinates of centers of dragged images.
"""
"""
import
json
import
json
from
collections
import
OrderedDict
def
grade
(
user_input
,
correct_answer
):
class
PositionsCompare
(
list
):
'''
"""Inputs are: "abc" - target
Grade drag and drop problem.
[10, 20] - list of integers
If use_targets is True - checks if image placed on proper target.
[[10,20], 200] list of list and integer
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
"""
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:
#check if self or other is not empty list (empty lists = false)
if use_targets is True:
if
not
self
or
not
other
:
{'1': 't1', 'name_with_icon': 't2'}
return
False
else:
{'1': '[10, 10]', 'name_with_icon': '[[10, 10], 20]'}
Returns:
# check correct input types
True or False.
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'
]
):
def
__ne__
(
self
,
other
):
return
False
return
not
self
.
__eq__
(
other
)
def
is_equal
(
user_answer
,
correct_answer
):
def
coordinate_positions_compare
(
self
,
other
,
r
=
10
):
""" Checks if
user_answer is equal to correct_answer
inside radius
""" Checks if
pos1 is equal to pos2
inside radius
of forgiveness (default 10 px).
of forgiveness (default 10 px).
Args:
Args:
user_answer: [x, y] - list of floats;
self, other: [x, y] or [[x, y], r], where
correct_answer: [x, y] or [[x, y], r], where
r is radius of forgiveness;
r is radius of forgiveness;
x, y, r: int
Returns: bool.
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
return
False
r
=
10
return
True
if
isinstance
(
correct_answer
[
0
],
list
):
# [(x, y), r] case
r
=
correct_answer
[
1
]
corr_x
=
correct_answer
[
0
][
0
]
class
DragAndDrop
(
object
):
corr_y
=
correct_answer
[
0
][
1
]
else
:
# (x, y) case
def
__init__
(
self
):
corr_x
=
correct_answer
[
0
]
self
.
correct_groups
=
OrderedDict
()
# groups
corr_y
=
correct_answer
[
1
]
self
.
correct_positions
=
OrderedDict
()
# positions of comparing
self
.
user_groups
=
OrderedDict
()
if
((
user_answer
[
0
]
-
corr_x
)
**
2
+
self
.
user_positions
=
OrderedDict
()
(
user_answer
[
1
]
-
corr_y
)
**
2
)
>
r
*
r
:
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
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"
]:
# Check fo every group that positions of every group element are equal
is_equal
=
lambda
user
,
correct
:
user
==
correct
if
(
# with positions
isinstance
(
user
,
unicode
)
and
isinstance
(
correct
,
str
))
else
False
for
draggable
in
user_answer
[
'draggables'
]:
# 'denied' rule
user_img_location
=
draggable
.
values
()[
0
]
# import ipdb; ipdb.set_trace()
corr_img_location
=
correct_answer
.
get
(
draggable
.
keys
()[
0
],
None
)
denied_positions
=
[
self
.
correct_positions
[
g
]
.
get
(
'denied'
,
[])
if
not
corr_img_location
:
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
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
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