Help with minesweeper simple code

Help with minesweeper simple code

Postby RafaelGoncalves » Sat Aug 02, 2014 10:00 pm

I'm using pygame for this, the messages that the code will display are in Portuguese , but it isn't important in the code, the main thing is in English. Below is the full code (messy and inefficient) but my issue is with the first click, can you help me how can I make to the player to click and open all the blank boxes as in a minesweeper game?

The function I tried to elaborate was 'open_blank':

Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, pygame, random
from pygame.locals import *

FPS = 30
WINDOW_WIDTH = 220
WINDOW_HEIGHT = 220
REVEAL_SPEED = 8
BOX_SIZE = 20
GAP_SIZE = 2

BOARD_WIDTH = 9
BOARD_HEIGHT = 9

X_MARGIN = int((WINDOW_WIDTH - (BOARD_WIDTH * (BOX_SIZE + GAP_SIZE))) / 2 )
Y_MARGIN = int((WINDOW_HEIGHT - (BOARD_HEIGHT * (BOX_SIZE + GAP_SIZE))) / 2 )

# colors      R    G    B
D_GRAY      = (125, 125, 125)
GRAY      = (192, 192, 192)
L_GRAY      = (224, 224, 224)
NAVY_BLUE   = ( 60,  60, 200)
WHITE      = (255, 255, 255)
RED         = (255,   0,   0)
GREEN      = (  0,   100, 0)
YELLOW      = (255, 255,   0)


BG_COLOR = GRAY
INNER_COLOR = D_GRAY
LIGHT_BG_COLOR = L_GRAY
HIGHLIGHT_COLOR = WHITE
BOX_COLOR = GRAY


BLANK = BG_COLOR
ICON = pygame.image.load('ICON.PNG')
BOMB = pygame.image.load('BOMB.PNG')
EXPLODE = pygame.image.load('EXPLODE.PNG')


def main():
   global FPS_CLOCK, DISPLAY_SURF, revealed_boxes
   pygame.init()
   FPS_CLOCK = pygame.time.Clock()
   DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
   
   mouse_x = 0 # used to store x coordinate of mouse event
   mouse_y = 0 # used to store y coordinate of mouse event
   
   pygame.display.set_caption('Campo Minado')
   
   revealed_boxes = generate_boxes_data(False)
   
   main_board = get_randomized_board()

   DISPLAY_SURF.fill(BG_COLOR)
   # start_game_animation(main_board)
   
   while True: # main game loop
      mouse_clicked_left = False
      mouse_clicked_right = False
      DISPLAY_SURF.fill(BG_COLOR) # drawing the window
      draw_board(main_board, revealed_boxes)

      # won_test(main_board)   #test
      
      for event in pygame.event.get(): # event handling loop
         if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE:
            pygame.quit()
            sys.exit()
         elif event.type == MOUSEMOTION:
            mouse_x, mouse_y = event.pos
         elif event.type == MOUSEBUTTONUP and event.button == 1:
            mouse_x, mouse_y = event.pos
            mouse_clicked_left = True
         elif event.type == MOUSEBUTTONUP and event.button == 3:
            mouse_x, mouse_y = event.pos
            mouse_clicked_right = True
            
      box_x, box_y = get_box_at_pixel(mouse_x, mouse_y)
      if box_x != None and box_y != None:
         # The mouse is currently over a box.
         if not revealed_boxes[box_x][box_y]:
            draw_highlight_box(box_x, box_y)
         if not revealed_boxes[box_x][box_y] and mouse_clicked_left:
            if main_board[box_x][box_y] == 'bomb':
               revealed_boxes[box_x][box_y] = None
               pygame.time.wait(100)
               loose(main_board)
            else:
               open_blank(box_x, box_y, main_board)
               if has_won(main_board):
                  game_won_animation(main_board)
      
      pygame.display.update()
      FPS_CLOCK.tick(FPS)

def generate_boxes_data(val):
   revealed_boxes   = []
   for i in range (BOARD_WIDTH):
      revealed_boxes.append(([val] * BOARD_HEIGHT))
   return revealed_boxes
   
def get_randomized_board():
   BOMB = 'bomb'
   icons = []
   for bombs in range(10):
      icons.append(BOMB)
   for empty in range(9*9 - 10):
      icons.append(None)
   random.shuffle(icons) # randomize the order of the icons list
   board = []
   for x in range(BOARD_WIDTH):
      column = []
      for y in range(BOARD_HEIGHT):
         column.append(icons[0])
         del icons [0] # remove icons already assigned
      board.append(column)
   return board      
      
def draw_board(board, revealed_boxes):
   for box_x in range(BOARD_WIDTH):
      for box_y in range(BOARD_HEIGHT):
         left, top = left_top_coords_of_box(box_x, box_y)
         if revealed_boxes[box_x][box_y] == False:
            # Draw covered box.
            DISPLAY_SURF.blit(ICON, (left, top))
         elif revealed_boxes[box_x][box_y] == True:
            if   board[box_x][box_y] == 'bomb':
               # Draw the bomb.
               DISPLAY_SURF.blit(BOMB, (left, top))
            else:
               #Draw numbers
               find_number_icon(box_x, box_y, board)
         else:
            DISPLAY_SURF.blit(EXPLODE, (left, top))
            
def find_number_icon(box_x, box_y, board):
   number = 0
   for x in range(box_x - 1, box_x + 2):
      for y in range (box_y - 1, box_y + 2):
         try:
            if board[x][y] == 'bomb':
               number += 1
         except:
            number = number
   if number != 0:
      font_obj = pygame.font.Font('freesansbold.ttf', 22)
      text_surface_obj = font_obj.render(str(number), True, GREEN)   
      text_rect_obj = text_surface_obj.get_rect()
      text_rect_obj.topleft = (left_top_coords_of_box(box_x, box_y))
      DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
   
def left_top_coords_of_box(box_x, box_y):
   """ Convert board coordinates to pixel coordinates"""
   left = box_x * (BOX_SIZE + GAP_SIZE) + X_MARGIN
   top = box_y * (BOX_SIZE + GAP_SIZE) + Y_MARGIN
   return (left, top)
   
def get_box_at_pixel(x, y):
   for box_x in range(BOARD_WIDTH):
      for box_y in range(BOARD_HEIGHT):
         left, top = left_top_coords_of_box(box_x, box_y)
         box_rect = pygame.Rect(left, top, BOX_SIZE, BOX_SIZE)
         if box_rect.collidepoint(x, y):
            return (box_x, box_y)
   return (None, None)
   
def has_won(board):
   num = 0
   for i in revealed_boxes:
      if i == False:
         num += 1
   if num == 5:
      return True
   else:
      return False
   
def open_blank(box_x, box_y, board):
   global revealed_boxes
   revealed_boxes[box_x][box_y] = True
   if board[box_x][box_y] == False:
      for x in range(box_x - 1, box_x + 2):
         for y in range(box_y - 1, box_y + 2):
            try:
               is_blank(x, y, board)
            except:
               None
               
def loose(board):
   generate_boxes_data(False)
   color1 = LIGHT_BG_COLOR
   color2 = BG_COLOR
   for i in range(13):
      color1, color2 = color2, color1
      DISPLAY_SURF.fill(color1)
      draw_board(board, revealed_boxes)
      pygame.display.update()
      pygame.time.wait(300)
   font_obj = pygame.font.Font('freesansbold.ttf', 30)
   text_surface_obj = font_obj.render(u'Você perdeu!', True, RED)   
   text_rect_obj = text_surface_obj.get_rect()
   text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
   text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
   DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
   pygame.display.update()
   pygame.time.wait(2000)
   main()
   
def is_blank(box_x, box_y, board):
   global revealed_boxes
   for x in range(box_x - 1, box_x + 2):
         for y in range(box_y - 1, box_y + 2):
            try:
               if board[x][y] != False:
                  return False
               else:
                  open_blank(x, y, board)
            except:
               None
   return True
               
def draw_highlight_box(box_x, box_y):
   left, top = left_top_coords_of_box(box_x, box_y)
   pygame.draw.rect(DISPLAY_SURF, HIGHLIGHT_COLOR, (left - 3, top - 3,\
   BOX_SIZE + 6, BOX_SIZE + 6), 3)
   
def game_won_animation(board):
   generate_boxes_data(False)
   color1 = LIGHT_BG_COLOR
   color2 = BG_COLOR
   for i in range(13):
      color1, color2 = color2, color1
      DISPLAY_SURF.fill(color1)
      draw_board(board, revealed_boxes)
      pygame.display.update()
      pygame.time.wait(300)
   font_obj = pygame.font.Font('freesansbold.ttf', 50)
   text_surface_obj = font_obj.render(u'Vitória!', True, YELLOW)   
   text_rect_obj = text_surface_obj.get_rect()
   text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
   text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
   DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
   pygame.display.update()
   pygame.time.wait(2000)
   main()
   
def won_test(main_board):
   revealed_boxes = [False, False, False, False, False]
   if has_won(main_board) == True:
      game_won_animation(main_board)
   

   
if __name__ == '__main__':
   main()


Thank you very much
RafaelGoncalves
 
Posts: 3
Joined: Tue Jul 01, 2014 1:30 pm

Re: Help with minesweeper simple code

Postby freddyhard » Wed Aug 06, 2014 12:21 am

i had to make substantial changes.

i think it is simpler to make the board a 2D array of objects that hold all the infomartion needed regarding that square.

so i created a class called Piece() and it's attributes are only a True/False if it has been clicked on and
then an INTEGER to represent what it is.
-1 = bomb
0 = blank
? = number of bombs adjacent to this square

at any stage press 'END' to get a print out of all the Pieces in the array

i have commented out your code that i didn't use and put in some more functions that i thought were needed to work it to this level

Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, pygame, random
from random import randint
from pygame.locals import *

