What I Think I'm Doing.
Hello, loves!
Some thoughts on how I work. It takes me a while to get there. If I got there. There must be an idea in here somewhere.
How I [think I] work.
- Added in Post
- It takes me a long time to figure out what I’m trying to communicate. I don’t think it’s profound, but I enjoyed trying to drag it out of my mind. If you want to skip over the development, here’s the bottom line.
This morning, I want to describe how I think I work. The main reason is that I’m thinking of two “ways” and I’m about to switch to the second way in the next bit I work on. That will be tomorrow, most likely. Today I feel the need to explain.
In these articles you get to see what I actually do, and what I’m thinking as I do it, to the extent that I can express the non-linear multi-threaded activities of the human mind in linear text. But be aware: any human’s report on what they do and why they do it is an incredibly over-simplified reconstruction of the processing of a highly parallel organic process that is not at all well understood, and that cannot possibly be fully described buy the organism carrying out the process, i.e. the person describing the process, in this case Yours Truly.
When we do object-oriented programming, which is mostly what we do here, I’d oversimplify grandly by thinking of two levels of objects. There is usually one object that is the focus of what I’m doing, and its methods. Then there are the objects that make up that one object and their methods.
Now of course, it’s objects all the way down, unless your programming language is some kind of abomination, but following both received and experiential wisdom, we try to deal only with the one focal object and its instance variables.
I believe that when I’m adding come capability, I operate in two distinct modes. One is a sort of top down kind of thinking, “given that I want this object to do or know this, how can these instance variables’ existing methods help me?” The other mode is more focused on one or more of the instance variables and its methods, when it seems like one that should be helping my top-level concern but it doesn’t have quite what I need.
In the second mode, there’s no convenient nearby object, no convenient nearby method that can do what I need, and, given what the objects know, I don’t even see a good way to get what I want.
In that second mode, well, let’s get specific: borders.
There is a tine during dungeon building when the notion of borders already arises, and it’s used to select the tiles for the floor of the dungeon. It’s the code that makes walls appear around the edges of rooms. The 200+ lines deleted from an article a while back had to do with reviewing that code and finding that it didn’t seem to do what I need now, which is to identify all the cells along a border between two rooms, and select where to put a “passage”, which will somehow grow up to support all the forms of moving from one room to the next that we can possibly ever need. The problem right now is just to find that border, classify the places where we could put a passage, and pick one according to some heuristic yet to be worked out. Nothing at all vague about that.
But my point is, in that mode I’m looking for algorithms, mechanisms, schemes that could exist but do not … yet. And I don’t even know what is possible with what we have, or what we need to build. So in that mode, I kind of mess around, moving the objects around, writing little methods, figuring out things that might be useful.
So, in yesterday’s article, I wrote one short method:
class Room:
def border_with(self, room):
result = set()
for my_cell in self:
for other_cell in room:
if my_cell.manhattan_distance(other_cell) == 1:
result.add(my_cell)
return result
My story is that I wrote that to learn how to write it. Given another room, could the Room class compute the subset of its cells that border on that other room. The answer is, of course, yes, and the code above is one way we could do it.
I am almost certain that we will not use that method in that form. It’s not very likely to be useful, although I think it’s close. Thinking about what we “reallY” want for passages, we want to “analyze” the border between two rooms and pick a place for a passage between them based on some heuristic. The one I have in mind is:
Passages tend to be in border sections that are somewhat complex, and are less likely to be in straight simple sections of the border.
I’m not sure quite what we’ll need for that — and we’ll come back to that in a moment — but it’s pretty clear to me that a simple set of the border cells on one side of the room border is insufficient. But I didn’t intend that method to be sufficient: I intended to learn from it. Here’s what I said in the article where it was created:
I like the simple
border_withmethod, but I’m not sure it’s going to be quite what we want. We’ll want matching pairs of cells across the border, and to select one such pair and make the door between them. But it’ll be the same kind of loop or comprehension that’s inborder_with. One interesting aspect will be that we want to be sure not to make a door between Room A and Room B, and then another door between Room B and Room A.
Doing the code helped me think about what the code could be, not just how to write the code to do the simple starting thing. And writing the simple thing helps me think about how to write the more complex thing.
Mode Switch
So, of course, since it’s objects all the way down, code all the way down, and Ron all the way down, I’m surely doing all the same things all the way down. But wait, there’s more:
Up at the top, wherever that is, we need to work out how to place passages, and to begin to learn just what a passage knows, and who knows about passages. And when I do that work, I often take on a different focus: “how would I solve this problem if I had exactly what I want?”
So … are passages a property of the layout, or a property of the dungeon? (Or are there objects around those where the passages should be, but for now, just those two.) As I ask that question right now, an answer bubbles up: there can be a Passage Maker. It needs to do its work before the contents are placed, since it needs to be free to put a passage anywhere and the contents need not to block passages.
Now I have a place to record my ideas as they turn to code: PassageMaker and a test file for it. But then, here’s the mode switch: “Exactly what would a PassageMaker want, and from which objects, in order to do its work?” So I’ll begin by thinking of data that a passage maker might want in order to make its decisions. In particular, since it “tends” to pick complex parts of the border, what will “parts of the border” look like, and how will we decide “more complex”?
I don’t know that yet: I’m not doing the work yet. But I know some things: in a squiggly section of the border, there are cells in one room that have two or three neighbors in the other room. But, generally, if a cell in room A has three neighbors in room B, the cells in room B may have only one or two neighbors in A. So it seems to depend on how you look at it, whether you’re analyzing from the viewpoint of room A or room B.
So … we’d like to have a measure not of one side of the border but something about both sides. And that’s what I think about. Right now I’m thinking:
Suppose we have one collection of the border cells from both rooms, each one associated with how many neighbors it has in the other room. So there might be a room A cell with a 3 and a couple of room B cells with 2s, and of course a bunch with 1s. So maybe we select randomly from that collection, with some weighting to give the 2s and 3s more chances, and that gives us a cell on one side of the border. We don’t even know which side it is on, though we can find out. But then what we do is get that cell’s neighbors from the other side and select one at random, and there’s your passage pair.
Then I might write a test for that code and I might try to code it. If I like how it’s going, and often I do, I’ll go with it. If I don’t, I’ll try another idea.
But the focus here is different. It’s not “how can I do this, given what I have?” It’s more “what could I have that would help me do this?”, and then I see whether I can readily have the thing I’d like.
Capsule
Let’s see if I can do a short summary of the two modes I’m trying to describe:
- Most commonly, I know what result objects I want and what I have, and I assemble what I want from what I have;
- Less commonly, I think about what the result objects should be and devise ways to get them.
Poppycock!
That division is malarkey, baloney, and largely bollocks. At no time am I that focused: at all times I’m probably doing some mixture of those two strategies, and six other things as well. Nonetheless, I feel that there is some meat here. Let me try again, without the numbers.
Capsule
Often, our objects are such that what we want to express is pretty straightforward, even if we have to enhance some of the subordinate ones a bit to get the job done.
But, also often, there could be a substantially better data structure to support what we need to do. It’s important to consider that possibility. We can probably sense the need when we begin writing complex procedures to do things that feel they should be simple.