Having written several versions of a TBA domain, helped dozens of students with what tripped them up with their version, and look through dozens of submitted, working domains, I now have an informed recommended design for your domain code.
If I were starting a new domain from scratch, knowing what I know now, here’s how I would do it.
I’d think of global variables in three categories:
I’d define the world in several global variables:
I’d have a list of items. Each would have either a location or a depth.
I’d have a dict of locations. Each would have a name, a description, a dict of directions a user can go and what locations each leads to, and a dict of commands a user can do in the location (converted to tuples or strings because lists can’t be dict keys).
I’d have a way of looking up locations to put items I’m hosting for other domains based on their depth.
I’d have a dict of any mutable state (doors open/closed, etc) set up the way a user would see it when first arriving. I’d include the user’s location as state, but not the location of items – I’d let the hub handle that.
I’d have a state-to-score function or dict. This might mean augmenting state a bit: for example, if I decide the score is based on how many locations have been visited or how many items picked up, then I’d add sets to track that to the mutable state dict.
I’d store three pieces of basic configuration in global variables: the hub’s url, my domain’s ID, and my domain’s secret. These would be set in /newhub
.
I’d also have a dict mapping item IDs to item definitions. I’d start that out empty.
I’d make helper functions for the commands I plan to send to the hub:
/newhub
I’d store the hub URL as global config information.
I’d send the list of items from the world definition to the hub. I’d use the response’s "items"
array to both
"id"
fields in each itemI’d also store my domain’s ID and secret in the global config information.
/arrive
If the arriving user is new (never seen before), I’d
copy.deepcopy
to clone the world definition starting state as an entry in the user progress dict for the user./transfer
each item in the world definition that has a location to that location for that user.I’d update the config list of items with any items from any of the lists sent in the /arrive
’s request that I don’t already have.
I’d /transfer
any item in the "prize"
list to a location appropriate for it’s depth.1 Except for prize
I’d ignore the difference between the lists: whether something is carried or dropped or owned is tracked by the hub and available on demand though the hub’s /query
endpoint.
I’d mark the user’s state as present.
/depart
/dropped
Nothing else needed here: the actually dropping is handled by the hub.
/command
I’d check that the user is present.
I’d /query
two lists of item IDs: those in the user’s inventory and those in the user’s current location.
I’d try to handle most commands in loops or with dict lookups; for example,
["go", direction]
, is direction
in the user’s current location’s dict of ways the user can go? If so, change the user’s location and respond with the same thing as look
. If not, respond with a can’t-go message.["take", item["name"]]
? If so, request the item enter the user’s inventory with /transfer
, and then respond with some type of success message.["look", item["name"]]
? If so, respond with the item’s description."verb"
, is the command [verb, item["name"]]
? If so, respond with that verb entry’s value.I’d also have a special function for each more complicated location to store code implementing more complicated behaviors;
globals()
function to get the dict that Python keeps for me) to avoid having to have a separate conditional for each loction.If I found myself repeating anything, I’d put it in a helper function. For example, look
and go
return very similar responses, so I’d make a function that creates those responses.