summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--monkey/action.py113
-rw-r--r--readme.md25
2 files changed, 75 insertions, 63 deletions
diff --git a/monkey/action.py b/monkey/action.py
index b8bbc40..8a1e477 100644
--- a/monkey/action.py
+++ b/monkey/action.py
@@ -17,32 +17,68 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Action:
- # type ∈ ['insert', 'remove', 'solve', 'solve_all', 'next', 'stop', 'test', 'hint']
- # time: absolute elapsed time since the attempt started, in ms
- # offset: position of the first inserted/removed character
- # text: inserted/removed text or query
- # total, passed: number of test cases
- def __init__(self, type, time, offset=0, text='', total=0, passed=0):
- self.type = type
- self.time = time
- if type in {'insert', 'remove'}:
- self.offset = offset
- self.length = len(text)
- self.text = text
- elif type in {'prolog_solve', 'solve_all'}:
- self.query = text
- elif type == 'test':
- self.total = total
- self.passed = passed
+ def __init__(self, abstime, data):
+ self.type = data['typ']
+ self.time = abstime # time from start
+
+ # generic actions
+ if self.type == 'open':
+ self.timestamp = data['time']
+ elif self.type == 'ins':
+ self.type = 'insert'
+ self.offset = data['off']
+ self.text = data['txt']
+ self.length = len(self.text)
+ elif self.type == 'rm':
+ self.type = 'remove'
+ self.offset = data['off']
+ self.text = data['txt']
+ self.length = len(self.text)
+ elif self.type == 'test':
+ self.feedback = data['feedback']
+ elif self.type == 'hint':
+ self.feedback = data['feedback']
+ elif self.type == 'hnt':
+ # obsolete Prolog hint action, with no additional info
+ self.type = 'hint'
+ self.feedback = None
+
+ # Prolog actions
+ elif self.type == 'prolog_solve':
+ self.query = data['query']
+ elif self.type == 'slva':
+ # obsolete Prolog "solve all" action
+ self.type = 'prolog_solve'
+ self.query = data['qry']
+
+ # Python actions
+ elif self.type == 'python_input':
+ self.text = data['txt']
+ elif self.type == 'python_run':
+ self.program = data['program']
+
+ # robot actions
+ elif self.type == 'robot_run':
+ self.program = data['program']
def __str__(self):
s = 't = ' + str(self.time/1000.0) + ' ' + self.type
if self.type in {'insert', 'remove'}:
s += ' "' + self.text.replace('\n', '\\n').replace('\t', '\\t') + '" at ' + str(self.offset)
- elif self.type in {'prolog_solve', 'solve_all'}:
- s += ' "' + self.query + '"'
elif self.type == 'test':
- s += ' {0} / {1}'.format(self.passed, self.total)
+ if self.feedback is not None:
+ for hint in self.feedback:
+ if hint['id'] == 'test_results':
+ args = hint['args']
+ s += ' {0} / {1}'.format(args['passed'], args['total'])
+ break
+ elif self.type == 'hint':
+ if self.feedback is not None:
+ s += ' ' + ', '.join(sorted([hint['id'] for hint in self.feedback]))
+ else:
+ s += ' ?'
+ elif self.type == 'prolog_solve':
+ s += ' "' + self.query + '"'
return s
# apply this action to text
@@ -63,16 +99,6 @@ class Action:
else:
return text
-_packet_action_map = {
- 'ins': lambda packet, time, code: Action('insert', time, offset=packet['off'], text=packet['txt']),
- 'rm': lambda packet, time, code: Action('remove', time, offset=packet['off'], text=packet['txt']),
- 'tst': lambda packet, time, code: Action('test', time, total=packet['tot'], passed=packet['pas']),
- 'hnt': lambda packet, time, code: Action('hint', time),
- 'slva': lambda packet, time, code: Action('solve_all', time, text=packet['qry']),
- 'prolog_solve': lambda packet, time, code: Action('prolog_solve', time, text=packet['query']),
- 'prolog_next': lambda packet, time, code: Action('next', time),
- 'prolog_end': lambda packet, time, code: Action('stop', time),
-}
# parse log from database into a list of actions, cleaning up some fluff.
# ignore non-text actions (queries and tests)
def parse(data):
@@ -87,7 +113,7 @@ def parse(data):
for packet in data:
try:
time += packet['dt']
- action = _packet_action_map[packet['typ']](packet, time, code)
+ action = Action(time, packet)
except:
# ignore any errors while decoding a packet
continue
@@ -112,7 +138,7 @@ def parse(data):
# replace current action with something better
length = action.length - prev.length
- new = Action('insert', prev.time, offset = prev.offset, text = action.text[:length])
+ new = Action(prev.time, {'typ': 'ins', 'off': prev.offset, 'txt': action.text[:length]})
actions.append(new)
code = new.apply(code)
@@ -127,25 +153,10 @@ def parse(data):
# replace current action with something better
length = prev.length - action.length
- new = Action('remove', prev.time, offset = prev.offset, text = prev.text[:length])
+ new = Action(prev.time, {'typ': 'rem', 'off': prev.offset, 'txt': prev.text[:length]})
actions.append(new)
code = new.apply(code)
- # discard INSERT/REMOVE pairs (typos)
- elif prev.type == 'insert' and action.type == 'remove' and \
- action.time - prev.time < 10000 and \
- action.offset == prev.offset and action.text == prev.text:
- # discard last and current actions
- code = prev.unapply(code)
- actions.pop()
-
- # discard REMOVE/INSERT pairs (deleted char then typed back)
- elif prev.type == 'remove' and action.type == 'insert' and \
- action.offset == prev.offset and action.text == prev.text:
- # discard last and current actions
- code = prev.unapply(code)
- actions.pop()
-
# otherwise, simply append the current action
else:
actions.append(action)
@@ -160,12 +171,14 @@ def expand(actions):
if actions[i].type == 'insert' and len(actions[i].text) > 1:
a = actions.pop(i)
for offset in range(len(a.text)):
- actions.insert(i+offset, Action('insert', a.time, a.offset+offset, a.text[offset]))
+ actions.insert(i+offset,
+ Action(a.time, {'typ': 'ins', 'off': a.offset+offset, 'txt': a.text[offset]}))
i += len(a.text)
elif actions[i].type == 'remove' and len(actions[i].text) > 1:
a = actions.pop(i)
for offset in range(len(a.text)):
- actions.insert(i, Action('remove', a.time, a.offset+offset, a.text[offset]))
+ actions.insert(i,
+ Action(a.time, {'typ': 'rm', 'off': a.offset+offset, 'txt': a.text[offset]}))
i += len(a.text)
else:
i += 1
diff --git a/readme.md b/readme.md
index 5e0053b..4abfbdb 100644
--- a/readme.md
+++ b/readme.md
@@ -159,18 +159,18 @@ Traces
Actions and corresponding additional attributes are specified here.
Generic:
- - open(time) # when opening the problem page, time = Date.now() on client
- - close() # when closing the problem page
- - ins(off, txt) # offset, text
- - rm(off, txt) # offset, text, was rm(off, len)
- - plan()
- - hint(feedback) # feedback = list of returned hint objects
- - test(feedback) # feedback = list of returned hint objects
+ - open(timestamp) # opened the problem page; timestamp = Date.now() on client
+ - close() # closed the problem page
+ - ins(off, txt) # inserted text; off = offset, txt = inserted characters
+ - rm(off, txt) # deleted text; off = offset, txt = deleted characters
+ - plan() # clicked "plan"
+ - hint(feedback) # clicked "hint"; feedback = list of returned hint objects
+ - test(feedback) # clicked "test"; feedback = list of returned hint objects
Prolog:
- - prolog_solve(query) # was slv(qry)
- - prolog_next() # was nxt
- - prolog_end() # was stp
+ - prolog_solve(query)
+ - prolog_next()
+ - prolog_end()
Python:
- python_run(program)
@@ -182,6 +182,5 @@ Robot:
- robot_stop()
Obsolete actions:
- - slva(qry) # "solve all" from tuProlog
- - hnt # hint button press
- - tst(tot, pas) # test results (total / passed)
+ - slva(qry) # "solve all" from tuProlog
+ - hnt # hint button press