FPS = 30
WINDOW_WIDTH = 220
WINDOW_HEIGHT = 220
REVEAL_SPEED = 8
BOX_SIZE = 20
GAP_SIZE = 2

BOARD_WIDTH = 9
BOARD_HEIGHT = 9

X_MARGIN = int((WINDOW_WIDTH - (BOARD_WIDTH * (BOX_SIZE + GAP_SIZE))) / 2 )
Y_MARGIN = int((WINDOW_HEIGHT - (BOARD_HEIGHT * (BOX_SIZE + GAP_SIZE))) / 2 )

# colors      R    G    B
D_GRAY      = (125, 125, 125)
GRAY      = (192, 192, 192)
L_GRAY      = (224, 224, 224)
NAVY_BLUE   = ( 60,  60, 200)
WHITE      = (255, 255, 255)
RED         = (255,   0,   0)
GREEN      = (  0,   100, 0)
YELLOW      = (255, 255,   0)


BG_COLOR = GRAY
INNER_COLOR = D_GRAY
LIGHT_BG_COLOR = L_GRAY
HIGHLIGHT_COLOR = WHITE
BOX_COLOR = GRAY


BLANK = BG_COLOR
ICON = pygame.image.load('ICON.PNG')
BOMB = pygame.image.load('BOMB.PNG')
EXPLODE = pygame.image.load('EXPLODE.PNG')



class Piece():
    def __init__(self):
        # set to show if object has been clicked on
        self.revealed = False
        # id = -1 for bomb
        # id = 0 for blank
        # id = ? for number of bombs adjacent to this object
        self.id = 0
   
   





 


def main():
    global FPS_CLOCK, DISPLAY_SURF#, revealed_boxes
    pygame.init()
    FPS_CLOCK = pygame.time.Clock()
    DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
   
    mouse_x = 0 # used to store x coordinate of mouse event
    mouse_y = 0 # used to store y coordinate of mouse event
   
    pygame.display.set_caption('Campo Minado')
   
    #revealed_boxes = generate_boxes_data(False)
   
    #main_board = get_randomized_board()
   
   
    # this builds a 2D array filled with objects from the class Piece()
    newBoard = [[Piece() for f in range(BOARD_WIDTH)]for f in range(BOARD_HEIGHT)]
   
    # this will insert 10 bombs into the above 2D array and then fill in the correct
    # blanks and numbers to match where the bombs are
    insertBombs(newBoard, 10)
   
   
    DISPLAY_SURF.fill(BG_COLOR)
    # start_game_animation(main_board)
   
    while True: # main game loop
        mouse_clicked_left = False
        mouse_clicked_right = False
        DISPLAY_SURF.fill(BG_COLOR) # drawing the window
       
        #draw_board(main_board, revealed_boxes)
        drawBoard2(newBoard)
       
        # won_test(main_board)   #test
       
       
        for event in pygame.event.get(): # event handling loop
            if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            # +++++++++++++++++++++++++ TESTING ONLY +++++++++++++++++++++++++
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_END:
                draw_ascii(newBoard)
            # +++++++++++++++++++++++++ END TEST +++++++++++++++++++++++++
            elif event.type == MOUSEMOTION:
                mouse_x, mouse_y = event.pos
            elif event.type == MOUSEBUTTONUP and event.button == 1:
                mouse_x, mouse_y = event.pos
                mouse_clicked_left = True
            elif event.type == MOUSEBUTTONUP and event.button == 3:
                mouse_x, mouse_y = event.pos
                mouse_clicked_right = True
       
        box_x, box_y = get_box_at_pixel(mouse_x, mouse_y)
        if box_x != None and box_y != None:
            # The mouse is currently over a box.
            if not newBoard[box_y][box_x].revealed:
                draw_highlight_box(box_x, box_y)
            if not newBoard[box_y][box_x].revealed and mouse_clicked_left:
                newBoard[box_y][box_x].revealed = True
                if newBoard[box_y][box_x].id == -1:
                    pygame.time.wait(100)
                    loose(newBoard)
                elif newBoard[box_y][box_x].id == 0:
                    findAdjacentBlanks(box_x, box_y, newBoard)

       
        """
        box_x, box_y = get_box_at_pixel(mouse_x, mouse_y)
        if box_x != None and box_y != None:
            # The mouse is currently over a box.
            if not revealed_boxes[box_x][box_y]:
                draw_highlight_box(box_x, box_y)
            if not revealed_boxes[box_x][box_y] and mouse_clicked_left:
                if main_board[box_x][box_y] == 'bomb':
                    revealed_boxes[box_x][box_y] = None
                    pygame.time.wait(100)
                    loose(main_board)
                else:
                    open_blank(box_x, box_y, main_board)
                    if has_won(main_board):
                        game_won_animation(main_board)
        """ 
        pygame.display.update()
        FPS_CLOCK.tick(FPS)


