Why does this code produce the error 'int is not subscriptable'? - python

I have converted the variable to a string, however Python still does not recognise this and says the integer is not subscriptable.
I've already tried viewing other questions with the same 'integer is not subscriptable' problem but none which answer my question specifically.
I have explicity converted the variable to a string the line before the error occurs.
import random
num = random.randint(1000, 9999)
tot_correct = 0
tot_tries = 0
while tot_correct != 4:
tot_correct = 0
tot_tries += 1
guess = input("Guess the number: ")
guess = str(guess)
#check 1st number
if guess[0] == num[0]:
tot_correct += 1
#check 2nd number
if guess[1] == num[1]:
tot_correct += 1
#check 3rd number
if guess[2] == num[2]:
tot_correct += 1
#check 4th number
if guess[3] == num[3]:
tot_correct += 1
print("You got " + tot_correct + " numbers right.")
print("You have guessed the number correctly! It took you " + tot_tries + " tries.")
I expected the string to become a string array, (but it still does not, and returns the same error) and then identify whether or not the individual number matches the one already

Your code isn't doing what you think it is. Right now you are inputting a number, converting it to a string and comparing the first character of that guess string to the first index of the number num[0] which isnt indexable.
edit:
Your code is doing a number of things wrong actually. One huge problem you have is you are setting tot_correct = 0 inside of your while loop which means it'll run forever and never finish.
But stepping back I think you are making this problem too complicated. Let's talk about the pseudocode for what I believe you are trying to do.
num_guessed = 0
number_to_guess = 4
total_guesses = 0
while num_guessed < number_to_guess:
# each pass we reset their guess to 0 and get a new random number
guess = 0
# get a new random number here
while guess != random:
# have a user guess the number here
total_guesses += 1 # we can increment their total guesses here too
# it would be a good idea to tell them if their guess is higher or lower
# when they guess it right it will end the loop
num_guessed += 1
# down here we can tell them game over or whatever you want
The code should at least give you an idea of how to approach the problem without solving it for you.

I respectfully disagree with the previous comment. It will be possible for the loop to end. I understand why you are setting tot_correct to 0 at the start of each loop. Because tot_correct is incremented up to 4 times, it is possible for tot_correct == 4 to be true.
Edit: The poster is trying to count the correct number of digits provided. So if the number to guess is '1234' and the user inputs '1564', the poster wants the code to return '2' to indicate that the '1' and '4' were correct numbers. It's like the game mastermind, where a player has to guess the correct colors and orientation of the colors. However, this code will not inform the user if a correct number is added in an incorrect position, just if the correct number is in the correct position.
However, he is correct that your error lies in your access of num[<index>]. numis an integer so you cannot index into it, hence 'integer is not subscriptable.' num needs to be a string in order to index the characters.
Edit: guess was already a string without the call to str() because the return from input() is a string
Some things to consider: Do you want your user to know they need a 4 digit number? What if there are whitespaces added? Currently your code does not remove whitespace. If you are looking for '6543' as the magic number and I enter ' 6543' your solution would not recognize my answer as correct.

Related

Can't determine why program terminates early

