                                                                    8/8/89
                           Santa Fe Institute's
              D O U B L E  A U C T I O N  T O U R N A M E N T


                    CHAPTER 3 -- THE SKELETON PROGRAMS
                    ----------------------------------

This chapter describes the structure of the skeleton programs and the
variables defined therein.  The description here is largely language-
independent; language-dependent details may be found in README files
and/or as comments in the software provided for each available language.


                               3.1 Introduction
                               ----------------
Skeleton player programs are presently available in C, Fortran, and Pascal.
The skeleton programs take care of all the bookkeeping and communication
details, allowing participants to concentrate on writing the central
decision-making routines to implement their strategy.  The skeleton programs
provided are actually complete programs with a simple built-in strategy, and
may be compiled and used as test players.  To produce their own player
programs, participants will modify the skeletons and re-compile.

A complete player program based on one of the skeleton programs consists of
the following parts:

1. The strategy routines, 'BID' and 'BUY' for a buyer, or 'OFFER' and 'SELL'
   for a seller.  These routines return a value indicating the user's
   decision.  In the skeleton programs as supplied these routines contain
   simple algorithms as examples.

2. Miscellaneous user routines that are called at different stages of the
   game to provide information to the user.  These are all empty dummy
   routines in the skeleton programs as supplied.  They do not need to be
   modified unless users desire to use them to gather information or
   initialize or update their own variables.

3. Control routines that take care of bookkeeping, communicating with the
   monitor, calling the strategy and miscellaneous routines, saving and
   restoring variables, displaying the game, providing random numbers, etc.
   Participants should not need to change these routines, or even to
   understand how they work.

Note that routine names are written in upper-case (e.g. BID) in this
document, but may need to be lower-case in actual programs.

In more detail, the user routines are as follows:


STRATEGY ROUTINES

BID For a buyer, called at the start of each bid-offer step to decide
        on a bid value, or to pass.

OFFER   For a seller, called at the start of each bid-offer step to decide
        on an offer value, or to pass.

BUY For a buyer, called at the start of each buy-sell step to decide
        whether to request to buy.

SELL    For a seller, called at the start of each buy-sell step to decide
        whether to request to sell.

Note that a player program can play a buyer or a seller, or may be able to
play either.  If only one of the roles is chosen, then only two of the four
strategy routines needs to be developed.  However, in the tournament, players
that can only play one role will be selected for fewer games, and thus have
less opportunity for profit.

More details about the return values of these routines is given in the last
section of this document.


MISCELLANEOUS ROUTINES

GBEGIN  Called once at the beginning of each game.

GEND    Called once at the end of each game.

RBEGIN  Called at the beginning of each round.

REND    Called at the end of each round.

PBEGIN  Called at the beginning of each period.

PEND    Called at the end of each period.

BOEND   Called at the end of each bid-offer step, after all players' bids
        and offers have been processed.

BSEND   Called at the end of each buy-sell step, after all players' buy
        and sell requests have been processed.


                      3.2 Variables in the user routines
                      ----------------------------------
The variables and arrays described below are available in all the user
routines (strategy routines and miscellaneous routines).  They provide all the
information available to the player, on which bid/offer/buy/sell decisions
must be made.  The variable names and meanings are almost the same in all
languages, and are defined here in a language-independent way.  See the
comments in the appropriate skeleton programs for all language-dependent
details.

None of the variables described should be altered by the user
routines themselves; doing so will not have any useful effect.

All variables are integers.  Prices are represented by integers in the range
1 - 8000.  It is of no consequence whether these values are regarded as
dollars, cents, or some other unit.

Some variables are one-dimensional arrays of fixed length.  The length is
given in square brackets.  Thus, for example, token[4] represents a 4-element
array.  How this is declared and referenced is language-dependent.  In general
array indices or subscripts run upwards from 1, not from 0.

It is convenient to divide the variables into three classes, according
to whether they are public (the same for all players) or private, and whether
they are constant or varying:


PUBLIC CONSTANTS

