5 — The Strategy

Due Wednesday, 27 October 2021, 11:59:59pm

Delivery Place the product of this week’s milestone into your repo as follows:

Programming Task Fundamentals I teaches to abstract after you have seen several similar pieces of code. In this situation, you can see ahead of time that the playing mechanics remains the same, that the decision-making changes, and what the decision-making is all about. It is therefore appropriate to abstract immediately. A player needs a strategy, and indeed, it may need more than one strategy to find out which is best. So a player component should clearly handle the mechanics of playing a game and should abstract over a strategy component.

In general, the purpose of a strategy component is to make decisions. The Trains game requires three kinds of decisions:
  1. during setup, it much pick destinations that it wishes to connect;

  2. for each turn, the player must decide whether to request additional colored cards or to acquire a connection.

    • if the player decides to acquire a connection, it must choose one.

Implement the following deterministic strategies:
  • The first one is dubbed Hold-10 and works like this:
    1. During setup, choose the two destination cards that come first in the lexicographic ordering specified below.

    2. For a turn,

      • The strategy requests more cards, if the player’s wallet contains 10 or fewer.

      • If the player owns more than 10 cards, it attempts to acquire a connection.

        The strategy acquires the first connection from the lexicographically sorted sequence for which it has enough cards and rails; if there aren’t any, it asks for additional cards.

  • The second is Buy-Now and shares some traits with the first:
    1. During setup, choose the two destination cards that come last in the lexicographic ordering specified below.

    2. For a turn, the strategy always tries to buy a connection if possible (using the same algorithm as Hold-10), and requests more cards otherwise.

Lexicographic Ordering of Destinations Given two ordered (string<)? pairs of cities, p1 and p2, a lexicographic ordering of the two pairs is p1, p2 if
  • string<? holds for the first cities in each pair, or

  • the two first cities are equal and string<? holds for the second cities in each pair.

Otherwise it is p2, p1.

Lexicographic Ordering of Connections Given two connections, a lexicographic ordering chooses the connection whose cities are ordered according to the lexicographic ordering for destinations. If those are equal, a lexicographic orders the two connections in ascending order of number of segments. If further tie-breaking is needed, the string<? comparison the two colors is used.

The player will also communicate with the tournament manager. See Trains.Com, a Plan. You do not need to address this aspect yet.

Design Task As 4 — The Game State already explains, the player components must communicate with the referee. This communication involves both function/method calls and orderings of those, i.e., a protocol. Since outsiders will program to this interface, it must be spelled out precisely and in detail. Hint To start your brainstorming—what is a software system? What are the key phases of the game?

A protocol supplements an API to explain the calling sequence. Protocols are rarely checked, violations hard to detect, and the resulting errors tend to be obscure.

Design the interaction protocol between the referee and the player(s). The document, named player-protocol.md, should be a well-organized English write-up. If you are familiar with UML sequence diagrams (or you have time to read up on them), illustrate the prose with one of those.

Two pages should suffice. Less is more.

Keep in mind our Trains.Com, a Plan when you work on designs.

Testing Task Create a test harness named xlegal. The harness consumes its JSON input from STDIN and produces its results to STDOUT. Create three tests; place them in Tests/.

Constraint No test file may exceed the size limit of 20Kb.

Its inputs are a Map followed by a PlayerState object and an Acquired. The latter represents the connection the active player wishes to acquire.

Its output is true or false, depending on whether the requested action is legal according to the rules with respect to the given map and state.

As always, the tests are well-formed and valid JSON.

Rationale Both the player and the referee must be able to decide whether a proposed or requested action, respectively, is legal. Hence it must suffice to use PlayerState.

Here are the relevant definitions:

    PlayerState is an object:

      { "this" : ThisPlayer, "acquired" : [Player, ..., Player]}


     INTERPRETATION The object describes the state of the now-active player itself and

      as much as it can know about the remaining players, plus the order in which

      they take turns.


      This information is exactly what is available to every player in a physical

      version of the game. If your game state represents more information than that,

      your deserialization program must compute it from here.


    Acquired is [Name, Name, Color, Length]


     CONSTRAINT The first Name must be string<? to the second Name.


     INTERPRETATION specifies an un-directed edge between two cities, its color, and

       the length of the segment between two cities


    ThisPlayer is an object:

      { "destination1" : Destination,

        "destination2" : Destination,

        "rails"        : Natural,

        "cards"        : Card*,

        "acquired"     : Player}


     INTERPRETATION describes the state of the player: its chosen destination

      cards, its number of rails, its colored cards, and its acquired connections


    Destination is [City, City, Name, Name]


     INTERPRETATION specifies a destination card


    Card* is an object whose domain elements are Colors

     and whose range elements are natural numbers.


     INTERPRETATION describes how many cards of each color this player has


    Player is a JSON array of Acquireds.


     INTERPRETATION denotes a set of connections (owned by a player)

GLOBAL CONSTRAINTS The PlayerState argument and the Acquired argument must be consistent with the given Map.

Pedagogy Building harnesses for integration tests doesn’t slow you down—it actually accelerates your progress because the goals are always compatible with the current task and lay its foundation. Work thru the integration testing task before tackling the programming task.