au.com.solidsoftware.multimahjong.mmc.co
Class ComputerOpponent

java.lang.Object
  |
  +--au.com.solidsoftware.multimahjong.mmc.game.Player
        |
        +--au.com.solidsoftware.multimahjong.mmc.co.ComputerOpponent

public final class ComputerOpponent
extends Player

SRS : CO level 2.0 + 1 Level 3 requirement (4.5.10)

This class is the brain of Computer Opponent (CO). That is to determine what kind of move Computer Opponent should make. If CO makes a move, what tile(s) associated with that move.

All the moves that CO can make are encapsulated into 3 public methods:

Author:
Long Tang 38467 (lqkt@ecr.mu.oz.au)

Field Summary
private  java.util.Vector allCombSet
          contains ALL possible combinations in CO' concealedhand
private  java.util.Vector allGroupSet
          A group is a set of combinations that are mutual exclusive (can't be kept in concaled hand at the same time).
private  AITile[] concealedHand
          concealedHand of CO.
private  java.util.Vector conSinSet
          From attribute allGroupSet above, pick discard tile that generate less number of singles
private static int FALSE
           
private  java.util.Vector halfSinSet
          contains all half (i.e.
private static int MAXORDINARYSUITS
          Number of ordinary suits
private static int MAXTILENUMBER
          Biggest number that an ordinary tile can have
private static int MAXTILES
          Maximum number of tiles in Chinese Mahjong
private  int playerId
          each player has an unique Id which can be 0, 1, 2, 3
private  java.lang.String playerName
          name of player
private  boolean selected
          any tile has been selected for a move
private static int TRUE
           
private  java.util.Vector unSinSet
          contains all unconditional (i.e.
 
Fields inherited from class au.com.solidsoftware.multimahjong.mmc.game.Player
CHOW2DOWN, CHOW2SIDES, CHOW2UP, DECLARED_KONG, DISCARD, EAST, EITHER_MOVE, EXTEND_PUNG, icon, isFishing, KONG, MAHJONG, name, NO_MOVE, NORTH, NOT_ROBBED, payout, PICKUP, playArea, playerHand, playerId, PUNG, ROBBED_KONG, score, selectedTile, SOUTH, standingHand, userGUI, WEST, wind, WONT_ROB
 
Constructor Summary
ComputerOpponent(java.lang.String name, javax.swing.ImageIcon icon, int score, int playerId)
          inits its base class Human.
 
Method Summary
private  void allPossibleCombsForCombSet()
          Uses result in the FIRST PASS.
private  boolean areTheyMu(AITile[] comb1, AITile[] comb2)
          Checks for mutual exclusive combinations.
private  java.util.Vector depthFirstFilter(AITile[] headNode, java.util.Vector curGroupClone)
          Picks the most optimal arrangement for mutual exclusive combinations.
 int determineCanRob(Tile selectedTile)
          Tries to find if player can rob the kong.
private  boolean finalChecking(Tile tile, Tile[] humanConcealedHand)
          Checks whether a tile exists in concealed hand or not.
private  AITile[] fromHumantoAIConcealedHand(Tile[] humanConcealedHand)
          Converts human style concealedHand to CO style concealedHand.
private  void getAllCombSet()
          Detects all possible combinations in concaledHand.
private  void getAllGroupSet()
          Bases on pre-genrated allCombSet to detect group of exclusive combinations.
private  java.util.Vector getAllMuCombFor(AITile[] comb, java.util.Vector allCombSetClone)
          Gets all mutual exclusive combinations of a given combination.
private  void getCombFor(int curPos)
          Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not.
private  void getConSinSet()
          Extracts an optimum tile for discard from allGroupSet.
private  java.util.Vector getConSinTilesFromGroup(java.util.Vector curGroup)
          Genrates all possible arrangements of mutual combinations in a group.
 int getDiscard(boolean playerFishing, Moves currentMove)
          Analyses computer opponent' concealed hand and selects the most optimal tile for discard.
private  void getHalfSinSet()
          Detects all half (50%) single tiles in concealed hand.
private  void getMinConSinsForConSinSet()
          Bases on result of FIRST PASS of conSinSet, keep optial conditional singles and remove non-optimal singles from conSinSet.
 int getPlayerSelection(Tile lastDiscard, int next)
          Tries to steal other player' tile.
private  void getUnSinSet()
          Detects all unconditional (100%) single tiles in concealed hand .
private  void insertStack(java.util.Vector stack, AITile[] node)
          Adds new element to the head of stack.
private  void insertStackPath(java.util.Vector stackPath, java.util.Vector path)
          Adds new element to the head of stack.
private  int isContainedIn(AITile tile, AITile[] comb)
          Checks whether a tile is contained in a combination or not.
private  AITile[] isDuplicated(AITile examedTile, java.util.Vector allCombSetClone)
          Compares a given tile with tiles in all combinations in allCombSetClone.
private  boolean isHalfSingle(AITile tile)
          Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not.
private  boolean isNodeInPath(AITile[] node, java.util.Vector path)
          Checks whether a node (combination) is covered by a path (arrangement)
private  boolean isSingle(AITile tile)
          Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not.
private  int tilesNotCoveredByPath(java.util.Vector path, java.util.Vector conSins, java.util.Vector curGroupClone)
          Checks whether any tile in a group not covered by the given path (given arrangement).
private  AITile[] vectorToArray(java.util.Vector combList)
          Convert Vector list of combinations to array list of combinations.
 
Methods inherited from class au.com.solidsoftware.multimahjong.mmc.game.Player
checkFishing, checkKong, checkMahjong, checkPung2Kong, declareKong, discard, findKong, findPung2Kong, getIcon, getId, getName, getScore, getWind, initPlayer, insertTile, insertTile, isStandingHand, mahjong, notStandingHand, robbedKong, runChow, runKong, runMahjong, runPung, runPung2Kong, setIcon, setMove, setName, setPlayArea, setPlayArea, setScore, setSelection, setWind
 
Methods inherited from class java.lang.Object
, clone, equals, finalize, getClass, hashCode, notify, notifyAll, registerNatives, toString, wait, wait, wait
 

Field Detail

FALSE

private static final int FALSE

TRUE

private static final int TRUE

MAXTILES

private static final int MAXTILES
Maximum number of tiles in Chinese Mahjong

MAXORDINARYSUITS

private static final int MAXORDINARYSUITS
Number of ordinary suits

MAXTILENUMBER

private static final int MAXTILENUMBER
Biggest number that an ordinary tile can have

unSinSet

private java.util.Vector unSinSet
contains all unconditional (i.e. 100%) single tiles

halfSinSet

private java.util.Vector halfSinSet
contains all half (i.e. 50%) single tiles. Half single is only applied for CHOW combination. E.g. having 2 and 4 but miss 3 => 2 and 4 are half singles

allCombSet

private java.util.Vector allCombSet
contains ALL possible combinations in CO' concealedhand

allGroupSet

private java.util.Vector allGroupSet
A group is a set of combinations that are mutual exclusive (can't be kept in concaled hand at the same time). E.g. 2 2 3 4 => can either keep 2-2 or 2-3-4. This attribute is the refinement of attribute allCombSet above.

conSinSet

private java.util.Vector conSinSet
From attribute allGroupSet above, pick discard tile that generate less number of singles

concealedHand

private AITile[] concealedHand
concealedHand of CO. Tiles in this concealedHand have Id

playerId

private int playerId
each player has an unique Id which can be 0, 1, 2, 3

playerName

private java.lang.String playerName
name of player

selected

private boolean selected
any tile has been selected for a move
Constructor Detail

ComputerOpponent

public ComputerOpponent(java.lang.String name,
                        javax.swing.ImageIcon icon,
                        int score,
                        int playerId)
inits its base class Human. CO only needs to keep playerId and playerName for itself.
Method Detail

fromHumantoAIConcealedHand

private AITile[] fromHumantoAIConcealedHand(Tile[] humanConcealedHand)
Converts human style concealedHand to CO style concealedHand. Because original concealedHand passed to CO was designed for human player, it does not contain tileId. Unique Id is added to every tiles in concealedHand. Without tileId, CO will not be able to recognise tile of the same kind.
Parameters:
humanConcealedHand - Concealed hand withoud Id
Returns:
concaledhand with tileId

getDiscard

public int getDiscard(boolean playerFishing,
                      Moves currentMove)
Analyses computer opponent' concealed hand and selects the most optimal tile for discard.
Parameters:
playerFishing - True if a player is fishing, otherwise false.
currentMove - Storage for players selected move.
Returns:
int Selected move made.
  • 0- if selected tile was for a discard.
  • 1- Reveal kong or extend pung when no player is fishing.
  • 2- Reveal kong when a player is fishing.
  • 3- Extend pung when a player is fishing.
    Overrides:
    getDiscard in class Player

  • finalChecking

    private boolean finalChecking(Tile tile,
                                  Tile[] humanConcealedHand)
    Checks whether a tile exists in concealed hand or not. This method is to double check the tile before discard. Discarding non-existing tile may crash the software.
    Parameters:
    tile - Selected tile for discard
    humanConcealedHand - Concealed hand without Id
    Returns:
    false, if the selected tile does not exist on concealed hand. true, otherwise.

    determineCanRob

    public int determineCanRob(Tile selectedTile)
    Tries to find if player can rob the kong.
    Parameters:
    selectedTile - Tile chosen to be revealed as a kong.
    Returns:
    int selected action of player.
    Overrides:
    determineCanRob in class Player

    getPlayerSelection

    public int getPlayerSelection(Tile lastDiscard,
                                  int next)
    Tries to steal other player' tile. It only steals if it is allowed under Chinee rule.
    Parameters:
    lastDiscard - The most recent discarded tile from other player
    next - Flag that indicates whether this player can draw tile from Wall (i.e. only true when it is CO' turn).
    Returns:
    int move selection ranks from
  • 7- MAHJONG move (HIGHEST PRIORITY)
  • 6- KONG move
  • 5- PUNG move
  • 4- CHOW2UP move
  • 3- CHOW2DOWN move
  • 2- CHOW2SIDES move
  • 1- PICKUP tile from Wall (CO' turn)
  • 0- NO_MOVE (not CO' turn)
    Overrides:
    getPlayerSelection in class Player

  • getUnSinSet

    private void getUnSinSet()
    Detects all unconditional (100%) single tiles in concealed hand . The result is put in class attribute unSinSet. This method goes thorugh each tile in the concealedHand and check whether that tile is TRUE single and FALSE half single. This method needs access to concealed hand.
    Parameters:
    none -  
    Returns:
    none

    isSingle

    private boolean isSingle(AITile tile)
    Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not. This method needs information from CO' concealedHand.
    Parameters:
    tile - Examed tile that has a unique Id
    Returns:
    if tile is single, returns true. Retunrs false otherwise . This single can sometimes be also classified as half single.

    getHalfSinSet

    private void getHalfSinSet()
    Detects all half (50%) single tiles in concealed hand. The result is put in class attribute halfSinSet. This method goes thorugh each tile in the concealedHand and check whether that tile is TRUE single and TRUE half single. This method needs access to concealedHand.
    Parameters:
    none -  
    Returns:
    none

    isHalfSingle

    private boolean isHalfSingle(AITile tile)
    Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not. This method needs information from CO' concealedHand.
    Parameters:
    tile - Examed tile that has a unique Id
    Returns:
    if tile is halft single, returns true. Retunrs false otherwise.

    getAllCombSet

    private void getAllCombSet()
    Detects all possible combinations in concaledHand. It needs two passes before completes. In first pass, detects combinations that are unique. In second pass, detects duplicated combinations that were missed in the first pass. E.g. concaled Hand contains 2a 2b 3 4 (a and b are the Id) => first pass : 2a-2b, 2a-3-4 => second pass: 2b-3-4 (this is he duplicated comb) The result is stored in class attribute allCombSet.
    Parameters:
    none -  
    Returns:
    none

    getCombFor

    private void getCombFor(int curPos)
    Compares a tile with the remaining tiles in concaledHand and see whether that tile can combine with any tile or not. If tile can combine, the whole combination will be inserted in attribute allCombSet. This method can only detect unique combinations. These detected unique combinations are stored in class attribute allCombSet. This is the FIRST PASS to get allCombSet.
    Parameters:
    curPos - Position of the tile that is to get combinations for.
    Returns:
    none

    allPossibleCombsForCombSet

    private void allPossibleCombsForCombSet()
    Uses result in the FIRST PASS. Tries to substitute tile in combination with other tile of the smame kind but different Id. E.g. we have 2a-3-4, in second pass, 2a is replaced with 2b and a duplicated combination 2b-3-4 is created. Why Do We Need Duplicated Combinations ? Unlike human, CO see duplicated combinations as distint combinations. Without duplicated combinations CO may miss out some possible tile arrangements later on in method getConSinSet. Missing some arrangements => miscalculate number of single tiles generated while keeping some mutual exclusive combinations => optimal tile for discard may not be truely optimal. The result is stored in class attribute allCombSet. This is the SECOND PASS (last one) to get allCombSet
    Parameters:
    none -  
    Returns:
    none

    isContainedIn

    private int isContainedIn(AITile tile,
                              AITile[] comb)
    Checks whether a tile is contained in a combination or not.
    Parameters:
    tile - Tile to be checked
    comb - Combination that is used for checking
    Returns:
    If comb does contain this tile, returns the postion of that tile in comb. Otherwise, returns FALSE (i.e. -1)

    getAllGroupSet

    private void getAllGroupSet()
    Bases on pre-genrated allCombSet to detect group of exclusive combinations. Group is a set of mutual exclusive combinations. The result is stored in class attribute allGroupSet.
    Parameters:
    none -  
    Returns:
    none

    getAllMuCombFor

    private java.util.Vector getAllMuCombFor(AITile[] comb,
                                             java.util.Vector allCombSetClone)
    Gets all mutual exclusive combinations of a given combination. First tiles in given comb are inserted to a list. Tiles in that list is compared with other combinations to see whether these tiles are duplicated in other combinations or not. If any of these tiles do appeare elsewhere other than given comb, combination thet has duplicated tile is inserted to group or muCombList (list of mutual exclusive combinations).
    Parameters:
    comb - Combination that is to get all of its mutual exclsuive combination.
    allCombsetClone - Clone of class attribute allCombSet
    Returns:
    a group (a set of mutual exclusive combinations)

    isDuplicated

    private AITile[] isDuplicated(AITile examedTile,
                                  java.util.Vector allCombSetClone)
    Compares a given tile with tiles in all combinations in allCombSetClone. If any tile in these combs has the same tileId as given tile => given tile is duplicated in that comb. This method inexplicitly removes combination that contains examined tile.
    Parameters:
    examedTile - Tile to exam
    allCombsetClone - Clone of class attribute allCombSet
    Returns:
    a combination that contains examined tile

    areTheyMu

    private boolean areTheyMu(AITile[] comb1,
                              AITile[] comb2)
    Checks for mutual exclusive combinations. Mutual exclusive combinations are those which contain at least a tile with the same tileId.
    Parameters:
    comb1 - Combination 1
    comb2 - Combination 2
    Returns:
    returns true if these 2 combination are mutual exclusive. Returns false if they are not.

    getConSinSet

    private void getConSinSet()
    Extracts an optimum tile for discard from allGroupSet. "Optimum" because throw away this tile generate the less number of single tiles than throwing other conditional tiles. conSinSet needs TWO PASSES before getting any optimal discard tile. FIRST PASS: conditional singles in each group in allGroupSet are put in conSinSet SECOND PASS: compare these conditional singles to see which one generates the least number of single tiles. This method needs pre-computed allGroupet. The result is stored in conSinSet.
    Parameters:
    none -  
    Returns:
    none

    getMinConSinsForConSinSet

    private void getMinConSinsForConSinSet()
    Bases on result of FIRST PASS of conSinSet, keep optial conditional singles and remove non-optimal singles from conSinSet. That is to count number of singles genrated by each condional single. This method needs pre-computed allGroupet and result of FIRST PASS of conSinSet. Class attribute conSinSet is updated with only optimal discard tiles => Non optimal conditional singles generated in FIRST PASS are removed from conSinSet. This is the SECOND PASS (last pass) to get conditional single tiles.
    Parameters:
    none -  
    Returns:
    none

    getConSinTilesFromGroup

    private java.util.Vector getConSinTilesFromGroup(java.util.Vector curGroup)
    Genrates all possible arrangements of mutual combinations in a group. Group is defined a set of mutual exclusive tiles. This method uses deep first search to genrate all possible arrangements of mutual combinations in a group. Compeare each different arrangement to see which arrangement generates the least number of singles. This method needs access to pre-computed allGroupet. This is the FIRST PASS to get conditional single tiles.
    Parameters:
    curGroup - Current group to be examed
    Returns:
    conditional singles of a group

    depthFirstFilter

    private java.util.Vector depthFirstFilter(AITile[] headNode,
                                              java.util.Vector curGroupClone)
    Picks the most optimal arrangement for mutual exclusive combinations. This is the most important method because intelligence of CO depends on this method. Depth first genrates all possible paths (arrangements) from a given headNode to different deadEnd.
    Parameters:
    headNode - HeadNode of tree. This tree contains all possible arrangements while keeping the headNode.
    curGroupClone - Clone of pre-computed allGroupet
    Returns:
    the least number of conditional singles when try to keep the headNode

    tilesNotCoveredByPath

    private int tilesNotCoveredByPath(java.util.Vector path,
                                      java.util.Vector conSins,
                                      java.util.Vector curGroupClone)
    Checks whether any tile in a group not covered by the given path (given arrangement). The uncovered tiles are single tiles genrated when choosing to this arrangement.
    Parameters:
    path - Is a arrangement of non-mutual exlcusive combinations
    conSins - Conditional singles
    curGroupClone - Clone of pre-computed allGroupet
    Returns:
    how many tiles in a group not convered by this path way. Those missed tiles are conditional single tiles if we choose to keep this path way (arrangement).

    vectorToArray

    private AITile[] vectorToArray(java.util.Vector combList)
    Convert Vector list of combinations to array list of combinations.
    Parameters:
    combList - A vector of combinations
    Returns:
    combList An array of combinations

    isNodeInPath

    private boolean isNodeInPath(AITile[] node,
                                 java.util.Vector path)
    Checks whether a node (combination) is covered by a path (arrangement)
    Parameters:
    node - Is a combination of tiles
    path - Is a arrangement of non-mutual exlcusive combinations
    Returns:
    whether this node is contained in this path (arrangement)

    insertStack

    private void insertStack(java.util.Vector stack,
                             AITile[] node)
    Adds new element to the head of stack. This does not change (delete) existing elements in stack. We need this because Vector.addElement only adds new node to the end of Vector.
    Parameters:
    stack - Contains nodes that are not yet process by deep first
    node - Is a combination of tiles
    Returns:
    none

    insertStackPath

    private void insertStackPath(java.util.Vector stackPath,
                                 java.util.Vector path)
    Adds new element to the head of stack. This does not change (delete) existing elements in stackPath. We need this because Vector.addElement only adds new node to the end of Vector.
    Parameters:
    stackPath - Contains paths that should not be re-processed by deep first search.
    path - Is a arrangement of non-mutual exlcusive combinations
    Returns:
    none