Changeset 4079d777d3ba…
Parent 59f8a41baee7…
by
Changes to one file · Browse files at 4079d777d3ba Showing diff from parent 59f8a41baee7 Diff from another changeset...
|
@@ -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)
|
Loading...