one-file-projects/minesweeper-curses.py
trollhase 10be440641 bla
2013-10-22 15:40:40 +02:00

154 lines
4 KiB
Python

from random import randint
import curses
class Game:
COVERED = 0
UNCOVERED = 1
FLAG = 2
PLAYING = 0
WON = 1
LOST = 2
def __init__(self,width,height,bombs):
self.width = width
self.height = height
self.bombs = bombs
if self.bombs > self.width*self.height:
raise ValueError("Too much bombs")
self.running = True
self.cursorx = 0
self.cursory = 0
self.state = self.PLAYING
self.__generate()
def mapdone(self):
for y in range(self.height):
for x in range(self.width):
if self.discovered[y][x] == self.COVERED:
return False
if self.discovered[y][x] == self.FLAG and not self.bombmap[y][x]:
return False
return True
def __generate(self):
self.bombmap = [ [False for x in range(self.width) ] for y in range(self.height) ]
self.discovered = [ [0 for x in range(self.width) ] for y in range(self.height) ]
for i in range(self.bombs):
x,y = randint(0,self.width-1),randint(0,self.height-1)
while self.bombmap[y][x]:
x,y = randint(0,self.width-1),randint(0,self.height-1)
self.bombmap[y][x] = True
def countbomb(self,y,x):
n = 0
for dy in range(-1,2):
for dx in range(-1,2):
if y+dy < 0 or y+dy >= self.height: continue
if x+dx < 0 or x+dx >= self.width: continue
if self.bombmap[y+dy][x+dx]:
n+=1
return n
def uncover(self,y,x):
if y < 0 or y >= self.height: return
if x < 0 or x >= self.width: return
if self.discovered[y][x] != self.UNCOVERED and not self.bombmap[y][x]:
self.discovered[y][x] = self.UNCOVERED
if self.countbomb(y,x) == 0:
self.uncover(y+1,x)
self.uncover(y+1,x+1)
self.uncover(y,x+1)
self.uncover(y-1,x+1)
self.uncover(y-1,x)
self.uncover(y-1,x-1)
self.uncover(y,x-1)
self.uncover(y+1,x-1)
def update(self,key):
if self.state == self.PLAYING:
if key == ord('f'): #Set a flag
if self.discovered[self.cursory][self.cursorx] == self.COVERED:
self.discovered[self.cursory][self.cursorx] = self.FLAG
if self.mapdone():
self.state = self.WON
elif self.discovered[self.cursory][self.cursorx] == self.FLAG:
self.discovered[self.cursory][self.cursorx] = self.COVERED
elif key == ord(' '):
if self.bombmap[self.cursory][self.cursorx]:
self.state = self.LOST
else:
self.uncover(self.cursory,self.cursorx)
if self.mapdone():
self.state = self.WON
elif key == curses.KEY_DOWN:
if self.cursory+1 < self.height:
self.cursory+=1
elif key == curses.KEY_UP:
if self.cursory-1 >= 0:
self.cursory-=1
elif key == curses.KEY_RIGHT:
if self.cursorx+1 < self.width:
self.cursorx+=1
elif key == curses.KEY_LEFT:
if self.cursorx-1 >= 0:
self.cursorx-=1
if key == ord('q'):
self.running = False
def draw(self,screen):
for y in range(self.height):
for x in range(self.width):
if self.discovered[y][x] == self.COVERED:
char = "-"
attr = curses.A_NORMAL
elif self.discovered[y][x] == self.UNCOVERED:
if self.bombmap[y][x]:
char = "*"
attr = curses.A_BOLD
else:
n = self.countbomb(y,x)
if n == 0:
char = " "
else:
char = str(n)
attr = curses.A_NORMAL
elif self.discovered[y][x] == self.FLAG:
char = "F"
attr = curses.A_BOLD
screen.addch(y,x,ord(char),attr)
if self.state == self.PLAYING:
screen.addstr(self.height,0,"f - Set Flag, Space - Uncover, q - Quit")
elif self.state == self.LOST:
screen.addstr(self.height,0,"--- LOST (q to quit) ---")
screen.clrtoeol()
elif self.state == self.WON:
screen.addstr(self.height,0,"--- WON (q to quit) ---")
screen.clrtoeol()
def run(self, screen):
sh, sw = screen.getmaxyx()
#l = (sw-self.width)//2
l = t = 0
#t = (sh-self.height)//2
#window = curses.newwin(self.height,self.width,t,l)
while self.running:
self.draw(screen)
screen.move(t+self.cursory,l+self.cursorx)
k = screen.getch()
self.update(k)
if __name__ == '__main__':
s = curses.initscr()
curses.savetty()
curses.noecho()
s.keypad(1)
#curses.curs_set(2)
Game(40,20,70).run(s)
curses.resetty()
curses.endwin()