def findAdjacentBlanks(box_x, box_y, board):
    testSquares = [(box_x, box_y)]
    while len(testSquares) > 0:
        # remove the first position from the array to test for blanks
        (x, y) = testSquares.pop(0)
       
        # test all possible 8 squares around the current one
        for rowCount in range(-1, 2):
            for colCount in range(-1, 2):
                if withInRange(colCount + x, BOARD_WIDTH) and withInRange(rowCount + y, BOARD_HEIGHT):
                    if (board[rowCount + y][colCount + x].id == 0 and
                         not board[rowCount + y][colCount + x].revealed):
                        # if blank found make it visible
                        board[rowCount + y][colCount + x].revealed = True
                        # add this square to the array to further test for more blanks
                        testSquares.append((colCount + x, rowCount + y))
                    else:
                        board[rowCount + y][colCount + x].revealed = True



   


def insertBombs(board, numberOfBombs):
    # insert random bombs
    for f in range(numberOfBombs):
        while True:
            rand_x = randint(0, BOARD_WIDTH - 1)
            rand_y = randint(0, BOARD_HEIGHT - 1)
           
            if board[rand_y][rand_x].id == 0:
                board[rand_y][rand_x].id = -1
                break
   
    # change the id for each object to count the number of
    # bombs adjacent to this square
    for rows in range(BOARD_HEIGHT):
        for cols in range(BOARD_WIDTH):
            if board[rows][cols].id != -1:
                board[rows][cols].id = countAdjacentBombs(board, cols, rows)



def countAdjacentBombs(board, x, y):
    bombCount = 0
    for rowCount in range(-1, 2):
        for colCount in range(-1, 2):
            # IndexError exception not thrown, so i'll do this instead
            if withInRange(colCount + x, BOARD_WIDTH) and withInRange(rowCount + y, BOARD_HEIGHT):
                if board[rowCount + y][colCount + x].id == -1:
                    bombCount += 1
   
    return bombCount



def withInRange(num, upperLimit):
    return num >= 0 and num < upperLimit




"""
def generate_boxes_data(val):
    revealed_boxes   = []
    for i in range (BOARD_WIDTH):
        revealed_boxes.append(([val] * BOARD_HEIGHT))
    return revealed_boxes
   
def get_randomized_board():
    BOMB = 'bomb'
    icons = []
    for bombs in range(10):
        icons.append(BOMB)
    for empty in range(9*9 - 10):
        icons.append(None)
    random.shuffle(icons) # randomize the order of the icons list
    board = []
    for x in range(BOARD_WIDTH):
        column = []
        for y in range(BOARD_HEIGHT):
            column.append(icons[0])
            del icons [0] # remove icons already assigned
        board.append(column)
    return board     
"""

def drawBoard2(board):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            if not board[box_y][box_x].revealed:
                # Draw covered box.
                DISPLAY_SURF.blit(ICON, (left, top))
               
           
            elif board[box_y][box_x].id == -1:# revealed_boxes[box_x][box_y] == True:
                DISPLAY_SURF.blit(BOMB, (left, top))
               
            elif board[box_y][box_x].id > 0:
                drawNumber(box_x, box_y, board[box_y][box_x].id)
            elif board[box_y][box_x].id == 0:
                continue
            else:
                DISPLAY_SURF.blit(EXPLODE, (left, top))



def drawNumber(box_x, box_y, number):
    font_obj = pygame.font.Font('freesansbold.ttf', 22)
    text_surface_obj = font_obj.render(str(number), True, GREEN)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.topleft = (left_top_coords_of_box(box_x, box_y))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)




"""
def draw_board(board, revealed_boxes):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            if revealed_boxes[box_x][box_y] == False:
                # Draw covered box.
                DISPLAY_SURF.blit(ICON, (left, top))
            elif revealed_boxes[box_x][box_y] == True:
                if   board[box_x][box_y] == 'bomb':
                    # Draw the bomb.
                    DISPLAY_SURF.blit(BOMB, (left, top))
                else:
                    #Draw numbers
                    find_number_icon(box_x, box_y, board)
            else:
                DISPLAY_SURF.blit(EXPLODE, (left, top))








def find_number_icon(box_x, box_y, board):
    number = 0
    #----------------------------------------------------------------------------------------------------
    #----------------------------------------------------------------------------------------------------
    for x in range(box_x - 1, box_x + 1):
        for y in range (box_y - 1, box_y + 1):
            try:
                if board[x][y] == 'bomb':
                    number += 1
            except:
                number = number
    if number != 0:
        font_obj = pygame.font.Font('freesansbold.ttf', 22)
        text_surface_obj = font_obj.render(str(number), True, GREEN)   
        text_rect_obj = text_surface_obj.get_rect()
        text_rect_obj.topleft = (left_top_coords_of_box(box_x, box_y))
        DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)


"""







def left_top_coords_of_box(box_x, box_y):
    """ Convert board coordinates to pixel coordinates"""
    left = box_x * (BOX_SIZE + GAP_SIZE) + X_MARGIN
    top = box_y * (BOX_SIZE + GAP_SIZE) + Y_MARGIN
    return (left, top)
   
