From a37c3602e0deaa6da902b1202325b80624e21724 Mon Sep 17 00:00:00 2001
From: Timotej Lazar <timotej.lazar@fri.uni-lj.si>
Date: Sun, 20 Mar 2016 17:13:12 +0100
Subject: Prolog: add triggers for palindrome/min/max hints

---
 prolog/problems/lists_advanced/max_2/common.py     | 42 +++++++++++++++++++---
 prolog/problems/lists_advanced/max_2/sl.py         | 24 +++++++++++++
 prolog/problems/lists_advanced/min_2/common.py     | 42 +++++++++++++++++++---
 prolog/problems/lists_advanced/min_2/sl.py         | 24 +++++++++++++
 .../problems/lists_advanced/palindrome_1/common.py | 31 ++++++++++++++--
 prolog/problems/lists_advanced/palindrome_1/sl.py  | 20 +++++++++++
 6 files changed, 172 insertions(+), 11 deletions(-)

(limited to 'prolog/problems')

diff --git a/prolog/problems/lists_advanced/max_2/common.py b/prolog/problems/lists_advanced/max_2/common.py
index 86f0e5a..35fe299 100644
--- a/prolog/problems/lists_advanced/max_2/common.py
+++ b/prolog/problems/lists_advanced/max_2/common.py
@@ -26,6 +26,12 @@ hint_type = {
     'base_case': Hint('base_case'),
     'recursive_case': Hint('recursive_case'),
     'timeout': Hint('timeout'),
+    'empty_list_base_case': Hint('empty_list_base_case'),
+    'list_instead_of_elem_base_case': Hint('list_instead_of_elem_base_case'),
+    'duplicates_not_covered': Hint('duplicates_not_covered'),
+    'args_not_instantiated': Hint('args_not_instantiated'),
+    'unprotected_branch': Hint('unprotected_branch'),
+    'one_branch_missing': Hint('one_branch_missing'),
 }
 
 test_cases = [
@@ -72,14 +78,42 @@ def hint(code, aux_code):
             return [{'id': 'eq_instead_of_equ_markup', 'start': m[0], 'end': m[1]} for m in marks] + \
                    [{'id': 'eq_instead_of_equ'}]
 
-        # missing/failed base case
-        if not prolog.engine.ask_truthTO(engine_id, 'max([-45], -45)'):
-            return [{'id': 'base_case'}]
-
         # target predicate seems to always be false
         if not prolog.engine.ask_truthTO(engine_id, 'max(_, _)'):
             return [{'id': 'predicate_always_false'}]
 
+        if prolog.engine.ask_truthTO(engine_id, 'max([], _)'):
+            return [{'id': 'empty_list_base_case'}]
+
+        if prolog.engine.ask_truthTO(engine_id, 'max([39], [39])'):
+            return [{'id': 'list_instead_of_elem_base_case'}]
+
+        if prolog.engine.ask_truthTO(engine_id,
+                'max([1, 3, 9], 9), max([3, 9, 27, 1], 27), \+ max([3, 3, 3], 3)'):
+            return [{'id': 'duplicates_not_covered'}]
+
+        reply, output = prolog.engine.ask(engine_id,
+                'max([1, 2, 2, 2, 3], 3), max([3, 2, 2, 2, 1], 3)', timeout=1)
+        if reply.get('code') == 'instantiation_error':
+            return [{'id': 'args_not_instantiated'}]
+
+        # TODO is the ! necessary here?
+        if prolog.engine.ask_truthTO(engine_id,
+                'findall(M, max([3, 5, 2, 4, 1], M), L), member(X, L), X < 5, !'):
+            return [{'id': 'unprotected_branch'}]
+
+        if prolog.engine.ask_truthTO(engine_id, '''\
+                max([1, 2, 3, 4, 5], 5),
+                \+ max([5, 4, 3, 2, 1], 5)
+                ;
+                \+ max([1, 2, 3, 4, 5], 5),
+                max([5, 4, 3, 2, 1], 5)'''):
+            return [{'id': 'one_branch_missing'}]
+
+        # missing/failed base case
+        if not prolog.engine.ask_truthTO(engine_id, 'max([-45], -45)'):
+            return [{'id': 'base_case'}]
+
         # 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, 'max([2, 41, -22], 41)'):
diff --git a/prolog/problems/lists_advanced/max_2/sl.py b/prolog/problems/lists_advanced/max_2/sl.py
index 86159aa..c335978 100644
--- a/prolog/problems/lists_advanced/max_2/sl.py
+++ b/prolog/problems/lists_advanced/max_2/sl.py
@@ -43,5 +43,29 @@ da je <code>X</code> hkrati starš in sestra od <code>Y</code> ali kaj podobno z
     'timeout': '''\
 <p>Je morda na delu potencialno neskončna rekurzija? Kako se bo ustavila?</p>
 <p>Morda pa je kriv tudi manjkajoč, neustrezen ali preprosto nekompatibilen (s splošnim primerom) robni pogoj?</p>
+''',
+
+    'empty_list_base_case': '''\
+<p>empty_list_base_case</p>
+''',
+
+    'list_instead_of_elem_base_case': '''\
+<p>list_instead_of_elem_base_case</p>
+''',
+
+    'duplicates_not_covered': '''\
+<p>duplicates_not_covered</p>
+''',
+
+    'args_not_instantiated': '''\
+<p>args_not_instantiated</p>
+''',
+
+    'unprotected_branch': '''\
+<p>unprotected_branch</p>
+''',
+
+    'one_branch_missing': '''\
+<p>one_branch_missing</p>
 ''',
 }
