''' Soren DeOrlow IDSN 599, Fall 2021 deorlow@usc.edu Homework 3 ''' from tkinter import * import random from PIL import Image, ImageTk import time images = [] cave = [] percepts = [] root = Tk() root.title("Welcome to Wumpus World") root.geometry("440x440") root.grid() #Player must be global so it can be moved img = Image.open('player.png') playerImage = ImageTk.PhotoImage(img) #playerImage = PhotoImage(file="player.png") playerLabel = Label(root, image=playerImage) empty = Image.open('empty.png') emptyImage = ImageTk.PhotoImage(empty) class Room: def __init__(self, pit, wumpus, gold, walls): self.hasPit = pit self.hasWumpus = wumpus self.hasGold = gold self.walls = walls def __str__(self): return str(self.hasPit) + " " + str(self.hasWumpus) + " " + str(self.hasGold) + " " + str(self.walls) class Player: def __init__(self): self.rowLocation = 0 self.columnLocation = 0 self.directionFacing = 'right' self.hasGold = False def __str__(self): return str(self.columnLocation) + ',' + str(self.rowLocation) + ',' + self.directionFacing def makeCave(): # Make the 10x10 cave pitChance = 1 for i in range(10): caveRow = [] for j in range(10): value = random.randrange(100) if value <= pitChance: pit = True else: pit = False if i == 0 and j == 0: # Can't have a pit at 0,0 pit = False caveRow.append(Room(pit, False, False, [])) cave.append(caveRow) # pick a random room for the wumpus. Remove any pit if there is one in the room while True: wumpusX = random.randrange(10) wumpusY = random.randrange(10) if wumpusX == 0 and wumpusY == 0: continue # can't have the Wumpus at 0,0 break # pick a random room for the gold. Remove any pit if there is one in the room. Can't be the wumpus room while True: goldX = random.randrange(10) goldY = random.randrange(10) if goldX == 0 and goldY == 0: continue # can't have the gold at 0,0 row = cave[goldX] if row[goldY].hasWumpus: #Can't have the gold where the Wumpus is continue break #Set the wumpus. Can't have a pit where the Wumpus is row = cave[wumpusX] row[wumpusY].hasWumpus = True row[wumpusY].hasPit = False #Set the gold. Can't have a pit where the gold is row = cave[goldX] row[goldY].hasGold = True row[goldY].hasPit = False def makePercepts(): # Create the blank percept lists for all rooms for i in range(10): perceptRow = [] for j in range(10): percept = ['', '', '', '', ''] perceptRow.append(percept) percepts.append(perceptRow) # Do the wumpus for i in range(10): caveColumn = cave[i] for j in range(10): if caveColumn[j].hasWumpus: rooms = [[j - 1, i], [j + 1, i], [j, i - 1], [j, i + 1]] for roomCoords in rooms: column = roomCoords[0] row = roomCoords[1] if column == -1 or column == 10: continue if row == -1 or row == 10: continue tempColumn = percepts[column] tempRoom = tempColumn[row] tempRoom[0] = 'Stench' # Do the pits for i in range(10): caveRow = cave[i] perceptRow = percepts[i] for j in range(10): if caveRow[j].hasPit: rooms = [[j - 1, i], [j + 1, i], [j, i - 1], [j, i + 1]] for roomCoords in rooms: row = roomCoords[0] column = roomCoords[1] if row == -1 or row == 10: continue if column == -1 or column == 10: continue tempRow = percepts[row] tempRoom = tempRow[column] tempRoom[1] = 'Breeze' def getPercept(player): #Given the player's location, return the percept at that location perceptRow = percepts[player.rowLocation] return perceptRow[player.columnLocation] def getRoom(player): caveRow = cave[player.columnLocation] return caveRow[player.rowLocation] def doAction(action, player): #Perform the action given by the user direction = player.directionFacing row = player.columnLocation column = player.rowLocation directions = ['right','up','left','down'] dirIndex = directions.index(direction) if action == "TL": dirIndex += 1 if dirIndex == 4: dirIndex = 0 direction = directions[dirIndex] player.directionFacing = direction return "done" elif action == "TR": dirIndex -= 1 if dirIndex < 0: dirIndex = 3 direction = directions[dirIndex] player.directionFacing = direction return "done" elif action == "FW": #Move the player forward one room if they don't hit a wall if dirIndex == 0: moveDirection = [1,0] elif dirIndex == 1: moveDirection = [0,-1] elif dirIndex == 2: moveDirection = [-1,0] else: moveDirection = [0,1] row += moveDirection[0] column += moveDirection[1] if row < 0 or row > 9: #player tried to move into wall print("You bumped into a wall. You didn't move") return 'bump' if column < 0 or column > 9: #player tried to move into wall print("You bumped into a wall. You didn't move") return 'bump' #This is a valid move. Remove the player image from this location. Put an empty image here oldRow = row - moveDirection[0] oldColumn = column - moveDirection[1] l = images[oldRow] l[oldColumn].config(image=emptyImage) #Move is correct. Check for a pit or an alive wumpus player.rowLocation = column player.columnLocation = row caveRow = cave[row] room = caveRow[column] if room.hasWumpus: #player is dead print("You were horribly eaten by the Wumpus") return 'dead' elif room.hasPit: #player is dead print("You fell into a pit and died a nasty death") return "dead" elif room.hasGold: print("You have found the gold") percept = getPercept(player) percept[2] = "Glitter" l = images[row] l[column].config(image=playerImage) return "gold" else: #Update player image location l = images[row] l[column].config(image=playerImage) elif action == "GR": room = getRoom(player) if room.hasGold: #correct Grab action print("You have the gold") player.hasGold = True percept = getPercept(player) percept[2] = "" room.hasGold = False return "gold" else: print("You are not in the room with the gold") return "no gold" elif action == "CL": if row == 0 and column == 0: #correct Climb action. Game is over print("You have successfully exited the cave!") if player.hasGold: print("You exited the cave with the gold. Congratulations!") else: print("You exited the cave without the gold. Shame on you!") return "over" else: print("You are not in the correct room") return "not over" return 'alive' def main(): player = Player() # modify the window makeCave() makePercepts() # Create the empty seeming cave for i in range(10): imagerow = [] for j in range(10): emptyLabel = Label(root, image=emptyImage) imagerow.append(emptyLabel) emptyLabel.grid(row=j, column=i, rowspan=1, columnspan=1) images.append(imagerow) #Remove all this code except for the Player when ready # Add the Player to the cave l = images[0] l[0].config(image=playerImage) while True: root.update() # This is necessary so you see the graphics updated # This is where your code goes percept = getPercept(player) # Gives you the percept for the room you are in print(percept) # This is where you have your code to decide what action to take given the current percept action = chooseAction(percept, player) # With a selected action, have it executed returnValue = doAction(action, player) if returnValue == "dead" or returnValue == "over": exit(0) ''' This is where your code is going to go. Define all your data structures and the chooseAction method below here. Do not change any code that has been provided to you without asking permission first. Define your data structures above the chooseAction function ''' actionList = [] emptyPercept = ['', '', '', '', ''] movingForward = True roomDictionary = {} nextActions = [] visitedRoomList = [] goHome = False usedSafeRooms = [] roomSafetyDictionary = {} time.sleep(.25) #Pauses the program so your agent doesn't run too fast #write global so that pyCharm can identify the global outside of def chooseAction def makeDictKey(player): return str(player.rowLocation) + str(player.columnLocation) def chooseAction(percept, player): global movingForward global actionList global visitedRoomList global nextActions print("moving forward:", movingForward) if len(roomSafetyDictionary) == 0: for i in range(10): for j in range(10): key = str(i) + str(j) roomSafetyDictionary[key] = 0 key = makeDictKey(player) roomDictionary[key] = percept if len(visitedRoomList) > 0: lastRoom = visitedRoomList[-1] if key != lastRoom: visitedRoomList.append(key) else: visitedRoomList.append(key) print("Room:", key) if percept == emptyPercept: changeImages(percept, player, emptyImage) changeSafety(player, percept) if "Glitter" in percept: print("found the gold. Grabbing it") goHome = True return 'GR' if len(nextActions) > 0: print("Popping from next actions", nextActions) action = nextActions.pop() print(action, "na:", nextActions) return action if percept != emptyPercept: print("We have moved to a room that is not safe. Must turn around.") changeSafety(player, percept) #changeImages(percept, player, questionImage) nextActions = [] nextActions.append('FW') nextActions.append('TL') movingForward = False print('TL') return 'TL' if not movingForward: action = chooseTurn(player) print("Choose turn action:", action) if action == "": print("Couldn't find a new room to move to.") #action = computeTurnToRoom(player) action = 'FW' actionList.append(action) return action print("Found another room to move to", action) nextActions = ['FW'] movingForward = True print(action, "mf:",movingForward) return actionList if percept == emptyPercept and movingForward: action = 'FW' else: if len(visitedRoomList) == 1: exit(0) nextActions = [] nextActions.append('FW') nextActions.append('TL') movingForward = False print('TL') return 'TL' if action == "FW": if bumpWall(player): print("Can't move forward would bump into wall") action = chooseTurn(player) if action == "": print("No safe room to move to") action = moveBackToPriorRoom(player) print(action) return action def changeSafety(player, percept): # change safety levels for adjacent rooms based on the percept global roomSafetyDictionary i = player.rowLocation j = player.columnLocation rooms = [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]] # safe if percept == emptyPercept: for room in rooms: key = str(room[0]) + str(room[1]) if len(key) == 2: roomSafetyDictionary[key] = -1 elif 'Breeze' in percept or 'Stench' in percept: for room in rooms: key = str(room[0]) + str(room[1]) if len(key) == 2 and roomSafetyDictionary[key] != -1: roomSafetyDictionary[key] = 1 # This is a safe room print(roomSafetyDictionary) def chooseTurn(player): print("have to choose a turn to make. cant move forward.") turn = "" possibleRooms = chooseSafeAdjacentRooms(player) #iterate over possible rooms and remove any room that we've already visited goodRooms = [] for room in possibleRooms: key = "" + str(room[0]) + str(room[1]) if key not in roomSafetyDictionary: goodRooms.append([room[0], room[1]]) if len(goodRooms) == 0: return "" #no room to turn to room = goodRooms[0] currentRoom = [player.rowLocation, player.columnLocation] turn = computeTurnToRoom( player, currentRoom, room ) return turn def moveBackToPriorRoom(player): global visitedRoomList global movingForward global nextActions print("visited rooms:", visitedRoomList) key = makeDictKey(player) currentRoomIndex = visitedRoomList.index(key) priorRoomIndex = currentRoomIndex - 1 if priorRoomIndex < 0: print("we are in room 0,0. Find another safe room to move to") room = chooseSafeRoomWithMoves(player) if room == []: return 'CL' print("safe room to move into:", room) actionList(player, room) print("sr na:", nextActions) action = nextActions.pop() print(action) return action print("moving backward to room:", visitedRoomList[priorRoomIndex]) currentRoom = [player.rowLocation, player.columnLocation] priorRoom = visitedRoomList[priorRoomIndex] priorRow = int(priorRoom[0]) priorColumn = int(priorRoom[1]) action = computeTurnToRoom(player, currentRoom, [priorRow, priorColumn]) prior("compute turn to room: ", action) nextActions = ['FW'] print('action in move back to prior room', action) movingForward = False return action def generateActions(player, currentRoom, nextRoom): global nextActions print("in generate actions") turn = computeTurnToRoom(player, currentRoom, nextRoom) print(turn) if turn != "": nextActions.append(turn) nextActions.append('FW') print("in ga:", nextActions) def bumpWall(player): directions = ['right', 'up', 'left', "down"] if player.directionFacing== directions[0] and player.columnLocation == 9: return True elif player.directionFacing== directions[2] and player.columnLocation == 0: return True elif player.directionFacing== directions[1] and player.columnLocation == 0: return True elif player.directionFacing== directions[3] and player.columnLocation == 9: return True return False def chooseSafeAdjacentRooms(player): i = player.rowLocation j = player.columnLocation rooms = [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]] possibleRooms = [1] for room in rooms: key = str(room[0]) + str(room[1]) if key in roomSafetyDictionary: continue elif len(key) > 2: continue elif roomSafetyDictionary[key] == -1: return # added def computeTurnToRoom( player, currentRoom, room ): #defines the parameters of the cave rowChange = int(room[0]) - int(currentRoom[0]) #print("rowChange", rowChange) colChange = int(room[1]) - int(currentRoom[1]) #print("colChange", colChange) turn = "" # determining left or right turn if rowChange > 0: if player.directionFacing == "right": turn = "TR" elif player.directionFacing == "left": turn = "TL" elif colChange > 0: if player.directionFacing == "up": turn = "TR" elif player.directionFacing == "down": turn = "TL" if rowChange < 0: if player.directionFacing == "right": turn = "TL" elif player.directionFacing == "left": turn = "TR" elif colChange < 0: if player.directionFacing == "up": turn = "TL" elif player.directionFacing == "down": turn = "TR" print("turn is:", turn) return turn def chooseSafeRoomWithMoves(player): global usedSafeRooms print(roomDictionary) for key in roomDictionary: print(key, roomDictionary[key]) if roomDictionary[key] == emptyPercept: j = int(key[0]) i = int(key[1]) rooms = [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]] print(rooms) possibleRooms = [] for room in rooms: row = room[0] column = room[1] key = str(row) + str(column) print(key) if len(key) > 2 or key in roomSafetyDictionary: continue elif key in usedSafeRooms: continue possibleRooms.append(room) print(possibleRooms) goodRooms = [] if len(possibleRooms) > 0: for room in possibleRooms: key = str(room[0]) + str(room[1]) if key in usedSafeRooms: continue goodRooms.append(room) if len(goodRooms) == 0: return goodRooms[0] print("No safe rooms available to move to") return [] def findUnvisitedRoom(player): global roomDictionary i = player.rowLocation j = player.columnLocation rooms = [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]] for room in rooms: key = str(room[0]) + str(room[1]) if key in roomDictionary: #we've already visited this room continue elif len(key) > 2: # eliminates -1 & 10 perimeter rooms continue return room return "" main()