Putting stuff on stuff…

After finishing containers the other day, I also decided to create supporters. A supporter is an object on which you can put things—like a table, for example, or a shelf.

Very quickly, I realized that supporters are no different from containers, really. Instead of putting things IN them, you put things ON them. Since everything in a text adventure is abstract, it doesn’t really matter either way. So, when you think about it, supporters are essentially containers without a lid, meaning that they are always open.

In practical terms, this means that the code base is virtually identical. All that changes is the output text when I am listing the contents.

For a container, I will print something like…

The box contains a key and a newspaper.

…whereas a supporter would print…

You see a key and a newspaper on the table.

Minor text differences, as you’ll certainly agree.

The functionality to add or remove items is also identical, so I’ve decided to do a little rewrite. I made a Supporter class and use it as the superclass for my containers.

class Supporter ( object ):
	""" This class defines all sorts of supporters where items can be placed on """

	def __init__ ( self, _contents=None, *args, **kwargs ):
		super ().__init__( *args, **kwargs  )
		self.Contents = _contents
		self.EmptyString = "There's nothing on it."
		self.FullString = "You see {1} on the {0}."
		self.Silent = True								# Empty contents do not spawn a message

	def PrintContents ( self ):
		_listString = self.ListContents()

		if not _listString:
			if False == self.Silent:
				print ( self.EmptyString )
			print ( self.FullString.format( globals.theNounString, _listString ))

		return True

	def ListContents ( self ):
		_counter = 0
		_outString = ""

		if self.Contents:
			for _item in self.Contents:
				if 0 != _counter:
					_outString += " and "

				_outString += _item.GetName ( globals.Articles.Undef )
				_counter += 1

			if _counter:
				_outString = _outString.replace ( " and ", ", ", _counter - 2 )

		return _outString

	def HasItem ( self, _token ):
		""" Check for a particular item and return the first match """

		if self.Contents:
			for _item in self.Contents:
				if _token == _item.Token:
					return _item
		return None

	def RemoveItem ( self, _token ):
		""" Remove an item from the contents list """
		if self.Contents:
			for _item in self.Contents:
				if _token == _item.Token:
					self.Contents.remove ( _item )
					return _item

		return None

	def AddItem ( self, _item ):
		self.Contents.append( _item )

	def Evaluate ( self ):
		if Tokens.Look == globals.theVerb and not globals.thePrep:
			self.Describe ()
			return self.PrintContents()

		return False

This is what the class looks like, complete with various helper methods to check for items in the supporter’s contents, add items, remove items, etc.

If you recall my previous Container class, you will notice that they look eerily similar. But not for much longer, because my original Container class has become almost entirely redundant.

Here is what it looks like now…

class Container ( Supporter ):
	""" This class defines all sorts of container behavior """

	def __init__ ( self, _initState=globals.ContainerStates.Open, *args, **kwargs ):
		super ().__init__( *args, **kwargs  )
		self.State = _initState
		self.EmptyString = "There's nothing in it."
		self.FullString = "The {0} contains {1}."
		self.Silent = False									# Do empty contents create a message?

	def ListContents ( self ):

		# Put check in here if the container is closed/locked, etc. before listing contents

		return super().ListContents ()

Pay attention to line 2, where I am now deriving my Container class from the Supporter class, making sure all of its functionality is coming along with it.

As you can see also, all relevant functionality has been delegated to the Supporter superclass. The only main difference is that I am catching the ListContents() function so I can add some checks that will make sure the container is actually open and not, by any chance, closed or even locked. I haven’t gotten to that yet, but it should be simple enough to add when I need it.

One of the interesting tidbits here that you may want to pay attention to is that I initialize the text string EmptyString and FullString differently in the Container than in the Supporter class. This will automatically match the correct text output to indicate things are supposedly “in” the container as opposed to “on top” of it.

I am using the string format() function here to do a bit of string magic, as it allows me to use any sentence structure and still fill in the correct text subject and the list, wherever it needs to be. The parameters in the function allow me to do that just nicely.

Funny how going deeper down the rabbit hole sometimes changes your whole perspective. I had thought my containers are a clean-cut thing, and yet, here I am after shuffling code around to accommodate the same thing in a different way. It just goes to show you that in programming, there is no one right solution.

Leave a Reply

Your email address will not be published. Required fields are marked *