Are there arrays in TADS? Or anything that behaves that way?

The short version:

Are there arrays in TADS 3.1? Or is there a dynamic data structure I can use like an array, to call up a datum by two or more indices?

The long version:

[rant]Armed with Ben’s Rock-Paper-Scissors code, I now want to create a general NPC-NPC game playing module. This will consult an NPCgame object for the rules.

The advantage to this is that now you can simply define the game rules and add it to the list of games the NPC can play, rather than rewriting the game code many times over. Further down the road this may make it possible to create games where moves can be added in on the fly.

–If it’s not clear, I’m using games as a well-defined instance of social interaction. Fuzz out the “win” and “lose” reporting and make a little more narrative the move and countermove, and you have a sort of model for social interaction that doesn’t require coding every line by hand. (E.g. The Games People Play, by Eric Berne.)

To this end, it would be much simpler if I could just set up a grid in something akin to the normal form game theorists use:

    R   P   S  <--p1
R   -  p1 p2
P  p2  -  p1
S  p1 p2  -
^
p2

And then call up winResult = gameMatrix[p1move][p2move], or suchlike.[/rant]

Any way of accessing a datum on two (or more) indices?

Conrad.

Possibly making a list of lists?

I guess that would be a tree, right?

NPCgameObject.player1moveNode.player2moveNode… I seem to recall doing something like that for a different application some time ago. Probably could do it again.

Thanks, Jim.

Conrad.

TADS provides three types for this: ByteArray, Vector and List. ByteArray is a basic datatype, Vector and List are classes. You can find information about them in the system manual. Pick your poison:

tads.org/t3doc/doc/sysman/toc.htm

Like Jim mentioned, they work similarly to C-like languages. To get a 2D array, you do an array of arrays (or vector/list of vectors/lists).

Edit:
Correction to the above: ByteArray is also a class, not a basic type.

Well, ByteArray is worrisome in that it only stores bytes. In the Lists v. Vectors lineup, it seems Vectors would allow the code to tinker with the data more easily.

So I guess Vectors it is!

Thanks, RealNC & Jim.

Conrad.

Alright… I’ve been trying to figure this out for a while, kind of like the Mutual of Omaha footage with a lion trying to figure out a porcupine.

Currently, I’m considering setting this up as a LookupTable. They’re designed for stowing away data on a key, which is what I’m doing.

The catch is that I need to stow data away based on TWO keys. Now rather than create an index table of index tables, as I had thought to do with lists / vectors, I’m considering creating an index table of a special object that takes two parameters (=two keys), and indexing on that. Each parameter would be an enumerated, er, thingy. (Symbol? Token?)

The other way to use a two-key system would be to concatenate two strings together. For example, I could create a function that would smash together two player’s moves like this:

smashTogetherTwoPlayersMoves (p1move, p2move) // both beings strings { return (p1move + '-vs-' + p2move); } ;

Thus the lookupTable would operate on strings like ‘ROCK-vs-PAPER’.

I can’t help but notice that the lookupTable key examples in the docs all seem to be strings. I expect lookupTables can key on objects of any kind, but I just want something simple and easily doable.

Any thoughts on which approach will be simplest and easiest, for extension into as-yet-unthought-of game move keys?

Conrad.

…is there a data class that functions like a set in TADS? Like a list, but without ordering? Or like enum, but with grouping?

C.

Why don’t you use a two element list as the index value? The ordering is actually useful since the expected result from (Rock, Paper) is not the same as (Paper, Rock).

Yeah, but how do I assign content to a filled-out two-item list?

–Or do you mean, use a two-item list as the key?

C.

Yes, use a two-item list as a key.

enum ROCK, PAPER, SCISSORS;
enum WIN, LOSE, DRAW;

modify WaitAction
	execAction() {
		local tab = new LookupTable();

		tab[(ROCK,PAPER)] = LOSE;
		tab[(ROCK,SCISSORS)] = WIN;
		tab[(ROCK,ROCK)] = DRAW;

		if (tab[(ROCK,PAPER)] == LOSE)
			"PAPER beats ROCK. ";
		if (tab[(ROCK,SCISSORS)] == WIN)
			"ROCK beats SCISSORS. ";
		if (tab[(ROCK,ROCK)] == DRAW)
			"ROCK and ROCK is a draw. ";
	}
