Package edu.wisc.game.sql

## Class PlayerInfo

- java.lang.Object
- - edu.wisc.game.sql.PlayerInfo

-     @Entity
      public class PlayerInfo
      extends Object

  A PlayerInfo object represent information about a player (what trial list he's in, what episodes he's done etc) stored in the SQL database. It is identiied by a playerId (a string). A humans playing the Rule Game may create just one PlayerInfo object (a single playerId), if he comes from the Mechanical Turk, or goes directly to the GUI Client URL; or he can create many such objects (each one with a particular experiment plan), if he starts many games from the Repeat User Launch page, or from the Android app. In the latter case, all such PlayerInfo objects are linked to a single User object.

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class | Description
    --- | --- | ---
    `static class` | `PlayerInfo.Action` | What type of action takes the player to a particular destination?
    `static class` | `PlayerInfo.COMPLETION` | Completion modes
    `class` | `PlayerInfo.Series` | A Series is a list of all episodes played under a specific param set.
    `static class` | `PlayerInfo.Transition` | Where can we go from here?
    `class` | `PlayerInfo.TransitionMap` |

  - ### Field Summary

    Fields
    Modifier and Type | Field | Description
    --- | --- | ---
    `double` | `pseudoHalftime` | This is used in pseudo-AI bots, to indicate how fast it pretends to learn

  - ### Constructor Summary

    Constructors
    Constructor | Description
    --- | ---
    `PlayerInfo()` |

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method | Description
    --- | --- | ---
    `void` | `abandon()` | This may be invoked by a maintenance thread in 2PG, when it detects that this player has been inactive for a while.
    `void` | `activateBonus​(javax.persistence.EntityManager em)` | Switches this player from the main subseries to the bonus subseries, and saves the information about this fact in the SQL server.
    `void` | `addEpisode​(EpisodeInfo c)` |
    `boolean` | `alreadyFinished()` | Returns true if the current series number is set beyond the possible range, which indicates that it has gone through the last possible increment (and, therefore, the completion code has been set as well).
    `boolean` | `canActivateBonus()` |
    `int` | `countBonusEpisodes​(int k)` | How many bonus episodes (complete or not) are currently in series No.
    `EpisodeInfo` | `episodeToDo()` | Returns the currently unfinished last episode to be resumed, or a new episode (in the current series or the next series, as the case may be), or null if this player has finished with all series.
    `boolean` | `gameAbandoned()` |
    `Vector<EpisodeInfo>` | `getAllEpisodes()` |
    `boolean` | `getAmBot()` |
    `String` | `getCompletionCode()` | The completion code, a string that the player can report as a proof of his completion of the experiment plan.
    `int` | `getCompletionMode()` |
    `int` | `getCurrentSeriesNo()` |
    `Date` | `getDate()` |
    `String` | `getExperimentPlan()` | The experiment plan historically was just a directory name, e.g.
    `ParaSet` | `getFirstPara()` | Gives a link to the first ParaSet.
    `long` | `getId()` |
    `Date` | `getLastActivityTime()` |
    `boolean` | `getNeedChat()` | Do we need a between-player chat element in the GUI? (In 2PG only, based on para.chat of the first para set of this player.
    `int` | `getPairState()` | For a player in a two-player game, this is his current status with respect to pairing.
    `ParaSet` | `getPara​(EpisodeInfo epi)` | Gives a link to the ParaSet associated with a given episode
    `String` | `getPartnerPlayerId()` | The playerId value of the partner, if this is a two-player game, and this player has already been paired with a partner.
    `PlayerInfo` | `getPlayerForRole​(int mover)` | The PlayerInfo of the player with the specified role.
    `String` | `getPlayerId()` | A human-readable string ID for this player.
    `int` | `getRoleForPlayerIdPermissive​(String pid)` | This method recognizes that an older 1PG client may not pass a playerId; thus, it interprets null as Player 0 (the default player)
    `PlayerInfo.Series` | `getSeries​(int k)` |
    `int` | `getSuperseriesSize​(int k)` | How many episodes are in the current super-series?
    `int` | `getTotalRewardEarned()` | The total reward shown to this player.
    `String` | `getTrialListId()` | For traditional (static) and "P:"-type dynamic experiment plans, this is the name of the actual trial list file in the appropriate experiment plan directory (without the ".csv" extension).
    `User` | `getUser()` |
    `void` | `giveUp​(int seriesNo)` | "Gives up" the current series, i.e.
    `double` | `goodnessScore()` | Compute the "goodness score" of this player, intended to measure how good this player has been, to be used during the postgame experience to decide if the demographics page should contain an invitation to participate in additional research (only offered to good players).
    `boolean` | `hasBotAssist()` |
    `void` | `initPairing()` | Sets certain pairing-related fields in the object for a newly created player.
    `void` | `initSeries​(TrialList trialList)` | This is usesd when a player is first registered and a PlayerInfo object is first created.
    `boolean` | `is2PG()` |
    `boolean` | `isAdveGame()` |
    `boolean` | `isBotGame()` |
    `boolean` | `isCoopGame()` |
    `void` | `linkToPartner​(PlayerInfo _partner, int myRole)` | Sets links in both directions, and saves both objects
    `EpisodeInfo` | `mostRecentEpisode()` | Retrieves the most recent episode, which may be completed or incomplete.
    `void` | `postLoad()` | Sets some (transient) properties of this object which depend on the name of the experiment plan.
    `void` | `postLoadPart1()` | Sets some (transient) properties of this object which depend on the name of the experiment plan.
    `void` | `removeEpisode​(EpisodeInfo c)` |
    `String` | `report()` | Generates a concise report on this player's history, handy for debugging.
    `void` | `restoreTransientFields()` | This method should be called after restoring the object from the SQL database, in order to re-create some of the necessary non-persistent structures.
    `void` | `saveMe()` | Saves this object (and the associated Episode objects, via cascading) data in the SQL database.
    `int` | `seriesAttemptCnt()` | The total number of attempts in all episodes of this series.
    `int` | `seriesSize​(int k)` | How many episodes are currently in series No.
    `void` | `setAllEpisodes​(Vector<EpisodeInfo> _allEpisodes)` |
    `void` | `setAmBot​(boolean _amBot)` |
    `void` | `setCompletionCode​(String _completionCode)` |
    `void` | `setCompletionMode​(int _completionMode)` |
    `void` | `setDate​(Date _date)` | Sets the creation date (and the last activity date).
    `void` | `setExperimentPlan​(String _experimentPlan)` |
    `void` | `setLastActivityTime​(Date _lastActivityTime)` |
    `void` | `setPairState​(int _pairState)` |
    `void` | `setPartnerPlayerId​(String _partnerPlayerId)` |
    `void` | `setPlayerId​(String _playerId)` |
    `void` | `setTotalRewardEarned​(int _totalRewardEarned)` |
    `void` | `setTrialListId​(String _trialListId)` |
    `void` | `setUser​(User _user)` |
    `String` | `toString()` |
    `PlayerInfo` | `xgetPartner()` |

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- - ### Field Detail

    - #### pseudoHalftime

          public double pseudoHalftime

      This is used in pseudo-AI bots, to indicate how fast it pretends to learn

  - ### Constructor Detail

    - #### PlayerInfo

          public PlayerInfo()

  - ### Method Detail

    - #### getId

          public long getId()

    - #### getUser

          public User getUser()

    - #### setUser

          public void setUser​(User _user)

    - #### getPlayerId

          public String getPlayerId()

      A human-readable string ID for this player. A mandatory non-null value, which we strive to keep unique (by the PlayerResponse code).

    - #### setPlayerId

          public void setPlayerId​(String _playerId)

    - #### getExperimentPlan

          public String getExperimentPlan()

      The experiment plan historically was just a directory name, e.g. "pilot06". Starting from ver. 3.004, dynamic experiment plans are also supported, in the form P:plan:modifer or R:ruleSet:modifier.

    - #### setExperimentPlan

          public void setExperimentPlan​(String _experimentPlan)

    - #### postLoadPart1

          public void postLoadPart1()

      Sets some (transient) properties of this object which depend on the name of the experiment plan. For new objects, this method is called (via postLoad()) from PlayerResponse, after an object has been created and some basic initialization (setExperimentPlan(), initSeries()) took place. For those restored from the database, it is called automatically due to the @PostLoad directive.

      This method looks for "coop." or "adve." prefix in the experiment plan directory name (for a static or dynamic plan) to decide if this is a 2PG of some kind.

    - #### postLoad

          public void postLoad()

      Sets some (transient) properties of this object which depend on the name of the experiment plan. For new objects, this method is called from PlayerResponse, after an object has been created and some basic initialization (setExperimentPlan(), initSeries()) took place. For those restored from the database, it is called via restoreTransientFields().

      Note: this method can only be called after initSeries(), because otherwise getFirstPara() won't work.

      FIXME: What if an object restored from the database, e.g. in a MW tools context, needs the needChat flag?

    - #### isCoopGame

          public boolean isCoopGame()

      Returns:
        true if the name of the experiment plan indicates that this is a cooperative two-player game

    - #### isAdveGame

          public boolean isAdveGame()

      Returns:
        true if the name of the experiment plan indicates that this is an adversarial two-player game

    - #### is2PG

          public boolean is2PG()

      Returns:
        true if the name of the experiment plan indicates that this is a two-player game (cooperative or adversary)

    - #### isBotGame

          public boolean isBotGame()

    - #### hasBotAssist

          public boolean hasBotAssist()

    - #### getAmBot

          public boolean getAmBot()

    - #### setAmBot

          public void setAmBot​(boolean _amBot)

    - #### getNeedChat

          public boolean getNeedChat()

      Do we need a between-player chat element in the GUI? (In 2PG only, based on para.chat of the first para set of this player.

    - #### getTrialListId

          public String getTrialListId()

      For traditional (static) and "P:"-type dynamic experiment plans, this is the name of the actual trial list file in the appropriate experiment plan directory (without the ".csv" extension). For "R:"-type dynamic experiment plans (which do not involve any trial list files) this field, rather tautologically, contains the rule set name.

    - #### setTrialListId

          public void setTrialListId​(String _trialListId)

    - #### getDate

          public Date getDate()

    - #### setDate

          public void setDate​(Date _date)

      Sets the creation date (and the last activity date). This is used on initialization

    - #### getLastActivityTime

          public Date getLastActivityTime()

    - #### setLastActivityTime

          public void setLastActivityTime​(Date _lastActivityTime)

    - #### getPartnerPlayerId

          public String getPartnerPlayerId()

      The playerId value of the partner, if this is a two-player game, and this player has already been paired with a partner. Null otherwise.

    - #### setPartnerPlayerId

          public void setPartnerPlayerId​(String _partnerPlayerId)

    - #### getPlayerForRole

          public PlayerInfo getPlayerForRole​(int mover)

      The PlayerInfo of the player with the specified role. This should only be called on a paired player in 2PG.
      Parameters:
        `mover` - Whose PlayerInfo do you want?

    - #### getRoleForPlayerIdPermissive

          public int getRoleForPlayerIdPermissive​(String pid)

      This method recognizes that an older 1PG client may not pass a playerId; thus, it interprets null as Player 0 (the default player)

    - #### xgetPartner

          public PlayerInfo xgetPartner()

    - #### linkToPartner

          public void linkToPartner​(PlayerInfo _partner,
                                    int myRole)

      Sets links in both directions, and saves both objects

    - #### getPairState

          public int getPairState()

      For a player in a two-player game, this is his current status with respect to pairing. The value is from Pairing.Mode.

    - #### setPairState

          public void setPairState​(int _pairState)

    - #### initPairing

          public void initPairing()

      Sets certain pairing-related fields in the object for a newly created player. The settings are to the initial "not paired yet" state.

    - #### addEpisode

          public void addEpisode​(EpisodeInfo c)

    - #### removeEpisode

          public void removeEpisode​(EpisodeInfo c)

    - #### getAllEpisodes

          public Vector<EpisodeInfo> getAllEpisodes()

    - #### setAllEpisodes

          public void setAllEpisodes​(Vector<EpisodeInfo> _allEpisodes)

    - #### toString

          public String toString()

      Overrides:
        `toString` in class `Object`

    - #### getSeries

          public PlayerInfo.Series getSeries​(int k)

    - #### alreadyFinished

          public boolean alreadyFinished()

      Returns true if the current series number is set beyond the possible range, which indicates that it has gone through the last possible increment (and, therefore, the completion code has been set as well). Since ver 8.012, also returns true if the game has been abandoned.

    - #### getSuperseriesSize

          public int getSuperseriesSize​(int k)

      How many episodes are in the current super-series?
      Parameters:
        `k` - (internal) series number. It is assumed that this is the last (internal) series in its super-series.

    - #### seriesAttemptCnt

          public int seriesAttemptCnt()

      The total number of attempts in all episodes of this series. This is used in pseudo-learning.

    - #### canActivateBonus

          public boolean canActivateBonus()

      Returns:
        true if an "Activate Bonus" button can be displayed, i.e. the player is eligible to start bonus episodes, but has not done that yet

    - #### activateBonus

          public void activateBonus​(javax.persistence.EntityManager em)

      Switches this player from the main subseries to the bonus subseries, and saves the information about this fact in the SQL server.
      Parameters:
        `em` - The active EM to use. (We have this because this method is called from a method that has an EM anyway, and this object is NOT detached.)

    - #### giveUp

          public void giveUp​(int seriesNo)
                      throws IOException

      "Gives up" the current series, i.e. immediately switches the player to the next series (if there is one).
      Throws:
        `IOException`

    - #### abandon

          public void abandon()
                       throws IOException

      This may be invoked by a maintenance thread in 2PG, when it detects that this player has been inactive for a while. (The method should be usable in 1PG too, but it's not a major concern).

      If this is 2PG (i.e. players are listening to web sockets), we send a Ready.DIS message to both players, so that their clients will update their screens

      Note that, inside this method, we "abandon" the episode before marking the player as "abandoner", because otherwise getCurrenSeries() won't retrieve the episode.

      Throws:
        `IOException`

    - #### seriesSize

          public int seriesSize​(int k)

      How many episodes are currently in series No. k?

    - #### countBonusEpisodes

          public int countBonusEpisodes​(int k)

      How many bonus episodes (complete or not) are currently in series No. k?

    - #### getCurrentSeriesNo

          public int getCurrentSeriesNo()

    - #### initSeries

          public void initSeries​(TrialList trialList)
                          throws IOException,
                                 IllegalInputException,
                                 ReflectiveOperationException,
                                 RuleParseException

      This is usesd when a player is first registered and a PlayerInfo object is first created.
      Throws:
        `IOException`
        `IllegalInputException`
        `ReflectiveOperationException`
        `RuleParseException`

    - #### restoreTransientFields

          public void restoreTransientFields()
                                      throws IOException,
                                             IllegalInputException,
                                             ReflectiveOperationException,
                                             RuleParseException

      This method should be called after restoring the object from the SQL database, in order to re-create some of the necessary non-persistent structures. Typically, this may be needed if player resumes his activity after the Game Server has been restarted. In particular, we restore the "series" structure, reloading paramter sets from the disk files and and putting episodes in their series arrays.

      We also review the episodes, and "give up" all incomplete ones, because they don't have their transcripts and rules loaded, and cannot be continued. This may happen only rarely, when an episode had been persisted before beeing completed (thru cascading from the player being persisted), and then the server was restarted.

      Throws:
        `IOException`
        `IllegalInputException`
        `ReflectiveOperationException`
        `RuleParseException`

    - #### mostRecentEpisode

          public EpisodeInfo mostRecentEpisode()

      Retrieves the most recent episode, which may be completed or incomplete.

    - #### episodeToDo

          public EpisodeInfo episodeToDo()
                                  throws IOException,
                                         RuleParseException

      Returns the currently unfinished last episode to be resumed, or a new episode (in the current series or the next series, as the case may be), or null if this player has finished with all series. This is used by the /GameService2/newEpisode web API call.
      Throws:
        `IOException`
        `RuleParseException`

    - #### getPara

          public ParaSet getPara​(EpisodeInfo epi)

      Gives a link to the ParaSet associated with a given episode

    - #### getFirstPara

          public ParaSet getFirstPara()

      Gives a link to the first ParaSet. This is used for things that are determined by the first ParaSet, e.g. the pregame experience.
      Returns:
        the ParaSet for the first series, or null if none exists.

    - #### getCompletionCode

          public String getCompletionCode()

      The completion code, a string that the player can report as a proof of his completion of the experiment plan. It is set when the current series number is incremented beyond the last parameter set number.

    - #### setCompletionCode

          public void setCompletionCode​(String _completionCode)

    - #### getCompletionMode

          public int getCompletionMode()

    - #### setCompletionMode

          public void setCompletionMode​(int _completionMode)

    - #### gameAbandoned

          public boolean gameAbandoned()

    - #### getTotalRewardEarned

          public int getTotalRewardEarned()

      The total reward shown to this player. In 2PG, each PlayerInfo has a value stored; the two partners' value are the same in a coop game, but different in an adversarial game

    - #### setTotalRewardEarned

          public void setTotalRewardEarned​(int _totalRewardEarned)

    - #### report

          public String report()

      Generates a concise report on this player's history, handy for debugging. It gives summaries of all episodes done (or in progress) by this player, broken down by series.

    - #### saveMe

          public void saveMe()

      Saves this object (and the associated Episode objects, via cascading) data in the SQL database. The assumption is that this object is detached, so we call a method which will create a new EM and merge this object to the new persistence context.

    - #### goodnessScore

          public double goodnessScore()

      Compute the "goodness score" of this player, intended to measure how good this player has been, to be used during the postgame experience to decide if the demographics page should contain an invitation to participate in additional research (only offered to good players). At present (ver 6.029), this score is only computed in a non-trivial way in games with the incentive plan Incentive.DOUBLING.

      In 2PG, the record is stored in Player 0' PlayerInfo object, so we refer to it. In oop games, goodness is "joint" for the pair of players, since that's how xfactor etc are computed and stored.

      Returns:
        For players in games with the incentive plan Incentive.DOUBLING (or LIKELIHOOD), the value of the score, in the range [0..1], is simply the fraction of all rule sets so far that the player has fully mastered (received X4), plus 1/2 of those that were partially mastered (received X2). For players in other incentive plans, 0 is returned.