So I'm trying to make a simple text based game from scratch, and I'm running into a problem right away. I'm trying to create a class for events that will happen in-game to make writing the code easier. Here's what I mean:
class event(object):
def __init__(self, text, trigger1, trigger2, outcome1, outcome2):
print(text)
time.sleep(1)
choice= input("What will you do?")
if choice == trigger1:
(Somehow execute outcome 1)
if choice == trigger2:
(Somehow execute outcome 2)
but I don't know how to make the outcomes contain code that I will write later, so any help would be appreciated!
The pythonic way is to use a dictionary with function objects:
def outcome1():
print("Outcome 1")
def outcome2():
print("Outcome 2")
def event(text, triggers):
print(text)
time.sleep(1)
choice= input("What will you do?")
triggers[choice]()
event("You can got west or east.", {
"go west": outcome1,
"go east": outcome2,
})
I do hope I'm understanding your question appropriately, so feel free to correct me if this isn't on target.
When you create a new instance of the class Event (and it's convention to capitalize the first character of classes). Assign a function to the value of outcome1 and outcome2, which will be executed according to their respective triggers.
def outcomeFunction1():
#Whatever you'd like to do for first outcome
print("Hello")
def outcomeFunction2():
#Whatever you'd like to do for second outcome
print("Bye")
Event('text', 'trigger1', 'trigger2', outcomeFunction1(), outcomeFunction2())
In your class definition write:
if choice == trigger1:
outcome1
elif choice == trigger2:
outcome2
Hope this helps!
Why is this in init? Are you really going to create new instance on every new event? To your question, if I got your question correctly, then this is code you may want to have.
def outcome1(text):
print("outcome1: %s" % text)
def outcome2(text):
print ("outcome2: %s" % text)
trigger_map = {
trigger1 : outcome1,
trigger2 : outcome2,
}
class event(object):
def __init__(self, trigger_map):
sefl._tmap = trigger_map
def onEvent (self, text):
print(text)
time.sleep(1)
choice= input("What will you do?")
return self._tmap [choice] (text)
Sorry if I misunderstood your question, but here I go...
The answer here depends on whether you want to have to make a new instance for every event. If you do, the code might look something like this (and as Jeremy E. pointed out, it's a good idea to capitalize the first character of classes):
class Event:
def __init__(self, text, question, trigger1, trigger2, outcome1, outcome2):
self.text, self.question = text, question
self.trigger1, self.trigger2 = trigger1, trigger2
self.outcome1, self.outcome2 = outcome1, outcome2
def get_choice(self):
print(self.text)
self.choice = input(self.question)
def execute(self):
if self.choice == self.trigger1:
exec(self.outcome1)
if self.choice == self.trigger2:
exec(self.outcome2)
I used the exec function to execute the outcomes. I moved some of the code to different functions, leaving the __init__ function to save the variables for the other functions. Then, you can make an instance for each event, like this:
room = Event("You are in a room with exits to the north and east.", "Where will you go?", "north", "east", "print('You went north.')", "print('You went east.'")
Notice I also added a question parameter, as to not force the What will you do? question on every event.
Now, if you wanted to only need one instance of the Event class, the code is a bit different:
class Event:
def make_event(self, text, question, trigger1, trigger2, outcome1, outcome2):
print(text)
choice = input(question)
if choice == trigger1:
exec(outcome1)
if choice == trigger2:
exec(outcome2)
You can see that the code is much shorter. To create an event with this, you would do something like this (with the same example as before):
event = Event() # This is only needed once, at the start of the program
event.make_event("You are in a room with exits to the north and east.", "Where will you go?", "north", "east", "print('You went north.')", "print('You went east.')")
EDIT: You may want to remove the class definition entirely, leaving just the make_event function I wrote for you above.
You can choose between either of these class examples, or use their ideas to make a customized one. I hope I answered your question.
Related
I am currently making a program with a text based menu, and I was wondering if there was anyway to avoid an excessive amount of if-statements while keeping it object oriented. I thought of something like this:
class Options:
def displayOptions():
#display user options
def option1():
#do option 1
def option2():
#do option 2
def option3():
#do option 3 and so on
class Menu(Options):
options = {1: option1(), 2: option2(), 3: option3()} #and so on
def promptUser():
#prompts user to make a choice
def printHeader():
#prints header
def handleInput():
#checks if input is valid
def begin():
#initialize menu
Would something like this be convoluted? Is the Options class pointless? I'm pretty new to OOP and I was wondering how this would most efficiently be done.
This is a bit hacky but it gets the job done.
class Options:
def doOption(self, opt):
option = f'option{opt}'
func = type(self).__dict__.get(option)
if hasattr(func, '__call__'):
return func(self)
raise ValueError(f'Unsupported option: {opt}')
class Menu(Options):
def option1(self):
print('Foo!')
def option2(self):
print('Bar!')
def optionbang(self):
print('Bang!')
menu = Menu()
menu.doOption(1) # Foo!
menu.doOption(2) # Bar!
menu.doOption('bang') # Bang!
What this does is look through the the class' properties and try to find a function (i.e., hasattr(func, '__call__')) with the right name. The nice thing is that the logic doesn't even require opt to be an integer.
That being said, if this is your only use case, then I agree with #GradyPlayer in the comments that the abstraction probably isn't worth it.
I am trying to implement the switch in Dictionary in Python. But when I call the method
chooices.get(x, "Ther is no program") It call all the Function in the statment rather than calling x function.
I have read this implementation
Replacements for switch statement in Python?
but it was not helpful in my case as my function has print statement
Main file contain the code
from Day1.Day1 import Day1
from Day2.TipCalculator import TipCalculator
def choose():
print("Choose From the following Program:\n")
day1 = Day1()
day1.day1()
day2 = TipCalculator()
day2.day2()
x = int(input());
chooices={
1: day1.program1(),
2: day2.program1(),
}
chooices.get(x, "Ther is no program")
choose()
Day1 Class contain code
class Day1:
def day1(self):
print('1. Band name Generator\n')
def program1(self):
print('Welcome to Band Name Generator.\n')
cityName=input('What\'s is the name of city you grew up?\n')
petName = input('What\'s your pet\'s name?\n')
print('Your Band Name could be : '+cityName+" "+petName)
Class Tip Calculator Code
class TipCalculator:
def day2(self):
print("2. Tip Calculator For Bill.\n")
def program1(self):
print('Welcome to tip calculator.\n')
I just need the implementation Of switch statement which call Requested Program just like switch. I know Its possible through If-else but Dictionary mapping seems too be good alternative of switch
Overview: the interpretor creates a closure for the variables that the child function uses that are non local. In this example the child variable, value is 22 and stored in the closure cell.
def parent(arg_1, arg_2):
value=22
my_dict = {'chocolate':'yummy'}
def child():
print(2*value)
print(my['chocolate'])
print(arg_1 + arg_2)
return child
new_function=parent(3,4)
print(cell.cell_contents for cell in new_function.__closure__])
If you don't have a lot of variants, the if/elif/else statements can be streamlined using a helper function for the switch. This is only syntactic candy but it may be sufficient for small value sets.
def switch(v): yield lambda *c: v in c
Example usage:
x = int(input())
for case in switch(x):
if case(1): day1.program1()
elif case(2): day2.program1()
else: print("there is no program")
supporting multiple values for the same method call:
x = int(input())
for case in switch(x):
if case(1,5): day1.program1()
elif case(2,3,4): day2.program1()
else: print("there is no program")
you can also use it in a more C-like style
x = int(input())
for case in switch(x):
if case(1,5):
day1.program1()
break
if case(2,3,4):
day2.program1()
break
else:
print("there is no program")
If you have python 3.10 or higher, a proper switch analogue was implmemented called "match" which should work quite well in replacing any nested if statments the other answers may have.
If you dont have 3.10, and you are okay with a pretty hacky solution, mine uses the ideas from withhacks (specifically from AnonymousBlocksInPython). I have recently created my own version of a switch statment in python that acts more like how i am used to in C#. You can expand this as much as you want, way past single line arguments or assignments.
It uses context managers so that you can treat each case as its own code block with indentation and all. It will never enter the cases if the case value does not match the switch value so for code that is extremely system taxing, you can be sure it is not running code that does not need to be.
import sys
class CaseReturn(Exception):pass
class Case:
def __init__(self, caseVal): self._caseVal_ = caseVal
def _trace_(self,frame,event,arg): raise CaseReturn
def __enter__(self):
if self._caseVal_ == Switch._singleton_._switch_: return
sys.settrace(lambda *args, **keys: None)
sys._getframe(1).f_trace= self._trace_
def __exit__(self,ExType,ExVal,ExTrace):
if ExType is None: raise CaseReturn
return ExType is CaseReturn
class Switch:
_singleton_:'Switch' = None
def __init__(self, switchVal,Default=None): self._switch_ = switchVal
def __enter__(self):Switch._singleton_ = self
def __exit__(self,ExType,ExVal,ExTrace):
Switch._singleton_ = None
return ExType is CaseReturn
with Switch(2):
with Case(1):
print('This should not make it')
with Case(2):
print('I made it')
with Case(3):
print('This should never be called')
You can easily extend this out to check multiple cases by just changing the caseVal to a list and doing if Switch._singleton_._switch_ in self._caseVal_:
One caveat is, you cannot make the Case statments one-liners like:
Case(0): print('I am one line')
That will not work and end up calling the code in that case no matter what.
I hope this is useful to you or anyone who is searching for custom Switch statments!
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
My understanding of python is zero to none... Been exhausting myself reading what seems like a hundred different ways to approach this. Below I put the assignment description and my code... As of now I am having trouble using the 'getAnimal()' command. I'm not sure what it does or how it works. Thanks in advance :D
Assignment description: "Write a class definition for a class 'Zoo.' It should have instance variables for animal type, herbivore/carnivore/omnivore, and inside/outside. It should also have a getAnimal() method to show the animals information. Write a separate "ZooDriver" class to a) create three instances of zoo animals, b) get user input on which animal to view (1,2,3)c) show the animal info suing getAnimal()."
~~~~~~~~ My code:
class Zoo:
def __init__(self, animal, animal_type, habitat):
self.animal = animal
self.animal_type = animal_type
self.habitat = habitat
user_input=raw_input("Enter the number 1, 2, or 3 for information on an animal.")
if user_input == "1":
my_animal = Zoo("Giraffe", "herbivore", "outside")
elif user_input == "2":
my_animal = Zoo("Lion", "carnivore", "inside")
elif user_input == "3":
my_animal = Zoo("Bear", "omnivore", "inside")
print "Your animal is a %s, it is a %s, and has an %s habitat." % (my_animal.animal, my_animal.animal_type, my_animal.habitat)
A class defines a type of thing. An instance is one thing of that type. For example, you could say Building is a type of thing.
Let's start with a class named Building:
class Building():
pass
Now, to create an actual building -- an instance -- we call it almost like it was a function:
b1 = Building()
b2 = Building()
b3 = Building()
There, we just created three buildings. They are identical, which isn't very useful. Maybe we can give it a name when we create it, and store it in an instance variable. That requires creating a constructor that takes an argument. All class methods must also take self as its first argument, so our constructor will take two arguments:
class Building():
def __init__(self, name):
self.name = name
Now we can create three different buildings:
b1 = Building("firehouse")
b2 = Building("hospital")
b3 = Building("church")
If we want to create a "driver" class to create three buildings, we can do that pretty easily. If you want to set an instance variable or do some work when you create an instance, you can do that in a constructor. For example, this creates such a class that creates three buildings and stores them in an array:
class Town():
def __init__(self):
self.buildings = [
Building("firehouse"),
Building("hospital"),
Building("church")
]
We now can create a single object that creates three other objects. Hopefully that's enough to get you over the initial hurdle of understanding classes.
OK I will try to answer the main question here: What a class is.
From Google: class /klas/
noun: class; plural noun: classes
1.
a set or category of things having some property or attribute in common and
differentiated from others by kind, type, or quality.
In programming, a class is just that. say, for example you have class Dog. Dogs bark "ruf ruff".
We can define the dog class in python using just that information.
class Dog:
def bark(self):
print "ruf ruff"
To use the class, it is instantiated by calling () its constructor:
Spot = Dog()
We then want Spot to bark, so we call a method of the class:
Spot.bark()
To further explain the details of the code here would be to go outside of the scope of this question.
Further reading:
http://en.wikipedia.org/wiki/Instance_%28computer_science%29
http://en.wikipedia.org/wiki/Method_%28computer_programming%29
As a direct answer:
class Zoo(object):
def __init__(self, name="Python Zoo"):
self.name = name
self.animals = list()
def getAnimal(self,index):
index = index - 1 # account for zero-indexing
try:
print("Animal is {0.name}\n Diet: {0.diet}\n Habitat: {0.habitat}".format(
self.animals[index]))
except IndexError:
print("No animal at index {}".format(index+1))
def listAnimals(self,index):
for i,animal in enumerate(self.animals, start=1):
print("{i:>3}: {animal.name}".format(i=i,animal=animal))
class Animal(object):
def __init__(self, name=None, diet=None, habitat=None):
if any([attr is None for attr in [name,diet,habitat]]):
raise ValueError("Must supply values for all attributes")
self.name = name
self.diet = diet
self.habitat = habitat
class ZooDriver(object):
def __init__(self):
self.zoo = Zoo()
self.zoo.animals = [Animal(name="Giraffe", diet="Herbivore", habitat="Outside"),
Animal(name="Lion", diet="Carnivore", habitat="Inside"),
Animal(name="Bear", diet="Herbivore", habitat="Inside")]
def run(self):
while True:
print("1. List Animals")
print("2. Get information about an animal (by index)"
print("3. Quit")
input_correct = False
while not input_correct:
in_ = input(">> ")
if in_ in ['1','2','3']:
input_correct = True
{'1':self.zoo.listAnimals,
'2':lambda x: self.zoo.getAnimal(input("index #: ")),
'3': self.exit}[in_]()
else:
print("Incorrect input")
def exit(self):
return
if __name__ == "__main__":
ZooDriver().run()
I haven't actually run this code so some silly typos may have occurred and the usual "off-by-one" errors (oops), but I'm fairly confident in it. It displays a lot of concepts your instructor won't expect you to have mastered yet (such as string formatting, most likely, and almost certainly hash tables with lambdas). For that reason, I STRONGLY recommend you not copy this code to turn in.
I'm trying to get my head around OOP using Python. Working through a tutorial I've been instructed to make a game. Earlier in the tutorial I made a game just using functions but now I have to use classes and objects.
Once I have my objects though I'm unsure how the get things moving. Here's the gist of it:
class Scene(object):
def enter(self):
pass
class Scene1(Scene):
def enter(self):
print "Some text describing the scene bla bla"
def someFunction that requires raw_input and a correct answer
return 'Scene2'
class Scene2(Scene):
def enter(self):
print "Some text describing the scene bla bla"
def someFunction that requires raw_input and a correct answer
return 'Scene3'
class Scene3(Scene):
def enter(self):
print "Some text describing the scene bla bla"
def someFunction that requires raw_input and a correct answer
return 'finished'
There is more to the game than that, but I've just slimmed it right down to the part I'm having trouble with.
The tutorial author hints to use another object to run the game, an "engine" that would start with scene1 and run through each scene till 'finished' is returned. He does have an example but it was for a more complex game so I've tried to ignore it. I think he wants us to use a while loop though.
But while what? What logic could I use to run the game? I'm a learner as you may be able to tell. Do I have all of the objects that I need? What would be the best way to "run" the game?
Create a Class that holds all scenes. The run() method loops through all scenes and execute the enter() method, which will output both: the print and the return string.
class Engine:
def __init__(self):
self.scenes = [Scene1(),Scene2(),Scene3()]
def run(self):
for s in self.scenes:
print s.enter()
Engine().run()
Output:
Some text describing the scene bla bla
Scene2
Some text describing the scene bla bla
Scene3
Some text describing the scene bla bla
finished
Update to comment: do it more dynamically:
class Scene1(Scene):
def enter(self):
print "Some text describing the scene bla bla"
raw = raw_input("Guess the number")
if raw != "42":
return 'Scene1'
return 'Scene2'
class Engine:
def __init__(self):
self.scenes = {'Scene1':Scene1(),'Scene2':Scene2(),'Scene3':Scene3()}
def run(self):
next = 'Scene1'
while True:
if next == 'finished':
break;
next = self.scenes.get(next).enter()
Engine().run()
the arguments about this being a good canidate for oop not withstanding
class Scene1:
def enter(self):
print "a scene"
raw_input("Hit Enter To Go To Next Scene")
return "Scene2"
class Scene2:
def enter(self):
print "a different scene"
raw_input("Hit Enter To Go Back:")
return "Scene1"
class Engine:
def __init__(self,sceneDict,startKey=1):
self._scenes = sceneDict
self._current = self._scenes[startKey]
def run(self):
while True:
next_scene_key = self._current.enter()
self._current = self._scenes[next_scene_key]
Engine({"Scene1":Scene1(),"Scene2":Scene2()},"Scene1").run()
is one example of many ways to accomplish this
First of all, if you see a lot of repeated code in an OOP-project, you most probably are working against OOP and not with it.
Don't make a new class for each scene, but one object (of scene) for each.
This is a very simple example of how to implement your "engine" (last 4 lines):
#! /usr/bin/python3
class Scene:
def __init__(self, name, welcome, question, answer):
self.name = name
self.welcome = welcome
self.question = question
self.answer = answer
self.connected = []
def connect(self, otherScene):
self.connected.append(otherScene)
def enter(self):
print(self.welcome)
while (input(self.question + ' ') != self.answer): pass #raw_input in py2
if not self.connected: return
print('\nWhither goest thou?')
for i, scene in enumerate(self.connected):
print('{}: {}'.format(i, scene.name))
while True:
try:
i = int(input('? '))
return self.connected[i]
except ValueError:
print('I understand thee not.')
except IndexError:
print('I understand thee not.')
#creating the scenes
house = Scene('A house',
'Thou art standing in front of a house. The landlord talketh to thee.',
'What is the top speed of an uncharged swallow?',
'42')
bridge = Scene('A bridge',
'Thou seest a bridge guarded by a knight clothèd in black.',
'What is the capital of England?',
'London')
swamp = Scene('A swamp',
'Thou enterst a foul morast and a witch eyeballth thee.',
'What is the capital of Azerbaijan?',
'Baku')
castle = Scene('A castle',
'The castle! A fair maiden greeteth thee.',
'What is my name?',
'Peach')
#connecting the scenes
house.connect(bridge)
house.connect(swamp)
bridge.connect(castle)
swamp.connect(castle)
#the game engine
nextScene = house
while nextScene:
nextScene = nextScene.enter()
print('Fin')
Trying to make my own RPG character generator for ex 45 in Zed Shaw's LPTHW. Part of the assignment is to make a new class for each 'room' of the program, like WelcomeScreen or ChooseMutations.
Here is the main program.
import rooms
class Program(object):
def __init__(self, start):
self.start = start
def run(self):
next_room_name = self.start
while True:
room = getattr(self, next_room_name)
next_room_name = room()
x = rooms.WelcomeRoom()
Program(x.hello_user())
And here is the rooms file its trying to pull stuff from.
class WelcomeRoom(object):
def __init__(self):
pass
def hello_user(self):
print '*' * 79
print '\n'
print '\t\tWelcome to the'
print '\t\tMetamorphosis Alpha Character & Random Encounter Generator'
print '\t\tProgrammed poorly by Raymond Weiss'
print '\n'
print '*' * 79
raw_input('Please press enter to continue')
return 'get_name'
def get_name(self):
name = raw_input('Hello, whats your name?',
'\n',
':> ')
But when I run the main program in python, it just logs out instead of returning the function get_name() from rooms. Output posted below.
Raymond-Weisss-MacBook-Pro:macgre Raylug$ python macgre.py
*******************************************************************************
Welcome to the
Metamorphosis Alpha Character & Random Encounter Generator
Programmed poorly by Raymond Weiss
*******************************************************************************
Please press enter to continue
Raymond-Weisss-MacBook-Pro:macgre Raylug$
I apologize in advance if my question title isn't exactly what im trying to ask, as a newbie its sometimes hard not knowing what exactly to ask.
You're returning a string, not a function (or function result). You probably want something like:
def hello_user(self):
return self.get_name
or
def hello_user(self):
return self.get_name()
Based on your program, I think you probably want the second one. The difference is that the first one returns the get_name function, whereas the second one returns the results of the get_name function.