Trying to implement a poker deck as a container.

(tads 3)

Imagine that I have a Container called ‘tube’. It starts out empty, but then I do this with it:

ball1.moveInto( tube );
ball2.moveInto( tube );
ball3.moveInto( tube );
ball4.moveInto( tube );

Am I guaranteed that now the order of tube.contents is something predictable, meaning I can treat the contents like a data type of stack or queue, or should I conceptually treat tube like it’s a “bag” data structure, where I can’t assume anything about the order of items inside it?

Where this is coming into play is that I’m having a very hard time trying to implement a container that behaves like a stack. The rules of the container are supposed to be that only the most recently added item can be removed or even looked at. The stack hides the objects underneath it, and using the archetypical “key under welcome mat” hidden item construct doesn’t work because that allows you to peek under the top item and take the items underneath without actually removing the covering item out of place. This is something I’m trying to do so I can make a poker deck in-game, where “take card from deck” automatically resolves to the topmost card in the deck without a disambiguator asking “did you mean one of these other 51 cards? [big list follows]”

This is made more problematic by the fact that the poker deck is allowed to be in a “face up” or “face down” state by a boolean variable, and if it’s face down, you’re not supposed to see the real names of the cards. All the cards are meant to look identical from the backside, so when drawing a card from the deck, the disambiguator will make the silly question: “did you mean the poker card, the poker card, the poker card, the poker card, the poker card, the…” etc for all 52 cards, and not only does this not make sense, there’s no way for the player to actually disambiguate that anyway because when they’re face down they all have the same vocabulary, and the vocabulary only shifts to things like ‘8/eight (of) hearts card’ when they’re face up.

Any ideas what’s the best way to implement this? Here’s a list of what I already tried that seems to be messy:

1 - Make the deck be a Dispenser.
Problem: A Dispenser dispenses new instances of items, and decides what they are based on what the player asked for. There doesn’t seem to be a way for the player to ask for a generic “card” and then have the dispenser decide what card they end up with. Instead it seems like the player has to ask for a named card “8 of spades” and then the dispenser can check to see if that’s a thing it allows itself to dispense. This might still be the right answer, but I’m not understanding how to do it. Keep in mind that total randomness is not a solution. I need the deck to remember the order of the cards that are in it and have it dispense the next one in the list, then adjust the list to remove the card it just dispensed. This does not seem to be compatible with how a Dispenser works because a dispenser lets the player tell it what object the player is pulling from it.

2 - Make the deck a RestrictedContainer that only holds objects of type “PlayingCard”, and then also make it contain an “inner” secret hidden RestrictedContainer that has no vocabulary (so a player can’t name it in a command). The inner secret container is what holds the inaccessable part of the deck, and the main container on top only holds the accessable part of the container (the top card in the deck). Then do some ugly re-mapping of its internal behavior via the notifyRemove and notifyInsert methods so that when someone takes the one card from the outer container, it moves the first item from the “inner” container out to the “outer container” to represent the next card coming up and becoming accessable. Then it does the reverse when a new card is added to the top of the deck - it moves the card that was there into the inner container instead. This messy behavior is designed to make the parser stop asking “which card do you mean” and giving 52 choices, because only 1 card is reachable, and the other 51 cards are inside the inner secret container. The problem I’m having here is the accidental recursion I cause when I try to use moveItem() to move objects between the inner and outer containers, and thus re-trigger the very same notifyInsert and notifyRemove routines that were causing those moves to happen. I tried basicMoveItem() instead to avoid this but it just doesn’t seem to actually have any effect and doesn’t really move the items at all.

It seems to me that some sort of a StackContainer would be a really useful addition to the standard library. Not only could it implement decks of cards, but it could also implement things like a stack of crates, or a Pez™ dispenser, or a life-size towers of Hanoi problem where you have to lift the rings off the giant spindles, and so on. Basically it could be useful for any pile of things where only the topmost thing is accessible. The material of the container itself would determine whether or not you can at least see the items under the top even though you can’t manipulate them. I.e. an opaque container only lets you sense the top item, and only if it’s “open”, while a transparent one lets you sense all the items in the stack but you still can only use the top item in a non-sense verb.

(replying to self here)

I did eventually get something that works but it feels a bit messy. Basically my “deck” is now a container who’s “contents” property never has more than 1 card in it, representing the topmost card of the deck. The rest of the deck is held in reserve inside an “inactiveContents” List that I am using as a stack data structure. I manipulate it with notifyRemove and notifyInsert such that whenever the card in the top is removed, the next card in inactiveContents is popped off the stack and moved into the deck’s contents, and whenever a card is inserted into the container, the card that used to be in the top is pushed onto the inactiveContents List and the new card takes its place as the only card officially in the container. Thus the parser only ever “sees” the topmost card for vocabulary matching because in reality only the topmost card is really actually “in” the container’s contents list. This was a straightforward solution except that manipulating the contents list directly is sort of bypassing a lot of the adventure library and thus not a great idea, thus why I call it a bit messy. I did try to use the adventure library as much as possible (using moveInto() in preference over contents = contents + newItem, for example), but I couldn’t avoid direct manipulation in some places here and there.

Well, one thing I can think of right away that’ll be of some help to you is the “isEquivalent” property.

class Card: Thing
isEquivalent = true

that’ll solve your disambiguation problems, because it’ll treat one card as interchangeable with another.

as for keeping cards in order…
I’m thinking you’re going to need a list somewhere, and you may have to override dobjFor(Take) on the cards. Something like…


deck : Thing
cardList = [] //You'd fill this up with your cards
dealCard()
{
 cardList[1].moveInto(me) //This takes the first item off the list and gives it to you
 cardList -= cardList[1] //And this removes the missing card from the list
}
;

class Card: Thing
isEquivalent = true
dobjFor(Take)
{
verify() {}
check(){}
action()
{
    if(self.isIn(deck)) 
    {
      deck.dealCard();  //if it's in the deck, we kick the action over to the deck's deal method
     }
    else
     inherited;
}
}

This is untested and probably sloppy, but it’s how I would start to approach the problem. Whenever you’re dealing with “items in a certain order”, you’re going to want a List, 99 times out of 100.

Hope this helps. :slight_smile: