From 8a9f429b6c126e00af8d5f2650d6c4d705917b6a Mon Sep 17 00:00:00 2001
From: Aleksander Sadikov <aleksander.sadikov@fri.uni-lj.si>
Date: Fri, 11 Mar 2016 19:58:03 +0100
Subject: Plans for conc/3 added. Order of hints in dup/2 corrected.

---
 prolog/problems/lists/conc_3/common.py | 43 +++++++++++++++++++++++-
 prolog/problems/lists/conc_3/sl.py     | 61 +++++++++++++++++++++++++++++++++-
 2 files changed, 102 insertions(+), 2 deletions(-)

(limited to 'prolog/problems/lists/conc_3')

diff --git a/prolog/problems/lists/conc_3/common.py b/prolog/problems/lists/conc_3/common.py
index 67f9481..ce81bbe 100644
--- a/prolog/problems/lists/conc_3/common.py
+++ b/prolog/problems/lists/conc_3/common.py
@@ -18,6 +18,15 @@ conc([H|T], L2, [H|L]) :-
   conc(T, L2, L).
 '''
 
+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'),
+    'timeout': Hint('timeout'),
+    'final_hint': Hint('final_hint'),
+}
+
 test_cases = [
     ('conc([j, b], [l], X)',
         [{'X': '[j, b, l]'}]),
@@ -46,8 +55,40 @@ 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):
-    # TODO
+    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'}]
+
+        # recursion is getting bigger and bigger
+
+
+        # missing/failed base case
+        if not prolog.engine.ask_truthTO(engine_id, 'memb(qq, [qq,_,_,_])'):
+            return [{'id': 'base_case'}]
+
+        # target predicate seems to always be false
+        if not prolog.engine.ask_truth(engine_id, 'memb(_, [_,_,_,_,_,_])'):
+            return [{'id': 'predicate_always_false'}]
+
+    except socket.timeout as ex:
+        return [{'id': 'timeout'}]
+
+    finally:
+        if engine_id:
+            prolog.engine.destroy(engine_id)
+
     return []
diff --git a/prolog/problems/lists/conc_3/sl.py b/prolog/problems/lists/conc_3/sl.py
index 0d5af8f..779b3ed 100644
--- a/prolog/problems/lists/conc_3/sl.py
+++ b/prolog/problems/lists/conc_3/sl.py
@@ -12,4 +12,63 @@ description = '''\
   X = [1,2,3].
 </pre>'''
 
-hint = {}
+plan = ['''\
+<p>Začnimo z enostavnim vprašanjem: kaj bi bil rezultat, če konkateniram prazen seznam in seznam <code>L2</code>?</p>
+''', '''\
+<p>Sedaj recimo, da ima prvi seznam točno en element. Začasno ga vzemimo stran, ostali smo s praznim prvim seznamom.
+Kaj ni ta situacija podobna oni od prej? Seveda, problem smo zmanjšali za en element in ga tako prevedli na manjši
+problem! Uporabimo rekurzijo za rešitev tega manjšega problema. A na koncu ne pozabimo rezultat rekurzije ustrezno
+dopolniti s prej odvzetim prvim elementom...</p>
+''', '''\
+<p>Deklarativno/logično razmišljanje: Recimo, da ima prvi seznam <code>L1</code> glavo <code>H</code> in rep
+<code>T</code>. Če je (rekurzivni) rezultat konkatenacije <code>T</code> in <code>L2</code> nek seznam
+<code>L3</code> in če seznamu <code>L3</code> na začetek dodam element <code>H</code>, kaj s tem dobim?
+Konkatenacijo seznamov <code>L1</code> in <code>L2</code>!</p>
+''']
+
+hint = {
+    'eq_instead_of_equ': '''\
+<p>Operator <code>==</code> je strožji od operatorja <code>=</code> v smislu, da je za slednjega dovolj,
+da elementa lahko naredi enaka (unifikacija). Morda z uporabo <code>=</code> narediš predikat
+<code>conc/3</code> delujoč tudi v kakšni drugi smeri.</p>
+<p>Seveda pa lahko nalogo rešiš brez obeh omenjenih operatorjev, spomni se, da lahko unifikacijo narediš
+implicitno že kar v argumentih predikata (glavi stavka).</p>
+''',
+
+    'eq_instead_of_equ_markup': '''\
+<p>Morda bi bil bolj primeren operator za unifikacijo (=)?</p>
+''',
+
+    'base_case': '''\
+<p>Si pomislil na robni pogoj? Kaj je najbolj enostaven primer?
+Kaj bi bil, recimo, rezultat, če je prvi seznam kar prazen?</p>
+''',
+
+    'predicate_always_false': '''\
+<p>Vse kaže, da tvoj predikat vedno vrne "false". Si mu dal pravilno ime, si se morda pri imenu zatipkal?</p>
+<p>Če je ime pravilno, se morda splača preveriti tudi, če se nisi zatipkal kje drugje,
+je morda kakšna pika namesto vejice ali obratno, morda kakšna spremenljivka z malo začetnico?</p>
+<p>Možno je seveda tudi, da so tvoji pogoji prestrogi ali celo nemogoči (kot bi bila npr. zahteva,
+da je <code>X</code> hkrati starš in sestra od <code>Y</code> ali kaj podobno zlobnega).</p>
+''',
+
+    '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?
+Morda npr. v rekurziji zmanjšuješ prvi seznam, ustaviš pa se pri praznem drugem seznamu (ali obratno)?</p>
+''',
+
+    'final_hint': '''\
+<p>Predikat <code>conc/3</code> bomo večinoma uporabljali za vse drugo kot samo za konkatenacijo dveh seznamov.
+Med drugim je uporaben "v obratni smeri" za delitev seznama na dva dela, poskusi naslednja vprašanja:</p>
+<p><code>?- conc(L1, L2, [a,b,c,d]).</code></p>
+<p><code>?- conc([X,Y], L2, [a,b,c,d,e,f]).</code></p>
+<p>Si opazil, da je drugo vprašanje v bistvu vrnilo prva dva elementa iz seznama <code>[a,b,c,d,e,f]</code>?</p>
+<p>Nadalje je <code>conc/3</code> uporaben za iskanje vzorcev v seznamu, npr. takole:</p>
+<p><code>?- conc(_, [X,X|_], [a,b,c,c,d,e,f,f,g,h,h]).</code></p>
+<p>Tako je, to vprašanje najde vse možnosti, kjer se dva elementa ponovita drug za drugim v seznamu (vzorec X,X).
+V bistvu smo rekli "nekaj poljubnih elementov (lahko tudi nič) je spredaj, potem sta dva enaka, potem pa spet nekaj
+poljubnih elementov (lahko nič) zadaj."
+Še veliko drugih koristi bo od <code>conc/3</code>, jih boš že še sproti spoznal.</p>
+''',
+}
-- 
cgit v1.2.1