Пример #1
0
    bool SolveCompleteDescriptionLines(bool firstCall, int num, List <Line[, ]> linesOnFaces, List <Line> completeLines, MyPuzzle myPuzzle, LineHeap Q)
    {
        // num개의 complete-description 라인을 푼다
        for (int i = 0; i < Mathf.Min(num, completeLines.Count); ++i)
        {
            // solved 아닌 라인을 찾는다
            Line lineToSolve = FindUnSolvedCompleteLine(completeLines, myPuzzle);
            if (lineToSolve == null)
            {
                return(firstCall);  // unsolved인 complete-description이 하나도 없음. first call이 아니라면 false 반환
            }

            // line solver로 라인을 푼다
            List <CELLSTATE> beforeLineSolver = GetBeforeLine(lineToSolve.line, myPuzzle);
            List <CELLSTATE> afterLineSolver  = lineSolver.lineSolver(lineToSolve.clue, lineToSolve.line, myPuzzle);
            lineToSolve.mark   = true;
            lineToSolve.solved = true;

            // line solver 적용 전, 후의 라인을 비교한다
            int lineLen             = afterLineSolver.Count;
            List <puzzleIndex> line = lineToSolve.line;

            for (int j = 0; j < lineLen; ++j)
            {
                if (beforeLineSolver[j] != afterLineSolver[j])
                {
                    // cell state 영구적으로 변경하기
                    myPuzzle.puzzleState[line[j].z, line[j].y, line[j].x] = afterLineSolver[j];


                    if (afterLineSolver[j] == CELLSTATE.EMPTY)
                    {
#if SolveTheActualPuzzle
                        puzzleCube[line[j].z, line[j].y, line[j].x].PlayDestoryEffect();
#endif
                        myPuzzle.myBreaks++;
                    }
                    else if (afterLineSolver[j] == CELLSTATE.SOLID)
                    {
#if SolveTheActualPuzzle
                        puzzleCube[line[j].z, line[j].y, line[j].x].isProtected = true;
                        puzzleCube[line[j].z, line[j].y, line[j].x].SetColor(Color.cyan, (int)Cube.MATERIAL_INDEX.BACKGROUND);
                        puzzleCube[line[j].z, line[j].y, line[j].x].PlayProtectAnimation();
#endif
                    }

                    // 수직 라인의 우선순위 높이기
                    Line[] perpendicularLines = GetPerpendicularLines(linesOnFaces, lineToSolve.faceType, line[j]);
                    if (afterLineSolver[j] == CELLSTATE.SOLID)
                    {
                        perpendicularLines[0].priority += 2;
                        perpendicularLines[1].priority += 2;
                    }
                    else if (afterLineSolver[j] == CELLSTATE.EMPTY)
                    {
                        perpendicularLines[0].priority += 1;
                        perpendicularLines[1].priority += 1;
                    }

                    // 수직 라인들 힙에 넣기
                    for (int index = 0; index < 2; ++index)
                    {
                        if (!perpendicularLines[index].insideHeap)
                        {
                            Q.Insert(perpendicularLines[index]);
                        }
                    }
                }
            }
        }

        return(true);
    }
