Commit 68528695be5a690d9614a33a9ea268e572784789

Authored by Miguel Barao
1 parent e831c259
Exists in master and in 1 other branch dev

- working! but crashes when topic has no questions

BUGS.md
1 1  
2 2 BUGS:
3 3  
  4 +- enter faz GET /question, que responde com json no ecran
4 5 - tabs em textarea nao funcionam correctamente (insere 1 espaco em vez de 4)
5 6 - reportar comentarios após submeter.
6 7 - os topicos locked devem estar inactivos no sidebar.
... ...
knowledge.py
... ... @@ -29,9 +29,6 @@ class Knowledge(object):
29 29 # compute recommended sequence of topics ['a', 'b',...]
30 30 self.topic_sequence = nx.topological_sort(self.depgraph)
31 31  
32   - print(self.topic_sequence)
33   - print(self.depgraph.edges())
34   -
35 32 # select a topic to do and initialize questions
36 33 self.start_topic()
37 34  
... ... @@ -40,29 +37,42 @@ class Knowledge(object):
40 37 # If all levels > 0.8, will stay in the last one forever...
41 38 # ------------------------------------------------------------------------
42 39 def start_topic(self, topic=''):
43   - print(f'knowledge.start_topic "{topic}"')
  40 + # unlock topics that have satisfied dependencies
  41 + unlock_topics = []
  42 + for t in self.topic_sequence:
  43 + if t not in self.state: # is locked
  44 + deps = self.depgraph.predecessors(t)
  45 + if all(d in self.state and self.state[d]['level'] > 0.01 for d in deps): # dependencies done
  46 + unlock_topics.append(t)
  47 +
  48 + for t in unlock_topics:
  49 + self.state[t] = {'level': 0.0, 'date': datetime.now()}
  50 + logger.info(f'User "{self.student}" unlocked "{t}"')
  51 +
  52 + # choose topic
44 53 if not topic:
45 54 for topic in self.topic_sequence:
46 55 unlocked = topic in self.state
47 56 needs_work = unlocked and self.state[topic]['level'] < 0.8
48 57 factory = self.depgraph.node[topic]['factory']
49   - print(f'{topic}, unlocked={unlocked}, needs_work={needs_work}')
50 58 if factory and (not unlocked or needs_work):
51 59 break
52   - # logger.info(f'{self.student} skipped topic "{topic}"')
  60 +
  61 + # use given topic if possible
53 62 else:
  63 + unlocked = topic in self.state
54 64 factory = self.depgraph.node[topic]['factory']
55   - # FIXME if factory is empty???
  65 + if not factory or not unlocked:
  66 + logger.debug(f'User "{self.student}" cannot start topic "{topic}"')
  67 + return
56 68  
57 69 self.current_topic = topic
58   - logger.info(f'User "{self.student}" topic = "{topic}"')
  70 + logger.info(f'User "{self.student}" topic set to "{topic}"')
59 71  
60 72 # generate question instances for current topic
61 73 questionlist = self.depgraph.node[topic]['questions']
62   - factory = self.depgraph.node[topic]['factory']
63 74 self.questions = [factory[qref].generate() for qref in questionlist]
64   -
65   - self.current_question = self.questions.pop(0)
  75 + self.current_question = self.questions.pop(0) # FIXME crashes if questions==[]
66 76 self.current_question['start_time'] = datetime.now()
67 77 self.finished_questions = []
68 78  
... ... @@ -78,14 +88,18 @@ class Knowledge(object):
78 88 # new question if answer is correct
79 89 if grade > 0.999:
80 90 self.finished_questions.append(q)
  91 + print('questions: ', self.questions)
  92 + print('finished: ', self.finished_questions)
81 93 try:
82 94 self.current_question = self.questions.pop(0) # FIXME empty?
83 95 except IndexError:
  96 + print('no more questions!')
84 97 self.current_question = None
85 98 self.state[self.current_topic] = {
86 99 'level': 1.0,
87 100 'date': datetime.now()
88 101 }
  102 + self.start_topic()
