Message='int' object is not subscriptable - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: Message='int' object is not subscriptable (/thread-34570.html) |
Message='int' object is not subscriptable - DanielCook - Aug-10-2021 I'm trying to make battle ships in python and for program works for the most part apart from supposedly randomly when the computer is generating coordinates to attack the player and misses instead of creating a coordinate it creates a number. The coordinate generator works by having a list ["a","b","c","d","e","f","g","h"] then generating a random number for the row (0,7) which is then used to take a letter from the list e.g. if the random number is 2 it would take c from the list. Then it would generate a second number for the column (1,8) then put them together to create a coordinate. e.g. c5. This works a lot of the time but at some points instead of getting c5 it would give 25 and i'm not sure why as it doesn't do it all the time. import sys import random import time # GUI print("Welcome to battle boats\n1. New game\n2. Continue game\n3. Quit") startMenuInput = input("Enter 1, 2 or 3 to make your choice: ") ## Subroutines here def printGrid(nums,lines,a,b,c,d,e,f,g,h): print(*nums, sep = '') print(*lines, sep = '') print(*a, sep='') print(*b, sep='') print(*c, sep='') print(*d, sep='') print(*e, sep='') print(*f, sep='') print(*g, sep='') print(*h, sep='') print("\n") def printCOMGrid(COMnums,COMlines,COMa,COMb,COMc,COMd,COMe,COMf,COMg,COMh): print(*COMnums, sep = '') print(*COMlines, sep = '') print(*COMa, sep='') print(*COMb, sep='') print(*COMc, sep='') print(*COMd, sep='') print(*COMe, sep='') print(*COMf, sep='') print(*COMg, sep='') print(*COMh, sep='') print("\n") def printTargetTracker(TTnums,TTlines,TTa,TTb,TTc,TTd,TTe,TTf,TTg,TTh): print(*TTnums, sep = '') print(*TTlines, sep = '') print(*TTa, sep='') print(*TTb, sep='') print(*TTc, sep='') print(*TTd, sep='') print(*TTe, sep='') print(*TTf, sep='') print(*TTg, sep='') print(*TTh, sep='') print("\n") def newGame(): enteredCoordinates = [] COMenteredCoorindates = [] COMattackCoordinates = [] nums = [" "," 1 "," 2 "," 3 "," 4 "," 5 "," 6 "," 7 "," 8 "] lines = [" ---------------------------------"] a = ["a| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] b = ["b| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] c = ["c| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] d = ["d| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] e = ["e| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] f = ["f| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] g = ["g| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] h = ["h| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMnums = [" "," 1 "," 2 "," 3 "," 4 "," 5 "," 6 "," 7 "," 8 "] COMlines = [" ---------------------------------"] COMa = ["a| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMb = ["b| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMc = ["c| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMd = ["d| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMe = ["e| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMf = ["f| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMg = ["g| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] COMh = ["h| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTnums = [" "," 1 "," 2 "," 3 "," 4 "," 5 "," 6 "," 7 "," 8 "] TTlines = [" ---------------------------------"] TTa = ["a| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTb = ["b| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTc = ["c| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTd = ["d| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTe = ["e| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTf = ["f| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTg = ["g| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] TTh = ["h| ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] ","[ ] "] for i in range (5): alreadyEntered = True placementCoordinate = input("Enter the coordinates of your boat: ") print("\n") while alreadyEntered == True: if placementCoordinate in enteredCoordinates: alreadyEntered = True placementCoordinate = input("Coordinate already entered, enter another coordinate: ") else: alreadyEntered = False if alreadyEntered == False: enteredCoordinates.append(placementCoordinate) row = placementCoordinate[0] column = placementCoordinate[1] column = int(column) if row == "a": a.pop(column) a.insert(column,"[*] ") if row == "b": b.pop(column) b.insert(column,"[*] ") if row == "c": c.pop(column) c.insert(column,"[*] ") if row == "d": d.pop(column) d.insert(column,"[*] ") if row == "e": e.pop(column) e.insert(column,"[*] ") if row == "f": f.pop(column) f.insert(column,"[*] ") if row == "g": g.pop(column) g.insert(column,"[*] ") if row == "h": h.pop(column) h.insert(column,"[*] ") printGrid(nums,lines,a,b,c,d,e,f,g,h) cRowsList = ["a","b","c","d","e","f","g","h"] for i in range (5): alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol while alreadyEntered == True: if COMcoordinate in COMenteredCoorindates: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol else: alreadyEntered = False if alreadyEntered == False: COMenteredCoorindates.append(COMcoordinate) if cRow == "a": COMa.pop(randCol) COMa.insert(randCol,"[*] ") if cRow == "b": COMb.pop(randCol) COMb.insert(randCol,"[*] ") if cRow == "c": COMc.pop(randCol) COMc.insert(randCol,"[*] ") if cRow == "d": COMd.pop(randCol) COMd.insert(randCol,"[*] ") if cRow == "e": COMe.pop(randCol) COMe.insert(randCol,"[*] ") if cRow == "f": COMf.pop(randCol) COMf.insert(randCol,"[*] ") if cRow == "g": COMg.pop(randCol) COMg.insert(randCol,"[*] ") if cRow == "h": COMh.pop(randCol) COMh.insert(randCol,"[*] ") print("All your coordinates and the computers coordinates have been selected. This is your target tracker:\n") printTargetTracker(TTnums,TTlines,TTa,TTb,TTc,TTd,TTe,TTf,TTg,TTh) print("You can use it to track where you have attacked and if the have hit or missed enemy boats.\n") gameWon = False printCOMGrid(COMnums,COMlines,COMa,COMb,COMc,COMd,COMe,COMf,COMg,COMh) while gameWon == False: #Player attack playerScore = 0 comScore = 0 attack = input("Enter the coordinates of where you want to attack:\n ") #Player hit computer if attack in COMenteredCoorindates: print("HIT!\n") row = attack[0] column = attack[1] column = int(column) if row == "a": TTa.pop(column) TTa.insert(column,"[H] ") if row == "b": TTb.pop(column) TTb.insert(column,"[H] ") if row == "c": TTc.pop(column) TTc.insert(column,"[H] ") if row == "d": TTd.pop(column) TTd.insert(column,"[H] ") if row == "e": TTe.pop(column) TTe.insert(column,"[H] ") if row == "f": TTf.pop(column) TTf.insert(column,"[H] ") if row == "g": TTg.pop(column) TTg.insert(column,"[H] ") if row == "h": TTh.pop(column) TTh.insert(column,"[H] ") printTargetTracker(TTnums,TTlines,TTa,TTb,TTc,TTd,TTe,TTf,TTg,TTh) playerScore = playerScore + 1 if playerScore == 5: gameWon = True else: #Player miss computer print("MISS!\n") row = attack[0] column = attack[1] column = int(column) if row == "a": TTa.pop(column) TTa.insert(column,"[M] ") if row == "b": TTb.pop(column) TTb.insert(column,"[M] ") if row == "c": TTc.pop(column) TTc.insert(column,"[M] ") if row == "d": TTd.pop(column) TTd.insert(column,"[M] ") if row == "e": TTe.pop(column) TTe.insert(column,"[M] ") if row == "f": TTf.pop(column) TTf.insert(column,"[M] ") if row == "g": TTg.pop(column) TTg.insert(column,"[M] ") if row == "h": TTh.pop(column) TTh.insert(column,"[M] ") printTargetTracker(TTnums,TTlines,TTa,TTb,TTc,TTd,TTe,TTf,TTg,TTh) #Computer Attack time.sleep(3) alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol while alreadyEntered == True: if COMcoordinate in COMattackCoordinates: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = randRow + randCol else: alreadyEntered = False if alreadyEntered == False: print("Computer attacks", COMcoordinate) COMattackCoordinates.append(COMcoordinate) #Computer hit player if COMcoordinate in enteredCoordinates: print(COMcoordinate,"\n") print("HIT!\n") row = COMcoordinate[0] column = COMcoordinate[1] column = int(column) if row == "a": a.pop(column) a.insert(column,"[H] ") if row == "b": b.pop(column) b.insert(column,"[H] ") if row == "c": c.pop(column) c.insert(column,"[H] ") if row == "d": d.pop(column) d.insert(column,"[H] ") if row == "e": e.pop(column) e.insert(column,"[H] ") if row == "f": f.pop(column) f.insert(column,"[H] ") if row == "g": g.pop(column) g.insert(column,"[H] ") if row == "h": h.pop(column) h.insert(column,"[H] ") printGrid(nums,lines,a,b,c,d,e,f,g,h) else: #Computer miss player print(COMcoordinate,"\n") print("MISS!\n") row = COMcoordinate[0] column = COMcoordinate[1] column = int(column) if row == "a": a.pop(column) a.insert(column,"[M] ") if row == "b": b.pop(column) b.insert(column,"[M] ") if row == "c": c.pop(column) c.insert(column,"[M] ") if row == "d": d.pop(column) d.insert(column,"[M] ") if row == "e": e.pop(column) e.insert(column,"[M] ") if row == "f": f.pop(column) f.insert(column,"[M] ") if row == "g": g.pop(column) g.insert(column,"[M] ") if row == "h": h.pop(column) h.insert(column,"[M] ") printGrid(nums,lines,a,b,c,d,e,f,g,h) ## Main program from here if startMenuInput == "1": print("\nNew game") newGame() if startMenuInput == "2": print("\nContinue game") if startMenuInput == "3": sys.exit(0) RE: Message='int' object is not subscriptable - buran - Aug-10-2021 (Aug-10-2021, 10:47 AM)DanielCook Wrote: This works a lot of the time but at some points instead of getting c5 it would give 25 and i'm not sure why as it doesn't do it all the time.It is not serious to expect that we/anyone will look into 350 lines of code to debug an error that you get sparingly from time to time... Even without error your code is in despread need of refactoring. RE: Message='int' object is not subscriptable - deanhystad - Aug-10-2021 Your code would benefit greatly from a new representation of the grid. A grid is a 2D array. An easy way to represent this in Python is to make a list of lists. tracker_grid = [[' ']*8 for _ in range(8)]This list comprehension makes 8 rows, each row being [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '] Coordinates are combinations of letters and numbers. 'a1' is the first row, first column and 'h8' the last row last column. You can convert a coordinate to the row and column using the ordinal values of the letters. row = ord(coords[0])-ord('a') col = ord(coords[1])-ord('1')Now you can easily get or set the marker for any position in the grid with only a few lines of code. Since this will be done often, I would write a couple of functions. def get(board, coords): '''Get marker on board at coords''' row = ord(coords[0])-ord('a') col = ord(coords[1])-ord('1') return board[row][col] def set(board, coords, marker): '''Set marker on board at coords''' row = ord(coords[0])-ord('a') col = ord(coords[1])-ord('1') board[row][col] = markerA big part of your game is getting input from the player. This is done at the start of the game to position the players boats, and then through the game to get the player's attack. Since this is done in two separate places it is a candidate for a function. def enter_coords(prompt, board=None): '''Enter coordinates. Verify coordinates are valid''' while True: coords = input(prompt).lower() if coords[0] in 'abcdefgh' and coords[1] in '12345678': if board is None or get(board, coords) == ' ': # Check if coords already entered return coords print('Coordinates already entered.') else: print('Coordinates are rc where r is a letter a-g and c is a number 1-8')Add a function that can print a grid, and you are ready to play a game. This code encapsulates the grid and a hit counter in a class. import random import time EMPTY = ' ' BOAT = 'B' HIT = '*' MISS = '-' class Grid(): '''8x8 playing field. The grid starts empty. The player and computer place BOATs at different coordinates. Player and computer take turns launching attacks. A successful attack is marked as a HIT. The first to get 5 hits wins. ''' def __init__(self, id=None): self.grid = [[EMPTY]*8 for _ in range(8)] self.hits = 0 self.id = id def __getitem__(self, coords): '''Return grid[coords]''' return self.grid[ord(coords[0])-ord('a')][ord(coords[1])-ord('1')] def __setitem__(self, coords, value): '''Set grid[coords] = value''' self.grid[ord(coords[0])-ord('a')][ord(coords[1])-ord('1')] = value def attack(self, coords): '''Attack coords. Update grid and hit counter. Return 1 for hit, 0 for miss''' hit = 1 if self[coords] == BOAT else 0 self.hits += hit self[coords] = (MISS, HIT)[hit] return hit def print(self, header=None, allowed=(BOAT, HIT, MISS)): '''Print grid. Center header over grid. Only print markers in the allowed list''' if header is not None: print('', f'{header:^35}', sep='\n') print(" 1 2 3 4 5 6 7 8\n -------------------------------") for label, row in zip('abcdefgh', self.grid): print(f'{label} ', ' | '.join([f'{x}' if x in allowed else f'{EMPTY}' for x in row])) def enter_coords(prompt, grid, allowed=(EMPTY, BOAT)): '''Enter coordinates. Verify coordinates are valid. If grid is provided verify coordinates are empty''' while True: coords = input(prompt).lower() if len(coords) < 2 or coords[0] not in 'abcdefgh' or coords[1] not in '12345678': print('Coordinates are rc where r is a-g and c is 1-8') elif grid[coords] not in allowed: print('Coordinates already entered.') else: return coords def new_game(): '''Play a new game''' player = Grid() computer = Grid() remaining_coords = [f'{r}{c}' for r in 'abcdefgh' for c in '12345678'] random.shuffle(remaining_coords) get_coords = [] # Place the boats for coords in random.sample(remaining_coords, 5): computer[coords] = BOAT player.print('Enter position for a boat') player[enter_coords("Coordinates: ", player, (EMPTY,))] = BOAT while True: #Player attack computer.print('Enter attack coordinates', (MISS, HIT)) coords = enter_coords("Coordinates: ", computer) result = ('MISS', 'HIT')[computer.attack(coords)] if computer.hits >= 5: computer.print(f'{coords} is a HIT. Player WINS!') return computer.print(f'{coords} is a {result}', (MISS, HIT)) time.sleep(3) #Computer Attack coords = remaining_coords.pop() result = ('MISS', 'HIT')[player.attack(coords)] if player.hits >= 5: player.print(f'Computer attacks {coords}. Computer WINS!') return player.print(f'Computer attacks {coords}, {result}') time.sleep(3) new_game() RE: Message='int' object is not subscriptable - deanhystad - Aug-10-2021 Your error is in this code that only gets called when the computer randomly selects a coordinate that was already used. Starting at line 260 in your code: while alreadyEntered == True: if COMcoordinate in COMattackCoordinates: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = randRow + randCol # Should be cRow + stringColThis code is used a couple times in your code making it a prime candidate for reuse. Putting frequently used code in a function reduces overall code, but more importantly reduces chances for errors like the one in your program. def random_coord(used_coords): while True: coords = random.choice('abcdefgh') + random.choice('12345678') if coords not in (used_coords): used_coords.append(coords) return coordsThis simple function reduces this: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol while alreadyEntered == True: if COMcoordinate in COMattackCoordinates: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = randRow + randCol else: alreadyEntered = False if alreadyEntered == False: print("Computer attacks", COMcoordinate) COMattackCoordinates.append(COMcoordinate)to this: COMcoordinate = random_coords(COMattackCoordinates) print("Computer attacks", COMcoordinate)and this cRowsList = ["a","b","c","d","e","f","g","h"] for i in range (5): alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol while alreadyEntered == True: if COMcoordinate in COMenteredCoorindates: alreadyEntered = True randRow = random.randint(0,7) randCol = random.randint(1,8) cRow = cRowsList[randRow] stringCol = str(randCol) COMcoordinate = cRow + stringCol else: alreadyEntered = False if alreadyEntered == False: COMenteredCoorindates.append(COMcoordinate) if cRow == "a":to for i in range (5): COMcoordinate = random_coords(COMenteredCoorindates) if cRow == "a": RE: Message='int' object is not subscriptable - deanhystad - Aug-10-2021 Your method for randomly choosing coordinates is very inefficient. Here's a little program that counts how long it takes to randomly select 64 different numbers in the range 1..64. import random for _ in range(10): used_spots = set() i = 0 while len(used_spots) < 64: used_spots.add(random.randint(1, 64)) i += 1 print(i) You do not put cards back in the deck while dealing a hand, so why not use the same kind of subtractive logic for coordinates. This code makes a "deck" of coordinates and shuffles the deck. To get a random coordinate you just deal the top card.import random random_coords = [r+c for r in 'abcdefgh' for c in '12345678'] # Make list of all coordinates random.shuffle(random_coords) for _ in range(5): print(random_coords.pop()) # Deal the top card |