public static bool HasMatch(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
    {
        bool hasMatch = false;

        foreach(var pieceObject in puzzleData.pieceObjectList)
        {
            PuzzlePiece nowPiece = pieceObject.GetComponent<PuzzlePiece>();

            if(nowPiece.used)
            {
                int nowColumNo 			= PuzzleCalculator.GetPieceColumnNo(puzzleParam,(nowPiece.ID));
                int nowRowNo 			= PuzzleCalculator.GetPieceRowNo(puzzleParam,nowPiece.ID);
                int rowLimitBorder		= PuzzleCalculator.GetRowLimitBorder(puzzleParam);
                int columnLimitBorder	= PuzzleCalculator.GetColumnLimitBorder(puzzleParam);
                int numChaine 			= 1;

                // Check Column
                if(nowColumNo < columnLimitBorder)
                {
                    // Search to the last column
                    for(int i = 1;
                        nowRowNo == PuzzleCalculator.GetPieceRowNo(puzzleParam,(i + nowPiece.ID));
                        i++,numChaine++)
                    {
                        int targetIndex = i + nowPiece.ID;
                        if(HasNoChaine(puzzleData,nowPiece.ID,targetIndex))
                            break;
                    }
                    if(numChaine >= puzzleParam.stdNumChaines)
                    {
                        Matched(nowPiece.ID,numChaine,ref puzzleData,(nextIndex) => nextIndex + nowPiece.ID);
                        hasMatch = true;
                    }
                }

                // Check Row
                numChaine = 1;
                if(nowRowNo < rowLimitBorder)
                {
                    // Search to the last line
                    int targetIndex;
                    for(int i = puzzleParam.maxColumns;
                        nowColumNo == PuzzleCalculator.GetPieceColumnNo(puzzleParam,(i + nowPiece.ID));
                        i += puzzleParam.maxColumns,numChaine++)
                    {
                        targetIndex = i + nowPiece.ID;
                        if(HasNoChaine(puzzleData,nowPiece.ID,targetIndex))
                            break;
                    }

                    if(numChaine >= puzzleParam.stdNumChaines)
                    {
                        Matched(nowPiece.ID,numChaine,ref  puzzleData,(nextIndex) => nextIndex * puzzleParam.maxColumns + nowPiece.ID);
                        hasMatch = true;
                    }
                }
            }
        }
        return hasMatch;
    }
    public static void ChangeID(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam,int targetID)
    {
        PuzzlePiece selectedPuzzle = puzzleData.pieceObjectList[puzzleData.selectedPieceNo].GetComponent<PuzzlePiece>();
        PuzzlePiece nowPiece;
        int targetObjectIdx 	= puzzleData.FindPieceObjectIndex(targetID);
        int tempID 				= selectedPuzzle.ID;

        // debug
        if(PuzzleStateChecker.HasIndexOutOfRange(puzzleData,targetObjectIdx))
            return;

        // The amount of movement becomes a constant value,Change ID
        Vector3 amount = puzzleData.pieceObjectList[targetObjectIdx].transform.position - selectedPuzzle.transform.position;
        if( amount.x < puzzleParam.puzzleSpace && amount.x > -puzzleParam.puzzleSpace &&
           	amount.z < puzzleParam.puzzleSpace && amount.z > -puzzleParam.puzzleSpace )
        {
            nowPiece 		= puzzleData.pieceObjectList[targetObjectIdx].GetComponent<PuzzlePiece>();
            nowPiece.ID	 	= tempID;
            selectedPuzzle.ID 	= targetID;

            selectedPuzzle.MoveAmountClear(PuzzleCalculator.GetPiecePosition(puzzleParam,targetID));
            nowPiece.Move(PuzzleCalculator.GetPiecePosition(puzzleParam,tempID),puzzleParam.moveTime);
        }

        // Register puzzles traced
        puzzleData.selectedPieceNameList.Add(puzzleData.pieceObjectList[targetObjectIdx].name);
    }
    public static void CreateAtEmpty(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam,Material[] puzzleColorList)
    {
        // Rearranged in ascending order of ID puzzles
        puzzleData.Sort();
        // Create
        puzzleData.pieceObjectList.ForEach((GameObject pieceObject) =>
        {
            PuzzlePiece targetPiece = pieceObject.GetComponent<PuzzlePiece>();
            // Create a new puzzle piece ID that is not used
            if(targetPiece.used == false)
            {
                // Resume Puzzle Piece
                targetPiece.Resume();

                // Set Puzzle position
                Vector3 endPos 		= PuzzleCalculator.GetPiecePosition(puzzleParam,targetPiece.ID);
                Vector3 startPos	= endPos;
                endPos.z			= -50;
                targetPiece.Move(startPos,endPos,puzzleParam.moveTime);

                // Set the color to random.
                int typeNo = Random.Range(0,puzzleColorList.Length);
                targetPiece.SetColor(typeNo,puzzleColorList[typeNo]);
            }
        } );
    }
    public static void Operate(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
    {
        PuzzlePiece selectedPiece 	= puzzleData.pieceObjectList[puzzleData.selectedPieceNo].GetComponent<PuzzlePiece>();
        Vector3 moveAmount 			= selectedPiece.moveAmount;
        float amountRange 			= PuzzleCalculator.GetAmountRangeCrissCross(puzzleParam);
        float amountRangeDiagonal 	= PuzzleCalculator.GetAmountRangeDiagonal(puzzleParam);

        // The amount of movement becomes a constant value,Move it

        // Move diagonal
        if(moveAmount.x >= amountRangeDiagonal && moveAmount.z >= amountRangeDiagonal)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID + 1 + puzzleParam.maxColumns);
        else if(moveAmount.x >= amountRangeDiagonal && moveAmount.z <= -amountRangeDiagonal)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID + 1 - puzzleParam.maxColumns);
        else if(moveAmount.x <= -amountRangeDiagonal && moveAmount.z >= amountRangeDiagonal)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID - 1 + puzzleParam.maxColumns);
        else if(moveAmount.x <= -amountRangeDiagonal && moveAmount.z <= -amountRangeDiagonal)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID - 1 - puzzleParam.maxColumns);
        // Move right.
        else if(moveAmount.x >= amountRange)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID + 1);
        // Move left.
        else if(moveAmount.x <= -amountRange)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID - 1);
        // Move up.
        else if(moveAmount.z >= amountRange)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID + puzzleParam.maxColumns);
        // Move down.
        else if(moveAmount.z <= -amountRange)
            ChangeID(ref puzzleData,puzzleParam,selectedPiece.ID - puzzleParam.maxColumns);
    }
 public static Vector3 GetPiecePosition(PuzzleOperaterParam puzzleParam,int targetId)
 {
     Vector3 puzzlePos;
     puzzlePos.x = ((targetId % puzzleParam.maxColumns) - (puzzleParam.maxRows / 2) - 1) * puzzleParam.puzzleSpace;
     puzzlePos.y = 0;
     puzzlePos.z = ((targetId / puzzleParam.maxColumns) - (puzzleParam.maxRows / 2)) * puzzleParam.puzzleSpace;
     return puzzlePos;
 }
 public static bool IsSelectedPiece(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
 {
     bool existsSelectedPiece = false;
     foreach(var peiceObject in puzzleData.pieceObjectList.Select((piece, index) => new {piece,index}))
     {
         if(peiceObject.piece.GetComponent<PuzzlePiece>().selected)
         {
             puzzleData.selectedPieceNo = peiceObject.index;
             existsSelectedPiece = true;
             break;
         }
     }
     return existsSelectedPiece;
 }
    public static void CreatePuzzlePieceObject(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam,
	                       GameObject puzzlePiecePrefab,Material[] puzzleColorList)
    {
        for(int i = 0;i < puzzleParam.maxPuzzles;i++)
        {
            // Create new piece.
            puzzleData.pieceObjectList.Add(Object.Instantiate(puzzlePiecePrefab,
                                                              PuzzleCalculator.GetPiecePosition(puzzleParam,i),
                                                              Quaternion.identity) as GameObject);
            puzzleData.pieceObjectList[i].name = "Puzzle" + i.ToString();

            // Set Parameters
            PuzzlePiece newPiece = puzzleData.pieceObjectList[i].GetComponent<PuzzlePiece>();
            newPiece.ID = i;
            newPiece.Resume();

            // Set the color to random.
            int colorIdx = Random.Range(0,puzzleColorList.Length);
            newPiece.SetColor(colorIdx,puzzleColorList[colorIdx]);
        }
    }
    public static bool IsCompletedDestroy(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
    {
        bool isCompleted = false;

        if(TimeCounter.IsTimeOver(ref puzzleData.destroyTimeCounter,puzzleParam.destroyTime))
        {
            int nowChaineID = puzzleData.numChaine;
            puzzleData.pieceObjectList.ForEach((GameObject pieceObject) =>
            {
                PuzzlePiece nowPiece = pieceObject.GetComponent<PuzzlePiece>();
                if(nowPiece.chaineID == nowChaineID)
                    nowPiece.Stop();
            });

            TimeCounter.StartTimer(ref puzzleData.destroyTimeCounter);
            puzzleData.numChaine--;
            if(puzzleData.numChaine < 0)
                isCompleted = true;
        }
        return isCompleted;
    }
    public static void SortByRefEmpty(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
    {
        // Rearranged in ascending order of ID puzzles
        puzzleData.Sort();

        for(int puzzleNo = puzzleData.pieceObjectList.Count - 1; puzzleNo >= 0;puzzleNo--)
        {
            Vector3 puzzlePos = Vector3.zero;
            PuzzlePiece nowPiece = puzzleData.pieceObjectList[puzzleNo].GetComponent<PuzzlePiece>();

            // It moves one on the target is empty
            int targetRowNo = PuzzleCalculator.GetPieceRowNo(puzzleParam,nowPiece.ID);
            if(targetRowNo < puzzleParam.maxRows - 1)
            {
                // Check until it can move
                for(int id = nowPiece.ID + puzzleParam.maxColumns;id < puzzleParam.maxPuzzles;id += puzzleParam.maxColumns)
                {
                    GameObject emptyTemp = puzzleData.pieceObjectList[puzzleData.FindPieceObjectIndex(id)];
                    PuzzlePiece emptyPuzzle = emptyTemp.GetComponent<PuzzlePiece>();
                    if(emptyPuzzle.used == false)
                    {
                        emptyPuzzle.ID 	= nowPiece.ID;
                        nowPiece.ID = id;
                        emptyPuzzle.Stop();
                        emptyTemp.transform.position = PuzzleCalculator.GetPiecePosition(puzzleParam,emptyPuzzle.ID);
                    }
                }
            }

            nowPiece.MoveAmountClear();

            // Move puzzle piece
            Vector3 nowPos 		= puzzleData.pieceObjectList[puzzleNo].transform.position;
            Vector3 targetPos 	= PuzzleCalculator.GetPiecePosition(puzzleParam,nowPiece.ID);
            if(Vector3.Distance(nowPos,targetPos) > PuzzleCalculator.GetPieceSpaceOffset(puzzleParam))
                nowPiece.Move(targetPos,puzzleParam.moveTime);
        }
    }
 public static bool IsFinishedSelectTime(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
 {
     bool isFinished = false;
     return isFinished;
 }
    public static void SortByRefID(ref PuzzleData puzzleData,PuzzleOperaterParam puzzleParam)
    {
        // Rearranged in ascending order of ID puzzles
        puzzleData.Sort();

        puzzleData.pieceObjectList.ForEach((GameObject pieceObject) =>
        {
            PuzzlePiece targetPiece = pieceObject.GetComponent<PuzzlePiece>();
            Vector3 targetPos = PuzzleCalculator.GetPiecePosition(puzzleParam,targetPiece.ID);
            targetPiece.Move(targetPos,puzzleParam.moveTime);

        });
    }
 public static float GetAmountRangeCrissCross(PuzzleOperaterParam puzzleParam)
 {
     return (puzzleParam.puzzleSpace / 1.2f);
 }
 public static int GetRowLimitBorder(PuzzleOperaterParam puzzleParam)
 {
     return (puzzleParam.maxRows - (puzzleParam.stdNumChaines - 1));
 }
 public static float GetPieceSpaceOffset(PuzzleOperaterParam puzzleParam)
 {
     return (puzzleParam.puzzleSpace / 10.0f);
 }
 public static int GetPieceRowNo(PuzzleOperaterParam puzzleParam,int targetId)
 {
     return (targetId / puzzleParam.maxColumns);
 }
 public static float GetAmountRangeDiagonal(PuzzleOperaterParam puzzleParam)
 {
     return (puzzleParam.puzzleSpace / 2.0f);
 }