Drop Item If More Than 1 Item Present - python

I'm working on a piece of code, and it is for a little AI creature to randomly come into a room, and look to see if there is anything there. If there is anything that the player has touched before, then it takes the item. The next room it goes to it drops that item and may pick up a new one. So far, I have:
import random
rooms = ['kitchen', 'livingroom', 'basement']
itemsstatus = {'Umbrella': 1, 'Coin': 1}
itemsstatus['Umbrella'] = raw_input()
print "itemstatus['Umbrella']", itemsstatus['Umbrella']
roominventory = ['Umbrella', 'Coin']
goblininventory = ['baseball']
notpickedanythingelse = 'true'
gotoroom = random.choice(rooms)
if(gotoroom == 'kitchen') or (gotoroom == 'livingroom') or (gotoroom == 'basement'):
ininventory = len(goblininventory)
if(ininventory >= 1):
roominventory.append(goblininventory[0])
goblininventory.remove([0])
else:
print ""
for items in roominventory:
if(itemsstatus[items] == 1) and (notpickedanythingelse == 'true'):
goblininventory.append(items)
roominventory.remove(items)
notpickedanythingelse = 'false'
else:
print ""
notpickedanythingelse = 'true'
print roominventory
print goblininventory
The itemstatus[''] = rawinput() will be done automatically by the game and won't be a raw imput, it is just here so I can test it. As well, each room will have it's own inventory and loop, but this is just for the simplicity of it. The goblin will pick up an item, and keep it, but it won't drop the one it already has (it can only carry 1 thing at a time). How can I get it so that it will drop the item it is holding once entering a new room?

goblininventory.remove([0]) is incorrect. You should use goblininventory.pop() to remove the first element from the list.
See here for more info on remove and pop: https://docs.python.org/2/tutorial/datastructures.html#more-on-lists

Related

Looping through attributes within Class instances?

I am trying to simulate a baseball game to learn more about python and programming in general... I ran into an interesting learning point in programing... and was wondering if someone could explain this error...
import random
rosterHome = []
rosterAway = []
class Player:
def __init__(self, number, battingAverage):
self.number = number
self.battingAverage = battingAverage
class Game:
def __init__(self):
self.inning = 0
self.homeScore = 0
self.awayScore = 0
self.outs = 0
def createStats():
for i in range(40):
stats = random.random()
x = Player(i, stats)
rosterHome.append(x)
for y in range(40):
stats = random.random()
y = Player(i, stats)
rosterAway.append(y)
def startGame():
Game.createStats()
Game.inning = 0
Game.homeScore = 0
Game.awayScore = 0
Game.outs = 0
Game.playInning()
def playInning():
totalHits = 0
if Game.inning >= 10:
print('Game is Over')
return
while Game.outs < 3:
for i in rosterHome:
x = rosterHome[i]
if x.battingAverage > random.random():
totalHits += 1
player += 1
print('batter ', player, ' got a hit')
else:
Game.outs += 1
player += 1
print('batter ', player, ' got out')
print('there are ', Game.outs, ' outs.')
Game.startGame()
x = rosterHome[i]
TypeError: list indices must be integers or slices, not Player
TLDR:
List indices must be integers or slices
The interpreter says "Hey, I see you're trying to access an item in a List by its index, but indices should be of type integer, however, you passed a value of type Player"
In Python and most programming languages, to reference an item in a List/Array, one way would be by index. Lists are zero-indexed, so the first item is of index 0, the second index 1, and so on.
Given an Array
my_array = ["bread", "foo", "bar"]
my_array[0] # would give you "bread"
my_array[1] # would give you "foo"
my_array[2] # would give you "bar"
However in your case, if we trace back up from where the error occurred, right here:
x = rosterHome[i]
You want to ask, what is the value of i? above this line is a for loop, and i represents each value in a list called rosterHome. So what the heck is in rosterHome anyways?
Moving up into your createStats method where you populated the rosterHome list, we see that you're pushing an instance of Player into the rosterHome list.
x = Player(i, stats)
rosterHome.append(x)
So rosterHome really isn't a list of numbers but instead a list of Player instances. You might want to review and try again, maybe accessing the number property of the Player object instead.
The error happens because rosterHome is a list of instances of the Player class, so when you iterate on the list (for i in rosterHome) each element will be an instance of said class (i is a Player). If you want to access the number of each player you'll have to access the attribute number of your Player instances, but it seems like actually you want to find the player instance. This means, you don't even need to lookup the value in the table, just use the value of the for loop. I'll use a different naming of variables to improve readability:
while Game.outs < 3:
for player in rosterHome:
# x wanted to access a player, but we don't need to do that actually
if player.battingAverage > random.random():
# ...
else:
# ...
This part of the answer considers that you actually want to meet both requirements (number of outs and iterate players once):
player_index = 0
while Game.outs < 3 and player_index< len(rosterHome):
player = rosterHome[player_index]
if player.battingAverage > random.random():
# ...
else:
# ...
if Game.outs == 3:
# Reached 3 outs
else:
# No players left and game outs < 3

