オフラインリアルタイムどう書くF01の問題を Python で解く

問題と他者の回答はこちら
http://qiita.com/Nabetani/items/8e02ede04315b4eadd6d

「ふたマスの領域」のパターン（内側部分と周囲部分）を単純・地道に探してます。
zipで盤を90度ひねり回転させることで縦にふたマス並んでるパターンを探してます。

```py
#!/usr/bin/env python2
# -*- coding:utf-8 -*-

WHITE, BLACK = '0', '1'
INSIDE_YX = (0, 0), (0, 1)
AROUND_YX = (-1, 0), (-1, 1), (0, -1), (0, 2), (1, 0), (1, 1)

def is_color(cells, y, x, color):
    return not (0 <= y < len(cells) and 0 <= x < len(cells[y])) or cells[y][x] == color

def is_pattern(cells, y, x, inside_color, around_color):
    return (all(is_color(cells, y + dy, x + dx, inside_color) for dy, dx in INSIDE_YX) and
            all(is_color(cells, y + dy, x + dx, around_color) for dy, dx in AROUND_YX))

def count_pattern(cells, inside_color, around_color):
    return sum(is_pattern(cells, y, x, inside_color, around_color) # True is 1, False is 0
               for y in range(len(cells))
               for x in range(len(cells[y]) - len(INSIDE_YX) + 1))

def solve(data):
    horizontal_cells = [format(int(y, 16), '08b') for y in data.split('/')]
    vertical_cells = zip(*horizontal_cells)
    whites = count_pattern(horizontal_cells, WHITE, BLACK)
    blacks = count_pattern(horizontal_cells, BLACK, WHITE)
    whites += count_pattern(vertical_cells, WHITE, BLACK)
    blacks += count_pattern(vertical_cells, BLACK, WHITE)
    return '%d,%d' % (whites, blacks)

def test():
    sample_data = (
        (  0, 'dc/bc/a7/59/03/d5/d4/ea', '2,3' ),
        (  1, 'ff/ff/ff/ff/ff/ff/ff/ff', '0,0' ),
        (  2, '00/00/00/00/00/00/00/00', '0,0' ),
        (  3, 'cc/33/cc/33/cc/33/cc/33', '16,16' ),
        (  4, 'aa/aa/55/55/aa/aa/55/55', '16,16' ),
        (  5, 'ac/a3/5c/53/ca/3a/c5/35', '8,8' ),
        (  6, 'db/00/db/00/db/00/aa/aa', '0,13' ),
        (  7, '24/24/db/24/24/db/24/24', '0,12' ),
        (  8, 'd7/d7/e9/f1/f7/de/60/56', '3,2' ),
        (  9, '17/7d/64/9b/a5/39/53/a6', '2,2' ),
        ( 10, 'bb/8f/18/fb/89/c2/c7/35', '1,2' ),
        ( 11, '6d/63/20/08/54/cd/32/4f', '2,2' ),
        ( 12, 'a9/ca/cd/46/99/e6/f0/30', '2,2' ),
        ( 13, '5b/70/fd/45/e2/a1/ab/9a', '1,2' ),
        ( 14, '24/e4/a8/12/e1/a6/3f/f3', '2,1' ),
        ( 15, '79/32/2e/07/d5/10/e7/9d', '2,2' ),
        ( 16, '60/bc/ab/ec/1f/eb/63/2c', '4,2' ),
        ( 17, 'a5/dd/92/4e/67/c6/dc/34', '6,1' ),
        ( 18, 'aa/96/6d/67/d2/a8/ac/90', '3,2' ),
        ( 19, '95/72/7d/5c/47/dc/ef/99', '4,0' ),
        ( 20, '17/d6/6a/27/1f/25/26/b8', '2,1' ),
        ( 21, 'f0/f3/76/c5/31/ca/6b/ae', '1,2' ),
        ( 22, '01/59/26/fa/8c/70/12/cd', '1,4' ),
        ( 23, '1a/c3/1f/0b/83/b6/81/0d', '0,5' ),
        ( 24, '4c/49/05/cf/54/bb/1f/da', '1,2' ),
        ( 25, 'eb/7c/d5/09/2a/c2/14/6b', '0,7' ),
        ( 26, 'b4/d3/4c/c4/ed/19/e8/63', '1,3' ),
        ( 27, 'bd/bc/6d/60/9b/00/9a/32', '2,4' ),
        ( 28, '94/97/3f/e3/c7/06/15/c0', '2,2' ),
        ( 29, '5f/1d/67/16/b8/f7/0a/2a', '2,2' ),
        ( 30, 'df/e6/f9/4f/59/e9/1f/ee', '3,0' ),
        ( 31, '5a/53/9a/9a/73/b4/37/07', '3,2' ),
        ( 32, 'bd/87/7c/e7/c0/37/82/da', '2,3' ),
        ( 33, '3d/c0/13/ac/57/3d/15/78', '2,2' ),
        ( 34, '63/64/54/3a/40/28/4e/4e', '0,3' ),
        ( 35, 'f6/81/c9/15/00/4c/a0/a8', '1,4' ),
        ( 36, '19/41/df/f8/e3/74/6b/9b', '4,2' ),
        ( 37, 'd5/0b/dd/35/3b/d2/0b/6b', '1,5' ),
        ( 38, '08/b7/91/f3/6e/3c/74/a0', '0,0' ),
        ( 39, 'b8/a8/b4/a6/93/2c/94/3f', '0,0' ),
        ( 40, '88/22/21/ee/dc/19/43/01', '0,0' ),
        ( 41, 'e1/ee/35/bc/fc/00/8e/fe', '0,0' ),
        ( 42, '3c/42/63/5f/27/47/07/90', '0,0' ),
        )
    for number, data, correct in sample_data:
        answer = solve(data)
        result = "OK" if answer == correct else "NG"
        print result, '%2d' % number, data, '%-5s' % correct, '->', answer
        if answer != correct:
            print "Wrong!"
            break

if __name__ == '__main__':
    test()
```