I was working on this assignment for the EdX MIT Python course and decided I wanted the output to display differently. Based on my code, I thought that the task program would end when guesses = 0. However, I'm either getting "IndexError: list assignment index out of range" or the program ends at guess 2. This appears to depend on the length of the secretWord. Can anyone point me in the right direction?
def hangman(secretWord):
'''
secretWord: string, the secret word to guess.
Starts up an interactive game of Hangman.
* At the start of the game, let the user know how many
letters the secretWord contains.
* Ask the user to supply one guess (i.e. letter) per round.
* The user should receive feedback immediately after each guess
about whether their guess appears in the computers word.
* After each round, you should also display to the user the
partially guessed word so far, as well as letters that the
user has not yet guessed.
Follows the other limitations detailed in the problem write-up.
'''
trackedguess = []
letcount = ()
letterlist = []
guess = ''
for i in range(0, (len(secretWord)-1)):
trackedguess.append('_')
letcount = len(secretWord)
guessesleft = 8
for i in range(0, 7):
if ''.join(trackedguess) == secretWord:
print('You win!')
break
if guessesleft < 1:
print('You have 0 guesses remaining.')
break
print(trackedguess)
print("You have ", guessesleft, " guesses remaining.")
guess = input('Please guess a letter and press return: ')
if guess in letterlist:
print("You've already guessed that. Try again.")
else:
guessesleft -= 1
letterlist.append(guess)
for i in range(0, len(secretWord)):
if secretWord[i] in letterlist:
coordinate = i
trackedguess[coordinate] = secretWord[i]
hangman(chooseWord(wordlist))
A few things stick out to me:
range uses an exclusive end. That means range(0, (len(secretWord)-1) will iterate one time less than the length of secretWord. You want the lengths to match. More straightforward, less error-prone approaches would be just: trackedGuess = ['_'] * len(secretWord) or trackedGuess = list('_' * len(secretWord)).
You should verify your assumptions. For example, the above case could have been caught easily if you did assert(len(trackedGuess) == len(secretWord)).
for i in range(0, 7) suffers from the same problem as your earlier usage of range(). If you want to iterate 8 (guessesleft) times, then you should use range(0, 8). However, you're also decrementing guessesleft inside the loop and exiting when it reaches 0. Do one or the other, but not both. As your code currently is, if someone enters a guess that they've already made, it will count one iteration against them (which I'm not sure is what you want).
It's a very good attempt, but there are some things that are wrong. I'm going to try to walk through them one by one.
Instead of a for loop, I'd suggest using a while guessesleft>0. In the current implementation the for loop will run for 8 times regardless of whether or not there are any guesses left (for example, try providing the same letter as a guess every time). With the while, however, you gain much more control over the loop.
The trackedguess generation is flawed. It will always miss the last letter of the secretword (this is also the reason you were getting the IndexError) Try for i in range(len(secretWord)) instead. You'll also find it much more concise and readable.
I also took the liberty of moving the win or lose condition down in the loop. Previously, if you won on the last guess, you'd still lose (because the win check condition happened before the input and after that the loop ended); also, the guess wasn't printed if you won (because the loop would break before the print statement).
Revised code below:
def hangman(secretWord):
'''
secretWord: string, the secret word to guess.
Starts up an interactive game of Hangman.
* At the start of the game, let the user know how many
letters the secretWord contains.
* Ask the user to supply one guess (i.e. letter) per round.
* The user should receive feedback immediately after each guess
about whether their guess appears in the computers word.
* After each round, you should also display to the user the
partially guessed word so far, as well as letters that the
user has not yet guessed.
Follows the other limitations detailed in the problem write-up.
'''
trackedguess = []
letterlist = []
for i in range(len(secretWord)):
trackedguess.append('_')
guessesleft = 8
while guessesleft > 0:
print(trackedguess)
print("You have ", guessesleft, " guesses remaining.")
guess = input('Please guess a letter and press return: ')
if guess in letterlist:
print("You've already guessed that. Try again.")
else:
guessesleft -= 1
letterlist.append(guess)
for i in range(0, len(secretWord)):
if secretWord[i] in letterlist:
coordinate = i
trackedguess[coordinate] = secretWord[i]
if ''.join(trackedguess) == secretWord:
print(trackedguess)
print('You win!')
break
if guessesleft < 1:
print('You have 0 guesses remaining.')
break
hangman('test')
Hope that helps.

Need help shortening program (python beginner)

In response to the following task, "Create an algorithm/program that would allow a user to enter a 7 digit number and would then calculate the modulus 11 check digit. It should then show the complete 8-digit number to the user", my solution is:
number7= input("Enter a 7 digit number")
listnum= list(number7)
newnum=list(number7)
listnum[0]=int(listnum[0])*8
listnum[1]=int(listnum[1])*7
listnum[2]=int(listnum[2])*6
listnum[3]=int(listnum[3])*5
listnum[4]=int(listnum[4])*4
listnum[5]=int(listnum[5])*3
listnum[6]=int(listnum[6])*2
addednum= int(listnum[0])+int(listnum[1])+int(listnum[2])+int(listnum[3])+int(listnum[4])+int(listnum[5])+int(listnum[6])
modnum= addednum % 11
if modnum== 10:
checkdigit=X
else:
checkdigit=11-modnum
newnum.append(str(checkdigit))
strnewnum = ''.join(newnum)
print(strnewnum)
(most likely not the most efficent way of doing it)
Basically, it is this: https://www.loc.gov/issn/check.html
Any help in shortening the program would be much appreciated. Thanks.
It might be worth it to do some kind of user input error checking as well.
if len(number7) != 7:
print ' error '
else:
//continue
Using a while loop for that top chunk might be a good starting point for you. Then you can sum the list and take the modulus in the same step. Not sure if you can make the rest more concise.
number7= input("Enter a 7 digit number: ")
listnum= list(number7)
newnum=list(number7)
count = 0
while count < 7:
listnum[0+count] = int(listnum[0+count])*(8-count)
count += 1
modnum= sum(listnum) % 11
if modnum== 10:
checkdigit=X
else:
checkdigit=11-modnum
newnum.append(str(checkdigit))
strnewnum = ''.join(newnum)
print('New number:', strnewnum)
EDIT:
If you want it to print out in ISSN format, change your code after your if-else statement to this:
newnum.append(str(checkdigit))
strnewnum = ''.join(newnum)
strnewnum = '-'.join([strnewnum[:4], strnewnum[4:]])
print('ISSN:', strnewnum)
You can convert the list to contain only int elements right after the input
number7 = int(input())
Then you can perform those operations in a loop.
for i in range(len(listnum)):
listnum[i] *= (8-i)
also the sum function does the trick of performing the addition of every element in the list (if possible)
EDIT:
addedNum = sum(listNum)

python reverse guessing game different print messages

When I attempt to print a different message for there being more than one guess I am getting a double print message for when there is it is guessed in one iteration.
if guess >= 2:
print ('Your number is %d. I found it in %d guesses.' % (guess, iteration))
if iteration == 1:
print ('I found your number in 1 guess.')
current output:
Enter two numbers, low then high.
low = 2
high = 8
Think of a number in the range 2 to 8.
Is your number Less than, Greater than, or Equal to 4?
Type 'L', 'G', or 'E'): e
Your number is 4. I found it in 1 guesses.
I found your number in 1 guess.
You didn't defined what is "min_no" and "max_no" at first loop iteration in this line:
guess = guess_number(min_no, max_no)
And the last if is comparing the "guess" number instead of the "iteration" counter:
if guess == 1:
print ('I found your number in 1 guess.')
I can't figure out how to get the program to print a different message for the program guessing the number in 1 guess vs. it guessing it in more than one guess.
You are checking the wrong value. Change this:
if guess == 1:
to:
if iteration == 1:
I need the program to give me a message about input being inconsistent when the user fails to respond to the less than/greater than prompts properly.
You are using an else in a situation where it can never be true, since hint.lower() is already certainly a valid letter, and you already checked all possible values. Adding an else to that is futile and not what you need. An inconsistency is detected when min_no becomes greater than max_no. So change:
else:
raise ValueError('Your answers have not been consistent.')
to this:
if min_no > max_no:
raise ValueError('Your answers have not been consistent.')
Other improvements
For getting a random integer between two integers, including both as possible outcomes, don't use randrange, but randint. Otherwise the second value will never be selected.
Your code will sometimes produce the same number as the previous guess, even if the user answered with L or G. This is because you keep that guess in the new range of possible values. So change:
max_no = guess
to this:
max_no = guess - 1
And also:
min_no = guess
to this:
min_no = guess + 1

Python 'Guess Your Age' Remember Last Integer

I am relatively new to programming with python (actually programming in general). I am making this 'Guess My Age' program that only has one problem:
import random
import time
import sys
print("\tAge Guesser!")
print("\t8 tries only!")
name = input("\nWhat's your name? ")
num = 80
min_num = 6
tries = 1
number = random.randint(min_num, num)
print("\nLet me guess... You are", number, "years old?")
guess = input("'Higher', 'Lower', or was it 'Correct'? ")
guess = guess.lower()
while guess != "correct":
if tries == 8:
print("\n I guess I couldn't guess your age....")
print("Closing...")
time.sleep(5)
sys.exit()
elif guess == "higher":
print("Let me think...")
min_num = number + 1 #### Here is my trouble - Don't know how to limit max number
time.sleep(3) # pause
elif guess == "lower":
print("Let me think...")
num = number - 1
time.sleep(3) # pause
number = random.randint(min_num, num) #<- Picks new random number
print("\nLet me guess... You are", number, "years old?")
guess = input("'Higher', 'Lower', or was it 'Correct'? ")
guess = guess.lower() #<- Lowercases
tries += 1 #<- Ups the tries by one
print("\nPfft. Knew it all along.")
time.sleep(10)
As you can see, I have 'num' as the max number for the random integer getting picked, but with:
elif guess == "higher":
print("Let me think...")
min_num = number + 1
it can go back up to however high it wants.
I want it to remember the last integer that 'num' was.
Say the program guessed 50 and I said 'Lower'. Then it said 30 and I said 'Higher'
I know I am probably sounding confusing, but please bear with me.
You need to define a maximum number as well as a minimum number. If they say their age is lower than a given age, you should set that age minus 1 as the maximum.
Of course, you also need to set an initial maximal age.
You might find it more useful to look into recursive functions for this kind of problem. If you define a function which takes min_age, max_age and tries_left as parameters, which comes up with a random number with between min_age and max_age and queries the user, you can then rerun the function (within itself) with a modified min_age, max_age and tries_left - 1. If tries_left is zero, concede defeat. This way you might get a better understanding of the logical flow.
I have left code out of this answer because, as you are a beginner, you will find it a useful exercise to implement yourself.
Cant you split out your guess into something like
max_num = 0
min_num = 0
elif guess =="lower":
max_num = number
if min_num!=0:
number = min_num+(max_num-min_num)/2
else:
number = max_num-1
elif guess =="higher":
min_num = number
if max_num!=0:
number=min_num+(max_num-min_num)/2
else:
number=min_num+1
Sorry it's not meant to be fully rigorous, and its a slight change on the logic you have there, but splitting out your variables so you have a higher and lower cap, that should help a lot?
Cheers
Please let me know if you need more elaboration, and I can try to write out a fully comprehensive version
It seems as though I was wrong in the fact that it did not remember the older integers. Before when running the program it would guess a number higher than the 'num' had specified. I don't know what I changed between then and now? But thank you for the help! #.#
This seems to work.
The only changes I really made:
-Variable names were confusing me, so I changed a couple.
-Note that if you try to mess with it (lower than 5, higher than 3... "Is it 4?" if you say it's higher or lower, you'll get an error).
The first time you set min and max numbers, you do it outside of the loop, so this script does "remember" the last guess and applies it to the new min, max inside of the loop. Each time it runs, the min will get higher or the max will get lower, based on the feedback from when the user checks the guess. If you had stuck the "min_num=6" and the "num=80" inside of the loop, the guesses would never get better.
import random
import time
import sys
print("\tAge Guesser!")
print("\t8 tries only!")
name = input("\nWhat's your name? ")
max_num = 10
min_num = 1
tries = 1
guess = random.randint(min_num, max_num)
print("\nLet me guess... You are", guess, "years old?")
check = raw_input("'Higher', 'Lower', or was it 'Correct'? ")
check = check.lower()
while check != "correct":
if tries == 8:
print("\n I guess I couldn't guess your age....")
print("Closing...")
time.sleep(5)
sys.exit()
elif check == "higher":
print("Let me think...")
min_num = guess + 1
time.sleep(3) # pause
elif check == "lower":
print("Let me think...")
max_num = guess - 1
time.sleep(3) # pause
guess = random.randint(min_num, max_num) # <- Picks new random number
print("\nLet me guess... You are", guess, "years old?")
check = input("'Higher', 'Lower', or was it 'Correct'? ")
check = check.lower() # <- Lowercases
tries += 1 # <- Ups the tries by one
print("\nPfft. Knew it all along.")
time.sleep(10)

Python number guessing game

I have found some practice problems online and I got most of them to work, but this one has stumped me. Its not homework so I'm not getting a grade. However, there isn't a solution provided so the only way to get the answer is by doing it.
The task asks for you to write a problem that plays a number guessing game for numbers 1-100. However, this one tries to guess the users number by interval guessing, such as [1, 100] and generates the next question by using first+last/2.
I have a sample run from the site.
Think of a number between 1 and 100 (inclusive).
Answer the following questions with letters y or Y for yes and n or N for no.
interval: [1,100]. Is your number <= 50? y
interval: [1,50]. Is your number <= 25? y
interval: [1,25]. Is your number <= 13? y
interval: [1,13]. Is your number <= 7? n
interval: [8,13]. Is your number <= 10? n
interval: [11,13]. Is your number <= 12? y
interval: [11,12]. Is your number <= 11? y
Your number is: 11
Here is my code so far, but I don't even quite know where to start because a while-loop constantly gives me an infinite loop. I know the "middle" number needs to be an integer or else it'll be an infinite loop, but I can't seem to figure out how to do that.
x = input("Is your numbr <=50?")
count = 100
while x=="y" or "Y":
count = count/2
x = input("Is your number <=",count,"?")
print(count)
If anyone has any tips it would be greatly appreciated.
The issue is here:
while x=="y" or "Y":
the expression "Y" will always evaluate to true.
You want
while x == "y" or x == "Y":
Even then, this will end the loop when the user types an "N". A working loop would be something like:
finished = False
while not finished:
if x == "y":
upper -= (upper-lower)/2
# prompt for input
elif x == "n":
lower += (upper-lower)/2
# prompt for input
if upper == lower or (upper - 1) == lower:
finished = True
# final output
You should be able to fill in the blanks from there.
The entire idea of the problem is to keep both "bounds" starting at 1 and 100, and each time you make a question "is you number <= X" you discard half of the range according to the answer, you are not doing this in your current solution.
like this.
lower = 1
high = 100
mid = (high + lower)/2 -> at start it will be 50
If the user answers Yes then you take the range from the current lower bound to the mid of the range, otherwise you continue with the range starting on mid+1 to the end, like this:
If user answers Yes:
high = mid
If user answers No:
lower = mid +1
The last part of the idea is to detect when the range lower-high contains only 2 numbers, or are the same number like this [11,12], you use the final answer of the user to choose the correct answer and the program terminates, the full code is here so you can test it:
found = False
range_lower_bound = 1
range_high_bound = 100
print "Think of a number between 1 and 100 (inclusive)."
print "Answer the following questions with letters y or Y for yes and n or N for no."
while not found:
range_mid = (range_high_bound + range_lower_bound) / 2
x = raw_input('interval: [%s,%s]. Is your number <= %s? ' % (range_lower_bound, range_high_bound, range_mid))
if x.lower() == 'y':
# Check if this is the last question we need to guess the number
if range_mid == range_lower_bound:
print "Your number is %s" % (range_lower_bound)
found = True
range_high_bound = range_mid
# here i'm defaulting "anything" no N for simplicity
else:
# Check if this is the last question we need to guess the number
if range_mid == range_lower_bound:
print "Your number is %s" % (range_high_bound)
found = True
range_lower_bound = range_mid + 1
Hope it helps!
One good idea would be to have a simple while True: loop, inside which you maintain a maximum guess and a minimum guess. You then ask the user whether their number is greater than the average of the two. If it is, update your minimum guess to the average. If not, you lower your maximum guess to the average. Repeat until the two guesses are equal, at which point you have found the number, and can break out of the infinite loop.
You'll have to do some simple parity checking of course, to make sure you actually change your guesses in each round. You should really use raw_input() for strings, input() is for python-formatted data.

Categories

Resources