#!/usr/bin/env python3

import os.path

lcg_seed = 301703
def lcg_rand( a, b ):
    global lcg_seed
    lcg_seed = lcg_seed * 239017 + 666
    lcg_seed &= 0xffffffffffffffff
    lcg_middle = (lcg_seed >> 16) & 0xffffffff
    return a + lcg_middle % (b - a + 1)

def output_test( test, f ):
    h = len(test)
    w = len(test[0])
    print("%d %d" % (h, w), file=f)
    for l in test:
        assert len(l) == w
        print(l, file=f)

manual = [
    # sample
    [".........",
     "..######X",
     "..#......",
     ".E..####.",
     "..##...#.",
     ".....#..."],
    # minimal tests
    ["EX"], ["XE"], ["E", "X"], ["X", "E"],
    # short lines
    ["E.X"], ["E#X"], ["X.E"], ["X#E"],
    ["E", ".", "X"], ["E", "#", "X"], ["X", ".", "E"], ["X", "#", "E"]
]

def empty( size ):
    assert size >= 2
    return ["E" + "." * (size - 1)] + ["." * size] * (size - 2) + ["." * (size - 1) + "X"];
 
def snake( h, w ):
    base = [['#' for x in range(w)] for x in range(h)]
    for i in range(w):
      if i % 2 == 0:
        for j in range(h):
          base[j][i] = '.'
      elif i % 4 == 1:
        base[h - 1][i] = '.'
      else:
        base[0][i] = '.'
    base[0][0] = 'E'
    if h % 4 < 2:
      base[h - 1][w - 1] = 'X'
    else:
      base[h - 1][0] = 'X'
    return [''.join(line) for line in base]

def random( h, w, k = 3):
    base = [['.' for x in range(w)] for x in range(h)]
    for i in range(h * w // k):
        y = lcg_rand(0, h - 1)
        x = lcg_rand(0, w - 1)
        base[y][x] = '#'
    y = lcg_rand(0, h - 1)
    x = lcg_rand(0, w - 1)
    base[y][x] = 'E'
    while base[y][x] == 'E':
        y = lcg_rand(0, h - 1)
        x = lcg_rand(0, w - 1)
    base[y][x] = 'X'
    return [''.join(line) for line in base]

def make_junction( a, hs, hz, ws, wz ):
    if hz - hs < 5 or wz - ws < 5:
        return
    hp = (hz - hs - 3) // 2
    wp = (wz - ws - 3) // 2
    make_junction(a, hs, hs + hp, ws, ws + wp)
    make_junction(a, hs, hs + hp, ws + 3 + wp, wz)
    make_junction(a, hs + 3 + wp, hz, ws, ws + wp)
    make_junction(a, hs + 3 + wp, hz, ws + 3 + wp, wz)
    for i in range(hs, hz):
        a[i][ws + wp] = '#'
        a[i][ws + wp + 2] = '#'
    for i in range(ws, wz):
        a[hs + hp][i] = '#'
        a[hs + hp + 2][i] = '#'
    a[hs + hp + 1][ws + wp] = '.'
    a[hs + hp + 1][ws + wp + 2] = '.'
    a[hs + hp][ws + wp + 1] = '.'
    a[hs + hp + 2][ws + wp + 1] = '.'
    a[hs + (hp - 1) // 2][ws + wp] = '.'
    a[hs + (hp - 1) // 2][ws + wp + 2] = '.'
    a[hs + 3 + hp + (hz - hp - 3 - hs - 1) // 2][ws + wp] = '.'
    a[hs + 3 + hp + (hz - hp - 3 - hs - 1) // 2][ws + wp + 2] = '.'
def junction( size ):
    base = [['.' for x in range(size)] for x in range(size)]
    make_junction(base, 0, size, 0, size)
    base[size // 2 - 1][size // 2 - 1] = 'E'
    base[0][0] = 'X'
    return [''.join(line) for line in base]

for index, test in enumerate(
    manual +
    [empty(x) for x in [2, 3, 5, 10, 30, 57, 99, 123, 255, 256, 499, 500]] +
    [snake(*x) for x in [(10, 10), (15, 17), (93, 311), (500, 497), (500, 500)]] +
    [random(*x) for x in [(12, 15), (37, 19), (128, 64), (444, 500), (500, 500)]] +
    [random(*x) for x in [(12, 15, 4), (37, 19, 5), (128, 64, 2), (444, 500, 2), (500, 500, 10)]] +
    [junction(x) for x in [10, 20, 97, 239, 500]] +
    []
, start=1):
    name = os.path.join('..', 'tests', '%02d' % index)
    with open(name, 'w') as f:
        output_test(test, f)