89 103 else:
90 104 self.current_question['start_time'] = datetime.now()
91 105 else:
... ... @@ -110,13 +124,23 @@ class Knowledge(object):
110 124 return self.current_topic
111 125  
112 126 # ------------------------------------------------------------------------
113   - def get_knowledge_state(self): # [('topic', 0.9), ...]
  127 + # Return list of tuples (topic, level).
  128 + # Levels are in the interval [0, 1] or None if the topic is locked.
  129 + # Topics unlocked but not yet done have level 0.0.
  130 + # Example: [('topic_A', 0.9), ('topic_B', None), ...]
  131 + # ------------------------------------------------------------------------
  132 + def get_knowledge_state(self):
114 133 ts = []
115 134 for t in self.topic_sequence:
116 135 if t in self.state:
117   - ts.append((t, self.state[t]['level']))
  136 + ts.append((t, self.state[t]['level'])) # already done
118 137 else:
119   - ts.append((t, 0.0))
  138 + # deps = self.depgraph.predecessors(t)
  139 + # # print(t, deps)
  140 + # if all(d in self.state for d in deps):
  141 + # ts.append((t, 0.0)) # unlocked not yet done
  142 + # else:
  143 + ts.append((t, None)) # locked
120 144 return ts
121 145  
122 146 # ------------------------------------------------------------------------
... ...
templates/learn.html
... ... @@ -168,6 +168,7 @@ function updateQuestion(response){
168 168 if (e.keyCode == 13 && e.shiftKey) {
169 169 e.preventDefault();
170 170 postQuestion();
  171 + return false;
171 172 }
172 173 });
173 174 $("textarea").keydown(function (e) {
... ... @@ -205,7 +206,6 @@ function updateQuestion(response){
205 206 case "finished_topic":
206 207 $('#topic_progress').css('width', '100%').attr('aria-valuenow', 100);
207 208 $("#topics").html(response["params"]["state"]);
208   -
209 209 $("#question_div").html('<img src="/static/trophy.png" alt="trophy" class="img-rounded img-responsive center-block">'); // FIXME size
210 210 break;
211 211 }
... ... @@ -228,7 +228,6 @@ function postQuestion() {
228 228 // Get current question
229 229 function getQuestion() {
230 230 $.ajax({
231   - // type: "GET",
232 231 url: "/question",
233 232 // headers: {"X-XSRFToken": token},
234 233 dataType: "json", // expected from server
... ...
templates/topics.html
... ... @@ -8,15 +8,30 @@
8 8 {% if t[0] == current_topic %}
9 9 <li class="active"> <!-- class="active" class="disabled" -->
10 10  
11   - <a href="#"> {{ gettopicname(t[0]) }}<br>
12   - {{ round(t[1]*5)*'<i class="fa fa-star text-success" aria-hidden="true"></i>' + round(5-t[1]*5)*'<i class="fa fa-star-o" aria-hidden="true"></i>' }}
  11 + <a href="#">
  12 + {{ gettopicname(t[0]) }}
  13 + </a>
  14 +
  15 + {% elif t[1] is None %}
  16 +
  17 + <li class="disabled">
  18 +
  19 + <a href="#">
  20 + {{ gettopicname(t[0]) }} <br>
  21 + <i class="fa fa-lock" aria-hidden="true"></i>
13 22 </a>
14 23  
15 24 {% else %}
16   - <li> <!-- class="active" class="disabled" -->
  25 + <li>
  26 +
  27 + <a href="/?topic={{ t[0] }}">
  28 + {{ gettopicname(t[0]) }} <br>
  29 + {% if t[1] < 0.01 %}
  30 + <i class="fa fa-unlock" aria-hidden="true"></i>
17 31  
18   - <a href="/?topic={{ t[0] }}"> {{ gettopicname(t[0]) }}<br>
19   - {{ round(t[1]*5)*'<i class="fa fa-star text-success" aria-hidden="true"></i>' + round(5-t[1]*5)*'<i class="fa fa-star-o" aria-hidden="true"></i>' }}
  32 + {% else %}
  33 + {{ round(t[1]*5)*'<i class="fa fa-star text-success" aria-hidden="true"></i>' + round(5-t[1]*5)*'<i class="fa fa-star-o" aria-hidden="true"></i>' }}
  34 + {% end %}
20 35 </a>
21 36  
22 37 {% end %}
... ...