Пример #2
0
    bool SolvePuzzle(Puzzle puzzle, List <Line[, ]> linesOnFaces, List <Line> completeLines)
    {
        MyPuzzle myPuzzle = new MyPuzzle(puzzle);

        LineHeap Q = new LineHeap(puzzle.zLen * puzzle.yLen * puzzle.xLen); // line solver가 사용 할 우선순위 큐

        // 처음 몇 개의 complete-description 라인을 마크하고 풀고, 상태가 바뀐 cell의 수직 라인들 우선순위 올리고 힙에 넣기
        SolveCompleteDescriptionLines(true, 3, linesOnFaces, completeLines, myPuzzle, Q);

        // complete-description 라인들만 빼고 모두 힙에 넣는다
        foreach (var face in linesOnFaces)
        {
            foreach (Line line in face)
            {
                if (!line.isCompleteDescription && !line.insideHeap)
                {
                    Q.Insert(line);
                }
            }
        }

        // 휴리스틱 알고리즘으로 풀기...
        while (myPuzzle.myBreaks != puzzle.breakCount)
        {
            Line lineToSolve = Q.Pop();

            if (lineToSolve == null)
            {
                // 풀다가 안 풀리면 complete-description 라인 하나씩 추가 해 주면서 진행
                if (SolveCompleteDescriptionLines(false, 1, linesOnFaces, completeLines, myPuzzle, Q))
                {
                    continue;
                }
                else
                {
                    Debug.Log("퍼즐 풀이 실패!");
                    return(false);  // 퍼즐 풀이 실패!
                }
            }

            if (isLinePassivelySolved(lineToSolve, myPuzzle))
            {
                lineToSolve.solved = true;  // 이미 풀려있는 라인임
                continue;
            }

            // line solver로 라인을 푼다
            List <CELLSTATE> beforeLineSolver = GetBeforeLine(lineToSolve.line, myPuzzle);
            List <CELLSTATE> afterLineSolver  = lineSolver.lineSolver(lineToSolve.clue, lineToSolve.line, myPuzzle);

            // line solver 적용 전, 후의 라인을 비교한다
            int lineLen             = afterLineSolver.Count;
            List <puzzleIndex> line = lineToSolve.line;

            for (int j = 0; j < lineLen; ++j)
            {
                if (beforeLineSolver[j] != afterLineSolver[j])
                {
                    lineToSolve.mark = true;    // deduction을 하나라도 만들었으므로 라인을 mark한다

                    // cell state 영구적으로 변경하기
                    myPuzzle.puzzleState[line[j].z, line[j].y, line[j].x] = afterLineSolver[j];


                    if (afterLineSolver[j] == CELLSTATE.EMPTY)
                    {
#if SolveTheActualPuzzle
                        puzzleCube[line[j].z, line[j].y, line[j].x].PlayDestoryEffect();
#endif
                        myPuzzle.myBreaks++;
                    }
                    else if (afterLineSolver[j] == CELLSTATE.SOLID)
                    {
#if SolveTheActualPuzzle
                        puzzleCube[line[j].z, line[j].y, line[j].x].isProtected = true;
                        puzzleCube[line[j].z, line[j].y, line[j].x].SetColor(Color.cyan, (int)Cube.MATERIAL_INDEX.BACKGROUND);
                        puzzleCube[line[j].z, line[j].y, line[j].x].PlayProtectAnimation();
#endif
                    }

                    // 수직 라인과 현재 라인의 우선순위 수정
                    Line[] perpendicularLines = GetPerpendicularLines(linesOnFaces, lineToSolve.faceType, line[j]);
                    if (afterLineSolver[j] == CELLSTATE.SOLID)
                    {
                        lineToSolve.priority           -= 2;
                        perpendicularLines[0].priority += 2;
                        perpendicularLines[1].priority += 2;
                    }
                    else if (afterLineSolver[j] == CELLSTATE.EMPTY)
                    {
                        lineToSolve.priority           -= 1;
                        perpendicularLines[0].priority += 1;
                        perpendicularLines[1].priority += 1;
                    }

                    // 수직 라인들 힙에 넣기
                    for (int index = 0; index < 2; ++index)
                    {
                        if (!perpendicularLines[index].insideHeap)
                        {
                            Q.Insert(perpendicularLines[index]);
                        }
                        else
                        {
                            // 이미 힙에 있다면 float up 해 주기
                            Q.Floatup(perpendicularLines[index].heapIndex);
                        }
                    }
                }
            }

            // line이 풀렸는가?
            if (isLineSolved(lineToSolve, myPuzzle))
            {
                lineToSolve.solved = true;
            }
        }

        // 성공!
        return(true);
    }