```text:実行結果
OK  0 dc/bc/a7/59/03/d5/d4/ea 2,3   -> 2,3
OK  1 ff/ff/ff/ff/ff/ff/ff/ff 0,0   -> 0,0
OK  2 00/00/00/00/00/00/00/00 0,0   -> 0,0
OK  3 cc/33/cc/33/cc/33/cc/33 16,16 -> 16,16
OK  4 aa/aa/55/55/aa/aa/55/55 16,16 -> 16,16
OK  5 ac/a3/5c/53/ca/3a/c5/35 8,8   -> 8,8
OK  6 db/00/db/00/db/00/aa/aa 0,13  -> 0,13
OK  7 24/24/db/24/24/db/24/24 0,12  -> 0,12
OK  8 d7/d7/e9/f1/f7/de/60/56 3,2   -> 3,2
OK  9 17/7d/64/9b/a5/39/53/a6 2,2   -> 2,2
OK 10 bb/8f/18/fb/89/c2/c7/35 1,2   -> 1,2
OK 11 6d/63/20/08/54/cd/32/4f 2,2   -> 2,2
OK 12 a9/ca/cd/46/99/e6/f0/30 2,2   -> 2,2
OK 13 5b/70/fd/45/e2/a1/ab/9a 1,2   -> 1,2
OK 14 24/e4/a8/12/e1/a6/3f/f3 2,1   -> 2,1
OK 15 79/32/2e/07/d5/10/e7/9d 2,2   -> 2,2
OK 16 60/bc/ab/ec/1f/eb/63/2c 4,2   -> 4,2
OK 17 a5/dd/92/4e/67/c6/dc/34 6,1   -> 6,1
OK 18 aa/96/6d/67/d2/a8/ac/90 3,2   -> 3,2
OK 19 95/72/7d/5c/47/dc/ef/99 4,0   -> 4,0
OK 20 17/d6/6a/27/1f/25/26/b8 2,1   -> 2,1
OK 21 f0/f3/76/c5/31/ca/6b/ae 1,2   -> 1,2
OK 22 01/59/26/fa/8c/70/12/cd 1,4   -> 1,4
OK 23 1a/c3/1f/0b/83/b6/81/0d 0,5   -> 0,5
OK 24 4c/49/05/cf/54/bb/1f/da 1,2   -> 1,2
OK 25 eb/7c/d5/09/2a/c2/14/6b 0,7   -> 0,7
OK 26 b4/d3/4c/c4/ed/19/e8/63 1,3   -> 1,3
OK 27 bd/bc/6d/60/9b/00/9a/32 2,4   -> 2,4
OK 28 94/97/3f/e3/c7/06/15/c0 2,2   -> 2,2
OK 29 5f/1d/67/16/b8/f7/0a/2a 2,2   -> 2,2
OK 30 df/e6/f9/4f/59/e9/1f/ee 3,0   -> 3,0
OK 31 5a/53/9a/9a/73/b4/37/07 3,2   -> 3,2
OK 32 bd/87/7c/e7/c0/37/82/da 2,3   -> 2,3
OK 33 3d/c0/13/ac/57/3d/15/78 2,2   -> 2,2
OK 34 63/64/54/3a/40/28/4e/4e 0,3   -> 0,3
OK 35 f6/81/c9/15/00/4c/a0/a8 1,4   -> 1,4
OK 36 19/41/df/f8/e3/74/6b/9b 4,2   -> 4,2
OK 37 d5/0b/dd/35/3b/d2/0b/6b 1,5   -> 1,5
OK 38 08/b7/91/f3/6e/3c/74/a0 0,0   -> 0,0
OK 39 b8/a8/b4/a6/93/2c/94/3f 0,0   -> 0,0
OK 40 88/22/21/ee/dc/19/43/01 0,0   -> 0,0
OK 41 e1/ee/35/bc/fc/00/8e/fe 0,0   -> 0,0
OK 42 3c/42/63/5f/27/47/07/90 0,0   -> 0,0
```