Can you access lines below the one being read in Python? - python

I'm trying to write a text-based adventure in Python, for which I created a class called Room. A Room consists of a description and 4 other Rooms in each direction (north, south, ...).
But when I create, for instance, two rooms next to each other, I have to create one of them first, meaning it can't understand what I pass as the Room next to it because it's a line below.
I was wondering what ways there are to fix such a problem, other than perhaps making and importing a new file for each room. I'll add a small example.
room_north = Room("RoomNorth", room_south)
room_south = Room("RoomSouth", room_north)
Thanks in advance :)

One way is to change your Room class so that it doesn't need the connections at construction. First create the rooms, and then add the connections:
room_north = Room("RoomNorth")
room_south = Room("RoomSouth")
room_north.south = room_south
room_south.north = room_north
Another way is restructure your code to store all rooms in a dictionary, identified by strings:
rooms = {
"room_north": Room("RoomNorth", "room_south"),
"room_south": Room("RoomSouth", "room_north"),
}
A possible drawback is that every lookup of a room will have to go through this dictionary, of course.

Related

What data structure should I use to define states at 3600 points?

I am working on a personal project that analyzes hockey player shot data. One thing that I would like to investigate is the effects of different game-states (5v5, power play, short handed). The problem that I have is that I am not sure how to structure this part of my program.
My initial thought is to define a dictionary with 3600 sub-dictionaries as follows:
game_state = {}
game_state[time] = {}
game_state[time][home] = []
game_state[time][away] = []
I can then use the time for each shot event that I am interested in to lookup each teams' game-state. This, however, seems like an inefficient way of doing things.
As I am writing this question up it occurs to me that most of the game is 5v5 for both teams. Perhaps I could set up a similar dictionary but only use the times that the game-state is not 5v5 to generate the keys, and then when looking up play data assume that no entry means a 5v5 game-state.
My Question: Is there something better suited than a dictionary for this kind of application?
Edit:
To #Karl Knechtel's point, I do not need to save any of this information beyond one iteration of a for loop in my main file. In the main file I loop through game_data (a pickled JSON file) and collect x, y coordinates for all shots to later be binned and plotted. I am trying to refine the shot data to consider only a specific game state by introducing an additional check into my data parsing loop.
This sounds like the perfect use case for a relational database like SQLite or Postgres. Without getting too much into the nitty gritties, you could define a relation called Shot with time as a primary key. This would allow you to also look up more interesting questions like "How many shots are made short handed when it's a powerplay?" You could potentially also have a relation called Game which allows you to know which shots happened in which game.
If you want a less labor intensive solution, I think grouping the data into a class would be good idea. For example,
class Shot:
def __init__(self, time: int, short_hand: bool, num_players: int):
self.time = time
self.short_hand = short_hand
self.num_players = num_players
You could then have a dictionary that maps time to Shot instances.
shots: dict[int, Shot] = {}
shots[100] = Shot(100, False, 10)
shots[150] = Shot(150, True, 9)
...
NB: I highly suggest the first option since it sounds like it will be more useful for your case.

What is the best way for allowing for dynamic object creation and removal in a Plotly Dash dashboard?

Currently, I have a class which stores a dictionary of Card elements, each of which is unique. The class can also generate these cards and append them to the dictionary or remove a card from a dictionary. However, I am not sure how to best allow for this action through a callback function since the ID for a card doesn't exist until the card is made, and the functionality isn't directly within the Dash framework since a dictionary object acts as an intermediary where the objects are stored.
Basically, I am wondering what the best way to dynamically create and destroy objects with a callback is?
Thank you!
Assuming you want to avoid extra computation for building cards you wont use, I'd suggest create a which creates each card and store those functions in a dictionary. (You can also create a universal function with params that allow specificity)
my_card_functions = {
'id_1': make_id_1,
'id_2': make_id_2,
}
Creating a card could be done as such:
my_id = 'id_1'
f = my_card_functions[my_id] # will break if id isn't registered
my_card = f()
You can store the cards you want to create in a dcc.store object. Here's an example of some code you might consider:
# Pretend these are structured properly
dcc.Store(id='cards_data')
html.Div(id='my_cards',children=[])
#app.callback(
Output('my_cards','children'),
[Input('cards_data','data')],
[State('my_cards','children')]
)
def make_cards(data, children):
"""Makes cards for each id"""
if not data:
raise PreventUpdate
# The following code is not correct but serves as a demonstrative example
# Some data structure manipulation is necessary to access
# the ids from the children elements
children_ids = [x['id'] for x in children]
# Assuming your data looks something like this:
# {'add':['id_1','id_2']}
for x in data['add']:
if x not in children_ids:
f = my_card_functions[my_id]
my_card = f()
# Store values
children.append(my_card)
return children
Note, this approach does not resolve removal of cards. That could easily be done but would probably require a more dynamic use of caching.
Just on the basis of your question, I have some immediate suggestions (since there is no working code that you have posted).
1. Generate all card elements by default. They can be generated, but not 'displayed'
2. Add your callbacks to toggle the display/rendering of the cards dynamically based on the use case. That way you will have card element ids to play around with in the callbacks.
Hope this helps.

py2neo cypher create several relations to central node in for loop

