diff --git a/minesweeper-curses.py b/minesweeper-curses.py new file mode 100644 index 0000000..9e65f7c --- /dev/null +++ b/minesweeper-curses.py @@ -0,0 +1,154 @@ +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()