def get_box_at_pixel(x, y):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            box_rect = pygame.Rect(left, top, BOX_SIZE, BOX_SIZE)
            if box_rect.collidepoint(x, y):
                return (box_x, box_y)
    return (None, None)
   
def has_won(board):
    num = 0
    for i in revealed_boxes:
        if i == False:
            num += 1
    if num == 5:
        return True
    else:
        return False

#----------------------------------------------------------------------------------------------------
def open_blank(box_x, box_y, board):
    global revealed_boxes
    revealed_boxes[box_x][box_y] = True
    if board[box_x][box_y] == False:
        for x in range(box_x - 1, box_x + 1):
            for y in range(box_y - 1, box_y + 1):
                try:
                    is_blank(x, y, board)
                except:
                    None


def is_blank(box_x, box_y, board):
    global revealed_boxes
    for x in range(box_x - 1, box_x + 1):
        for y in range(box_y - 1, box_y + 1):
            try:
                if board[x][y] != False:
                    return False
                else:
                    open_blank(x, y, board)
            except:
                None
    return True
#----------------------------------------------------------------------------------------------------

           
def loose(board):
    #generate_boxes_data(False)
    color1 = LIGHT_BG_COLOR
    color2 = BG_COLOR
    for i in range(13):
        color1, color2 = color2, color1
        DISPLAY_SURF.fill(color1)
        drawBoard2(board)
        #draw_board(board, revealed_boxes)
        pygame.display.update()
        pygame.time.wait(300)
    font_obj = pygame.font.Font('freesansbold.ttf', 30)
    text_surface_obj = font_obj.render(u'Você perdeu!', True, RED)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
    text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
    pygame.display.update()
    pygame.time.wait(2000)
    main()
   

               
def draw_highlight_box(box_x, box_y):
    left, top = left_top_coords_of_box(box_x, box_y)
    pygame.draw.rect(DISPLAY_SURF, HIGHLIGHT_COLOR, (left - 3, top - 3,\
    BOX_SIZE + 6, BOX_SIZE + 6), 3)
   
def game_won_animation(board):
    #generate_boxes_data(False)
    color1 = LIGHT_BG_COLOR
    color2 = BG_COLOR
    for i in range(13):
        color1, color2 = color2, color1
        DISPLAY_SURF.fill(color1)
        drawBoard2(board)
        #draw_board(board, revealed_boxes)
        pygame.display.update()
        pygame.time.wait(300)
    font_obj = pygame.font.Font('freesansbold.ttf', 50)
    text_surface_obj = font_obj.render(u'Vitória!', True, YELLOW)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
    text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
    pygame.display.update()
    pygame.time.wait(2000)
    main()
   
def won_test(main_board):
    revealed_boxes = [False, False, False, False, False]
    if has_won(main_board) == True:
        game_won_animation(main_board)
   


#---------------------------------- TESTING ONLY ----------------------------------
def draw_ascii(mBoard):
    for rows in range(BOARD_HEIGHT):
        for cols in range(BOARD_WIDTH):
            print "\t" + str(mBoard[rows][cols].id),
        print "\n"
    print"\n\n"
#---------------------------------- TESTING ONLY ----------------------------------

   
if __name__ == '__main__':
    main()


EDIT: i removed an extra condition test in the findAdjacentBlanks() that wasn't needed and added an extra check to display all numbers found beside the blanks
freddyhard
 
Posts: 36
Joined: Wed Jul 16, 2014 9:32 pm

Re: Help with minesweeper simple code

Postby freddyhard » Wed Aug 06, 2014 10:33 pm

i did a little more. when you right click on a square it will display a marker. i might have the sprites mixed up, but that is easy to change. to check for a completed board, i would count the revealed squares + the bomb count and if that equals the size of the grid then it is solved. but i wonder am i talking to myself... :lol:
Code: Select all
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys, pygame, random
from random import randint
from pygame.locals import *

FPS = 30
WINDOW_WIDTH = 220
WINDOW_HEIGHT = 220
REVEAL_SPEED = 8
BOX_SIZE = 20
GAP_SIZE = 2

BOARD_WIDTH = 9
BOARD_HEIGHT = 9

X_MARGIN = int((WINDOW_WIDTH - (BOARD_WIDTH * (BOX_SIZE + GAP_SIZE))) / 2 )
Y_MARGIN = int((WINDOW_HEIGHT - (BOARD_HEIGHT * (BOX_SIZE + GAP_SIZE))) / 2 )

# colors      R    G    B
D_GRAY      = (125, 125, 125)
GRAY      = (192, 192, 192)
L_GRAY      = (224, 224, 224)
NAVY_BLUE   = ( 60,  60, 200)
WHITE      = (255, 255, 255)
RED         = (255,   0,   0)
GREEN      = (  0,   100, 0)
YELLOW      = (255, 255,   0)


BG_COLOR = GRAY
INNER_COLOR = D_GRAY
LIGHT_BG_COLOR = L_GRAY
HIGHLIGHT_COLOR = WHITE
BOX_COLOR = GRAY