These variables are unchanging throughout a game (the same in all periods and
steps), and are known to all players:

nplayers        The total number of players in the game, including yourself.

nbuyers         The number of buyers in the game.  This will never exceed 20.

nsellers        The number of sellers in the game.  This will never exceed 20.
                Note that nbuyers+nsellers = nplayers.

bnumber[20]     A player-number for each buyer, in the range 1 - 9999.  There
                is one entry for each buyer, 1 to nbuyers, and the remaining
                entries are zero.  These numbers are intended to give a unique
                identification to each program and participant across all
                games, so that participants in the pre-tournament Santa Fe
                Token Exchange games can determine who they have and have not
                played against.  A directory will be available.  A value of
                9999 is used to mean a human player.  Some values may be
                reported as 0 to mean anonymous; all players will be anonymous
                in the actual tournament.  Do not confuse player-numbers with
                the player id's (described below) that are used to identify
                the players in a particular game.

snumber[20]     A player-number for each seller.  Like bnumber[20].

nrounds         The maximum number of rounds in the game.  This will never
                exceed 20.

nperiods        The maximum number of periods per round.  This will never
                exceed 5.

ntimes          The number of time units in each period.  This will never
                exceed 400.  At each time there is first a bid-offer step and
                then a buy-sell step.  A period will not be terminated
                before all 'ntimes' time units have been played if it is
                possible for any pair of players to trade with mutual profit.
                Early termination will not necessarily occur even when no
                more mutual profit is possible; see the description of the
                monitor's 'deadsteps' parameter.

minprice        The minimum price value allowed for any bid or offer.

maxprice        The maximum price value allowed for any bid or offer.
                Note that 1 <= minprice <= maxprice <= 8000.

gameid          An arbitrary unique integer in the range  1 - 9999 that
                identifies this particular game.  The gameid is useful for
                referring to particular games and for creating unique
                filenames, etc. It will normally increase from game to game.

gametype        A 4 (decimal) digit number conveying the values for RAN1,...,
                RAN4. The RAN(i) values govern the random generation of
                tokens as described in rule 25 of chapter 7.  The RAN(i) values
                are given by

                ran(i) = 3^k(i) - 1     i=1,...,4

                where k(i) is the i'th digit of gametype, counting from the
                left, and where 3^k(i) denotes 3 to the power k(i).  Thus,
                for example, gametype = 1236 means

                RAN1 = 3^1 - 1 = 2
                RAN2 = 3^2 - 1 = 8
                RAN3 = 3^3 - 1 = 28
                RAN4 = 3^6 - 1 = 728

                The values for the digits k(i) are restricted to (0,1,...,8).
                Values of gametype less than 1000 are taken as having leading
                zeroes.  gametype = 0 implies that the token generation
                method is not revealed.

The upper limits on nbuyers, nsellers, nrounds, nperiods, and ntimes specified
above may be relevant if you want to construct your own arrays to record
historical or strategic information about other players or the game so far.
In fact the upper limits will rarely be approached, and you can set lower
limits of your own if necessary; see the skeleton programs for details.  If
the parameters of a particular game exceed your own limits, your program will
automatically refuse to play in it. Note also that no token value is allowed
to exceed 8000 (due to technicalities of the software design). If the RAN(i)
values are set sufficiently high, this limitation will cause an upward
truncation in the token distribution at 8000. However rule 25 in chapter 7
guarantees that in the tournament RAN(i) values will be chosen so that such
truncation will never occur.


PUBLIC VARIABLES

These variables change with the progress of the game and are known to all
players.  All are set to 0 before the start of the game and (except r and p)
before the start of each new period (i.e. before the call to PBEGIN).  The
"unknown" values referred to below can only occur if a player makes a 'late'
response (see 'late' below).

r               The number of the current round, r = 1, 2, ..., nrounds.

p               The number of the current period within the current round,
                p = 1, 2, ..., nperiods.

t               The current time within the current period, t = 1, 2, ...,
                ntimes.

