Moderators: phlip, Moderators General, Prelates
I can't actually think of a situation where Object B would refer to Object A as its container, but part of the thing here is that I've got two 'types' of objects going on, and I haven't clarified which is which: Some of these objects are instanced, some of them are not.Ben-oni wrote:Cyclic dependencies are something that are neither good nor bad. Personally, I try to stay away from them, as I consider them inherently error prone. A common scenario is where object A contains object B, and then object B refers to object A as it's "container": sometimes this is useful, and at other times it can lead to errors if the property isn't properly maintained as an invariant.
The Great Hippo wrote:Actually, I think I just solved my own problem. Does this sound reasonable? Objects that modify their parents (i.e., the object that contains them) always have empty containers. There's no reason for the level of Fighter to contain anything; there's no reason for the rusty dagger to ever be contained. So I seem to have two actual types of objects--one with containers, one without. I just then have to create a structure that never allows an object with a container to be put inside of a container.
The Great Hippo wrote:Which brings me to another question, concerning errors--am I better off setting it up so errors are accounted for when it comes to file-reading (exception error? ignore this chunk of data, move on), or better off making it cause a crash with an explanation as to a basic guess as to why it crashed? If the latter, how can I cause the program to abruptly stop and send a message saying why it stopped?
EDIT: Nevermind, I figured it out. And as I'm gutting and cutting the code, I'm starting to figure out where 'full stop, this is bad' is a good idea, and 'just ignore this, move on' is also a good idea.
def hasPropVal(obj, prop, *args):
'''checks for the existence of a property, whether it's in a set of values, or if it satisfies a given predicate'''
if prop not in obj.properties:
return False
if len(args) == 0:
return True
if len(args) == 1 and callable(args[0]):
return args[0](obj.properties[prop])
return obj.properties[prop] in argshasPropVal(obj, 'blocked', True) # determines if obj is blocking
hasPropVal(obj, 'x') # determines if obj has an 'x' value
hasPropVal(obj, 'type', 'Floor', 'Wall') # determines if obj is a Floor or Wall
hasPropVal(obj, 'y', lambda(y): y>0 and y < MAX_HEIGHT) # determines if obj has a valid y coordinatedef move(self, dx, dy, dz):
def canMove():
return hasPropVal(self, 'x') and \
hasPropVal(self, 'y') and \
hasPropVal(self, 'z')
def getPosition(obj):
return (obj.properties['x'], obj.properties['y'], obj.properties['z'])
def isValidLocation(x, y, z):
return x < MAP_WIDTH and x > 0 and \
y < MAP_HEIGHT and y > 0 and \
z > 0 if dx == 0 and dy == 0 and dz == 0:
return
if not canMove():
raise Exception('Cannot Move')
(x, y, z) = getPosition(self)
x, y, z = x+dx, y+dy, z+dz
if not isValidLocation(x, y, z):
raise Exception('Out of Bounds')
# Objects already in the target location
objs = filter(lambda(obj): obj != self and \
hasPropVal(obj, 'x', x) and \
hasPropVal(obj, 'y', y) and \
hasPropVal(obj, 'z', z), objects)
if hasPropVal(self, 'blocked', True):
# Objects that 'block'
blocking = filter(lambda(obj): hasPropVal(obj, 'blocked, True), objs)
if len(blocking) > 0:
raise Exception('Blocked', *blocking)
for obj in objs:
# interact
self.properties['x'] = x
self.properties['y'] = y
self.properties['z'] = z
checkFloor(move):
def moveAndFall(self, dx, dy, dz):
def onFloor():
# test for floor
def fall():
move(self, 0, 0, -1)
move(self, dx, dy, dz)
try:
while True:
fall()
except Exception as e:
if e[0] != 'Blocked':
raise e
return moveAndFall
@checkFloor
def move(self, dx, dy, dz):The Great Hippo wrote:You've given me a tremendous amount of stuff to look up and read about, which is fantastic, because I can already see how pretty much everything here applies to my code--I'm definitely going to end up rewriting the whole thing with a lot of this in mind (I didn't know you could put definitions inside of definitions, for instance, and filter seems crazy useful and will get rid of so many wasteful loops I have--I can see a lot of places where *args will let me collapse multiple functions into one function--and I didn't know you could put multiple booleans in a single if-then statement and cause it to not fire if even one of those booleans came out false--this is going to make lots of my code much simpler and cleaner!).
* That first bit of code alone (with *args) cuts so much redundant code (particularly with how it does double-duty--allowing it to check if a property is present, and additionally if that property has a certain value!). Just from reading this bit alone, I think I've learned how to write much better, more powerful functions. But one chunk is throwing me about it--what is len(args) == 1: checking for? And I can't puzzle out what it's returning, either--obviously a boolean value, but I'm not sure how it's getting there or what it's measuring. Of the four statements you provided, is one of them an example of something that would hit this segment of code?
hasPropVal(obj, 'y', lambda(y): y>0 and y < MAX_HEIGHT)* I'm learning more about defining Exception subclasses now, and it's easy enough to write code that tests what they can and can't do, and I can see how extensive error-handling is going to pay off enormous dividends later down the road--I just wanted to double check, though--the 'raise Exception' argument is always intended to (outside of try: / except:) close the program with an error, right? So, in the example you gave, once replaced with calls to the exception subclasses, those would perform a full stop and give the custom error that would explain what caused the crash and (hopefully) why? Is there any way (or reason) to create Exception subclasses that don't crash the program when raised? Or is that essentially counter to their purpose?
def hasPropVal(obj, prop, val):
try:
return obj.properties[prop] == val
except Exception as e:
return False
(I beg your pardon for treating you as something of a Python tutor; there's tons of documentation for me to read out there, but without anyone to talk to about it, I lose a lot of the potential power and utility of the code I'm reading about--also, the few places I checked before coming here seem pretty hostile to newbie questions, and pretty prone to responding to them with 'go check the documentation')
def splitString(text, symbol = "="):
return (text[:text.find(symbol)], text[text.find(symbol) + len(symbol):]) \
if hasString(text, symbol) else (text, "")
def getString(text, str1, str2, return_strings = False):
def wildcard(str): return getString(text, *splitString(str, '*'), return_strings = True)
sym1 = wildcard(str1) if hasString(str1, "*") else str1
sym2 = wildcard(str2) if hasString(str2, "*") else str2
if not hasString(text, sym1, sym2):
return ""
result = text[(text.find(sym1) + len(sym1)):text.find(sym2)]
return sym1 + result + sym2 if return_strings else result
import re
def getString(text, str1, str2):
def escape(str): return re.sub(r"\\\*", ".*?", re.escape(str))
return re.search(escape(str1) + "(.*?)" + escape(str2), target).group(1)
object.properties['property'] = x # this is fine
getProp(object, 'property') = x # this is not fine
// Warning: definite pseudocode; don't try this at home
#define GET_PROP(obj, prop) obj.properties[prop]
rotate (a:as) = as ++ [a]
rotations as = take (length as) $ iterate rotate as
hasCircularProp n p = all (p . read) $ rotations $ show n
hasCircularProp n p = all (p . read) $ (\str -> take (length as) $ iterate (\as -> tail as ++ [head as]) str) $ show n
I find that highly useful when stepping through a function in a debugger. The "function returned" automatic tracking is more awkward to use, and it is harder to "back up" and repeat how it was generated if the result is anomalous, as well as harder to set up conditional breakpoints.Also, the bit about assigning the variables, and then straightway returning them made me die a little.
Yakk wrote:Each object has a class, which is an object. The basic (public) interface is "can I get a handler for this message" and "execute this message with this handler" and "can you produce a handler for this message on me?" which is distinct from sending a message directly (a class can handle messages to itself distinctly from messages that where directed at an instance of the class). Possibly I'd augment this with pre-handlers and post-handlers, whereby the instance asks the class for a pre and post-handler for each message.
When an object is sent a message, and the message isn't processed by the object, it asks its class if it has a handler for it, passing along a reference to itself.
My default class would have a meta-class of inheritance. The inheritance meta-class, when it was asked for a handler from a class, would query the class for parents, and see if any of them can handle the message.
Construction is a message you send to a class to produce an instance. The inheritance meta-class construction handler takes a list of parent classes, and builds the class instance (with no handlers in it by default). It builds a construction pre-handler for the class that builds the instance class heirarchy mayhap.
I'm rewriting the pseudo-parser from scratch; Ben-oni's posts helped me realize I've been trying to re-invent the wheel--all it needs to do is read a text-file and assign the values inside it to a dictionary. My purpose for doing so is to create a loadable type system, but a very gently enforced one (so I can have really weird things happen if I want to, but not if I don't want to). The text file will have entries for multiple types, import them in multiple dictionaries (kept in a master dictionary called 'Type'), import it into the game--and then whenever an object is created, the first thing that the code will look at will be its type property (error if an object is untyped), after which it will assign all the properties under that type to the object.Yakk wrote:The next thing I'd think about is your architecture. You are building a graph, so take a page from graph theory -- the Edge is as important as the Node.
And instead of one graph, have more than one graph, with nodes identified. So the physical graph can be distinct from the character experience graph, and you don't have the problem that a character "having a level of fighter" is distinct from a character "having a sword" in what kind of operations are allowed.
Your character "physically has a sword" while "build has a level of fighter". Both are has-a relationships.
...I'm sorry, but that's a fantastic idea and I can't imagine not wanting to do it regardless of what madness lies beyond. Just creating a system that treats body parts as added functionality for their holder (anything that has an arm can attack you and manipulate objects; anything with eyes can see you; anything with a mouth can talk to you) creates so many interesting consequences, particularly when bizarro magic enters the mix (walls that grapple, swords that chatter, floating eyeballs that relay their FOV to you, losing your arm and grafting it to your minion so he's got three). It would probably be tricky, because it involves intersecting rulesets (bodyparts are a container when they're 'in use' and an inventory object when they've been hacked off), but it's definitely interesting.Yakk wrote:I guess this can get tricky, distinguishing between equipped items and items you carry. I suppose some items you physically have might be body parts.You "have a" hand, which "has a" sword in it. The sword modifies the hand, which modifies the character. But that is probably a path down which madness lies.
One of the immediate things that occurs to me here is that floors would just be overglorified bags, or 'open chests' that you can walk on; players and creatures and such are just contained within their inventory (and if you're in its inventory, you're free to move objects in its inventory to your inventory). There'd have to be rulesets about allowing only one creature to occupy a floor's inventory space at a time, though (already handled by blocking, but teleportation... oh, wait, was that what you meant by teleportation creating a problem? Yeah, I see what you mean, then!)Yakk wrote:As an example, you can restrict physical objects in how they enter and exit other physical object's "possession". A physical object has a context (the thing that possesses it), and one can only enter the possession of another object which shares your context (and is not yourself) (you can only enter a bag if you are in the same room as the bag), or whose context is the context of your context (ie, you can leave a bag).
If you enforce that rule, then bag-inside-itself is impossible.
Now, teleportation can violate this if it doesn't rely on an overlying context. But that just means whenever you teleport you have to be careful, and otherwise the problem doesn't exist.
Another nice thing about this trick is that when (say) a gernade explodes, it can figure out where it is in order to damage its environment. And a bag can list its contents.
Yeah, those are definitely words you've typed there. And they're arranged in sentences!Yakk wrote:Spoiler:
The Great Hippo wrote:Of course, that's probably a late-game concern, not an immediate one.Yakk wrote:As an example, you can restrict physical objects in how they enter and exit other physical object's "possession". A physical object has a context (the thing that possesses it), and one can only enter the possession of another object which shares your context (and is not yourself) (you can only enter a bag if you are in the same room as the bag), or whose context is the context of your context (ie, you can leave a bag).
The Great Hippo wrote:I'm thinking it'll be easier to take it out--or collapse its function into something else--then to add it in later on.
I've been giving this a lot of thought at work (I do a graveyard shift, and by the time I get home I'm usually too exhausted to code, so I spend a lot of time thinking), and came to some conclusions that probably means a brief (hopefully last!) rewrite. It's going to be a little ranty, so I apologize in advance--I'm assembling my thoughts about the architecture in text for the first time.Ben-oni wrote:Oh so true. By the way, how are you implementing rulesets?
Something else occurred to me; if I went about things this way, it meant the move function would need a rehaul--what's more, since the floor has the x-y-z coordinate, and everything exists only in a floor's inventory (including walls), the only type of object that needs an x-y-z coordinate are floors. When anything else tries to move, a function will retrieve the floor that owns it, check the floor they're moving to (to see if it exists, and then check its inventory to see if something with 'blocked = True' is in it), then pass the actor from one inventory to another. I suspect this might be better than giving all objects their own x-y-z coordinate system and 'linking it up' with everything else, largely because it consolidates the most important, relevant data all in one place--the floor (if I'm completely wrong about this being a more efficient system, I'm definitely open to hearing about it; I'm not sure why this feels better to me, and I might just be interested in it because it's a weird--rather than an effective--solution).
I need one more type, though--because if things can only exist on floors, how do I handle things like a cursor to select a spot on the screen? Or just a cool visual affect using ASCII graphics? Or a camera--what if, instead of always moving the screen with the player, I want a 'trailing camera' affect to follow them around on the screen? How would the camera navigate this labyrinthian ruleset I've got going here? How would just a plain cursor navigate it?
So, I guess I need a fourth set--one for objects that have absolutely zero in-game consequences--have their own x-y-z coordinate system independent of the floor tiles--and only exist to let me do things outside of the ruleset, so I can throw in some neat visual effects or let the player select a large area (or even just edit maps and place floor tiles if I want to go that route later on). I'm guessing I'll call it the 'System' type.
As for how the rulesets will be enforced--I'm thinking lists. Specifically, there's a master list called 'Objects' which includes every object in the game (I can't imagine why I'd need this list, or need to filter it, but who knows?), a list for each instance of an individual type (all floors, all things, all effects), and possibly some lists that 'overlap' a little, to make some of the processing easier (though I suspect this can create some serious problems later on if I'm not excruciatingly careful). So, filter the lists to get the relevant objects, apply whatever selectively to those objects.
(Actually, it isn't--body-parts! I gave that a lot of thought too--the problem is that it would be a type that can cross between other types--being a 'thing', or being an 'effect'. That's complicated, and dangerous, I imagine--so my solution was to think of them as an effect with a property that creates a 'thing' when a certain action is performed upon its owner--so, if you blow a dude up, and one of his effects is 'arm', then under certain conditions that effect will cause a thing called 'arm' to be produced on the ground. Which, under similar conditions, might 'disappear' and cause an effect called 'arm' to appear in someone or something else's container--basically, 'arm' as an effect and 'arm' as a thing are two totally different objects, linked together by a property)
Ben-oni wrote:Why can't it be both an Effect and a Thing?
class Arm(Thing, Effect)I'm thinking that falling occurs when you try to move to a space where there's no floor (walls are just floors with a 'wall' object on them, so this doesn't usually happen). You drop down a z-level until you hit a map where there is a floor. If you reach the very bottom of the max-map-limit and this doesn't happen, you're dead (we say you fell into the eternal void, or into a deadly crevice, and leave it at that). One problem with this though--what happens if a player falls on a square with a wall? I suppose I could design maps to account for this (never put a 'wall' at the bottom of a pit), but I'd like it to be more automated than that (whenever you place a wall, the z-level above it automatically becomes a floor).Ben-oni wrote:What about falling? Climbing?
I was imagining two major rendering calls; one that draws floors (and their contents), and one that draws all the system types on top of it. That would let me do stuff like having a mirror-of-seeing things, since--currently--the way my screen works is by centering on whatever object is held in the variable 'focus' (and the move routine moves the focus around). I could just change 'focus' to a system object, and add a stipulation to the move function that allows it to move regardless of anything (except x-y-z limitations) if it's a system object.Careful, now. Rendering should be handled separate from game logic. You don't want tight coupling there. Ask yourself this: do you want a game module to be able to change the basic rules for how the player interacts with the game? (You might, actually. For instance, there could be a mirror-of-seeing-things-that-are-far-away. There are already good solutions for this sort of extensibility problem, though.)
I'm not actually sure; a property, maybe? That points to an object--an object that somehow contains the ruleset? This is something I assumed I would figure out as I worked, but thinking on it now, it's probably a major architectural concern and if I don't have some thoughts on how to do it now, I'm going to hit some major roadblocks on the way.But where do the rules go? Suppose I need to create a type of floor called a "trapdoor". How do I specify the rule that it's only triggered by "blocking" objects?
Why can't it be both an Effect and a Thing?
I had imagined 'Type' to be a single property with a single value (I'm enforcing the type system through the property system, rather than creating a whole new object class or another entirely new property of the current object class). I could certainly make 'type' part of the object class, but I'm hesitant about creating new classes if only because I'm worried it'll hamstring the flexibility I'm aiming for. But sub-classes might work, with each type being a sub-class of the main class, and with something like an 'arm' being an object that's inherited the properties of the effect and thing class.FYI, Python does allow one class to have two base classes.
The Great Hippo wrote:* I need to investigate tuples and some other data structures to see if it would be an effective method to 'phase out' the x-y-z coordinate system with cells and just use some sort of array or data structure (floor[2][4][1].properties['inventory'] would give me a list of everything inside the floor tile at coordinate 2-4-1, for example). I mean, since I'm going to have a cell on every possible point anyway...
* I've been thinking about your question (how do trap-doors work) a bit more and it lead me to some conclusions about how the Effect type will work. I'm renaming it the Action type, and creating a sub-element inside of it--a list of effects. Each effect consists of list of 'elements'. Each of these 'elements' is a type of value. There are conditional effects (which consist of conditional elements (like 'If True') and elements value (such as 'blocked', which is a key in an object's properties)) and 'acting effects' (which would consist of elements like '1d6' and 'damage' -- the first element would generate a number between 1-6, and the second would apply the value as damage). Every time a round passes--every time an object collides with another--and on several other occasions--we check the container of the object involved for any actions with effects that possess conditional elements that would apply--when they're found, we check the other conditional effects out of that group, and if any of them are true, we add those actions to the 'queue' of actions to be taken (to avoid errors created by effects that destroy or move objects, for example). So a trap door would be a floor with a 'fall' action in its effect; the effects would look like this: Effect 1 (conditional): 'on touch', Effect 2 (acting): 'Caller falls'. An action that would poison you would look like this: Effect 1 (acting): 1d6, damage. Effect 2 (conditional): 'every round'. Effect 3: 1d3, rounds, end effect.
(Actually, that last effect worries me--I'm not sure if it's a conditional or what. I might need a third type of effect, maybe 'duration')
EDIT: Or better yet, store the 'conditional' in Action rather than Effect, and make the conditional in Effect have relevance toward ending the effect (so when an effect says '1d3, round, end', that tells us to destroy the action it's contained in. When an Action says 'every round' (and that's all it would say), it tells us to take this action every round. I need some way to clarify that an action is already being taken and doesn't need to be repeated, though. Maybe the action queue can help with that... Point is, assuming this is a good way to go about it, I think the next major step is to try and generate a simple program that can interpret effects and actions and apply them to objects and their properties.
import random
timerActions = list()
def setTimer(when, what, *args):
timerActions.append((when, what, args))
# call this each round in the main program loop
def triggerTimerActions():
global timerActions
[what(*args) for (when, what, args) in timerActions if when <= 1]
timerActions = [(when-1, what, args) for (when, what, args) in timerActions if when > 1]
# To roll 1d6+2: dice(1, 6, 2)()
def dice(num, max, mod=0): return lambda: sum([random.randrange(1,max+1) for x in xrange(0,num)]) + mod
def damage(target, hp):
try:
target.properties['Hit Points'] -= (hp() if callable(hp) else hp)
if target.properties['Hit Points'] < 0:
target.properties['onDeath']({'target': target})
return True
except:
return False
def poison(target, hp, rounds):
def dealPoison(rounds): # shadowing
if (round <= 0): return
damage(target, hp)
setTimer(1, dealPoison, rounds-1)
setTimer(1, dealPoison, rounds)
return True
ancientSword.properties['onHit'] = lambda(event): damage(event['target'], dice(1, 6)) and \
poison(event['target'], dice(1, 4), dice(1, 3)())
# A Bloodbound sword deals one additional point of damage for each time it has made a kill
def makeBloodboundSword(sword):
onHit = sword.properties['onHit'] # The previous onHit action
sword.properties['bloodbound'] = 0 # The new 'Bloodbound' property
def bloodboundHit(event): # The new onHit action
wasDead = isDead(event['target'])
onHit(event)
damage(event['target'], sword.properties['bloodbound'])
if not wasDead and isDead(event['target']): sword.properties['bloodbound'] += 1
sword.properties['onHit'] = bloodboundHit
One thing that's confusing me here; grid[(x,y,z)]--the (x,y,z) here is a tuple being used as an index, right? But I thought indexes can only be integers (so grid[0] would bring up the first element of the list 'grid', for example -- while grid[(0, 0, 0)] raises a TypeErrror, noting that indexes must be integers, not tuples).Ben-oni wrote:There's no need to have an exhaustive array of cells. If the array has no cell at a certain point, the game engine should treat it as an empty cell. So, using arrays to represent the grid is unnecessary. Try "grid[(x,y,z)].properties['inventory']". Either test for "(x,y,z) in grid" before or catch the exception after.
map = [[[ Object("default", {"movement_blocked" : False,
"explored" : True,
"movement_blocks_sight" : False,
"char" : " ",
"RGB" : [10, 10, 10],
"inventory" : [] })
for a in range(0, MAP_Z + 1) ]
for b in range(0, MAP_WIDTH + 1) ]
for c in range(0, MAP_HEIGHT + 1) ]That sounds extraordinarily complex, but also extraordinarily interesting. I'm worried that it would make things much more precarious when dealing with ideas like tunneling, or mining, or accidentally teleporting into cells that don't even exist--assuming I want consequences for that action rather than just a 'teleport failed, bwah' message--but a lot of the routines you're describing sound like they could easily address that (try to teleport into a coordinate with no cell? create a cell at that coordinate, deposit you in said cell).Zamfir wrote:You can use tuples as keys in a dictionary. That's in fact an important aspect of them
So 'grid' itself could simply be a dictionary, or it could be an object with a "getCell(x,y,z)" method, that stores cells internally in a dictionary for lookup.
The latter is more complicated, but has the advantage that you could have an orderly "setCell(cell, x, y, z)" method that checks on the sanity of the inputs (like whether the location is already occupied, or whther the cell variable really contains a Cell object). Or do things like "setBlockOfCells(celltype, xmin, xmax, ymin, ymax, zmin, zmax)" or "setArrayOfCells(listOfCells, listOfCoordinates)"
In a typical Python move, you could even inherit the Grid class from dict. At first you'd do nothing except inherit (so a Grid instance would just be a standard dictionary), then add those extra methods when they come in handy, or override __setitem__ when you discover that you need more checks.
myCell = Cell()
myCell.inventory = ['shoes', 'shield']
grid={}
grid[(3,4,5)] = myCell
print( grid[(3,4,5)].inventory[0] ) // 'shoes'
gridZ = dict(((loc, cell) for loc,cell in grid.items() if loc[2]==currentZ))
Yeah, I want multiple maps--I was thinking of how to tackle this, but turning grids into dictionaries is probably good enough (grid holds all the entries for the map we're currently on; when you 'portal' to a new map, we overwrite the old grid with the new grid's dictionary). A natural consequence is probably that since game-operations only matter on a one-grid-at-a-time level, when you leave a grid, it's 'frozen', and any changes that occur on it will have to be abstracted. This is probably much more sane than the alternative, though (keep the grid running round-by-round even when you're not on it!).Zamfir wrote:As last thing: do want just one grid? You can have multiple maps with "gates" in between. So if you walk onto the "cave entry" cell you leave this grid and enter another grid. If movement in z-direction is relatively rare, you can even implement different levels as separate grids.
The Great Hippo wrote:(square entries just point to cube entries, so anything I change on cube auto-changes for square... I think? I'm pretty sure. Sometimes, it's hard to wrap my brain around how object-oriented programming works).
allGrids={}
allGrids['inside cave'] = GetMapFromSomewhere()
allGrids['outside cave'] = GetMapFromSomeOtherPlace()
activeGrid = allGrids['inside cave']
activeGrid = allGrids['outside cave']
keys = grid.keys()
keys = filter(lambda keys: keys[2] == 0, grid.keys())
for i in keys:
square[i] = grid[i]singles = range(2,15)
doubles = [number*2 for number in singles] aboveTens = [number for number in singles if number>10]
aboveTenDoubled = [number*2 for number in singles if number>10]names2Numbers = {
'one': 1,
'two': 2,
'three': 3
}
aboveOnes = [name for name, number in names2Numbers.iteritems() if number>1 ]
// ['two', 'three'] or ['three', 'two'], order is uncertain
aboveOnesTuples = [(name, number) for name, number in names2Numbers.items() if number>1]
// [('three', 3), ('two', 2)]
dict(abovesOnesTuples)
//makes a dictionary from the tuples
dict( (name, number) for name, number in names2Numbers.iteritems() if number>1) entry = dict((key, value) for key, value in grid.iteritems() if value == self)
xyz = entry.items()
xyz = xyz[0][key for key, value in grid if value==requiredvalue]Users browsing this forum: Majestic-12 [Bot] and 8 guests