Coding

Minesweeper Kata

Published · 2min

I did the minesweeper kata a few days back. It was a bit too easy, though it’s quite possible that this is more an artifact of how I approached it. Given that it’s a simple one, it might be an idea to see if I can take it in smaller steps, much smaller steps.

There’s not really much to say, so here’s the code:

#!/usr/bin/env python

import doctest
import sys


def unpack_line(s):
    """
    >>> unpack_line('.....')
    [0, 0, 0, 0, 0]
    >>> unpack_line('')
    []
    >>> unpack_line('.*.')
    [0, '*', 0]
    """
    line = []
    for c in s:
        if c == '*':
            line.append('*')
        else:
            line.append(0)
    return line


def mark_adjacents(lines):
    """
    >>> mark_adjacents([[0, 0], [0, 0]])
    [[0, 0], [0, 0]]
    >>> mark_adjacents([['*', 0], [0, 0]])
    [['*', 1], [1, 1]]
    >>> mark_adjacents([['*', 0], [0, '*']])
    [['*', 2], [2, '*']]
    >>> mark_adjacents([[0, 0, 0], [0, '*', 0], [0, 0, 0]])
    [[1, 1, 1], [1, '*', 1], [1, 1, 1]]
    >>> mark_adjacents([['*', 0, 0], [0, 0, 0], [0, 0, '*']])
    [['*', 1, 0], [1, 2, 1], [0, 1, '*']]
    """
    for y in range(len(lines)):
        for x in range(len(lines[y])):
            if lines[y][x] == '*':
                for oy in [y - 1, y, y + 1]:
                    if oy < 0 or oy == len(lines):
                        continue
                    for ox in [x - 1, x, x + 1]:
                        if ox < 0 or ox == len(lines[y]):
                            continue
                        if lines[oy][ox] != '*':
                            lines[oy][ox] += 1
    return lines


def process_fields(iterable):
    start = True
    for line in iterable:
        line = line.rstrip()
        if start:
            start = False
            lines = []
            height, width = [int(x) for x in line.split(' ')]
            if width == 0 and height == 0:
                break
        else:
            lines.append(unpack_line(line))
            height -= 1
            if height == 0:
                start = True
                yield mark_adjacents(lines)


def main():
    field = 0
    for f in process_fields(sys.stdin):
        field += 1
        if field > 1:
            print
        print "Field #%d:" % field
        for l in f:
            print ''.join([str(x) for x in l])


def _test():
    doctest.testmod()


if __name__ == '__main__':
    main()

I should really buckle down and finish the code that’s meant to replace the crappy one-evening hack the this blog runs on.