diff --git a/prolog/problems/lists_advanced/min_2/common.py b/prolog/problems/lists_advanced/min_2/common.py
index f2412fd..c9a697c 100644
--- a/prolog/problems/lists_advanced/min_2/common.py
+++ b/prolog/problems/lists_advanced/min_2/common.py
@@ -26,6 +26,12 @@ hint_type = {
     'base_case': Hint('base_case'),
     'recursive_case': Hint('recursive_case'),
     'timeout': Hint('timeout'),
+    'empty_list_base_case': Hint('empty_list_base_case'),
+    'list_instead_of_elem_base_case': Hint('list_instead_of_elem_base_case'),
+    'duplicates_not_covered': Hint('duplicates_not_covered'),
+    'args_not_instantiated': Hint('args_not_instantiated'),
+    'unprotected_branch': Hint('unprotected_branch'),
+    'one_branch_missing': Hint('one_branch_missing'),
 }
 
 test_cases = [
@@ -72,14 +78,42 @@ def hint(code, aux_code):
             return [{'id': 'eq_instead_of_equ_markup', 'start': m[0], 'end': m[1]} for m in marks] + \
                    [{'id': 'eq_instead_of_equ'}]
 
-        # missing/failed base case
-        if not prolog.engine.ask_truthTO(engine_id, 'min([-45], -45)'):
-            return [{'id': 'base_case'}]
-
         # target predicate seems to always be false
         if not prolog.engine.ask_truthTO(engine_id, 'min(_, _)'):
             return [{'id': 'predicate_always_false'}]
 
+        if prolog.engine.ask_truthTO(engine_id, 'min([], _)'):
+            return [{'id': 'empty_list_base_case'}]
+
+        if prolog.engine.ask_truthTO(engine_id, 'min([39], [39])'):
+            return [{'id': 'list_instead_of_elem_base_case'}]
+
+        if prolog.engine.ask_truthTO(engine_id,
+                'min([1, 3, 9], 1), min([3, 9, 27, 1], 1), \+ min([3, 3, 3], 3)'):
+            return [{'id': 'duplicates_not_covered'}]
+
+        reply, output = prolog.engine.ask(engine_id,
+                'min([1, 2, 2, 2, 3], 1), min([3, 2, 2, 2, 1], 1)', timeout=1)
+        if reply.get('code') == 'instantiation_error':
+            return [{'id': 'args_not_instantiated'}]
+
+        # TODO is the ! necessary here?
+        if prolog.engine.ask_truthTO(engine_id,
+                'findall(M, min([1, 5, 2, 4, 3], M), L), member(X, L), X > 1, !'):
+            return [{'id': 'unprotected_branch'}]
+
+        if prolog.engine.ask_truthTO(engine_id, '''\
+                min([1, 2, 3, 4, 5], 1),
+                \+ min([5, 4, 3, 2, 1], 1)
+                ;
+                \+ min([1, 2, 3, 4, 5], 1),
+                min([5, 4, 3, 2, 1], 1)'''):
+            return [{'id': 'one_branch_missing'}]
+
+        # missing/failed base case
+        if not prolog.engine.ask_truthTO(engine_id, 'min([-45], -45)'):
+            return [{'id': 'base_case'}]
+
         # 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, 'min([2, 41, -22], -22)'):
diff --git a/prolog/problems/lists_advanced/min_2/sl.py b/prolog/problems/lists_advanced/min_2/sl.py
index 38581d6..8f80e3f 100644
--- a/prolog/problems/lists_advanced/min_2/sl.py
+++ b/prolog/problems/lists_advanced/min_2/sl.py
@@ -43,5 +43,29 @@ da je <code>X</code> hkrati starš in sestra od <code>Y</code> ali kaj podobno z
     'timeout': '''\
 <p>Je morda na delu potencialno neskončna rekurzija? Kako se bo ustavila?</p>
 <p>Morda pa je kriv tudi manjkajoč, neustrezen ali preprosto nekompatibilen (s splošnim primerom) robni pogoj?</p>
+''',
+
+    'empty_list_base_case': '''\
+<p>empty_list_base_case</p>
+''',
+
+    'list_instead_of_elem_base_case': '''\
+<p>list_instead_of_elem_base_case</p>
+''',
+
+    'duplicates_not_covered': '''\
+<p>duplicates_not_covered</p>
+''',
+
+    'args_not_instantiated': '''\
+<p>args_not_instantiated</p>
+''',
+
+    'unprotected_branch': '''\
+<p>unprotected_branch</p>
+''',
+
+    'one_branch_missing': '''\
+<p>one_branch_missing</p>
 ''',
 }
