Esempio n. 1
0
def simulate(problem: Problem, submit: Submit):
    '''
    simulates given solution of the problem, animation works only when run from command line
    :param problem:
    :param solution:
    :return: dictionary with simulation information
    '''

    board = problem.getBoardCopy()
    flowersLeft = problem.getFlowerCount()

    simInfo = SimulationInfo()

    # current recursion depth
    recDepth = 0

    # ordering of functions - number which will be associated  with the next function run
    # F1 must alway be F1, so we start from 2
    order = 2

    col = problem.robotCol
    row = problem.robotRow
    rot = problem.robotDir
    simInfo.visited.append((row, col))  # visited fields

    moves = list(reversed(
        submit.functions[0].moves))  # stack of steps to simulate
    stack = [[1, 0]]  # stack of functions and positions of simulated steps
    # while there are flowers and steps to make, make a step, maximum is 1000 steps, plus max 5000 steps to go (to avoid recursion without any moving)
    while (moves != [] and flowersLeft > 0 and len(simInfo.visited) < 1000
           and len(moves) < 5000):
        move = moves[-1]
        moves.pop()

        # find the function and position of simulated step
        actf, actp = stack[-1]

        # if recursion is ending, pop from stack
        if move.action in "vt":
            stack.pop()
        # otherwise move to next position in the same function
        else:
            stack[-1][1] += 1

        # if the color of current field is the same as the condition or there is no condition
        if move.condition == board[row][col] or move.condition == "_":
            if move.action != "v" and move.action != "t":
                # if it is the actual command (not the info about recursion ending) set the command to executed
                # command is not considered executed if it is recoloring to the same color
                if move.action != board[row][col]:
                    simInfo.movesExecuted.add(move)
            if move.action.isdigit():
                # if the command is F1 - F5
                if moves != [] and moves[-1].action != "v" and moves[
                        -1].action != "t":
                    # if its not the tail recursion
                    recDepth += 1  # increase recursion depth
                    # update maximum recursion depth
                    simInfo.maxRecDepth = max(recDepth, simInfo.maxRecDepth)
                    moves.append(Move("_v"))
                else:
                    moves.append(
                        Move('_t')
                    )  # otherwise it is tail rec - append info about tail rec ending

                moves += list(
                    reversed(submit.functions[int(move.action) - 1].moves)
                )  # add commands from called function on steps stack
                stack.append(
                    [int(move.action), 0]
                )  # add first position of function on the top of positions stack
                simInfo.functionsExecuted[
                    int(move.action) -
                    1] = True  # function was executed right now

                # if function was not executed before, set its execution order
                if simInfo.functionsOrdering[int(move.action) - 1] == 9:
                    simInfo.functionsOrdering[int(move.action) - 1] = order
                    order += 1
            else:
                # command is NOT a function call
                if move.action == "v":
                    # recursion ended - decrease depth
                    recDepth -= 1
                if move.action == "L":
                    # rotate left and increase LR steps
                    rot = (rot - 1) % 4
                    simInfo.LRsteps += 1
                    simInfo.visited.append((row, col))
                if move.action == "R":
                    # rotate right and increase LR steps
                    rot = (rot + 1) % 4
                    simInfo.LRsteps += 1
                    simInfo.visited.append((row, col))
                if move.action == "F":
                    # move in the direction given by rotation
                    col += [1, 0, -1, 0][rot]
                    row += [0, 1, 0, -1][rot]

                    if row < 0 or row >= len(board):
                        break
                    if col < 0 or col >= len(board[row]):
                        break
                    if board[row][col] == " ":
                        break

                    simInfo.Fsteps += 1
                    simInfo.visited.append((row, col))

                if move.action in "rgb":
                    # recolor if necessary
                    if board[row][col] != move.action:
                        board[row] = board[row][0:col] + move.action + board[
                            row][col + 1:]
                        simInfo.recoloredCount += 1
                if board[row][col].istitle():
                    # if there was a flower, it is now taken
                    board[row] = board[row][0:col] + board[row][col].lower(
                    ) + board[row][col + 1:]
                    flowersLeft -= 1
        else:
            # command was not executed because the condition was False
            # therefore this condition was useful
            simInfo.conditionWasFalse.add(move)

    simInfo.stackLeft = recDepth  # save recursion depth at the end of simulation
    simInfo.flowersLeft = flowersLeft
    return simInfo