aboutsummaryrefslogtreecommitdiff
path: root/challenge-101/tyler-wardhaugh/python/ch-1.py
blob: 963f7ef3190cb5f6b950d59a3e2c53061e8f100b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env python3
"""Challenge 101, Task 1"""

import sys


DEFAULT_INPUT = [1, 2, 3, 4]


def print_matrix(mat, colsep=' '):
    """Pretty print a matrix (list of lists)"""
    strs = [[str(x) for x in row] for row in mat]
    lens = [max(len(x) for x in col) for col in zip(*strs)]
    fmt = colsep.join(f'{{:{x}}}' for x in lens)
    tbl = (fmt.format(*row) for row in strs)

    for row in tbl:
        print(row)


def get_min_size(coll_len):
    """Determine the minimum shape necessary for a matrix to hold len items."""
    f = lambda x: abs(x - coll_len // x)
    candidates = {x: f(x) for x in range(1, 1+coll_len) if coll_len % x == 0}

    rows = min(candidates, key=candidates.get)
    cols = coll_len // rows
    return rows, cols


def rotate_matrix(mat):
    """Rotate the matrix counterclockwise"""
    rotated_mat = [list(x) for x in zip(*mat)]
    rotated_mat.reverse()
    return rotated_mat



def _pack(coll, m, n):
    """Recursively pack an incoming coll into an m x n spiral matrix. This is a
    helper function for pack_spiral, not meant to be called directly."""
    if m == 1:
        yield [coll]
    elif n == 1:
        yield from ([x] for x in reversed(coll))
    else:
        result = rotate_matrix(list(_pack(coll[n:], n, m-1))) + [coll[:n]]
        yield from result


def pack_spiral(coll):
    """Return coll as a packed spiral matrix."""
    m, n = get_min_size(len(coll))
    spiral = list(_pack(coll, m, n))
    return spiral


def main(args=None):
    """Run the task"""
    if args is None:
        args = sys.argv[1:]

    coll = None
    if args:
        import json
        coll = json.loads(args[0])
    else:
        coll = DEFAULT_INPUT

    print_matrix(pack_spiral(coll))


if __name__ == '__main__':
    sys.exit(main())