from operator import itemgetter import socket import prolog.engine import prolog.util from server.hints import Hint import server.problems id = 97 number = 5 visible = True facts = 'family_relations' solution = '''\ brother(X, Y) :- parent(P, X), parent(P, Y), male(X), X \== Y. ''' hint_type = { 'x_must_be_male': Hint('x_must_be_male'), 'common_parent_needed': Hint('common_parent_needed'), 'y_can_be_of_any_gender': Hint('y_can_be_of_any_gender'), 'x_y_must_be_different': Hint('x_y_must_be_different'), 'neq_used_too_early': Hint('neq_used_too_early'), 'neq+_instead_of_neq': Hint('neq+_instead_of_neq'), 'predicate_always_false': Hint('predicate_always_false'), } test_cases = [ ('brother(X, _)', [{'X': 'alessandro'}, {'X': 'andrew'}, {'X': 'jeffrey'}, {'X': 'kramer'}, {'X': 'michael'}, {'X': 'william'}]), ('brother(andrew, X)', [{'X': 'melanie'}]), ('brother(X, sally)', [{'X': 'jeffrey'}, {'X': 'william'}]), ] 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) # use of \= or =\= instead of \== if prolog.util.Token('NEQU', '\=') in tokens or prolog.util.Token('NEQA', '=\=') in tokens: return [{'id': 'neq+_instead_of_neq'}] # target predicate seems to always be false if not prolog.engine.ask_truth(engine_id, 'brother(_, _)'): return [{'id': 'predicate_always_false'}] # X must be male if prolog.engine.ask_truth(engine_id, 'female(X), brother(X, _)'): return [{'id': 'x_must_be_male'}] # X and Y must have a common parent if prolog.engine.ask_truth(engine_id, 'brother(X, Y), \+ (parent(P, X), parent(P, Y))'): return [{'id': 'common_parent_needed'}] # Y can be of any gender, incl. female if prolog.engine.ask_truth(engine_id, 'brother(_, Y)') and \ prolog.engine.ask_one(engine_id, 'brother(_, Y), female(Y)') == 'false': return [{'id': 'y_can_be_of_any_gender'}] # X and Y must be different if prolog.util.Token('NEQ', '\==') not in tokens and prolog.engine.ask_truth(engine_id, 'setof(X, (member(X, [william, alessandro, andrew]), brother(X, X)), L), length(L, 3)'): return [{'id': 'x_y_must_be_different'}] # X and Y must be different, but \== was used if prolog.util.Token('NEQ', '\==') in tokens and prolog.engine.ask_truth(engine_id, 'setof(X/Y, brother(X, Y), L), member(alessandro/alessandro, L), member(andrew/andrew, L), member(william/william, L)'): return [{'id': 'neq_used_too_early'}] except socket.timeout as ex: pass finally: if engine_id: prolog.engine.destroy(engine_id) return []