cbid            The current bid value if any, or zero if none.  In a SELL
                routine this is the value you accept in a sell request.  In a
                BID routine this is the value to beat; a new bid must be
                above this value.  In a bid-offer step the highest bid (if
                any) determines the new cbid value before the call to BOEND.
                The current bid is removed (cbid=0) whenever a trade occurs,
                before the call to BSEND.

coffer          The current offer value if any, or zero if none.  In a BUY
                routine this is the value you accept in a buy request.  In an
                OFFER routine this is the value to beat; a new offer must be
                below this value.  In a bid-offer step the lowest offer (if
                any) determines the new coffer value before the call to BOEND.
                The current offer is removed (coffer=0) whenever a trade
                occurs, before the call to BSEND.

bidder          The id of the holder of the current bid, or zero if none.
                Between 1 and nbuyers when cbid>0, always 0 when cbid=0.

offerer         The id of the holder of the current offer, or zero if none.
                Between 1 and nsellers when coffer>0, always 0 when coffer=0.

nbids           The number of new bids made by buyers in the last bid-offer
                step, or 0 if none or unknown.  Updated before each BOEND
                call.

noffers         The number of new offers made by sellers in the last bid-offer
                step, or 0 if none or unknown.  Updated before each BOEND
                call.

bids[20]        The actual bids made by each buyer in the last bid-offer step,
                or zero if none or unknown.  There is one entry for each
                buyer, 1 to nbuyers, and the remaining entries are zero.  The
                whole array is reset to reflect the new bids before each BOEND
                call.

offers[20]      The actual offers made by each seller in the last bid-offer
                step, or zero if none or unknown.  There is one entry for each
                seller, 1 to nsellers, and the remaining entries are zero.
                The whole array is reset to reflect the new bids before each
                BOEND call.

bstype          A code telling what happened in the last buy-sell step:  0 if
                no trade occurred, 1 if a buy request was accepted,  2 if a
                sell request was accepted, -1 if unknown because of a 'late'
                condition.  This is set before each BSEND call.  The next
                three variables provide more detail about the transaction if
                bstype>0.  They are set at the same time as bstype.  They are
                all set to zero if bstype<=0.

price           The price of the transaction.

buyer           The id of the buyer involved in the transaction.  If bstype=1
                this is a buyer whose 'buy' request was accepted.  If bstype=2
                this is the buyer whose current bid was accepted by 'seller'.

seller          The id of the seller involved in the transaction.  If bstype=2
                this is a seller whose 'sell' request was accepted.  If
                bstype=1 this is the seller whose current offer was accepted
                by 'buyer'.

btrades[20]     A summary array giving the number of trades that each buyer
                has made so far in this period.  There is one entry for each
                buyer, 1 to nbuyers, and the remaining entries are zero.  A
                trade for a buyer is an accepted buy request or the acceptance
                by a seller of that buyer's current bid; in either case one
                token is consumed.  Updated before each call to BSEND.

strades[20]     A summary array giving the number of trades that each seller
                has made so far in this period.  There is one entry for each
                seller, 1 to nsellers, and the remaining entries are zero.  A
                trade for a  seller is an accepted sell request or the
                acceptance by a buyer of that seller's current offer; in
                either case one token is consumed.  Updated before each call
                to BSEND.

ntrades         The total number of trades made by all players so far in this
                period.

prices[80]      The price of every trade that has occurred so far in this
                period.  There is one entry for each trade, 1 to ntrades, and
                the remaining entries are zero.  The value is negative
                (multiplied by -1) if the trade was made by you.

lasttime        The time (value of t) at which the most recent trade occurred
                in this period, or 0 if no trade has occurred yet in this
                period.


PRIVATE VARIABLES

Most of these variables change with the progress or the game and are in
general different for each player.  All are set to 0 before the start of the
game.  mytrades, mylasttime, pprofit, nobidoff, bo, nobuysell, bs, and late
are reset to 0 at the start of every period and round.  In addition at the
start of each round, rprofit, tradelist[5], and profitlist[5] are reset to
zero, and ntokens and tokens[4] are set to their new values.

