import sys
from math import floor
from random import randint
import pygame
from pygame import QUIT, MOUSEBUTTONDOWN, KEYDOWN
WIDTH = 20
HEIGHT = 15
SIZE = 50
NUM_OF_BOMBS = 20
EMPTY = 0
BOMB = 1
OPENED = 2
OPEN_COUNT = 0
CHECKED = [[False for _ in range(WIDTH)] for _ in range(HEIGHT)]
pygame.init()
SURFACE = pygame.display.set_mode([WIDTH * SIZE, HEIGHT * SIZE])
FPSCLOCK = pygame.time.Clock()
def init_game():
global OPEN_COUNT, CHECKED
OPEN_COUNT = 0
CHECKED = [[False for _ in range(WIDTH)] for _ in range(HEIGHT)]
field = [[EMPTY for _ in range(WIDTH)] for _ in range(HEIGHT)]
count = 0
while count < NUM_OF_BOMBS:
xpos, ypos = randint(0, WIDTH - 1), randint(0, HEIGHT - 1)
if field[ypos][xpos] == EMPTY:
field[ypos][xpos] = BOMB
count += 1
return field
def num_of_bomb(field, x_pos, y_pos):
result = 0
for yoffset in range(-1, 2):
for xoffset in range(-1, 2):
xpos, ypos = (x_pos + xoffset, y_pos + yoffset)
if xpos < 0 or WIDTH <= xpos:
continue
if ypos < 0 or HEIGHT <= ypos:
continue
if field[ypos][xpos] != BOMB:
continue
result += 1
return result
def open_tile(field, x_pos, y_pos):
global OPEN_COUNT
if CHECKED[y_pos][x_pos]:
return
CHECKED[y_pos][x_pos] = True
for yoffset in range(-1, 2):
for xoffset in range(-1, 2):
xpos, ypos = (x_pos + xoffset, y_pos + yoffset)
if xpos < 0 or WIDTH <= xpos:
continue
if ypos < 0 or HEIGHT <= ypos:
continue
if field[ypos][xpos] == EMPTY:
field[ypos][xpos] = OPENED
OPEN_COUNT += 1
count = num_of_bomb(field, xpos, ypos)
if count == 0 and not (xpos == x_pos and ypos == y_pos):
open_tile(field, xpos, ypos)
def main():
smallfont = pygame.font.SysFont(None, 36)
largefont = pygame.font.SysFont(None, 72)
message_clear = largefont.render("!!CLEARED!!", True, (0, 255, 225))
message_over = largefont.render("GAME OVER!!", True, (0, 255, 225))
message_restart = smallfont.render("Press R to restart", True, (255, 255, 255))
message_rect = message_clear.get_rect()
message_rect.center = (WIDTH * SIZE / 2, HEIGHT * SIZE / 2)
field = init_game()
game_over = False
while True:
cleared = (OPEN_COUNT == WIDTH * HEIGHT - NUM_OF_BOMBS)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == pygame.K_r:
field = init_game()
game_over = False
if event.type == MOUSEBUTTONDOWN and event.button == 1:
# 게임오버 또는 클리어 이후에는 타일 열기 금지
if game_over or cleared:
continue
xpos = floor(event.pos[0] / SIZE)
ypos = floor(event.pos[1] / SIZE)
if field[ypos][xpos] == BOMB:
game_over = True
else:
open_tile(field, xpos, ypos)
SURFACE.fill((0, 0, 0))
for ypos in range(HEIGHT):
for xpos in range(WIDTH):
tile = field[ypos][xpos]
rect = (xpos * SIZE, ypos * SIZE, SIZE, SIZE)
if tile == EMPTY or tile == BOMB:
pygame.draw.rect(SURFACE, (192, 192, 192), rect)
if game_over and tile == BOMB:
pygame.draw.ellipse(SURFACE, (225, 225, 0), rect)
elif tile == OPENED:
pygame.draw.rect(SURFACE, (80, 80, 80), rect)
count = num_of_bomb(field, xpos, ypos)
if count > 0:
num_image = smallfont.render(str(count), True, (255, 255, 0))
SURFACE.blit(num_image, (xpos * SIZE + 10, ypos * SIZE + 10))
for index in range(0, WIDTH * SIZE, SIZE):
pygame.draw.line(SURFACE, (96, 96, 96), (index, 0), (index, HEIGHT * SIZE))
for index in range(0, HEIGHT * SIZE, SIZE):
pygame.draw.line(SURFACE, (96, 96, 96), (0, index), (WIDTH * SIZE, index))
if cleared:
SURFACE.blit(message_clear, message_rect.topleft)
SURFACE.blit(message_restart, (WIDTH * SIZE / 2 - 100, HEIGHT * SIZE / 2 + 50))
elif game_over:
SURFACE.blit(message_over, message_rect.topleft)
SURFACE.blit(message_restart, (WIDTH * SIZE / 2 - 100, HEIGHT * SIZE / 2 + 50))
pygame.display.update()
FPSCLOCK.tick(15)
if __name__ == '__main__':
main()