#======================================================================
# CSCI 1020, Lab 06
#
# Your name(s):
#
#======================================================================

#
# You must implement the following functions in order for the entire
# program to work properly.  By default, when executing this program
# it will run a random experiment with 25 characters, using an initial
# shuffle with 15 reversals (though it might be that fewer that 15 reversals
# will be needed to fix the sequence).
#
# For a test that triggers use of find_increasing_strip, try running function
# experiment(25,15,8)
#
# For a more general test with sequence of length n, and using r initial reversals, call
# experiment(n, r)


def perform_reversal(data, a, b):
    """Return a new sequence that reflects inverting the portion of data from
    indices a to b, inclusive.
    """


def count_breakpoints(data):
    """Return the current number of breakpoints for the given sequence."""


def count_breakpoints_fixed(data, a, b):
    """Return the net number of breakpoints that are resolved if performing a reversal [a,b].
    For example, returning +1 means that one existing breakpoint would disappear with a reversal."""


def find_increasing_strip(data):
    """Return [a,b] defining the second increasing strip (presuming there are two or more such strips)."""



#======================================================================
# Do not change below this line
#======================================================================
import sys
import random

def find_best_reversal(data):
    """Return [a,b] that represents a reversal that would resolve the greatest number of breakpoints."""
    best = 0
    bestA,bestB = -1, -1
    for a in range(1,len(data)-2):
        for b in range(1+a,len(data)-1):
            temp = count_breakpoints_fixed(data,a,b)
            if temp > best:
                best = temp
                bestA = a
                bestB = b
    return bestA,bestB
    
def solve(data):
    """Convert original data back to the identity, and return the number of reversal steps that were used."""
    reversals = 0
    bp = count_breakpoints(data)
    while bp != 0:
        a,b = find_best_reversal(data)
        if a == -1:
            best = 0
        else:
            best = count_breakpoints_fixed(data,a,b)
        if best <= 0:     # did not find way to reduce breakpoints
            a,b = find_increasing_strip(data)   # reverse an increasing strip instead

        print('Able to remove %d breakpoint%s' % (best, '' if best==1 else 's'))
        data = verbose_reversal(data, a, b)
        bp -= best
        actual = count_breakpoints(data)
        if actual != bp:
            print("WARNING: error detected")
        reversals += 1
    return reversals

def display(seq, a=None, b=None):
    """Display given sequence with indices, highlight range [a,b] if specified."""
    n = len(seq)
    if a is None: a = 0
    if b is None: b = a-1
    print('      k: ' + ' '.join('%2d'%val for val in range(n)))
    print('         ' + '---'*a + '='*(3*(1+b-a)-1) + '---'*(n-b-1))
    print('data[k]: ' + ' '.join('%2d'%val for val in seq))
    bp = count_breakpoints(seq)
    print('There are %s breakpoints in this pattern' % ('?' if bp is None else str(bp)))
    print('')

def verbose_reversal(seq, a, b):
    """Perform the reversal, and annotate the result."""
    seq = perform_reversal(seq, a, b)
    print('performing inversion for a=%d, b=%d results in' % (a,b))
    display(seq,a,b)
    return seq

def make_random(n, k, seed=None):
    """Make a random instance with numbers 0 to n-1, such that 0 remains at the left
    and n-1 remains at the far right. n should be at least 4.

    Seed for random number generator is optional.
    """
    random.seed(seed)
    print('Creating initial random pattern:')
    seq = list(range(n))
    for j in range(k):
        # do a single reversal
        a = random.randint(1,n-3)
        b = random.randint(a+1,n-2)
        seq = verbose_reversal(seq, a, b)
    return seq

def experiment(n,r,seed):
    """Perform an experiment for sequence of length n using r initial reversals."""
    data = make_random(n,r,seed)
    print('')
    print('='*30)
    print('Time to solve...')
    count = solve(data)
    print('Used %d reversals' % count)

if __name__ == '__main__':
    seed = None
    if len(sys.argv) > 1:
        seed = int(sys.argv[1])
    experiment(25,15,seed)


