from operator import itemgetter import socket import prolog.engine from server.hints import Hint, HintPopup id = 124 number = 50 visible = True facts = None solution = '''\ pivoting(_, [], [], []). pivoting(P, [H|T], [H|S], G) :- H =< P, pivoting(P, T, S, G). pivoting(P, [H|T], S, [H|G]) :- H > P, pivoting(P, T, S, G). ''' hint_type = { 'eq_instead_of_equ_markup': HintPopup('eq_instead_of_equ_markup'), 'eq_instead_of_equ': Hint('eq_instead_of_equ'), 'predicate_always_false': Hint('predicate_always_false'), 'base_case': Hint('base_case'), 'recursive_case': Hint('recursive_case'), 'timeout': Hint('timeout'), '>_and_<_mixed_up': Hint('>_and_<_mixed_up'), 'duplicates_not_considered': Hint('duplicates_not_considered'), 'all_elements_in_either_S_or_G': Hint('all_elements_in_either_S_or_G'), 'arbitrary_solution': Hint('arbitrary_solution'), 'unprotected_branch': Hint('unprotected_branch'), 'forcing_result_onto_recursion': Hint('forcing_result_onto_recursion'), 'no_recursion_in_one_branch': Hint('no_recursion_in_one_branch'), } test_cases = [ ('pivoting(5, [], A, B)', [{'A': '[]', 'B': '[]'}]), ('pivoting(5, [6, 7, 6], A, B), msort(B, BS)', [{'A': '[]', 'BS': '[6, 6, 7]'}]), ('pivoting(4, [2, 1, 8, 9, 3, 4, 2], A, B), msort(A, AS), msort(B, BS)', [{'AS': '[1, 2, 2, 3, 4]', 'BS': '[8, 9]'}]), ('pivoting(4, [22, 1, 0, 8, 3, 5, 7, -2], A, B), msort(A, AS), msort(B, BS)', [{'AS': '[-2, 0, 1, 3]', 'BS': '[5, 7, 8, 22]'}]), ] def test(code, aux_code): n_correct = 0 engine_id = None try: engine_id, output = prolog.engine.create(code=code+aux_code, timeout=1.0) if engine_id is not None and 'error' not in map(itemgetter(0), output): # Engine successfully created, and no syntax error in program. for query, answers in test_cases: if prolog.engine.check_answers(engine_id, query=query, answers=answers, timeout=1.0): n_correct += 1 except socket.timeout: pass finally: if engine_id: prolog.engine.destroy(engine_id) hints = [{'id': 'test_results', 'args': {'passed': n_correct, 'total': len(test_cases)}}] return n_correct, len(test_cases), hints def hint(code, aux_code): tokens = prolog.util.tokenize(code) try: engine_id, output = prolog.engine.create(code=code+aux_code, timeout=1.0) # strict equality testing instead of simple matching # this is usually (but not necessarily) wrong targets = [prolog.util.Token('EQ', '==')] marks = [(t.pos, t.pos + len(t.val)) for t in tokens if t in targets] if marks: return [{'id': 'eq_instead_of_equ_markup', 'start': m[0], 'end': m[1]} for m in marks] + \ [{'id': 'eq_instead_of_equ'}] if prolog.engine.ask_truthTO(engine_id, '''\ pivoting(4, [3, 5, 9, 6, 3, 7, 2], A, B), msort(A, [5, 6, 7, 9]), msort(B, [2, 3, 3])'''): return [{'id': '>_and_<_mixed_up'}] if prolog.engine.ask_truthTO(engine_id, '''\ pivoting(4, [2, 1, 3], [2, 1, 3], []), pivoting(4, [3, 5, 9, 5, 2], [3 | yowza], [5 | brix]) ; pivoting(4, [6, 5, 7], [], [6, 5, 7]), pivoting(4, [3, 5, 9, 5, 2], [3 | yowza], [5 | brix])'''): return [{'id': 'no_recursion_in_one_branch'}] if prolog.engine.ask_truthTO(engine_id, '''\ pivoting(4, [3, 5, 9, 6, 3, 7, 2], [3, 3, 2], [5, 9, 6, 7]), findall(q, pivoting(4, [3, 5, 9, 6, 3, 7, 2], _, _), [q, q | _])'''): return [{'id': 'unprotected_branch'}] if prolog.engine.ask_truthTO(engine_id, '''\ pivoting(4, [3, 5, 9, 5, 2], [3, 2], [5, 9, 5]), \+ pivoting(4, [3, 5, 4, 5, 2], _, _)'''): return [{'id': 'duplicates_not_considered'}] if prolog.engine.ask_truthTO(engine_id, '''\ pivoting(4, [5, 3], _, [5|yowza]) ; pivoting(4, [3, 5], [3|yowza], _)'''): return [{'id': 'arbitrary_solution'}] if prolog.engine.ask_truthTO(engine_id, 'pivoting(4, [3, 5, 9, 5, 2], S, G), (S = [] ; G = [])'): return [{'id': 'all_elements_in_either_S_or_G'}] if prolog.engine.ask_truthTO(engine_id, '''\ \+ pivoting(4, [3, 5], _, _), (asserta(pivoting(4, [5], [3, 5], [yowza])), pivoting(4, [3, 5], [5], [yowza]), retract(pivoting(4, [5], [3, 5], [yowza])) ; asserta(pivoting(4, [3], [yowza], [5, 3])), pivoting(4, [5, 3], [yowza], [3]), retract(pivoting(4, [3], [yowza], [5, 3])))'''): return [{'id': 'forcing_result_onto_recursion'}] # missing/failed base case if not prolog.engine.ask_truthTO(engine_id, 'pivoting(_, [], [], [])'): return [{'id': 'base_case'}] # target predicate seems to always be false if not prolog.engine.ask_truthTO(engine_id, 'pivoting(_, _, _, _)'): return [{'id': 'predicate_always_false'}] # base case works, the recursive doesn't (but it doesn't timeout) # this may be left as the last, most generic hint if not prolog.engine.ask_truth(engine_id, 'pivoting(4, [2, 1, 8, 9, 3, 4, 2], [2, 1, 3, 4, 2], [8, 9])'): return [{'id': 'recursive_case'}] except socket.timeout as ex: return [{'id': 'timeout'}] finally: if engine_id: prolog.engine.destroy(engine_id) return []