Changeset e6822d100bdf…
Parent 934ac23a0313…
by Benjamin Pollack
Changes to 2 files · Browse files at e6822d100bdf Showing diff from parent 934ac23a0313 Diff from another changeset...
|
|
@@ -1,207 +1,231 @@ - import os
-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()
- if answer in ('y', 'yes', 'yeah', 'si'):
- return True
- elif answer in ('n', 'no', 'nope'):
- return False
- else:
- 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
- self.true_question = true_question
- 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:
- self.questioner.advance_no()
-
-
-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
-
- def question(self):
- """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:
- self.questioner.mark_failed()
-
-
-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)
- if self.last_branch == True:
- self.last_question.true_question = new_question
- else:
- 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
- else:
- 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 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)
- else:
- 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)
+import os
+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()
+ print ''
+ if answer in ('y', 'yes', 'yeah', 'si'):
+ return True
+ elif answer in ('n', 'no', 'nope'):
+ return False
+ else:
+ 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
+ self.true_question = true_question
+ 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:
+ self.questioner.advance_no()
+
+
+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
+
+ def question(self):
+ """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:
+ self.questioner.mark_failed()
+
+
+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)
+ if self.last_branch == True:
+ false_answer = self.last_question.true_question
+ new_question = Determiner(self, question, true_answer, false_answer)
+ self.last_question.true_question = new_question
+ else:
+ false_answer = self.last_question.false_question
+ new_question = Determiner(self, question, true_answer, false_answer)
+ 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
+ else:
+ 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 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 dump(self):
+ queue = [self.root]
+ level = 0
+ while queue:
+ newqueue = []
+ for q in queue:
+ print ' ' * level + q.question()
+ t, f = q.true_question, q.false_question
+ if t:
+ if isinstance(t, Thing):
+ print ' ' * (level + 1) + 'TRUE: %s' % t.what
+ else:
+ newqueue.append(t)
+ if f:
+ if isinstance(f, Thing):
+ print ' ' * (level + 1) + 'FALSE: %s' % f.what
+ else:
+ newqueue.append(f)
+ level += 1
+ queue = newqueue
+
+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)
+ else:
+ 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)
|
@@ -1,6 +1,7 @@ #!/usr/bin/env python
from brain import load, save
+from magic import tell_me_about, take_me_to, image_of
BRAIN_DB = 'brain.db'
@@ -8,6 +9,7 @@ while True:
print question,
answer = raw_input().strip().lower()
+ print ''
if answer in ('y', 'yes', 'yeah', 'si'):
return True
elif answer in ('n', 'no', 'nope'):
@@ -22,7 +24,8 @@ question = questioner.next_question()
question.ask()
if questioner.solved():
- print 'I got it!'
+ print 'I got it!\n'
+ print tell_me_about(question.what)
if ask('Play again? '):
questioner.start()
else:
|
Loading...