BOMBS = 10

BLANK = BG_COLOR
ICON = pygame.image.load('ICON.PNG')
BOMB = pygame.image.load('BOMB.PNG')
EXPLODE = pygame.image.load('EXPLODE.PNG')



class Piece():
    def __init__(self):
        # set to show if object has been clicked on
        self.revealed = False
        self.flagged = False
        # id = -1 for bomb
        # id = 0 for blank
        # id = ? for number of bombs adjacent to this object
        self.id = 0
   
   





 


def main():
    global FPS_CLOCK, DISPLAY_SURF#, revealed_boxes
    pygame.init()
    FPS_CLOCK = pygame.time.Clock()
    DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
   
    mouse_x = 0 # used to store x coordinate of mouse event
    mouse_y = 0 # used to store y coordinate of mouse event
   
    pygame.display.set_caption('Campo Minado')
   
    #revealed_boxes = generate_boxes_data(False)
   
    #main_board = get_randomized_board()
   
   
    # this builds a 2D array filled with objects from the class Piece()
    newBoard = [[Piece() for f in range(BOARD_WIDTH)]for f in range(BOARD_HEIGHT)]
   
    # this will insert 10 bombs into the above 2D array and then fill in the correct
    # blanks and numbers to match where the bombs are
    insertBombs(newBoard, BOMBS)
   
   
    DISPLAY_SURF.fill(BG_COLOR)
    # start_game_animation(main_board)
   
    while True: # main game loop
        mouse_clicked_left = False
        mouse_clicked_right = False
        DISPLAY_SURF.fill(BG_COLOR) # drawing the window
       
        #draw_board(main_board, revealed_boxes)
        drawBoard2(newBoard)
       
        # won_test(main_board)   #test
       
        for event in pygame.event.get(): # event handling loop
            if event.type == QUIT or event.type == KEYUP and event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            # +++++++++++++++++++++++++ TESTING ONLY +++++++++++++++++++++++++
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_END:
                draw_ascii(newBoard)
            # +++++++++++++++++++++++++ END TEST +++++++++++++++++++++++++
            elif event.type == MOUSEMOTION:
                mouse_x, mouse_y = event.pos
            elif event.type == MOUSEBUTTONUP and event.button == 1:
                mouse_x, mouse_y = event.pos
                mouse_clicked_left = True
            elif event.type == MOUSEBUTTONUP and event.button == 3:
                mouse_x, mouse_y = event.pos
                mouse_clicked_right = True
       
        box_x, box_y = get_box_at_pixel(mouse_x, mouse_y)
        if box_x != None and box_y != None:
            # The mouse is currently over a box.
            if not newBoard[box_y][box_x].revealed:
                draw_highlight_box(box_x, box_y)
            if not newBoard[box_y][box_x].revealed and mouse_clicked_left:
                newBoard[box_y][box_x].revealed = True
                newBoard[box_y][box_x].flagged = False
                if newBoard[box_y][box_x].id == -1:
                    pygame.time.wait(100)
                    loose(newBoard)
                elif newBoard[box_y][box_x].id == 0:
                    findAdjacentBlanks(box_x, box_y, newBoard)
                # test for win here
                if win_test(newBoard):
                    game_won_animation(newBoard)
            elif not newBoard[box_y][box_x].revealed and mouse_clicked_right:
                newBoard[box_y][box_x].flagged = not newBoard[box_y][box_x].flagged

       
        """
        box_x, box_y = get_box_at_pixel(mouse_x, mouse_y)
        if box_x != None and box_y != None:
            # The mouse is currently over a box.
            if not revealed_boxes[box_x][box_y]:
                draw_highlight_box(box_x, box_y)
            if not revealed_boxes[box_x][box_y] and mouse_clicked_left:
                if main_board[box_x][box_y] == 'bomb':
                    revealed_boxes[box_x][box_y] = None
                    pygame.time.wait(100)
                    loose(main_board)
                else:
                    open_blank(box_x, box_y, main_board)
                    if has_won(main_board):
                        game_won_animation(main_board)
        """ 
        pygame.display.update()
        FPS_CLOCK.tick(FPS)


def findAdjacentBlanks(box_x, box_y, board):
    testSquares = [(box_x, box_y)]
    while len(testSquares) > 0:
        # remove the first position from the array to test for blanks
        (x, y) = testSquares.pop(0)
       
        # test all possible 8 squares around the current one
        for rowCount in range(-1, 2):
            for colCount in range(-1, 2):
                if withInRange(colCount + x, BOARD_WIDTH) and withInRange(rowCount + y, BOARD_HEIGHT):
                    if (board[rowCount + y][colCount + x].id == 0 and
                         not board[rowCount + y][colCount + x].revealed):
                        # if blank found make it visible
                        board[rowCount + y][colCount + x].revealed = True
                        # add this square to the array to further test for more blanks
                        testSquares.append((colCount + x, rowCount + y))
                    else:
                        # the square might already be revealed, but just to be sure
                        # don't add it to the list of blanks though
                        board[rowCount + y][colCount + x].revealed = True



   


