I want to design a text based game that has a house as a layout with Swift (coded in a Linux VM on Visual Studio Code). To achieve the house layout I have different 'Room' objects that have exits in each cardinal direction (North, East, South, West). When specifying which room has which exits, I also assign it the room the exit leads to with a dictionary structure.
enum Direction:String {
/// 4 main cardinal points
case North, East, South, West
}
/// A rudimentary implementation of a room (location) within the game map, based on a name and exits to other rooms. The exits are labeled with a `Direction`.
class Room {
/// The name of the room (does not need to be an identifier)
var name:String
/// The exit map (initially empty)
var exits = [Direction:Room]()
/// Initializer
init(name:String) {
self.name = name
}
/**
This function allows to retrieve a neighboring room based on its exit direction from inside the current room.
- Parameters:
- direction: A `Direction`
- Returns: The room through the exit in the next direction (if any)
*/
func nextRoom(direction:Direction) -> Room? {
return exits[direction]
}
}
/// Extension for the `CustomStringConvertible` protocol.
extension Room:CustomStringConvertible {
/// The description includes the name of the room as well as all possible exit directions
var description: String {
return "You are in \(self.name)\n\nExits:\n\(self.exits.keys.map { "- \($0.rawValue)" }.joined(separator: "\n"))"
}
}
I currently have designed a layout of rooms that looks like the following:
Diagram of the house's room layout
I already coded a textual representation of each room. The plan is to add different houses in the long run to introduce more levels, so I don't want to hardcode the map if possible.
The problem I am trying to solve for quite some time now is printing out the correct positioning of the rooms. I think I could solve the issue by writing an algorithm that parses through the rooms one by one and positions them accordingly in a 2D array.
Does anyone have any tips of solutions that could help me advance my code in some way?
I very much appreciate any feedback given on my problem.
- I tried splitting the rooms horizontally and parsing through the first row of rooms one by one starting from the left most room and advancing to the right most room. I would then assign each room a x and y coordinate and continue to the next room. Once I reached the right most room, I would then proceed to the left most room one row beneath and repeat the process. I would do that with each row, but I noticed that printing out that version of the map will position the rooms in the wrong position (e.g. kitchen would be aligned with bathroom, etc. )
- I also tried expanding the house's layout with "empty rooms" that I put on the outside edges of the house thinking that this way, the positioning while parsing through would be different than before. It wasn't.
I wasn't able to test much more since I didn't have many more ideas on how to fix this and searching the web didn't help much either since most results were linked to XCode and example code from other text-based games all had hard coded maps integrated.
In this answer I don't handle the one-way "door" from the main entrance to the hallway (as described in comments, when I asked what the red line meant).
I assume that rooms are all the same size, and can be viewed as occupying a single cell in a grid, and that exits are bidirectional, that is if there is an exit in A to B, there is also an exit in B to A, which apparently from comments, doesn't apply for the main entrance, but for printing a map, I think these assumptions will work. I also assume that if A has an exit to B then A is physically adjacent to B (ie, no teleports!).
Let's start by defining a type to represent a room location:
I also found it helpful to make
Roomconform toIdentifiable, so let's get that out of the way:I also assume that the positive x-axis points east, and that the positive y-axis points south.
Given those assumptions, we can work out the positions of the rooms, given a starting room. From a
Sequenceof rooms, I just use the first one as the reference, so I say that it's at(0, 0)I use that room'sidto add it to a dictionary that maps from theidto the room location.For each room remaining in the
Sequence, I go through that room's exits looking for an adjacent room that we've already got a position for in our dictionary. If I find such an adjacent room, then we can determine our current room's position from it: If we looked north for the adjacent room, then our current room'syis the adjacenty + 1, because the current room is to the south of the adjacent room. Similarly if we look south, then we use the adjacent room'sy - 1. If we look east, then use the adjacent room'sx - 1, and if we look west, use itsx + 1. If the current room doesn't have any adjacent rooms with known positions, then I put it in an "unaddedRooms" array to be tried again in another iteration after more rooms have been added. Along the way I'm keeping track of the maximum and minimumxanyvalues.Once I have a mapping for all the room ID's to positions, I offset all their positions by the negative of minimum
xandyin order to put the west-most room at x = 0, and the north-most room at y = 0, and I store all offset positions in a dictionary that maps locations to rooms. I call the result aLayout. Here's what it looks like:In
LayoutI try to handle the case of unconnected groups of rooms in some sensible way. Basically I just relocate them to the bottom of the layout. My sense is that such unreachable rooms are probably errors in building the rooms and assigning exits.Now that I have the rooms with actual locations assigned to them, I go one more step to create a
Map. TheMapis sort of an expanded version of theLayout. Whereas theLayoutjust has rooms in it, theMapcontains elements such as walls and doors that need to be drawn to show how rooms are connected, and it can produce aStringto print as an ASCII-art map. It looks like this:To test it, I programmatically define the rooms, connect them and put them in a list, duplicating rooms shown in the image you linked, except for the one clipped on the right of that image (which I think was supposed to be "Basement" - in any case, I didn't include it).
Here's what that "test" code looks like:
And here's the output
+---------------+---------------+ | | | | Kitchen Dining Room | | | | +---------------+------ -------+------ -------+ | | | | | Bathroom Hallway Living Room | | | | | +---------------+------ -------+---------------+ | | | Main Entrance | | | +---------------+