Manipulating list based on the first and second index integer

I need help fixing this code. My goal is to change the last element of the indexed string from "3" to "F" if the two indexes before are an even integer.
change = ['E013', 'E023', 'E033', 'E042', 'E054']
def help():
for i in change:
test = int(i[1:3])
if test % 2 == 0 and i[3] == "3":
subs = [i.replace("3","F") for i in change]
print(subs)
help()
So for example if you have a list:
INPUT
change = ['E013', 'E023', 'E033', 'E042', 'E054']
I want this to output:
OUTPUT
change = ['E013', 'E02F', 'E033', 'E042', 'E054']
Right now my code is outputting:
['E01F', 'E02F', 'E0FF', 'E042', 'E054']
You have to change just one of the elements in the list, not all of them:
change = ["E013", "E023", "E033", "E042", "E054"]
for index, value in enumerate(change):
test = int(value[1:3])
print(f"doing {index} {value} {test}")
if test % 2 == 0 and value[3] == "3":
print(f"changing index {index}")
# strings are immutable in python, and .replace creates a new one
# which has to be assigned in the list
change[index] = value.replace("3", "F")
print(change)
Note that I left the test value[3] == "3" that you had, so E042 is not modified, as it does not end with 3. If you only need to check if the number is even, remove that.
Cheers!

Python, "If if line is called on first time, do something else"

So the title is pretty self explanatory, but i'll go into more detail. I am creating a text dependent game and I will have millions of areas. And each time you enter a new area, you will be greeted with a one time only different reaction than if you came into the same place again later, and I need to find a way to to this:
if len(line) == 1:
do exclusive thing
else:
do normal thing
Sure, I could use a counter system like "a = 0" but then I would need to create a separate counter for every single area I create, and I don't want that.
You could just store a single dict to keep track of room visits, and probably even better to use a defaultdict
from collections import defaultdict
#Using a defaultdict means any key will default to 0
room_visits = defaultdict(int)
#Lets pretend you had previously visited the hallway, kitchen, and bedroom once each
room_visits['hallway'] += 1
room_visits['kitchen'] += 1
room_visits['bedroom'] += 1
#Now you find yourself in the kitchen again
current_room = 'kitchen'
#current_room = 'basement' #<-- uncomment this to try going to the basement next
#This could be the new logic:
if room_visits[current_room] == 0: #first time visiting the current room
print('It is my first time in the',current_room)
else:
print('I have been in the',current_room,room_visits[current_room],'time(s) before')
room_visits[current_room] += 1 #<-- then increment visits to this room
You need static var : What is the Python equivalent of static variables inside a function?
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
#static_var("counter", 0)
def is_first_time():
is_first_time.counter += 1
return is_first_time.counter == 1
print(is_first_time())
print(is_first_time())
print(is_first_time())

Why wont my python while loop stop?

