So I'm a python beginner and don't really know the gist of random functions. The following is my code (but only partially so it may not make sense but it has the point of what I wanted to ask. I put the conclusion of my code on the beginning of the paragraph after the code though. P.S. the code works):
if (1 <= numb_quiz <= 100):
from openpyxl import Workbook, load_workbook
book = load_workbook('Quiz_Problems.xlsx')
read_sheet = book['100 Questions']
length_row = read_sheet.max_row
sheet = book.active
numb_question = 1
point = 0
engagement = 0
correct = 0
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
As you can see, to conclude what I wanted to do with the code above is to print random rows in column 3 with the random function from xslx file using python. The thing is, I wanted to prevent the random function to print the row from column 3 more than once in one run. Since again, I don't really understand what the 'import random' library can actually do, perhaps there is a way to get what I wanted. Does anyone have a solution? thank you so much
P.S. Since I'm a python beginner, I also would fancy an explanation from you (so not just the code. thank you!)
So random just generates a number in that range you want. Computers don't generate numbers totally randomly. They use a "seed" to get started. If you pass the library the same seed each time (set it via random.seed(seedNo)), it will generate the same numbers in the same order. This can be useful for testing but also defeat the purpose of generating numbers. Therefore, a common practice is getting the current time of the system and using that as the seed.
Now for making sure you don't get the same question printed twice, I recommend you create a new empty list and each time you get a question, you add that index to the list. Then, put in a conditional checking if the index has come up before, and if it has, just pass (move on to the next iteration of the loop). The code might look like this:
askedAlready = []
while numb_question <= numb_quiz:
randrow = random.randint(2, length_row)
if randrow in askedAlready: continue
for row in read_sheet.iter_rows(randrow, randrow, min_col = 2, max_col = 2):
print("")
print("Question number", str(numb_question) + ":")
print([cell.value for cell in row])
for col in read_sheet.iter_rows(min_row = randrow, max_row = randrow, min_col = 3, max_col = 3):
print([cell.value for cell in col])
break
guest_answer = str(input("answer: "))
answer = str("D"+str(randrow))
correct_ans = sheet[answer].value
askedAlready.append(randrow)
You could also rethink how you make the random generation. Make a list of all the possible question numbers then shuffle it. It won't have any duplicates. Then you could just iterate through the shuffled list. Note that this also uses the seeding concept in the same way (random.seed())
(Inspired by thefourtheye's answer: Generate 'n' unique random numbers within a range)
listOfRandRows = list(range(2,length_row))
random.shuffle(listOfRandRows) #this will shuffle the list "in place"
#then iterate
for i in listOfRandRows:
#do your thing. i will be the row number randomly chosen
Edit per pjs's recommendation: shuffling is efficient enough but rejection can take a lot of extra time. Sample is better than rejection. It's described here: Generate 'n' unique random numbers within a range under Two-Bit Alchemist's answer
I am trying to make a quiz, in python, where I use quite a few while loops, so I can easily leave code, or re run it. The problem is, once one of my nested loops has finished running, the code doesn't continue to run. I will leave some pseudocode incase my logic is incorrect, and the actual code after that.
Pseudocode
i = 0
array = [0]
while i < 1:
while length of array < 11:
do something
print "done something!"
Basically, once the length of array has reached 11, the print doesn't happen.
Here is the actual code also
diff =int(input("Choose a difficulty; 1 2 3"))
diffs = [1, 2, 3]
while diff not in diffs:
diff = int(input("Invalid input; choose a difficulty; 1 2 3"))
data = []#This will hold all of the data in the quiz file
answers = []#This will hold the current answers available to the user
answers2 = []#This will hold the current questions used, so that the answers do appear in a random order
letters = ["A. ","B. ","C. ","D. "]#This is so that each answer has an identifier
Questions = [0]
i = 0
score = 0
with open(filenameq,"r") as quizFile:
fileReader = csv.reader(quizFile)
for row in fileReader:
data.append(row)#This creates a 2D array, so that the program can access specific values in the file
while i < 1:
while len(Questions) < 11:
a = 0
while a in Questions:
a = randint(0,9)
Questions.append(a)
print(data[0][a])#The cell where the question is located in the file
answers = []
answers2 = []
for x in range(0,(diff+1)):
answers.append(data[a+1][x])
x = 0
b = 0
correct = 0
while x <= diff:
b = randint(0,diff)
if b in answers2:
continue
answers2.append(b)
print(letters[x]+answers[b])
if b == 0:#the first item in the CSV file is the correct value
correct = x
x += 1
answer = input("Enter the letter of the answer you think is correct").upper()
if correct == letters.index(str(answer[0]+". ")):#This is the index of the letter that the user entered, in the letters list
score += 1
print("Quiz finished")
with open(filename,"a+") as scoreFile:
fileWriter = csv.writer(scoreFile)
fileReader = csv.reader(scoreFile)
for row in fileReader:
if row[0] == username:
print(row)
row[2] = "y"
print(row)
fileWriter.writerow(row)
Finally, here is the csv file i am trying to manipulate
What is the name of the gorgon in Greek Mythology?,How did a warrior defeat Medusa in Greek Mythology,Who is the God of the Yellow River in Chinese Mythology?,Who is the mother of Hephaestus in Greek Mythology?,Who is the mother of Hephaestus in Greek Mythology?,Which river was Achilles dipped in as a baby?,Where did Zeus cast the Titans after Cronus defeated them?,What does the Helm of Darkness grant to the wearer?,Which is a pantheon of Norse Gods - excluding the Aesir?,What is Yggdrasil?
Perseus,Medusa,Ares,Zeus
A Shield,A Virus,Laceration,Cavalry
He Bo,Yang Zing,Kukulkan Ah Puch
Hera,Aphrodite,Demeter,Persephone
Pomegranate,Orange,Guava,Apple
Styx,Cocytus,Acheron,Phlegethon
Tartarus,The Asphodel Meadows,The Underworld,The Mourning Fields
Invisibility,Invincibility,Immortality,Ignitability
Vanir,Hel,Tyr,Yggdrasil
A Plant,A Person,A Deity,A World
So, each question is at the top, and the possible answers are in the bottom for each question, with the correct answers as row[0], or the first index in each line.
Thank you in advance for helping me :)
EDIT: Added some extra code to my main code, that I forgot to include originally, to clarify what "diff" and "diffs" are
Seems to be due to the fact that you never close your initial while loop: while i < 1. Since the value of i stays at 0, your outermost while loop will never close, causing your program to be stuck in an infinite loop. If you close that loop by setting i = 1 at the end, this particular problem should be resolved.
Alright, I figured it out myself, and it is exactly what I thought it was; the logic in the 1st nested while loop prevented it from ending, as the Questions array was Questions = [0], and the a variable was prevented from being in Questions if a was already in Questions, but a could already be 0-9, when 0 was already in Questions. Basically, It never could end!
when I run this program, sometimes I receive an error.This error however is not possible as I am using an 8x8 grid and I limit the inputs so that they can only be numbers from 0-7, to obey the fact that list indexes start at 0.
The user must input coordinates (1-8),(A-H) and the program will check to see if those coordinates are correct, by systematically going through the CompShips list and repeatedly comparing those coordinates to ones given by the user. If the cords match, then a message will appear and a "Z" will change to an "X" on those coordinates, indicating a HIT. If the guess does not match, a "Z" will change to an "M" on those coordinates indicating a MISS.
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(Index)
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[[FireRow][FireIndex]]=("M")
PrintFireBoard()
I receive the error:
IndexError: string index out of range
Looks like these two lines
FireBoard[[FireRow][FireIndex]]=("H")
FireBoard[[FireRow][FireIndex]]=("M")
should be
FireBoard[FireRow][FireIndex]="H"
FireBoard[FireRow][FireIndex]="M"
Explanation: In your old code, FireBoard[[FireRow][FireIndex]]=("H")
[FireRow][FireIndex] means, given a list [FireRow] (which contains just one element), get the FireIndex-th element. This is not what you're trying to do.
For example [3][0] returns 3, and [3][1] gives IndexError.
Take a look at How to define a two-dimensional array in Python
Also note that ("H") is the same as the string "H". There is no need to add parentheses.
Here is a much cleaner code!
CompShips=[[1,0],[1,1],[2,2],[2,3],
[2,4],[3,0],[3,1],[3,2],
[5,4],[5,5],[5,6],[5,7],
[1,7],[2,7],[3,7],[4,7],
[5,7]]
FRow=[["Z"]*8]*8 #1 More Pythonic
def PrintFireBoard():
#print(Index)
for i in range(0,8):
print(FRow[i])
FireBoard=FRow[:] #NOTE THIS ONE!!!
mydict = {}
for i,key in enumerate(["A","B","C","D","E","F","G","H"]): #2 More Pythonic
mydict[key] = i
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
FireRow=int(FireRow)-1
FireIndex = mydict[FireIndex]
Guess=[FireRow,FireIndex]
print(Guess)
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="H" #3 your problem here
PrintFireBoard()
else:
print("MISS")
print(FireRow,FireIndex)
FireBoard[FireRow][FireIndex]="M"
PrintFireBoard()
1) As explained in the comments that's just a more nicer way to create a list of lists!. Remember DRY principle! Do Not Repeat yourself!
2) Instead of having all that if else to convert the 'A' to 0. You can use a dictionary lookup instead!
3) Your problem seems to be here! correct this to FireBoard[FireRow][FireIndex]="H"
PS: NOTE THIS ONE!!!: I'm not just making FireBoard as an alias to FRow! I'm copying it into a FireBoard as a new list! There's a subtle difference read about it here. I'm doing this incase you don't want your original FRow list to be modified!
The indentation in your question was off. I think that all the code from
Guess=[FireRow,FireIndex]
until the end should be preceded by 4 spaces.
I've removed print(Index) since it was not defined.
To access FireBoard use:
FireBoard[FireRow][FireIndex]
Instead of
FireBoard[[FireRow][FireIndex]]
This should be working
CompShips=[[1,0],[1,1],[2,2],[2,3],[2,4],[3,0],[3,1],[3,2],[5,4],
[5,5],[5,6],[5,7],[1,7],[2,7],[3,7],[4,7],[5,7]]
FRow1=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow2=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow3=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow4=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow5=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow6=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow7=["Z","Z","Z","Z","Z","Z","Z","Z",]
FRow8=["Z","Z","Z","Z","Z","Z","Z","Z",]
def PrintFireBoard():
print(FRow1)
print(FRow2)
print(FRow3)
print(FRow4)
print(FRow5)
print(FRow6)
print(FRow7)
print(FRow8)
FireBoard=[FRow1,FRow2,FRow3,FRow4,FRow5,FRow6,FRow7,FRow8]
while len(CompShips) !=0 or CompSuccess==17:
FireRow=input("Please Choose The Row That You Wish To Fire Upon (1-8) ")
FireIndex=input("Please Choose The Column That You Wish To Fire Upon (A-H) ")
#As Lists start at 0
FireRow=int(FireRow)-1
if FireIndex==("A"):
FireIndex=0
elif FireIndex==("B"):
FireIndex=1
elif FireIndex==("C"):
FireIndex=2
elif FireIndex==("D"):
FireIndex=3
elif FireIndex==("E"):
FireIndex=4
elif FireIndex==("F"):
FireIndex=5
elif FireIndex==("G"):
FireIndex=6
elif FireIndex==("H"):
FireIndex=7
Guess=[FireRow,FireIndex]
#Check To See If Correct
UserSuccess=0
for i in CompShips:
if Guess==i:
CompShips.remove(Guess)
UserSuccess=1
else:
pass
if UserSuccess==1:
print("HIT")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("H")
PrintFireBoard()
else:
print("MISS")
print(FireRow)
print(FireIndex)
FireBoard[FireRow][FireIndex]=("M")
PrintFireBoard()
Current assignment is building a basic text adventure. I'm having trouble with the following code. The current assignment uses only functions, and that is the way the rules of the assignment state it must be done.
def make_selections(response):
repeat = True
while repeat == True:
selection = raw_input('-> ')
for i, v in enumerate(response):
i +=1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
if selection == i:
print v[1]
else:
print "There's an error man, what are you doing?!?!?"
firstResponse = 'You chose option one.'
secondResponse = 'You chose option two.'
thirdResponse = 'You chose option three.'
responses = [(0, firstResponse), (1, secondResponse),( 0, thirdResponse)]
make_selections(responses)
My intention in that code is to make it so if the user selects a 1, it will return firstResponse, if the user selects 2 it will return secondResponse, etc.
I am basically just bug testing the code to make sure it produces the appropriate response, hence the "Error man..." string, but for some reason it just loops through the error message without printing the appropriate response string. Why is this?
I know that this code is enumerating the list of tuples and I can call them properly, as I can change the code to the following and get the expected output:
for i, v in enumerate(response):
i += 1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
print i, v
Also, two quick asides before anyone asks:
I know there is currently no way to get out of this while loop. I'm just making sure each part of my code works before I move on to the next part. Which brings me to the point of the tuples.
When I get the code working, a 0 will produce the response message and loop again, asking the user to make a different selection, whereas a 1 will produce the appropriate response, break out of the loop, and move on to the next 'room' in the story... this way I can have as many 'rooms' for as long of a story as I want, the player does not have to 'die' each time they make an incorrect selection, and each 'room' can have any arbitrary amount of options and possible responses to choose from and I don't need to keep writing separate loops for each room.
There are a few problems here.
First, there's no good reason to iterate through all the numbers just to see if one of them matches selection; you already know that will be true if 1 <= selection <= len(response), and you can then just do response[selection-1] to get the v. (If you know anything about dicts, you might be able to see an even more convenient way to write this whole thing… but if not, don't worry about it.)
But if you really want to do this exhaustive search, you shouldn't print out There is an error man after any mismatch, because then you're always going to print it at least twice. Instead, you want to only print it if all of them failed to match. You can do this by keeping track of a "matched" flag, or by using a break and an else: clause on your for loop, whichever seems simpler, but you have to do something. See break and continue Statements, and else Clauses on Loops in the tutorial for more details.
But the biggest problem is that raw_input returns a string, and there's no way a string is ever going to be equal to a number. For example, try '1' == 1 in your interactive interpreter, and it'll say False. So, what you need to do is convert the user's input into a number so you can compare it. You can do that like this:
try:
selection = int(selection)
except ValueError:
print "That's not a number!"
continue
Seems like this is a job for dictionaries in python. Not sure if your assignment allows this, but here's my code:
def make_selections(response):
selection = raw_input('-> ')
print response.get(selection, err_msg)
resp_dict = {
'1':'You chose option one.',
'2':'You chose option two.',
'3':'You chose option three.'
}
err_msg = 'Sorry, you must pick one of these choices: %s'%sorted(resp_dict.keys())
make_selections(resp_dict)
The problem is that you are comparing a string to an integer. Selection is raw input, so it comes in as a str. Convert it to an int and it will evaluate as you expect.
You can check the type of a variable by using type(var). For example, print type(selection) after you take the input will return type 'str'.
def make_selections(response):
repeat = True
while repeat == True:
selection = raw_input('-> ')
for i, v in enumerate(response):
i +=1 # adds 1 to the index to make list indices correlate to a regular 1,2,3 style list
if int(selection) == i:
print v[1]
else:
print "There's an error man, what are you doing?!?!?"