Public » Miscellaneous » Twenty
Clone URL:  
Pushed to one repository · View In Graph Contained in tip

add lots of comments and clean some stuff up

Changeset 4079d777d3ba

Parent 59f8a41baee7

by Benjamin Pollack

Changes to one file · Browse files at 4079d777d3ba Showing diff from parent 59f8a41baee7 Diff from another changeset...

Change 1 of 8 Show Entire File brain.py Stacked
 
2
3
4
 
5
6
7
 
13
14
15
 
 
 
 
 
 
 
16
17
18
 
20
21
22
 
23
24
25
 
 
 
 
 
 
 
26
27
28
 
30
31
32
 
 
 
 
 
33
34
35
 
36
37
38
 
 
 
 
 
 
39
40
 
 
 
 
 
 
 
41
42
43
 
45
46
47
 
 
 
 
48
49
50
51
 
52
53
54
55
56
 
 
 
 
 
 
57
58
59
 
 
 
 
 
60
61
62
63
64
 
 
 
 
 
65
66
67
68
69
 
70
71
72
 
73
74
75
 
 
 
 
 
 
 
76
77
78
 
82
83
84
 
 
 
 
 
 
85
86
87
 
89
90
91
 
 
 
 
 
 
92
93
94
 
 
 
 
 
 
95
96
97
 
 
 
 
 
 
98
99
100
101
 
 
 
 
 
 
 
102
103
 
104
105
106
 
108
109
110
 
111
112
 
2
3
4
5
6
7
8
 
14
15
16
17
18
19
20
21
22
23
24
25
26
 
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
46
47
48
49
50
51
52
53
54
55
 
56
57
58
 
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 
145
146
147
148
149
150
151
152
153
154
155
156
 
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
 
188
189
190
191
192
193
194
195
196
197
198
199
200
 
202
203
204
205
206
207
@@ -2,6 +2,7 @@
 import pickle    def ask(question): + """ask a question, and return True if the answer yes, False otherwise"""   while True:   print question,   answer = raw_input().strip().lower() @@ -13,6 +14,13 @@
  print 'Please type "yes" or "no"'    class Determiner(object): + """represents a question that helps us narrow down possible answers + + Determiners need to know about their questioner, so they can let + the questioner know how things are going. They also have a + true_question and a false_question property that stores the next + thing to ask if the user says yes/no, respectively. + """   def __init__(self, questioner, question, true_question, false_question):   self.questioner = questioner   self._question = question @@ -20,9 +28,17 @@
  self.false_question = false_question     def question(self): + """returns the question as a string"""   return self._question     def ask(self): + """asks the user on the command line + + You can use Determiner.question() to grab the question text, + and manually call Questioner.advance_yes() or + Questioner.advance_no(), if you want to ask users questions in + other ways. This is here just for convenience. + """   if ask(self.question()):   self.questioner.advance_yes()   else: @@ -30,14 +46,31 @@
     class Thing(object): + """represents a concrete thing that might be the right answer + + For example, valid Things might be "a dog", "a cat", "Apollo 11", + and so on. + """   def __init__(self, questioner, what):   self.questioner = questioner - self._what = what + self.what = what     def question(self): - return 'Are you thinking of %s?' % self._what + """returns the question as a string + + This nicely formats things for you in the form of a question + so you don't have to. + """ + return 'Are you thinking of %s?' % self.what     def ask(self): + """asks the user on the command line + + You can use Determiner.question() to grab the question text, + and manually call Questioner.mark_failed() or + Questioner.mark_succeeded(), if you want to ask users + questions in other ways. This is here just for convenience. + """   if ask(self.question()):   self.questioner.mark_succeeded()   else: @@ -45,34 +78,64 @@
     class Questioner(object): + """holds all knowledge in the universe as a form of yes/no questions + + Take a look at Thing and Determiner to learn more about how this works. + """   def __init__(self, initial_question):   self.root = Determiner(self, initial_question, None, None)     def start(self): + """resets the questioner and starts a new game"""   self.current_question = self.root   self._solved = False   self._failed = False     def next_question(self): + """returns the next question that you should ask + + This will actually keep returning the same question until you + tell the questioner to continue by calling advance_yes, + advance_no, mark_succeeded, or mark_failed, as appropriate. + """   return self.current_question     def advance_yes(self): + """tell the Questioner that his last Determiner was answered yes + + If the last question asked was actually a Thing, use + mark_succeeded instead + """   self.last_branch = True   self.last_question = self.current_question   self.current_question = self.current_question.true_question     def advance_no(self): + """tell the Questioner that his last Determiner was answered no + + If the last question asked was actually a Thing, use + mark_failed instead + """   self.last_branch = False   self.last_question = self.current_question   self.current_question = self.current_question.false_question     def out_of_ideas(self): + """tell the user if we don't have any idea what they were thinking of"""   return self.current_question is None or self._failed     def solved(self): + """return True if we're all done"""   return self._solved     def learn_thing_and_question(self, question, thing): + """learn both a new thing and a question to distinguish it + + We use this when we had the right general idea, but not the + right answer, so that we can distinguish our best guess from + the right answer. You call this when needs_clarification was + True. + """   true_answer = Thing(self, thing)   false_answer = self.last_question.true_question   new_question = Determiner(self, question, true_answer, false_answer) @@ -82,6 +145,12 @@
  self.last_question.false_question = new_question     def learn_thing(self, thing): + """learn just a new thing + + You can call this if we just have no more ideas, but we didn't + ever actually guess anything. You call this if + needs_clarification was False. + """   new_thing = Thing(self, thing)   if self.last_branch == True:   self.last_question.true_question = new_thing @@ -89,18 +158,43 @@
  self.last_question.false_question = new_thing     def needs_clarification(self): + """tell the user whether we need a clarifying question + + This happens when we tried to guess something--i.e., we'd + asked all the questions we thought we had to ask, but we + didn't get to the answer. + """   return self.current_question is not None     def mark_succeeded(self): + """tell the Questioner they succeeded + + Once you call this, the Questioner assumes they got it, even + if they didn't, so don't call this unless the user's really + gotten the right answer. + """   self._solved = True     def mark_failed(self): + """tell the Questioner they failed + + Once you call this, the Questioner assumes they messed up, + even if they secretly actually really got it. Don't lie. + It's not nice. + """   self._failed = True     def best_guess(self): - return self.current_question.what + """return our best guess, if we had one + + This will only return something if we tried to guess a Thing. + Otherwise, it returns None. + """ + if isinstance(self.current_question, Thing): + return self.current_question.what    def load(path): + """load an existing Questioner from a database"""   if os.path.exists(path):   with open(path, 'rb') as f:   return pickle.load(f) @@ -108,5 +202,6 @@
  return Questioner('Does it have four legs?')    def save(path, questioner): + """save an existing Questioner to a database"""   with open(path, 'wb') as f:   pickle.dump(questioner, f, pickle.HIGHEST_PROTOCOL)