Understanding ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))

I am trying to work on automate the boring stuff with python. In particular project 33 hacking.py where you try to create a row of characters with words that could be the potential password. The players are to get 3-4 attempts to do so and when they do guess they get a hint back saying that the word they selected has 3/7 correct words or 1/7 or none at all.

For more details on the project itself I have shown a link here to the instructions and one version of the solution code. I am not using the solution code and I am trying to recreate the project for myself.

https://inventwithpython.com/bigbookpython/project33.html

A part of this project requires me to fill the rows with garbage characters such as $*@#%… and python needs to be able to see how many spaces are left in the garbage characters. I thought my function solved it but that is not the case.

Can anyone give me advice or help me? The chat gpt fix did not work.

I ran my code through chat GPT and it said.

It looks like there’s an issue with the random.randint function call in your garbage_character_filler function. The error is occurring because the characters_left variable becomes negative, causing randrange to raise a ValueError due to an empty range.

To fix this issue, you should ensure that characters_left is a non-negative value before calling random.randint. You can use the max function to ensure that the value is at least 0. Modify the line where insertion is calculated as follows:

import sys
import random

Traceback Error

Traceback (most recent call last):
  File "/Users/andrewstribling/Desktop/dev/python-hacking-game/andrews_hacking.py", line 148, in <module>
    main()
  File "/Users/andrewstribling/Desktop/dev/python-hacking-game/andrews_hacking.py", line 142, in main
    garbage_character_filler(game_word_set)
  File "/Users/andrewstribling/Desktop/dev/python-hacking-game/andrews_hacking.py", line 116, in garbage_character_filler
    insertion = random.randint(1, characters_left)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/random.py", line 362, in randint
    return self.randrange(a, b+1)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/random.py", line 345, in randrange
    raise ValueError("empty range for randrange() (%d, %d, %d)" % (istart, istop, width))
ValueError: empty range for randrange() (1, -4, -5)

"""
https://inventwithpython.com/bigbookpython/project33.html
basically game_words is where I am telling python to grab the 15 words used fo the hacking mini game.

Players select from this list of words hoping to guess the password.

I need 3 words that have 0 letters in common with the password
and another 3 words that have 1,2,3,4 letters in common with the password respectivley and the password all stored in a way that python can know about it.
after that I need to make a game board that will display the characters and the words on the screen.
"""
# -----------------------------------------------------------------#

# CONSTANTS
# garbage characters system
garbage_chars = "~!@#$%^&*()_+-={}[]|;:,.<>?/"


def introduce():
    name = input("To start the game please type in your player name: ")
    print(
        f"Agent {name}! The evil dictator Kim Jong Un has decided to launch the nukes. All of humanity's hopes rest on your shoulders to hack into the system and stop the launch. You will see a series of possible words that are the password. Use our hint system software to determine if you are close to guessing the password. The hint system will tell you the letters that the word choice and the password have in common as well as positioning. You are our last hope.... \n Okay agent {name}, here are list of the possible passwords. \n Type in the word from the available list of words that you believe is the password."
    )


# this function will gather in the game words from the sevenletterwords.txt file
def get_word_list():
    with open("sevenletterwords.txt", "r") as file:
        word_list = [line.strip().upper() for line in file.readlines()]
        random.shuffle(word_list)
        # test print(full_list_of_words)
    return word_list


# This function generates a password for the player to guess.
def get_password(word_list):
    password = random.choice(word_list)
    # print("test: This is a test for the password: ", password)
    return password


def get_game_word_set(word_list, password):
    game_words_dictionary = {}
    game_words = []
    # we can target keys in a dictionary with variables!
    # I want to use this technique once I get all three of them in there.
    # place the words that have 0 letters in common into the dictionary at the 0 index.
    game_words_dictionary[0] = get_n_overlap(word_list, 0, password)
    # now do the same things for the other words
    game_words_dictionary[1] = get_n_overlap(word_list, 1, password)
    game_words_dictionary[2] = get_n_overlap(word_list, 2, password)
    game_words_dictionary[3] = get_n_overlap(word_list, 3, password)
    game_words_dictionary[4] = get_n_overlap(word_list, 4, password)
    # now we combine these values in the dictionary togather into a single list.
    game_word_set = sum(game_words_dictionary.values(), [])
    game_word_set.append(password)
    random.shuffle(game_word_set)
    print("This is the game words dictionary. " + str(game_word_set))
    print("This is the password for the game. " + str(password))
    return game_word_set


