Welcome, guest | Sign In | My Account | Store | Cart

Minesweeper expects the user to enter properly bounded integers for moves. Should the user enter something unexpected, the resulting exception can be caught and handled in some way other than exiting.

Python, 129 lines
  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
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"minesweeper"
from UserDict import UserDict

class Game(UserDict):

    def __init__(self, **kwargs):
        "initialize board"
        d = {"ROWS":8,"COLS":8,"BOMBS":10}
        d.update(kwargs)
        UserDict.__init__(self,d)
        self.reset()

    def random_bombs(self):
        "returns list of coordinates in tuple form"
        from random import choice
        coords = []
        for i in range(self['BOMBS']):
            while 1:
                row_idx = choice(range(self['ROWS']))
                col_idx = choice(range(self['COLS']))
                if not (row_idx,col_idx) in coords:
                    break
            coords.append((row_idx,col_idx))
        return coords

    def inc_neighbors(self,row_idx,col_idx):
        for r, c in [(r,c) for r in (-1,0,1) for c in (-1,0,1)]:
            try:
                ri = r + row_idx
                ci = c + col_idx
                if ri < 0 or ci < 0:
                    raise IndexError, "smaller than 0"
                v = self['BOARD'][ri][ci]
                self['BOARD'][ri][ci] = v + 1
            except:
                pass

    def reset(self):
        "reset board"
        self['BOARD'] = map ((lambda x,d=self: [0] * d['ROWS']),
                             range(self['COLS']))
        self['PLAYER'] = map ((lambda x,d=self: ['.'] * d['ROWS']),
                             range(self['COLS']))
        for (row,col) in self.random_bombs():
            self['BOARD'][row][col] = 'B'
            self.inc_neighbors(row,col)

    def to_string(self,board):
        str = ''
        for r in board:
            rstr = ''
            for c in r:
                rstr = rstr + '%s' % c
            str = str + '%s\n' % rstr
        return str
        
    def __repr__(self):
        board = self['BOARD']
        return self.to_string(board)

    def find_edges(self,row,col):
        "check up down left right"
        board = self['BOARD']
        player = self['PLAYER']
        to_explore = [(row,col)]
        try:
            if row < 0 or col < 0:
                raise IndexError, "smaller than 0"
            if player[row][col] is '.':
                v = board[row][col]
                player[row][col] = v
                ##print "updated,", row, col
                if v is 0:
                    for (r,c) in zip((0,0,-1,-1,-1,1,1,1),(-1,1,0,-1,1,0,-1,1)):
                        ri = row + r
                        ci = col + c
                        self.find_edges(ri,ci)
        except:
            pass

    def venture(self,row,col):
        msg = ''
        board = self['BOARD']
        player = self['PLAYER']
        v = board[row][col]
        
        if v is 'B':
            player[row][col] = 'X'
            msg = 'You lost!\n'
        elif v is 0:
            self.find_edges(row,col)
        else:
            player[row][col] = v
            if self.winp():
                msg = 'You won!\n'
        print msg + self.to_string(player)
        
    def winp(self):
        for (cb, cp) in zip(self['BOARD'], self['PLAYER']):
            cp = list(cp)
            for i in range(len(cp)):
                if cp[i] is '.': cp[i] = 'B'
            if tuple(cp) != tuple(cb):
                return 0
        return 1
        
if __name__ == '__main__':
    import string
    g = Game(ROWS=8,COLS=8, BOMBS=10)
        
    print '*' * 80
    print '*', "solution:"
    print '*' * 80
    print g

    while 1:
        try:
            r = string.atoi( raw_input('row:'))
            c = string.atoi( raw_input('col:'))
            g.venture(r,c)
        except:
            import sys
            print sys.exc_type, sys.exc_value
            if sys.exc_type is KeyboardInterrupt:
                raise KeyboardInterrupt
            print '*' * 80
            print '*', "solution:"
            print '*' * 80
            print g

2 comments

John Lee 21 years, 5 months ago  # | flag

Multiple except:s. A slightly nicer way of doing this is to explicitly catch the exceptions you're not interested in, rather than checking the exception type (for which purpose, by the way, the identity operator seems rather strict). It's also useful to print a debug message when you're testing the code, because the except: can easily mask real problems. For example, if you have a function called load which can raise IOError:

import traceback
from cStringIO import StringIO

DEBUG = 1

def debug(msg):
    print msg

def load(filename):
    try:
        # Some code that might raise IOError, or another exception that you
        # weren't expecting, if the user is imaginitive enough...
    except (KeyboardInterrupt, IOError):
        # NOTE WELL the brackets around the exception classes -- an except
        # with two arguments means something quite different!
        raise
    except:
        if DEBUG:
            f = StringIO()
            traceback.print_exc(None, f)
            debug("uncaught exception:\n%s" % f.getvalue())
        raise IOError, "invalid file '%s'" % filename

load("/some/nonsense/file.txt")
a 13 years, 11 months ago  # | flag

string.atoi() is deprecated. you should use int() instead