def insertBombs(board, numberOfBombs):
    # insert random bombs
    for f in range(numberOfBombs):
        while True:
            rand_x = randint(0, BOARD_WIDTH - 1)
            rand_y = randint(0, BOARD_HEIGHT - 1)
           
            if board[rand_y][rand_x].id == 0:
                board[rand_y][rand_x].id = -1
                break
   
    # change the id for each object to count the number of
    # bombs adjacent to this square
    for rows in range(BOARD_HEIGHT):
        for cols in range(BOARD_WIDTH):
            if board[rows][cols].id != -1:
                board[rows][cols].id = countAdjacentBombs(board, cols, rows)



def countAdjacentBombs(board, x, y):
    bombCount = 0
    for rowCount in range(-1, 2):
        for colCount in range(-1, 2):
            # IndexError exception not thrown, so i'll do this instead
            if withInRange(colCount + x, BOARD_WIDTH) and withInRange(rowCount + y, BOARD_HEIGHT):
                if board[rowCount + y][colCount + x].id == -1:
                    bombCount += 1
   
    return bombCount



def withInRange(num, upperLimit):
    return num >= 0 and num < upperLimit




"""
def generate_boxes_data(val):
    revealed_boxes   = []
    for i in range (BOARD_WIDTH):
        revealed_boxes.append(([val] * BOARD_HEIGHT))
    return revealed_boxes
   
def get_randomized_board():
    BOMB = 'bomb'
    icons = []
    for bombs in range(10):
        icons.append(BOMB)
    for empty in range(9*9 - 10):
        icons.append(None)
    random.shuffle(icons) # randomize the order of the icons list
    board = []
    for x in range(BOARD_WIDTH):
        column = []
        for y in range(BOARD_HEIGHT):
            column.append(icons[0])
            del icons [0] # remove icons already assigned
        board.append(column)
    return board     
"""

def drawBoard2(board):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            if not board[box_y][box_x].revealed and not board[box_y][box_x].flagged:
                # Draw covered box.
                DISPLAY_SURF.blit(ICON, (left, top))
               
            elif board[box_y][box_x].flagged:
                DISPLAY_SURF.blit(EXPLODE, (left, top))
               
            elif board[box_y][box_x].id == -1:# revealed_boxes[box_x][box_y] == True:
                DISPLAY_SURF.blit(BOMB, (left, top))
               
            elif board[box_y][box_x].id > 0:
                drawNumber(box_x, box_y, board[box_y][box_x].id)
               
            elif board[box_y][box_x].id == 0:
                continue




def drawNumber(box_x, box_y, number):
    font_obj = pygame.font.Font('freesansbold.ttf', 22)
    text_surface_obj = font_obj.render(str(number), True, GREEN)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.topleft = (left_top_coords_of_box(box_x, box_y))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)




"""
def draw_board(board, revealed_boxes):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            if revealed_boxes[box_x][box_y] == False:
                # Draw covered box.
                DISPLAY_SURF.blit(ICON, (left, top))
            elif revealed_boxes[box_x][box_y] == True:
                if   board[box_x][box_y] == 'bomb':
                    # Draw the bomb.
                    DISPLAY_SURF.blit(BOMB, (left, top))
                else:
                    #Draw numbers
                    find_number_icon(box_x, box_y, board)
            else:
                DISPLAY_SURF.blit(EXPLODE, (left, top))








def find_number_icon(box_x, box_y, board):
    number = 0
    #----------------------------------------------------------------------------------------------------
    #----------------------------------------------------------------------------------------------------
    for x in range(box_x - 1, box_x + 1):
        for y in range (box_y - 1, box_y + 1):
            try:
                if board[x][y] == 'bomb':
                    number += 1
            except:
                number = number
    if number != 0:
        font_obj = pygame.font.Font('freesansbold.ttf', 22)
        text_surface_obj = font_obj.render(str(number), True, GREEN)   
        text_rect_obj = text_surface_obj.get_rect()
        text_rect_obj.topleft = (left_top_coords_of_box(box_x, box_y))
        DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)


"""







def left_top_coords_of_box(box_x, box_y):
    """ Convert board coordinates to pixel coordinates"""
    left = box_x * (BOX_SIZE + GAP_SIZE) + X_MARGIN
    top = box_y * (BOX_SIZE + GAP_SIZE) + Y_MARGIN
    return (left, top)
   
def get_box_at_pixel(x, y):
    for box_x in range(BOARD_WIDTH):
        for box_y in range(BOARD_HEIGHT):
            left, top = left_top_coords_of_box(box_x, box_y)
            box_rect = pygame.Rect(left, top, BOX_SIZE, BOX_SIZE)
            if box_rect.collidepoint(x, y):
                return (box_x, box_y)
    return (None, None)