I've got a loop that is supposed to select features and keep looping until it is no longer selecting new features
arcpy.SelectLayerByLocation_management("antiRivStart","INTERSECT","polygon")
previousselectcount = -1
selectcount = arcpy.GetCount_management("StreamT_StreamO1")
while True:
#selectCount = arcpy.GetCount_management("StreamT_StreamO1")
mylist = []
with arcpy.da.SearchCursor("antiRivStart","ORIG_FID") as mycursor:
for feat in mycursor:
mylist.append(feat[0])
liststring = str(mylist)
queryIn1 = liststring.replace('[','(')
queryIn2 = queryIn1.replace(']',')')
arcpy.SelectLayerByAttribute_management('StreamT_StreamO1',"ADD_TO_SELECTION",'OBJECTID IN '+ queryIn2 )
arcpy.SelectLayerByLocation_management("antiRivStart","INTERSECT","StreamT_StreamO1","","ADD_TO_SELECTION")
previousselectcount = selectcount
selectcount = arcpy.GetCount_management("StreamT_StreamO1")
print str(selectcount), str(previousselectcount)
if selectcount == previousselectcount:
break
By my reckoning, once it starts print the name number twice it should stop, but it doesn't, its keeps print "15548 15548" over and over again. Is it ingnoring the break or is the if condition not being met?
I've also tried with
while selectcount != previousselectcount:
but this gave me the same result
Variables in Python are dynamic. Just because you initialise previousselectcount as an integer doesn't mean it will be one when you call previousselectcount = selectcount. You can feel free to get rid of that line.
If you replace:
selectcount = arcpy.GetCount_management("StreamT_StreamO1")
With:
selectcount = int(arcpy.GetCount_management("StreamT_StreamO1").getOutput(0))
For both lines you'll be comparing the integer values instead of whatever the equality operator is comparing for the object.
Even better, why not write a function to do it for you:
def GetCount():
return int(arcpy.GetCount_management("StreamT_StreamO1").getOutput(0))
Save yourself repeating yourself.

Python Continue inside nested loops, getting to the right level of the nesting

I am working on something that needs to make it's way through several levels of checking if conditions are met before either exiting all together or setting certain variables and then starting the loop over. My question revolves around how to jump back to the primary while loop from the internal for loop.
while True:
message = stomp.get
message = simplejson.loads(message.body)
if message[0]['fieldname1'] == False:
global ShutdownState
ShutdownState = True
break # Should leave the While loop all together
else:
for item in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'] == True:
list1_new[len(list_new):] = [item['fieldname2-1-2']
list1-state = set(list1) == set(list1_new)
if list1-state == True:
continue # should reset the while loop
else:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
continue
It's not clear whether the sample code was meant to be representative of your whole loop, or just the beginning of it. If it was the whole thing, then there are lots of ways you can restructure it. Here's a first stab (note that are some typos in the code (e.g., list1-state rather than list1_state, and things like that), so I've had to adjust some things. You'll need to check whether it still matches up with your original code. (For more about this implementation of finding the first element in the list, and some alternatives, have a look at Python: Find in list.)
while True:
message = stomp.get
message = simplejson.loads(message.body)
# If the message doesn't match this criterion,
# we need to abort everything.
if not message[0]['fieldname1']:
global ShutdownState
ShutdownState = True
break
try:
# get the first item in message[0]['fieldname2'][0]['fieldname2-1']
# such item['fieldname2-1-1'] is true. Whether we
# find one and do this code, or don't and catch the
# StopIteration, we wrap back to the while loop.
item = next(x
for x in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'])
list1_new[len(list_new),:] = item['fieldname2-1-2']
list1_state = (set(list1) == set(list1_new))
if not list1_state:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
except StopIteration:
# There was no such item.
pass
You might also clean this up by making it a do-while loop, but that's a less major factor. Based on Emulate a do-while loop in Python?, you could do something like:
def get_message():
message = stomp.get
return simplejson.loads(message.body)
message = get_message()
while message[0]['fieldname1']:
try:
# get the first item in message[0]['fieldname2'][0]['fieldname2-1']
# such item['fieldname2-1-1'] is true. Whether we
# find one and do this code, or don't and catch the
# StopIteration, we wrap back to the while loop.
item = next(x
for x in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'])
list1_new[len(list_new),:] = item['fieldname2-1-2']
list1_state = (set(list1) == set(list1_new))
if not list1_state:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
except StopIteration:
# There was no such item.
pass
message = get_message()
global ShutdownState
ShutdownState = True

Categories