import os
import random
import sys

MAX_N = 100
MAX_SCORE = 11

CASE = 1
DEST = os.path.join(os.getcwd(), '../data/secret')

def next_file(short_desc=None, long_desc=None):
    global CASE
    basename = os.path.join(DEST, '%02d' % CASE)
    CASE += 1
    if short_desc is not None:
        basename += '-' + short_desc
    if long_desc is not None:
        with open(basename+'.desc', 'w') as desc_out:
            desc_out.write(long_desc)
    return open(basename+'.in', 'w')

def save_case(seq, short_desc=None, long_desc=None, shuffle_adj_list=True):
    n = len(seq)
    sys.stderr.write('save case n %d\n' % (n))
    f = next_file(short_desc, long_desc)
    f.write('%d\n' % (n))
    for (a, b) in seq:
        f.write('%d-%d\n' % (a, b))
    f.close()


def random_garbage(n, max_score=MAX_SCORE):
    seq = [(random.randint(0, max_score), random.randint(0, max_score)) for _ in range(n)]
    save_case(seq)

def random_seq(n, random_scores=True, rubber_banding=False, dontstop=False):
    true_scores = [(0, 0)]
    while (min(true_scores[-1]) if dontstop else max(true_scores[-1])) < 11:
        (a, b) = true_scores[-1]
        if random_scores:
            if random.randint(0, 1): b += 1
            else: a += 1
        elif rubber_banding:
            if a < b or (a==b and random.randint(0, 1)): a += 1
            else: b += 1
        else:
            if (a < 11 and a > b) or (a==b and random.randint(0, 1)): a += 1
            else: b += 1
        if (a+b) % 2: (a, b) = (b, a)
        true_scores.append((a, b))

    idxs = [random.randint(0, len(true_scores)-1) for _ in range(n)]
    idxs.sort()
    seq = [true_scores[i] for i in idxs]
    return seq
    

def gen(n, errors=0, random_scores=True, rubber_banding=False, dontstop=False):
    seq = random_seq(n,
                     random_scores=random_scores,
                     rubber_banding=rubber_banding,
                     dontstop=dontstop)
    for _ in range(errors):
        idx = random.randint(0, n-1)
        (a, b) = seq[idx]
        t = random.random()
        if t < 0.1: # swap scores in line
            (a, b) = (b, a)
        elif idx > 0 and t < 0.2: # swap to adjacent lines
            (a, b) = seq[idx-1]
            seq[idx-1] = seq[idx]
        elif random.random() < 0.5: # add/remove to a
            d = 2*(random.randint(0, 1))-1 if a > 0 else 1
            a += d
            while a+d >= 0 and random.random() < 0.3: 
                a += d
        else: # add/remove to b
            d = 2*(random.randint(0, 1))-1 if b > 0 else 1
            b += d
            while b+d >= 0 and random.random() < 0.3: 
                b += d
        seq[idx] = (a, b)
    save_case(seq)
    

def main():
    random.seed(4711)

    random_garbage(1)
    random_garbage(MAX_N, max_score=11)

    gen(1)
    gen(30)
    gen(30, random_scores=False)
    gen(30, random_scores=False, rubber_banding=True)
    gen(30, errors=1)
    gen(30, errors=1, random_scores=False)
    gen(30, errors=1, random_scores=False, rubber_banding=True)
    
    gen(30)
    gen(30, random_scores=False)
    gen(30, random_scores=False, rubber_banding=True)

    save_case([(11, 0), (11, 1), (2, 11), (3, 11)])
    save_case([(11, 11)])

    gen(MAX_N)
    gen(MAX_N, random_scores=False, rubber_banding=True)
    
    for _ in range(20):
        n = random.randint(5, MAX_N)
        errs = int(random.expovariate(0.5))
        rs = random.randint(0, 1)
        rb = random.randint(0, 1)
        gen(n, errors=errs, random_scores=rs, rubber_banding=rb)
    

if __name__=='__main__':
    main()