id              Your own identification number, between 1 and nbuyers if you
                are a buyer, and between 1 and nsellers if you are a seller.
                When the id number of another player is given, it is always
                clear from context whether it is that of a buyer or that of
                a seller.

role            1 if you are a buyer, 2 if you are a seller.

timeout         The number of seconds of elapsed (wall) time that you have
                per step.  9999 implies infinity; the monitor will wait for
                ever.  0 means a relatively short time, normally used for
                pipe-based players, that depends on the monitor's
                'timefactors' parameters.

ntokens         The number of tokens that you have available to buy or sell.
                This is fixed for a given round, but may change from round to
                round. It will never exceed 4, and in the tournament it will
                be the same for all players.

token[4]        The redemption values of your tokens, in token[1], ...,
                token[ntokens].  The redemption values are given in
                decreasing order for a buyer and in increasing order for a
                seller, and are assumed to be used in that order, which
                maximizes any profits.  Any unused array elements are set to 0.

mytrades        The number of trades (0 - ntokens) that you have made so far
                in this period.  This is equal to the appropriate entry in
                btrades or strades.  If mytrades<ntokens your next available
                token value is token[mytrades+1].  If mytrades=ntokens you
                have used all your tokens and cannot make any further bid,
                offer, buy, or sell requests.

mylasttime      The time (value of t) at which your most recent trade occurred
                in this period, or 0 if you have not yet made any trades in
                this period.

pprofit         Your total profit so far in this period of the game, or 0 if
                you have not yet made any trades in this period.

rprofit         Your total profit so far in this round of the game, or 0 if
                you have not yet made any trades in this round.

gprofit         Your total profit so far in this game, or 0 if you have not
                yet made any trades.

nobidoff        0 if you are allowed to make a bid or offer, 1 if you can't
                because you have no tokens left.  -1 if unknown because of a
                'late' condition.  Reset before each call to BID or OFFER.

bo              A code that tells you the outcome of your request in the last
                bid-offer step.  This is updated before each call to BOEND.
                The meaning of the codes is as follows:

                0       You didn't make a bid or offer, and you don't still
                        hold the current one.
                1       You didn't make a bid or offer, but your previous
                        bid or offer is still the current one.
                2       Your bid or offer was chosen and is now the current
                        one.
                3       Your bid or offer was bettered by another player.
                4       Your bid or offer was equal to that of at least one
                        other player, and you lost the random tie-break.
                -1      Your bid or offer was unacceptable.  This could be
                        because it was outside the allowed range (minprice to
                        maxprice), or because it was a bid that wasn't above
                        the current bid, or an offer that wasn't below the
                        current offer, or because you have no tokens left to
                        trade.
                -2      A previous response to a bid-offer or buy-sell step
                        was late and was ignored.  See 'late' below.

                Note that your new bid or offer is reported to the other
                players in cases 2-4, but not in case -1 or -2.

nobuysell       0 if you are allowed to make a buy or sell request, non-zero
                if not.  -1 if unknown because of a 'late' condition.  This
                is reset before each call to BUY or SELL.  When non-zero the
                value is between 1 and 7, given by the sum of whichever of
                the following apply:

                1       No tokens left to trade.
                2       No current offer/bid to accept.
                4       You don't hold the current bid or offer.

bs              A code that tells you the outcome of your request in the last
                buy-sell step.  This is reset after each buy-sell step.  The
                meaning of the codes is as follows:

                0       You didn't make a buy or sell request.
                1       Your buy or sell request was accepted and you made
                        a trade.
                2       Your buy or sell request was rejected because both
                        the current bidder and the current offerer asked to
                        buy/sell, and you lost the random tie break (losing is
                        usually better than winning here).
                3       Your buy or sell request was rejected because another
                        buyer or seller (the same type as you) also made a
                        valid request, and won the random tie-break.
                -1      Your buy or sell request was unacceptable.  This could
                        be because there was no corresponding current offer or
                        bid, or because you had no tokens left to trade, or
                        because you didn't hold the current bid or offer.
                        This should not occur if you never try to buy or sell
                        when nobuysell is non-zero.
                -2      A previous response to a bid-offer or buy-sell step
                        was late and was ignored.  See 'late' below.

                Note that only successful buy/sell requests (bs=1) are
                reported to the other players.

                Note also that you may have made a trade even if bs is not
                equal to 1, because your current bid or offer may have been
                accepted by another player.  Check whether 'buyer' or 'seller'
                (as appropriate) is equal to your 'id' to know for sure.

