import os
import random
import sys

MAX_N = 100
MAX_M = 100
MAX_S = 100
MAX_D = 100

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(n, m, d, c, short_desc=None, long_desc=None, shuffle_adj_list=True):
    s = len(c)
    assert(1 <= n <= MAX_N)
    assert(1 <= m <= MAX_M)
    assert(1 <= s <= MAX_S)
    assert(1 <= d <= MAX_D)
    assert(0 <= min(c) <= max(c) <= d)
    assert(s*d - sum(c) >= n)
    sys.stderr.write('save case %d %d %d %d\n' % (n, m, s, d))
    f = next_file(short_desc, long_desc)
    f.write('%d %d %d %d\n' % (n, m, s, d))
    f.write('%s\n' % ' '.join(map(str, c)))
    f.close()


def random_bottles(s, d, b):
    c = [0]*s
    for _ in range(b):
        while True:
            i = random.randint(0, s-1)
            if c[i] < d: break
        c[i] += 1
    return c
            

def random_params(): 
    while True:
        n = random.randint(1, MAX_N)
        m = random.randint(1, MAX_M)
        s = random.randint(1, MAX_S)
        d = random.randint(1, MAX_D)
        if s*d >= n: break
    b = random.randint(0, s*d-n)
    return (n, m, s, d, b)

def random_case(n, m, s, d, b):
    c = random_bottles(s, d, b)
    save_case(n, m, d, c)

def find_thresholds(c, d):
    n = 0
    m = sum(c)
    res = []
    for x in sorted(c):
        n += d-x
        m -= x
        if x and d-x and 1 <= m <= 100 and 1 <= n <= 100:
            res.append((n, m))
    return res

def random_at_threshold(min_s=1, poss=True):
    while True:
        s = random.randint(min_s, MAX_S)
        d = random.randint(1, MAX_D)
        b = random.randint(1, s*d)
        c = random_bottles(s, d, b)
        thres = find_thresholds(c, d)
        if not thres: continue
        (n, m) = random.choice(thres)
        assert n <= s*d - sum(c)
        if not poss:
            if m == 100 and n == min(100, s*d-sum(c)): continue
            if m == 100: n += 1
            elif n == min(100, s*d-sum(c)) or random.randint(0, 1): m += 1
            else: n += 1
        assert n <= s*d - sum(c)
        break
    save_case(n, m, d, c)


def main():
    random.seed(13)

    save_case(1, 1, 50, [49], 'singleslot')
    save_case(1, 10, 10, [9, 9], 'twoslots_impossible')
    save_case(1, 10, 10, [10, 9], 'twoslots_possible')

    for _ in range(5):
        random_case(*random_params())

    random_case(MAX_N, MAX_M, MAX_S, MAX_D, MAX_S*MAX_D/2)
    random_case(MAX_N, 1, MAX_S, MAX_D, MAX_S*MAX_D/2)
    random_case(MAX_N, 1, MAX_N/2, 3, MAX_N/4)
    random_case(MAX_N, MAX_N/4, MAX_N/2, 3, MAX_N/4)

    for i in range(1, 9):
        random_at_threshold(min_s=2*i, poss=True)
        random_at_threshold(min_s=2*i, poss=False)

if __name__=='__main__':
    main()
