Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Nsutton

macrumors member
Original poster
Dec 29, 2009
92
0
6 Feet Under
I'm writing a basic 20 question type game with if statements in python.

My problem is that it runs the intro (welcome blah blah) and then runs the varibles when the if statements should run.

Here's the code..

Code:
print "Welcome to 20 Questions! Think of a animal, vegetable mineral  and answer the 20 questions that follow."


catr= raw_input ("Is it a [a]nimal, [v]egetable, or a [m]ineral?")
animal1 = raw_input("Is it a farm animal? ([y]es or [n]o)")

if catr == 'a' :
	print animal1 

if animal1 == "y" :
	print ""

Is there like a way to store the variables information without printing it?
 
I'm not entirely sure about the meaning of your question.

But just note that this kind of question requires the encoding of rules and facts. Your best choice is going to be a special-purpose language such as CLIPS (which I can recommend). If you do want to write it in Python, you should encode your rules as data and write an engine to process this. This kind of information is best represented as a dynamic data structure rather than a syntax tree.
 
I'm not sure about your question either, but I think you want to re-order your statements. Each of your raw_input statements will be executed from top-to-bottom. You actually don't want to ask the 2nd question unless the answer to the first question was "a"nimal.

So you need to put your first if statement in between them. It should look more like this.

Code:
catr= raw_input ("Is it a [a]nimal, [v]egetable, or a [m]ineral?")
if catr == 'a' :
        animal1 = raw_input("Is it a farm animal? ([y]es or [n]o)")
        if animal1 == "y" :
                farm1 = raw_input("Is it a cow? ([y]es or [n]o)")
        else:   
                pet1= raw_input("Is it a pet? ([y]es or [n]o)")

I think you might be thinking that you need to put your variables (catr, animal1) at the beginning of your program, but Python doesn't require you to declare your variables. So you put them in your program whenever you need them. However, when running the program Python may complain when a variable is used(evaluated) before it has a value.
 
I'm writing a basic 20 question type game with if statements in python.

Are you writing this game as an exercise from a tutorial, or is it something you decided to do by yourself?

If it's not from a tutorial, then it looks to me like you don't yet have enough skill in the basics to be solving this problem. And I don't want to be discouraging, but your adventure game idea takes even more skill, even in the relatively simple version you outlined.

Lots of things seem simple because they can be easily imagined, like speaking to a computer and having it do stuff. That doesn't mean those things are simple to write programs for.

You need to learn the basics, and be successful at all the boring stuff, before you tackle the harder stuff. You don't learn how to fly in the real world by hopping into the cockpit of an F-18. It doesn't matter if you already know how to drive a car, or even if you can imagine how to drive a car and think it's easy.
 
You need to learn the basics, and be successful at all the boring stuff, before you tackle the harder stuff. You don't learn how to fly in the real world by hopping into the cockpit of an F-18. It doesn't matter if you already know how to drive a car, or even if you can imagine how to drive a car and think it's easy.

Yup. I'm going to go back to what I said in the other thread about the adventure game: the first step in writing a program is understanding the problem that you're trying to solve, and modelling it accordingly.

The first steps in learning to pilot an F-18 is to understand the problem at hand: you're trying to fly. You understand the physics of airflow and drag and lift, then you learn how a simple airplane works. There's always an engine, there's always wings, and flaps of some kind to control the air. Once you understand that it's easier to break down how an F-18 works.

OK, so 20 questions. What is the problem you are trying to solve? You are trying to determine one choice, out of many possible options, and you are doing so by asking questions. Each question has a yes or no answer, which rules out certain categories and helps narrow down the answer. Getting the answer to one question leads to the choice of the next question to ask.

So, a set of questions, hierarchically interconnected with other questions... does this sound familiar?

Yes, it's a tree! Each node is a question and each node links to two other questions. Until the very final questions, when the links can be the answers instead of more questions (it must be a chicken!).

So I would first start with a piece of paper and write down all the possible questions you plan to ask, and how they relate, and draw it out on paper.

Then I might write my program as a set of functions, each designed to tackle smaller sections of the tree. For example, your first question, "animal, vegetable, or mineral?" leads to 3 different categories of questions. So you could break it down like this:

