I'm making a subclass for multiple choice questions under a superclass of trivia questions for my Python university course. The multiple choice aspect works, but I want to shuffle the order of the answers for extra credit.
Some of my code:
class ChoiceQuestion(Question) :
def __init__(self) :
super().__init__()
self._choices = []
def addChoice(self, choice, correct) :
self._choices.append(choice)
if correct :
# Convert len(choices) to string.
choiceString = str(len(self._choices))
self.setAnswer(choiceString)
# Override Question.display().
def display(self) :
# Display the question text.
super().display()
# Display the answer choices.
for i in range(len(self._choices)) :
choiceNumber = i + 1
print("%d: %s" % (choiceNumber, self._choices[i]))
The question choices are added in a seperate file I have no control over as a test-file. This is run by the professor after turning in whatever variation of the first code. Here is what he runs it on. Side note: there are of course import statements in the second file, but I have the other stuff solved and it's very long. Didn't want to include stuff that has been worked out.
print('\n')
mcq = ChoiceQuestion()
mcq.setText("In which country was the inventor of Python born?")
mcq.addChoice("Australia", False)
mcq.addChoice("Canada", False)
mcq.addChoice("Netherlands", True)
mcq.addChoice("United States", False)
for i in range(3) :
presentQuestion(mcq)
## Presents a question to the user and checks the response.
# #param q the question
#
def presentQuestion(q) :
q.display() # Uses dynamic method lookup.
response = input("Your answer: ")
if q.checkAnswer(response):
print("Correct")
else:
print("Incorrect") # checkAnswer uses dynamic method lookup.
# Start the program.
With that said, I need to display the options in a random order, while updating the number value tied to that choice slot. I.e. if Netherlands is randomized into slot 1, typing "1" will print "Correct". I also have to make sure I don't allow the same option to appear more than once.
How should I go about it? What are some suggestions? Note: I can only modify the first program
Here are a couple of things to think about:
As kiran.koduru mentioned, look at using the random module for easily shuffling lists.
Currently your code stores the correct answer as it is received. This makes it difficult because when the answers are shuffled the stored answer is no longer correct. An alternative is to store choice and correct together and calculate the correct answer after your choices are shuffled.
Your code does not know in addChoice whether or not there will be more choices added, so shuffling there will result in wasted computation.
Related
I'm making a text-based game, which is based largely in if-, elif- and else-statements. However, I also use while loops for different "areas" within the game. (Play_loop, Main_loop, Shop_loop, Fish_loop, etc.).
Lately I've implemented admin commands which I use in-game to change things on the go, and I want these to be available in every loop. I also have some general commands which I want to be available (help, leave, quit, logout, go to another area, check inventory, etc.).
The issue I'm facing is knowing that duplicated code should be avoided, but i'm wondering if this is necessary in this situation. I've already made many functions to make each command code pretty short, about 2-15 lines in general.
Should I add the code blocks into functions that do the same thing, and then just repeat the function, or should I just keep it as is? Or maybe I should do something else that I havent even thought about?
Example code:
elif command == '/user info':
if user.admin:
print(f'User-list: {users}')
who = input('Name of user: ').strip()
who_user = admin_load_user(who, users)
if who_user:
print(who_user.info())
print(who_user.display_inv())
else:
print(DNEError)
else:
print(PError)
elif command == '/add coins':
who = input('Who gets coins? ').strip()
amount = int(input('How much? ').strip())
admin_add_coins(who, amount, users)
save_users(users)
Code that is repeated should typically be put into functions, so that you have better overview and control over what they are doing. There you can also easily give them default arguments and expand on the code without bloating the main function of your program.
Here is a concise argument for using functions. It's written for C but applies to python as well.
Then, as Jason Chia pointed out, you should consider thinking about building your game into classes, as they solve some of the problems you mentioned and generally are an important control instrument for bigger programs where you need to coordinate different states (e.g. changing something in a room based on the player's actions).
This tutorial could help with that.
Does that about answer your question?
You should use decorator style to do it nice to read and write.
get inspiration here:
def requires_admin(f):
def wrapper(f):
#wraps(f)
def wrapped(*args, **kwargs):
#if not admin:
#return render_template('error.html')
return f(*args, **kwargs)
return wrapped
return wrapper
#app.route('/admin/action')
#requires_admin
def AdminAction():
whatyouwant()
I am facing challenges implementing OOP in python to enable me to call the functions whenever i want , so far i have no syntax errors which makes quite challenging for me . The first part of the code runs ehich is to accept data but the function part does not run.
I have tried different ways of calling the function by creating an instance of it.
print (list)
def tempcheck(self,newList):
temp=newList[0]
if temp==27:
print ("Bedroom has ideal temperature ")
elif temp>=28 or temp<=26:
print ("Bedroom Temperature is not ideal ,either too low or too cold. ")
print ("Please to adjust the temperature to the optimum temperature which is 27 degree Celsuis")
# now to initialize args
def __init__(self,temp,puri1,bedwashroom,newList):
self.temp=temp
self.puri1=puri1
self.bedwashroom=bedwashroom
tempcheck(newList)
# now calling the functions
newvalue=tempcheck(list)
# where list contains the values from the input function.
I expected the function to to check the specific value at the location in the list provided which is called list and also for the function to return a string based on the if statements.
i got it right ,i figured out an alternative to my bug thanks for the critique however any further addition is welcome,
the main goal was to create a function that takes input and passes it to list to be used later i guess this code is less cumbersome
the link to the full code is pasted below
I am very new to python, and am running into an issue I don't fully understand. I am trying to get a random variable to run multiple times, but for some reason it just returns the same random value x times.
I am not entirely certain what to try aside from the code I have already done.
lowTreasureList = "50 gold", "Healing Potion", "10x Magic Arrows", "+1 Magic Weapon"
def ranLowLoot(lowLootGiven):
# This function returns a random string from the passed list of strings.
lootIndex = random.randint(0, len(lowLootGiven) - 1)
return lowLootGiven[lootIndex]
lowLoot = ranLowLoot(lowTreasureList)
treasureSelection = int(input())
if treasureSelection == 1:
numLowTreasure = int(input('How many treasures? '))
for i in range(numLowTreasure):
ranLowLoot(lowTreasureList)
print(lowLoot)
When I do this I get the same random treasure (numLowTreasure) times, but I am trying to get it to select a new random treasure each time.
If you haven't already, it will help to read the documentation on the random module.
There are three alternatives to random.randint that are more suited to your purpose:
random.randrange(start, stop, [step]): step is optional and defaults to one. This will save you the len(...) - 1 you are using to get lootIndex, since stop is an exclusive bound.
random.randrange(stop): uses a default start of zero and default step of 1, which will save you passing 0 as your start index.
random.choice(seq): you can pass your function's parameter lowLootGiven to this as seq, which will save you from using indices and writing your own function entirely.
As for why you're getting the repeated treasure, that's because you aren't updating your variable lowLoot in your for loop. You should write:
for i in range(numLowTreasure):
lowLoot = ranLowLoot(lowTreasureList)
print(lowLoot)
Last thing I want to say is that python is nice for writing simple things quickly. Even if there was some bigger context that you were writing this code in, I might have written it like this:
lowTreasureList = ("50 gold", "Healing Potion", "10x Magic Arrows", "+1 Magic Weapon")
if int(input()) == 1:
for i in range(int(input('How many treasures? '))):
print(random.choice(lowTreasureList))
Using the round parentheses around the tuple declaration like I did isn't necessary in this case, but I like to use it because if you want to make the tuple declaration span multiple lines, it won't work without them.
Reading documentation on standard libraries is something I almost always find helpful. I think Python's documentation is great, and if it's bit too much to digest early on, I found tutorialspoint to be a good place to start.
The problem is that in the main loop you are discarding the result of the call to ranLowLoot(). As a minimal fix, in the main loop assign the result of that function call. Use:
lowLoot = ranLowLoot(lowTreasureList)
rather than simply:
ranLowLoot(lowTreasureList)
As a better fix, ditch your function completely and just use random.choice() (which does what you are trying to do, with much less fuss):
import random
lowTreasureList = ["50 gold", "Healing Potion", "10x Magic Arrows", "+1 Magic Weapon"]
treasureSelection = int(input())
if treasureSelection == 1:
numLowTreasure = int(input('How many treasures? '))
for i in range(numLowTreasure):
lowLoot = random.choice(lowTreasureList)
print(lowLoot)
I am trying to use a for loop in a dictionary to represent an unknown about of statements that may need to be in the dictionary (based on the specified amount when stating the class). I was wondering what the syntax for that would be if there is any at all.
Earlier today a friend asked me to make a Choose Your Own Adventure game.
I wanted to have a random page be the death page.
The rest of the pages are story/question pages.
I also wanted to have a dictionary that when I put in a page number
it returned the type of page it was.
I was trying to use a for statement to get a page number that is
called with the class. The pages are random so there is no way for me
to know.
from time import sleep
from random import randint
def ClearSys():
for i in range(0,100):
print("\n")
class Book:
def __init__(self,name,pages):
#self.DeathPage#
RandomPage=randint(2,pages)
self.DeathPage=RandomPage
del RandomPage
#self.pages#
self.pages=["Introduction Page"]
for i in range(2,pages):
if not i==self.DeathPage:
self.pages.append("QuestionPage")
else:
self.pages.append("DeathPage")
####MAIN SECTION I WOULD LIKE TO HIGHLIGHT####
##Page number dictionary##
self.PageNumberToType={
0:"Introduction Page",
for i in range(1,len(self.pages)):
i:self.pages[i]
}
########
I didn't really expect this to work, but I just wrote it out to see if it were possible.
None that I know of; but why does it need to be inside the dictionary literal?
self.PageNumberToType = { 0:"Introduction Page" }
for i in range(1, len(self.pages)):
self.PageNumberToType[i] = self.pages[i]
Because order is of little importance when it comes to dictionaries, you can do a dictionary-comprehension as well:
self.PageNumberToType = {i: self.pages[i]
for i in range(1, len(self.pages[i]))}
self.PageNumberToType.update({0: 'Introduction Page'})
Just got one other question for my python plugin.
Here is the code:
def cmd_give(self, data, client=None, cmd=None):
"""
^3<player> <money> - Give someone however much money you want.
"""
input = self._adminPlugin.parseUserCmd(data)
if not data:
client.message('^7 correct syntax is !give <player> <money>')
return False
else:
if len([x for x in data if x.isspace()]) < 1:
client.message('^7 correct syntax is !give <player> <money>')
return False
else:
input_data = data.split(' ',1)
scname = input_data[0]
ammount = int(input_data[1])
sclient = self._adminPlugin.findClientPrompt(scname, client)
if not sclient: return False
self.earn_money(sclient, ammount)
return True
Now this obviously adds the value given in the command to the user inputting into mysql.
I'm also wanting a command to subtract any value given in the command as well.
So this command above is a give and I also want a take.
My problem is I don't know what the change is to minus the amount off the value input instead of adding.
Hope someone can help,
Thanks guys.
Without modifying the function that does the actual addition, the suggestion by Rob Watts in a comment will work:
ammount = -int(input_data[1])
You can either create a new function, cmd_take, and do that there, or have a more general function (cmd_transaction?) that takes an extra argument (eg give) and has the appropriate logic:
if not give:
ammount = -int(input_data[1])
In the first case, it would be good practice to extract most of the code to a helper function, to avoid repetition, but if you don't know python and this is just a one time thing, having a cmd_take function that is exactly like command_give, except for that one line, is the simplest solution.