just starting out with neo4j, py2neo and Cypher.
I have encountered the following problem and google and my knowledge of what to ask have not yet given me an answer or a helpful hint in the right direction. Anyway:
Problem:
I don't know how to, in python/py2neo, create relations between a unique starting node and a number of following nodes that I create dynamically in a for loop.
Background:
I have a json object which defines a person object, who will have an id, and several properties, such as favourite colour, favourite food etc.
So at the start of my py2neo script I define my person. After this I loop through my json for every property this person has.
This works fine, and with no relations I end up with a neo4j chart with several nodes with the right parameters.
If I'm understanding the docs right I have to make a match to find my newly created person, for each new property I want to link. This seems absurd to me as I just created this person and still have the reference to the person object in memory. But for me it is unclear on how to actually write the code for creating the relation. Also, as a relative newbie in both python and Cypher, best practices are still an unknown to me.
What I understand is I can use py2neo
graph = Graph(http://...)
tx = graph.begin()
p = Node("Person", id)
tx.create(p)
and then I can reference p later on. But for my properties, of which there can be many, I create a string in python like so (pseudocode here, I have a nice oneliner for this that fits my actual case with lambda, join, map, format and so on)
for param in params:
par = "MERGE (par:" + param + ... )
tx.append(par)
tx.process()
tx.commit()
How do I create a relation "likes" back to the person for each and every par in the for loop?
Or do I need to rethink my whole solution?
Help?! :-)
//Jonas
Considering you've created a node Alice and you want to create the other as dynamic, I'll suggest while dynamically parsing through the nodes, store it everytime (in the loop) in a variable, make a node out of it and then implement in Relationship Syntax. The syntax is
Relationship(Node_1, Relation, Node_2)
Now key thing to know here is type(Node_1) and type(Node_2) both will be Node.
I've stored all the nodes (only their names) from json in a list named nodes.
Since you mentioned you only have reference to Alice
a = ("Person", name:"Alice")
for node in nodes: (excluding Alice)
= Node(, name:"")
= Relationship(a, ,
Make sure to iterate variable name, else it'll keep overwriting.

Referencing objects which don't exist yet

I am teaching myself Python by reinventing the wheel, i.e. writing a simple console adventure game with interconnected rooms. My interest is not so much in finishing a real game, rather in learning about abstraction and data structures.
I have defined a few basic classes such as World, which contains references to Rooms. These Rooms have Actions and Items. The program checks which Actions are available for each Room and displays them in a list. All of this is working pretty well so I'm trying to complexify things a bit.
I have two problems I can't get my head around. I'll try to explain
them with as little detail as possible.
This is how I defined a possible Action for a Room, in this instance it's a Room referenced by the variable called main (for now data is declared in a module, later to be read from a CSV or XML file):
main.actions = [Action(type = 'move',
result = 'west',
desc = 'Go to the West Room.')]
I need to define an action type because some actions are not movements (e.g. pick up, pull a lever). I'll modify this later to uses subclasses of Action, it's not the issue here.
The 'west' string here refers to the Room which will be the result of the action, i.e. it will become the current room when the action is executed.
However, I'd like the result to be the Room object itself, not a
string ID. But I can't do that until all the Rooms have been initialized.
So I've solved this with the following method of the World object, which works:
def connect_rooms(self):
'''
Once all the rooms have been created,
replace all the string reference to other rooms by the Room objects themselves.
'''
for room in self.rooms:
for action in room.actions:
if action.type == 'move':
room_object = fetch_room(self, action.result)
action.result = room_object
The fetch_room() function (global scope) just does this:
def fetch_room(world, shortname):
# Find a room item by its shortname
for room in world.rooms:
if room.shortname == shortname:
return room
return None
I am sure there is a better way to handle this, since creating connections between nodes seems to be a basic abstract idea.
The other (related) problem is that I'm trying to create conditions built into the Actions themselves, so that the program only proposes them to the player if the conditions defined in the Action are met. For the initial building of the data I can't reference anything else because it hasn't been created yet. I thought of adding a condition in string form and run it later with exec(), but it seems very silly and ugly:
main.actions = [Action(type = 'move',
result = 'west',
desc = 'Go to the West Room.',
conditions = ["player.has('smallkey')"])]
If there is a text somewhere about build such data structures without going insane, I'd be happy to read it.
Thank you.

python text rpg inventory system

I'm making a text-based rpg with python 3.3 and I am wanting a more dynamic inventory system for my game. I am currently using variables assigned to each item but with functions, the variables I am passing as arguments are becoming too many and quite cluttered. If there is a better way out there I would love help creating a better system.
Here is how my inventory call system looks right now:
print('Item1',item1)
print('Item2',item2)
print('Item3',item3)
and so on.
Well, I have an old text game I made and the inventory system I use is just a list named 'inv'. Then all you have to do when you gain an item of whatever type is to append the inventory list with the string.
inv = []
inv.append('Item1')
Then you can create a dictionary with the key as the item name and the value be a list you can reference. Try this:
itemvalues = {'Item1':[0,0,0]
}
And the list can be a bunch of different attributes such as buy sell price, strength or what have you. Hope this helps.
You could try and use a list:
inventory = []
inventory.append(some_item)
And you can implement an inventory cap:
if len(inventory) > inventory_size:
print('Inventory full.')
If you want to 'use' an item in the inventory, say, then it's also easy to remove (this is of course assuming the index exists):
# use the item
del inventory[index]
Obviously most of the functionality you need is accessible through standard list methods, so check the documentation out.

Categories

Resources