155 lines
4 KiB
Python
155 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()
|