public MoveSet getValidMoves(int player) {
        Move empty_move = new Move();
	MoveSet rtn_mset = null;
        int[] dice;
        int dice_left;
        if ((dc1==dc2)&&(use_doubles)) {
            dice_left = 4;
            dice = new int[4];
            dice[0]=dc1;
            dice[1]=dc1;
            dice[2]=dc1;
            dice[3]=dc1;

	    int s_pos = player==1 ? 0 : NUM_POINTS-1;
	    rtn_mset = getValidMovesDoublesRec(empty_move, player, dice_left, dice, s_pos);
	    // Doubles version does not guarrantee maximum number of dice is used.
	    if (rtn_mset != null)
		rtn_mset.maxify();
        } else {
            dice_left = 2;
            dice = new int[2];
	    
	    // Make two calls to getValidMovesRec, one for each ordering of the dice.
	    // Remove duplicate moves later.
	    dice[0]=dc1;
	    dice[1]=dc2;
	    rtn_mset = getValidMovesRec(empty_move, player, dice_left, dice);
	    
	    dice[0]=dc2;
	    dice[1]=dc1;
	    rtn_mset.addSet(getValidMovesRec(empty_move, player, dice_left, dice));

	    if (rtn_mset != null) {
		// Must use as many dice as possible.
		rtn_mset.maxify();
		// If you can only move one die, the larger must be used.
		rtn_mset.bigify(dc1,dc2);
	    }
        }
	// Remove duplicate moves from MoveSet.
	if (rtn_mset != null) {
	    rtn_mset.uniquify();
	    // Moves must be in descending order for player 0, ascending order for player 1.
	    for (Iterator iter = rtn_mset.getIterator(); iter.hasNext(); ) {
		if (player==0)
		    ((Move) iter.next()).sortDescend();
		else
		    ((Move) iter.next()).sortAscend();
	    }
	}
	return rtn_mset;
    }