#! /usr/bin/env python
#12-Feb-2008-Morning Pilpilon 001
#12-Feb-2008-Noon    Pilpilon 002
#13-Feb-2008-Evening Pilpilon 003
#18-Feb-2008-Evening Pilpilon  004 Added options

from random import randrange 
prompt = """enter s X Y for shot(open field),
enter m X Y for mark mine,
enter u X Y for unmark mine\n""" 

excl = ["\nI mean, letter and two integers, please!\n",
        "\nnever've heard of such a command!\n"]
comms = { "s":"shot", "m":"mark" , "u":"unmark"}
def bordhead( width):
	return ["\n\ny\\x %s\n" % " ".join(["%2d" % k for k in range(width)])] 

class Field :
        def __init__ (self, a, b ):
                self.coord = (a,b)
        def __eq__ (self , other):
                return self.coord == other.coord
	def __str__(self):
		return `self.coord`
        def neigh (self , other):
                a,b = [self.coord[i] - other.coord[i]   for i in (0,1)]
                return -1 <= a <= 1 and -1 <= b <= 1 
class Board :
	def __init__ ( self, num = 10, width = 10, height = 10):
		self.fields = []
		self.width = width
		self.height = height
		self.num = num
		while len(self.fields)  < num :
			f = Field ( randrange(0,width),randrange(0,height))
			if f not in self.fields:
				self.fields.append(f)
			
	def shot( self, a, b):
		f = Field(a,b)
		res = f in self.fields
		around = len([x for x in self.fields if f.neigh(x)])
		return (res, around)

	def __ch (self, a,b):
		if Field(a,b) in self.fields :
			return 'X'
		else :
			return '0'
		 
	def __str__ (self):
		a = bordhead + ["%d   " % j +" ".join([ self.__ch(i,j) 
						for i in range(self.width)])
						for j in range(self.height)]
		return "\n".join(a) 
		
	
class Gameboard:
	def __init__ ( self, num = 10, width = 10, height = 10):
		self.board = Board(num, width, height) 
		self.openedfields = {}
		self.ingame = True
		self.win = False
        def __ch (self, a,b):
		return self.openedfields.get( (a,b), "C")
	def __test (self, a,b):
		return self.openedfields.has_key((a,b)) or not self.ingame  or a < 0 or a >= self.board.width or b < 0 or b >= self.board.height
	def __win(self):
		return len([self.openedfields[x] for x in self.openedfields 
                       if self.openedfields[x] !="M"])+ self.board.num >= self.board.width * self.board.height
	def __str__ (self):
                a = bordhead(self.board.width) + ["%2d   " % j + "  ".join([ self.__ch(i,j) for i in range(self.board.width)])
                                             for j in range(self.board.height)]
		return "\n".join(a)
	def shot ( self, a, b):
		if self.__test(a,b) :
			return
		re, nu = self.board.shot(a,b)
		if re :
			self.__reveal("X")
			self.ingame = False
		else:
			self.openedfields[(a,b)] = `nu`
			self.win = self.__win()
			self.ingame = not self.win
			if not self.ingame:
				self.__reveal("D")
			if nu == 0 :
				self.__shotaround(a,b)
	def __reveal ( self, letter):
		for f in self.board.fields :
			self.openedfields[f.coord] = letter
	def __shotaround( self, a,b):
		for u in  [ (  c,d) for c in range( a-1, a+2)
                              for d in range( b-1, b+2)
                              if (c, d ) != (a,b)]:
			self.shot(u[0],u[1])
	def mark (self, a,b):
		if self.__test(a,b) :
			return
		self.openedfields[(a,b)] = "M"
	def unmark (self, a,b):
		if self.openedfields.get( (a,b), "C") == "M" :
			 self.openedfields.pop((a,b))


if __name__ == "__main__":
	from optparse import OptionParser
	parser = OptionParser()
	parser.add_option("-w", "--width", action="store", type="int", dest="width", default=10, help  = "width of the gameboard" )
	parser.add_option("-t", "--height", action="store", type="int", dest ="height", default=10, help = "height of the gameboard")
	parser.add_option("-n", "--number", action="store", type="int", dest ="number", default=10, help = "number of mines")
	(options, args) = parser.parse_args()

	a = Gameboard(options.number, options.width, options.height)
	while a.ingame:
		print a
		pr = raw_input(prompt)
		l = pr.split()
		while len(l) >= 3 :
			c, l = l[:3],l[3:]
			if not all( [getattr(x, "isdigit")() for x in c[1:]]):
				print excl[0]
				break
			if not comms.has_key(c[0]) :
				print excl[1]
				break
			getattr(a, comms[c[0]])(int(c[1]),int(c[2]))
	print a
	if a.win : print "you win"
	else     : print "you lose"