diff --git a/prolog/problems/lists_advanced/palindrome_1/common.py b/prolog/problems/lists_advanced/palindrome_1/common.py
index 3d202b9..f1baf4e 100644
--- a/prolog/problems/lists_advanced/palindrome_1/common.py
+++ b/prolog/problems/lists_advanced/palindrome_1/common.py
@@ -28,6 +28,11 @@ hint_type = {
     'predicate_always_false': Hint('predicate_always_false'),
     'base_case': Hint('base_case'),
     'timeout': Hint('timeout'),
+    '[X,X]_instead_of_[]_base_case': Hint('[X,X]_instead_of_[]_base_case'),
+    'one_base_case_missing': Hint('one_base_case_missing'),
+    'arbitrary_base_case': Hint('arbitrary_base_case'),
+    'last_used': Hint('last_used'),
+    'final_hint': Hint('final_hint'),
 }
 
 test_cases = [
@@ -56,6 +61,8 @@ def test(code, aux_code):
             prolog.engine.destroy(engine_id)
 
     hints = [{'id': 'test_results', 'args': {'passed': n_correct, 'total': len(test_cases)}}]
+    if n_correct == len(test_cases):
+        hints += [{'id': 'final_hint'}]
     return n_correct, len(test_cases), hints
 
 def hint(code, aux_code):
@@ -72,14 +79,32 @@ def hint(code, aux_code):
             return [{'id': 'eq_instead_of_equ_markup', 'start': m[0], 'end': m[1]} for m in marks] + \
                    [{'id': 'eq_instead_of_equ'}]
 
-        # missing/failed base case
-        if not prolog.engine.ask_truthTO(engine_id, 'palindrome([])'):
-            return [{'id': 'base_case'}]
+        if prolog.engine.ask_truthTO(engine_id,
+                'palindrome([q, q]), \+ palindrome([]), \+ palindrome([q, a])'):
+            return [{'id': '[X,X]_instead_of_[]_base_case'}]
+
+        if prolog.engine.ask_truthTO(engine_id, '''\
+                palindrome([a, b, b, a]),
+                \+ palindrome([c, e, p, e, c])
+                ;
+                \+ palindrome([a, b, b, a]),
+                palindrome([c, e, p, e, c])'''):
+            return [{'id': 'one_base_case_missing'}]
+
+        if prolog.engine.ask_truthTO(engine_id, 'palindrome(kokos(1))'):
+            return [{'id': 'arbitrary_base_case'}]
+
+        if any(t.val == 'last' for t in tokens):
+            return [{'id': 'last_used'}]
 
         # target predicate seems to always be false
         if not prolog.engine.ask_truthTO(engine_id, 'palindrome(_)'):
             return [{'id': 'predicate_always_false'}]
 
+        # missing/failed base case
+        if not prolog.engine.ask_truthTO(engine_id, 'palindrome([])'):
+            return [{'id': 'base_case'}]
+
     except socket.timeout as ex:
         return [{'id': 'timeout'}]
 
diff --git a/prolog/problems/lists_advanced/palindrome_1/sl.py b/prolog/problems/lists_advanced/palindrome_1/sl.py
index 400ac6b..6f4a715 100644
--- a/prolog/problems/lists_advanced/palindrome_1/sl.py
+++ b/prolog/problems/lists_advanced/palindrome_1/sl.py
@@ -39,5 +39,25 @@ da je <code>X</code> hkrati starš in sestra od <code>Y</code> ali kaj podobno z
     'timeout': '''\
 <p>Je morda na delu potencialno neskončna rekurzija? Kako se bo ustavila?</p>
 <p>Morda pa je kriv tudi manjkajoč, neustrezen ali preprosto nekompatibilen (s splošnim primerom) robni pogoj?</p>
+''',
+
+    '[X,X]_instead_of_[]_base_case': '''\
+<p>[X,X]_instead_of_[]_base_case')</p>
+''',
+
+    'one_base_case_missing': '''\
+<p>one_base_case_missing</p>
+''',
+
+    'arbitrary_base_case': '''\
+<p>arbitrary_base_case</p>
+''',
+
+    'last_used': '''\
+<p>last_used</p>
+''',
+
+    'final_hint': '''\
+<p>final_hint</p>
 ''',
 }
-- 
cgit v1.2.1