;

You might also want to have the table’s result be a two-item list, so that for example the result for player 1 is at position 1, and the result for player 2 is at position 2.

tab[(ROCK,PAPER)] = (LOSE, WIN);

This would allow you to mix up the output - you could print “Player 1 wins!” as often as “Player 2 loses!”, without having to negate the result from the table.

Hmm, this doesn’t work for lists constructed at runtime, since they do not have the same internal identifier. Let me get back to you on this.

Yeah, I need to code the results for each player individually anyway, because for some games the outcomes will be asymmetric.

–Why did you code all of this inside WaitAction?

Conrad.

I’ll use the string system, or an object passing a string. Try both, I guess.

Conrad.

Alright, lemme ask this –

Is it possible to save an object to a file and then re-load it, without having TADS go on strike because the game file has been updated since? Is this difficult, or is it on a par with the file manipulations we saw in setting script files?

In other words, can I have the T3 engine allow me to key in results of different move combinations, save that data, and access it subsequently, when the IF I’m building has been changed elsewhere?

I can’t be hard-coding everything, and might as well knock this out early with a basic game editor.

Conrad.

That’s just what I reach for whenever I have a chunk of code I want to test. It’s not meant to be used that way in a real game.

You can use my JSON serializer for saving objects to files in a persistent, cross-version format.

It’s not yet suitable as a replacement for save/restore, but it works well for individual objects.

Thanks, Ben, for the thoughts and the extensions. Also for the NPC check() discussion, one thread over.

I’ll post again when I have something substantial done.

Conrad.

All right… I’m not getting this, and the problem isn’t my ability to navigate the T3 syntax. The problem is my ability to think abstractly about programming tasks.

What I have (so far) is:

MoveThing : object 
    p1move = ''
    p2move = ''
    p1result = ''
    p2result = ''
    outcome = ''
    movekey () {
        return (p1move + '-v-' + p2move);
    }   
    
    resolveresult() {
        local bothmoves = movekey();
        switch (bothmoves) {
        case 'rock-v-rock' :
        case 'paper-v-paper':
        case 'scissors-v-scissors':
            "TIE! ";
            break;
        case 'rock-v-scissors':
        case 'scissors-v-paper':
        case 'paper-v-rock':
            "Player 1 wins! ";
            break;
        case 'scissors-v-rock':
        case 'paper-v-scissors':
        case 'rock-v-paper':
            "Player 2 wins! ";
            break;
        default : 
            "FUMBLE! ";
        }
    }
;

…this is good, this is fine, I’m sure this’ll work once I get it all together.

BUT, it’s very much not what I was setting out to do.

What I set out to do was to create a general little game-handler, such that in the future I’d create new games by entering in DATA, and the general game-handler would grab the moves, compare them against the win/lose critera, and assign outcomes.

So how do I get there from here?

–maybe I should create a p1winList, a p2winList, and a tieList? Then I can enter those conditions in as data, e.g. p1move-v-p2move, and have the resolver concat the moves and check for the result’s presence in the lists?

Conrad.

Does this do that?

    p1winList = []
    p2winList = []
    tieList = []
    
    resolveresult() {
        local bothmoves = movekey();
        if ( p1winList.indexWhich(bothmoves) )
            "Player 1 Wins! ";
        if ( p2winList.indexWhich(bothmoves) )
            "Player 2 Wins! ";
        if ( tieList.indexWhich(bothmoves) )
            "It's a tie -- thanks! ";
    }
;

–Or is there some more correct way to test for an element being in a set that I’m not finding in the manual?

C.

EDIT:

No, this does not work. I get the run-time error: Function Pointer Required.

The error comes up in the way I’m using indexWhich. Not sure why…

Working through this, I’ve found that .indexOf() works:

if ( p2winList.indexOf(bothmoves) ) "Player 2 Wins! ";

It seems that I’d have to use some kind of ({x:}x==bothmoves) expression I don’t fully understand to use the other one.

Hope you guys don’t mind me thinking out loud online like this.

Conrad.