(I'm writing this in "pseudo code", meaning it's not any particular language, but trying to give you a starting point to convert it into real code.)

Code:
program TwentyQuestions
{
   ask "Animal, Vegetable, Mineral?"
   if Animal:
      AskAnimalQuestions()
   else if Vegetable
      AskVegetableQuestions()
   else if Mineral
      AskMineralQuestions()

   exit
}

function AskAnimalQuestions
{
   ask "Is it a pet?"
   if Yes
      AskPetQuestions()
   else if No
      AskOtherAnimalQuestions()
}

function AskPetQuestions()
{
   ask "Does it bark?"
   if Yes
      print "Aha, it's a dog!"
   else if No
      print "Well, it must be a cat then!"
}
... you would write all of the other functions the same way.

Alternately you could write the whole thing as one gigantic IF.. THEN statement, but that would get VERY messy, and very repetitive, and become hard to understand, which is why I like to break it up into small pieces.
 
Hey Nsutton, I just realized I've responded to quite a few of your posts in the past few days, and I hope that I'm being helpful and not scaring you off or confusing you. I learned to program when I was around the same age as you so I've totally been there.

Just start small and work your way bigger and bigger!

Good luck and don't be afraid to ask questions!
 
Hey Nsutton, I just realized I've responded to quite a few of your posts in the past few days, and I hope that I'm being helpful and not scaring you off or confusing you. I learned to program when I was around the same age as you so I've totally been there.

Just start small and work your way bigger and bigger!

Good luck and don't be afraid to ask questions!

I dont take offense to people helping me. Im happy your even bothering to post! I totally understand i'm a noob at this and am open to help.

Also, thanks everyone, I got it working! you guys rock!
 
Then I might write my program as a set of functions, each designed to tackle smaller sections of the tree.

It might make more sense to write the program as outlined for the adventure game.

Each question corresponds to a single room. Each room/question has two exits: North (no) and South (yes), which lead to other rooms/questions. Then the game-engine/question-engine simply prints the question, gets the user's response, and follows either the yes or no path.

There's a bit more work because the engine must identify nodes that are answers ("It's a duck") from nodes that are additional questions, but that's not too hard to figure out. For example, if there are no paths (doors) out of the node (room), it's an answer instead of another question.

Also, the first node (animal, vegetable, mineral) has 3 paths leading out, but that's easy to handle, too. Make that one a simple question, and the user's choice selects the animal-tree, vegetable-tree, or mineral-tree of nodes.
 
It might make more sense to write the program as outlined for the adventure game.

Yeah, I thought about that, but I figured this might be a simpler way of explaining the process. Should I ever find myself teaching a data structures class, however, I think this could be a fun assignment. (I have given thought to becoming a teacher should I tire of the software development world). With such an engine complete, one could start having a lot of fun because the input data, assuming it's being read from a file, can now also be manipulated by the program itself...