# the game words need to have a certain amount of characters in common with the password.
def get_n_overlap(word_list, n, password):
    overlapping_words = []
    x = 0
    for word in word_list:
        if x < 3:
            # if the number of matching letters is the same as n than append that word to the list.
            overlap = set(password) & set(word)
            if len(overlap) == n and word != password:
                overlapping_words.append(word)
                x += 1
                if x == 3:
                    break
    return overlapping_words


# I want the function to generate a hex number.
# game row
# Ox217_ _ _ _ _ _ _ _ _ _ _
def hex_number():
    number = random.randint(1000, 1500)
    hex_number = hex(number)
    return hex_number


def game_word_selection(game_word_set, already_selected_words=None):
    if already_selected_words is None:
        already_selected_words = []

    for game_word in game_word_set:
        if game_word not in already_selected_words:
            return game_word, already_selected_words

        # If the game word is already selected I need python to try again to find a game word that is not already used.
        else:
            continue


# I than want the function to generate a random number indicating the starting position of the garbage characters and fill the row after the hex number. In this case lets say 4
# Ox217 _ _ _ _ _ _ _ _ _ _ _
# I than want the game word to be generated and appended to the list.
# I than want the garbage character filler to fill the remainder of the row with garbage characters.
# i need 16 rows not one row generator


def garbage_character_filler(game_word):
    character_row_limit = 16
    garbage_row = []
    garbage_row.append(hex_number())
    characters_left = character_row_limit - len(garbage_row[0]) - len(game_word)
    insertion = random.randint(1, characters_left)
    garbage_chars = "~!@#$%^&*()_+-={}[]|;:,.<>?/"
    garbage_row.extend(random.choices(garbage_chars, k=5))
    garbage_row.insert(insertion, game_word)
    game_row = "".join(garbage_row)
    return game_row

print(garbage_character_filler(game_word="PERHAPS"))


# DRIVER CODE ---------------------
# these lines of code are here to prevent not defined issues.


def main():
    introduce()
    word_list = get_word_list()
    password = get_password(word_list)

    game_word_set = get_game_word_set(word_list, password)

    one_game_word, already_selected_words = game_word_selection(
        game_word_set, already_selected_words=[]
    )
    gamerow = garbage_character_filler(one_game_word)

    garbage_character_filler(game_word_set)


# If this program was run (instead of imported), run the game:
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        sys.exit()  # When Ctrl-C is pressed, end the program.
# random will change things in place. there is no need for variables.


If you read the traceback carefully, you can see that the problematic line in main() is garbage_character_filler(game_word_set). Just based on what the funtion is supposed to do, this is obviously nonsense since it expects a single word and not a set of words. From what I can tell, just removing the line is enough.

1 Like

I think you are right about the game_word_set. I need to be able to call one word at a time not all of the words at once. If I call all of the words at once of course the length of garbage characters would be 0 as there would be no room left.
I do however need to be able to generate 16 rows with the words and garbage characters so maybe I need to change what I am passing in.

Thank you for your insight.


Traceback (most recent call last):
  File "/Users/andrewstribling/Desktop/dev/python-hacking-game/andrews_hacking.py", line 150, in <module>
    main()
  File "/Users/andrewstribling/Desktop/dev/python-hacking-game/andrews_hacking.py", line 144, in main
    garbage_character_filler(game_word)
                             ^^^^^^^^^
NameError: name 'game_word' is not defined. Did you mean: 'game_word_set'?
andrewstribling@Andrews-MacBook-Pro python-hacking-game % 

somehow game_word is not defined anymore. I am considering calling the function that returns it and getting a variable to hold it.

I can explain how to examine code for logical errors, yes. I can’t tell you what is wrong with your code, first off because I can’t see it at the moment, and secondly because it will not help you develop important fundamental skills.

This is, according to the error trace, the last time that Python is looking at your code. Therefore, if there is any problem you can solve, this is where it would be. So, this is where you should start looking.

When the code runs and the error occurs, what is the value of characters_left? (You should try to use a debugger, or add some print calls to the code, etc., in order to figure out what value you get when the problem occurs.)

Does it make sense to you, that this could be the value for characters_left, at this point in the code? (Should this part of the code be running, if characters_left has that value? Should it be possible for characters_left to have that value, ever?)

Does it make sense to you, if characters_left has such a value, to call random.randint? (What do you think should happen in that case, and what do you expect the results to look like?)

ChatGPT literally does not understand what it is saying (outputting) as text. It is best used as an advanced search engine. It does not attempt logical reasoning and the only “knowledge” it has is a model for figuring out what word comes next. It does not “think” any more than Lucky was doing in that scene from Waiting for Godot.

Again, we can only possibly diagnose issues in code that is actually shown to us.