"""   
def has_won(board):
    num = 0
    for i in revealed_boxes:
        if i == False:
            num += 1
    if num == 5:
        return True
    else:
        return False

#----------------------------------------------------------------------------------------------------
def open_blank(box_x, box_y, board):
    global revealed_boxes
    revealed_boxes[box_x][box_y] = True
    if board[box_x][box_y] == False:
        for x in range(box_x - 1, box_x + 1):
            for y in range(box_y - 1, box_y + 1):
                try:
                    is_blank(x, y, board)
                except:
                    None


def is_blank(box_x, box_y, board):
    global revealed_boxes
    for x in range(box_x - 1, box_x + 1):
        for y in range(box_y - 1, box_y + 1):
            try:
                if board[x][y] != False:
                    return False
                else:
                    open_blank(x, y, board)
            except:
                None
    return True
#----------------------------------------------------------------------------------------------------
"""
           
def loose(board):
    #generate_boxes_data(False)
    color1 = LIGHT_BG_COLOR
    color2 = BG_COLOR
    for i in range(13):
        color1, color2 = color2, color1
        DISPLAY_SURF.fill(color1)
        drawBoard2(board)
        #draw_board(board, revealed_boxes)
        pygame.display.update()
        pygame.time.wait(300)
    font_obj = pygame.font.Font('freesansbold.ttf', 30)
    text_surface_obj = font_obj.render(u'Você perdeu!', True, RED)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
    text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
    pygame.display.update()
    pygame.time.wait(2000)
    main()
   

               
def draw_highlight_box(box_x, box_y):
    left, top = left_top_coords_of_box(box_x, box_y)
    pygame.draw.rect(DISPLAY_SURF, HIGHLIGHT_COLOR, (left - 3, top - 3,\
    BOX_SIZE + 6, BOX_SIZE + 6), 3)
   
def game_won_animation(board):
    #generate_boxes_data(False)
    color1 = LIGHT_BG_COLOR
    color2 = BG_COLOR
    for i in range(13):
        color1, color2 = color2, color1
        DISPLAY_SURF.fill(color1)
        drawBoard2(board)
        #draw_board(board, revealed_boxes)
        pygame.display.update()
        pygame.time.wait(300)
    font_obj = pygame.font.Font('freesansbold.ttf', 50)
    text_surface_obj = font_obj.render(u'Vitória!', True, YELLOW)   
    text_rect_obj = text_surface_obj.get_rect()
    text_rect_obj.centerx = ((WINDOW_WIDTH / 2))
    text_rect_obj.centery = ((WINDOW_HEIGHT / 2))
    DISPLAY_SURF.blit(text_surface_obj, text_rect_obj)
    pygame.display.update()
    pygame.time.wait(2000)
    main()


"""
def won_test(main_board):
    revealed_boxes = [False, False, False, False, False]
    if has_won(main_board) == True:
        game_won_animation(main_board)
"""

def win_test(board):
    squareCount = 0
    for rows in range(BOARD_HEIGHT):
        for cols in range(BOARD_WIDTH):
            if board[rows][cols].revealed:
                squareCount += 1
    return (BOMBS + squareCount == BOARD_WIDTH * BOARD_HEIGHT)


#---------------------------------- TESTING ONLY ----------------------------------
def draw_ascii(mBoard):
    for rows in range(BOARD_HEIGHT):
        for cols in range(BOARD_WIDTH):
            print "\t" + str(mBoard[rows][cols].id),
        print "\n"
    print"\n\n"
#---------------------------------- TESTING ONLY ----------------------------------

   
if __name__ == '__main__':
    main()


EDIT: i put in a test for win function, so now the game is playable!
freddyhard
 
Posts: 36
Joined: Wed Jul 16, 2014 9:32 pm

Re: Help with minesweeper simple code

Postby mr ham » Wed Aug 27, 2014 9:23 am

That's cool (just made 20x20 surface for ICON etc and filled with plain colors and removed Portuguese so I could play it). I briefly looked at the code of the last message and suspect it could be made to not eat less cpu power, like just be idle until something is clicked then do stuff (or I could be wrong maybe it already does).
Also its possible to hit a bomb on the 1st click. So probably after first click, set that first square to 'no bomb' and then set the rest of the grid right after the first click.
mr ham
 
Posts: 21
Joined: Wed Aug 27, 2014 3:36 am

Re: Help with minesweeper simple code

Postby freddyhard » Wed Sep 03, 2014 10:49 am

i never played minesweeper before and didn't even have it installed on my OS. so only after a short burst of playing it did i attempt to adjust so of the OP's code.
to avoid clicking on a bomb to start with the insertBombs(newBoard, BOMBS) would need to be called (only once on a first mouse click) in the main game loop. the (x,y) position of the first valid mouse click position will need to be passed to the insertBombs() and additional code put in the insertBombs() function to not allow a bomb being placed at that position of the array.
have a go and see if you can get it to work. i'll be disappearing off the internet shortly.
freddyhard
 
Posts: 36
Joined: Wed Jul 16, 2014 9:32 pm


Return to Game Development

Who is online

Users browsing this forum: No registered users and 0 guests