late            The number of times in this period that you were late and
                failed to respond on time.  If this is non-zero, be aware that
                the following variables may be incorrect in this period, even
                long after the late response, because information from the
                monitor may have been missed: btrades[20], strades[20],
                ntrades, prices, lasttime, mylasttime, pprofit.  The following
                variables may be incorrect in this period and/or in future
                periods if you were ever late: rprofit, gprofit,
                profitlist[5], efficiency.  The following variables may be
                temporarily incorrect, while either bo or bs is set to -2,
                but should recover correctly: nbids, noffers, bids[20],
                offers[20], bstype, price, buyer, seller, nobidoff, nobuysell,
                t.  Except for t this last group is set to well defined
                "unknown" values when a correct value is not known because of
                a late response; see the entries for the individual variables
                above.  t may temporarily be smaller than its true value after
                a late response.

tradelist[5]    The number of trades you made in each period of this round.
                There is one entry for each period, 1 to p, started so far
                in this round, and the remaining entries are 0.  Updated
                after each trade.

profitlist[5]   The profit you made in each period of this round.  There is
                one entry for each period, 1 to p, started so far in this
                round, and the remaining entries are 0.  Updated after
                each trade.

efficiency      A measure of your overall performance in this game, available
                only in the GEND routine at the end of the game.  The measure
                is a ratio (times 100) of your actual profit to your expected
                profit predicted by economic theory (computed at the midpoint
                competitive equilibrium price).  100 is average, higher values
                are better.


                             3.3 Working variables
                             ---------------------
If file-based communication is in use, each player program must be reloaded
for each step, and all needed variables must be saved to a  disk file and
restored from it.  The control routines do this automatically for all the
variables discussed above, and can also save specified variables of your own.
How this is done is language dependent; see the comments in the README file
and skeleton programs for your chosen language.

If pipe-based or internet-based communication is used, the player programs
are continuously loaded during a  game, and the save/restore mechanism is
not needed.  You may create new variables as you please (including global or
common ones), and expect them to retain their values according to the
usual conventions of the language used.

Player programs may also create and use external files of their own; each
player program will normally exist in its own sub-directory.  Such files will
be preserved from game to game.


                               3.4 Return values
                               -----------------
In a BID or OFFER routine you must specify a bid or offer value, or none.  In
a BUY or SELL routine you must say if you want to buy or sell.  The way that
these return values from your strategy routines are passed back to the control
routines is language-dependent.  For details see the comments in the skeleton
program for your language.  Here we simply define the values concerned.  All
values are integers.

BID     (buyer only)  For a BID routine, return the value of the bid if you
        want to make one, or 0 if you don't.  If you do make a bid it must be
        between minprice and maxprice inclusive, and must be higher than the
        current bid 'cbid' if there is one.  You must return 0 if nobidoff is
        non-zero.

OFFER   (seller only)  For an OFFER routine, return the value of the offer if
        you want to make one, or 0 if you don't.  If you do make an offer it
        must be between minprice and maxprice inclusive, and must be lower
        than the current offer 'coffer' if there is one.  You must return 0
        if nobidoff is non-zero.

BUY     (buyer only)  For a BUY routine, return 1 if you want to request a
        buy at the current offer price 'coffer', or 0 if you don't.  You must
        return 0 if nobuysell is non-zero.

SELL    (seller only)  For a sell routine, return 1 if you want to request a
        sell at the current bid price 'cbid', or 0 if you don't.  You must
        return 0 if nobuysell is non-zero.

