#!/usr/bin/env python3

import sys
import random
import math

SPECIALS = [ 'middle', 'middle_fuzzy', 'sides', 'sides_fuzzy', 'even', 'mul3', 
    'mul3_byclass', 'sqrt', 'sqrt_byclass', 'sqrt_fuzzy', 'mul10_fuzzy', 'merge_segments', 'merge_segments2',
    'bimodal', 'bimodal2', 'midbimodal', 'midbimodal2' ]
SPECIALS += [ f'ambiguous{x}{y}{z}' for x in range(2) for y in range(2) for z in range(2) ]

def cmdlinearg(name, default=None):
    for arg in sys.argv:
        if arg.startswith(name + "="):
            return arg.split("=")[1]
    assert default is not None, name
    return default

def logrand(lo, hi):
    while True:
        b = random.randint(1, 30)
        x = random.randint(2**(b-1), (2**b)-1)
        if lo <= x <= hi: return x

def distort_local_swaps(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    sc = logrand(1, n)
    for _ in range(sc):
        i = random.randint(0, n-2)
        arr[i], arr[i+1] = arr[i+1], arr[i]
    assert len(arr) == len(orig_arr)
    return arr

def distort_arbitrary_swaps(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    sc = logrand(1, n//2)
    for _ in range(sc):
        while True:
            i = random.randint(0, n-1)
            j = random.randint(0, n-1)
            if i != j: break
        arr[i], arr[j] = arr[j], arr[i]
    assert len(arr) == len(orig_arr)
    return arr

def distort_reverse(orig_arr): 
    return list(reversed(orig_arr))

def distort_arbitrary_moves(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    sc = logrand(1, min(n, 100))
    for _ in range(sc):
        while True:
            i = random.randint(0, n-1)
            j = random.randint(0, n-1)
            if i != j: break
        elem, arr = arr[i], arr[:i]+arr[i+1:]
        arr = arr[:j] + [elem] + arr[j:]
    assert len(arr) == len(orig_arr)
    return arr

def distort_rotate(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    rc = random.randint(1, n-1)
    arr = arr[rc:] + arr[:rc]
    assert len(arr) == len(orig_arr)
    return arr

def distort_reverse_segment(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    sl = logrand(1, n-1)
    i = random.randint(0, n-sl)
    arr = arr[:i] + list(reversed(arr[i:i+sl])) + arr[i+sl:]
    assert len(arr) == len(orig_arr)
    return arr

def distort_move_segment(orig_arr):
    arr = orig_arr[:]
    n = len(arr)
    if n < 2: return arr
    sl = logrand(1, n-1)
    i = random.randint(0, n-sl)
    seg, rest = arr[i:i+sl], arr[:i] + arr[i+sl:]
    j = random.randint(0, n-sl)
    arr = rest[:j] + seg + rest[j:]
    assert len(arr) == len(orig_arr)
    return arr

DISTORTS = [ distort_local_swaps, distort_arbitrary_swaps, distort_reverse, distort_arbitrary_moves,
    distort_rotate, distort_reverse_segment, distort_move_segment ]

def make_friends(arr, friendify):
    i, j = arr.index(0), arr.index(1)
    if i > j: i, j = j, i
    if friendify == 1:
        if random.randint(0, 1):
            return arr[:i] + [arr[i]] + [arr[j]] + arr[i+1:j] + arr[j+1:]
        else:
            return arr[:i] + arr[i+1:j] + [arr[i]] + [arr[j]] + arr[j+1:]
    if friendify == 2:
        without = arr[:i] + arr[i+1:j] + arr[j+1:]
        pair = [0,1] if random.randint(0,1) else [1,0]
        where = random.randint(0,2)
        if where == 0: return pair + without
        if where == 1: return without + pair
        return without[ : len(without)//2 ] + pair + without[ len(without)//2 : ]
    assert False

def gen(t, minn, maxn, mode, offset, two, friendify):
    if friendify:
        assert two == 1
        assert mode != "specials"
        assert mode != "fixed"

    print(f'gen t={t} minn={minn} maxn={maxn} mode={mode} two={two} friendify={friendify}', file=sys.stderr)
    if mode == "specials":
        tcs = []
        for tc in range(t):
            n = random.randint(minn, maxn)
            tcs.append( (n,0,[SPECIALS[(offset+tc)%len(SPECIALS)]]) )
        return tcs

    if mode == "random":
        assert t >= 1 and 5 <= minn <= maxn
        tcs = []
        for tc in range(t):
            n = random.randint(minn, maxn)
            arr = list(range(n))
            random.shuffle(arr)
            if friendify: arr = make_friends(arr, friendify)
            tcs.append((n,two,arr))
        return tcs

    if mode[:9] == "distorted":
        assert t >= 1 and 5 <= minn <= maxn
        try:
            discnt = int(mode[9:])
        except:
            discnt = 1
        tcs = []
        for tc in range(t):
            n = random.randint(minn, maxn)
            arr = list(range(n))
            for d in range(discnt):
                distort = random.choice(DISTORTS)
                arr = distort(arr)
            if friendify: arr = make_friends(arr, friendify)
            tcs.append((n,two,arr))
        return tcs

    if mode == "fixed":
        arrs = cmdlinearg("arrs").split(";")
        tcs = []
        for arr in arrs:
            arr = [ int(_) for _ in arr.split(",") ]
            tcs.append( (len(arr), two, arr) )
        return tcs
    
    raise Exception(f"bad mode: {mode}")

def main():
    try:
        seed = int(sys.argv[-1])
        random.seed(seed)
        offset = seed
    except:
        random.seed(47)
        offset = 0

    t = int(cmdlinearg("t", -1))
    subtask = int(cmdlinearg("subtask", -1))
    assert subtask != -1
    minn = int(cmdlinearg("minn", -1))
    maxn = int(cmdlinearg("maxn", -1))
    two = int(cmdlinearg("two", 1))
    friendify = int(cmdlinearg("friendify", 0))
    mode = cmdlinearg("mode", "random")
    
    tcs = gen(t, minn, maxn, mode, offset, two, friendify)

    print(-47)
    print(subtask)
    print(len(tcs))
    for n, det, arr in tcs:
        print(n, det)
        print(*arr)

main()