I saw an example of this once, way back when, on the Apple ][. The computer had a basic set of questions and guesses (e.g. a minimal tree structure to start off with), and if it traversed to the end of a tree and got the answer wrong, it would have this conversation with you:

Computer: "Is it a duck?"
You: No
Computer: "Darn, I give up, what is it?"
You: Chicken
Computer: "And what question could I have asked to distinguish a duck from a chicken?"
You: "Does it swim?"

It would then turn the existing end node ("duck") into another question node. The more you played, the more it learned!
 
...
Computer: "Is it a duck?"
You: No
Computer: "Darn, I give up, what is it?"
You: Chicken
Computer: "And what question could I have asked to distinguish a duck from a chicken?"
You: "Does it swim?"

It would then turn the existing end node ("duck") into another question node. The more you played, the more it learned!

Funny, I was thinking of exactly the same program, but it wasn't on an Apple ][. It was a BASIC program listing in a book whose name I can't remember. The book had Hammurabi, Hunt the Wumpus, and other entertaining programs in it.

Anyway, I thought the similarity between the adventure game and 20 questions was worth noting. That's another important part of being a programmer: noticing similarities. "This X problem is like the Y program I solved before, only it's {simpler,more complex} and represents P's instead of Q's." In this case, the similarity is that the data is a mesh or graph of nodes and directed edges, and the program is a traversal program.
 
This kind of problem comes down to trying to represent a set of predicates (the equivalent to your yes/no questions).

Let's say that we have a world of three objects, let's call them X, Y and Z. We also have 5 predicates: P1, P2, P3, P4 and P5 (which are yes/no questions).

If we can describe the objects thus:


Code:
X satisfies P1, P3, P5
Y satisfies P2 and P4
Z satisfies P1, P2, P5

I.e. you could ask P1, P2, P3, P4, and P5 and from this know what the object is. You could just ask all 5 questions and from that know the object. But that's useless when you have thousands and thousands of predicates. "Five thousand questions" isn't much of a fun game to play.

If you assume that you know about every possible object that exists, you could cut this down a bit (you would only have to ask two correct questions to get Y).

If you represented this in a code tree, it might look like this:

Code:
If P1:
  If P3:
    If P5:
      => It's X
    Else:  # not p5
      => It's unknown
  Else: # not P3
    If P2:
      If P5:
        => It's Y
      Else: 3 not P5
        => It's unknown
    Else: 3 # not P2
Else: # not P1
  If P2:
    If P5:
      => It's Z
    Else: # not P5
      => It's unknown
  Else: not P2
    => It's unknown

You could simplify that a little if you took out the unknowns, but the point still stands.

Note that you're repeating yourself quite a lot. You have to put P5 in the code three times. Imagine the complexity for P6, P16 or P160.

This is because whilst some of the questions can lead on from another ("is it an animal? Is it a mammal?") others may be cross-cutting an unrelated. As such, you might find the same question in two branches of the code. And since it's a binary tree, complexity could get bad the worse case.

And imagine you wanted to extend your code. You might have to make changes in dozens if not hundreds of places. And such large nested conditional structures make mistakes easy. Even the above code is confusing to read, even when I put helpers in.

What you really want to do is represent predicates as above, as a list of objects and the predicates that must be fulfilled to decide that the object has been chosen.

These predicates are the real 'information'. The python code is just the way the game is implemented with this information. The information is a graph structure and you're trying to coerce it into a binary tree structure. It'll go, but it won't be pretty.

There are two classes of special-purpose languages (that I know of): backward chaining logic programming languages (for example Prolog) and forward chaining rule based systems (for example CLIPS). They work in very different ways, but are both centred around representing your knowledge in a natural way. The language runtime takes care of executing the code in a meaningful manner. Prolog has a very nice feature called back-tracking which means if you wrote a 20Q game it could go down one avenue of questioning, and if that failed, back-track up and try a different direction.

I used both these languages and they were the most fun of my computer science degree. I suggest you have a play with them. Get a feeling for logic programming. This will give you the mental framework to implement this in Python. It's certainly very doable. But a massive set of if statements really isn't the way to go. It really won't be much fun!

Good luck with it!
 
Code:
program TwentyQuestions
{
   ask "Animal, Vegetable, Mineral?"
   if Animal:
      AskAnimalQuestions()
   else if Vegetable
      AskVegetableQuestions()
   else if Mineral
      AskMineralQuestions()

   exit
}

function AskAnimalQuestions
{
   ask "Is it a pet?"
   if Yes
      AskPetQuestions()
   else if No
      AskOtherAnimalQuestions()
}

function AskPetQuestions()
{
   ask "Does it bark?"
   if Yes
      print "Aha, it's a dog!"
   else if No
      print "Well, it must be a cat then!"
}

Just a word about the above code from a maintainability perspective: the context of AskPetQuestions isn't formally encoded. You have no way of knowing the context under which it is called except by trusting the function that called it. You want to ensure that it's only been called if it's a pet. I could come along in a year's time, not quite understand the purpose of the function, and call it from a function called "Does it have wheels". Suddenly my bicycle which doesn't bark is a cat. You would need to somehow store the full context under which you expect the function to be called ... and hey presto you've just encoded your full rules for each object by another route.

This is a good reason why in these kinds of systems, the facts should be stored directly with the objects they describe somehow (I suggest as dynamic data, for example). If the code to ask questions can be generated from this data automatically, or can operate directly on the data, there's going to be much less head-banging.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.