minesweeper_full.py

Created by maelstudio

Created on October 18, 2023

9.41 KB

Ceci est la version complète (non-optimisée) de mon démineur. Vous trouverez la version optimisée ici.


from time import *
from math import floor, sqrt
from random import randint
from kandinsky import *
from ion import *

GRASS_COLORS = [(142, 204, 57), (167, 217, 72)]
DIRT_COLORS = [(215, 184, 153), (229, 194, 159)]
CURSOR_COLOR = (0, 0, 0)
MINE_BG_COLOR = (255, 0, 0)
MINE_COLORS = [(0, 0, 0), (255, 255, 255)]
FLAG_COLORS = [(255, 0, 0), (220, 0, 0)]
TIME_COLORS = [(255, 255, 255), (255, 190, 0), (221, 160, 17), (0, 0, 0)]
TEXT_COLOR = (255, 255, 255)
BAR_COLOR = ((73, 117, 43))
NUMBER_COLORS = [
  (255, 255, 255),
  (25, 118, 210),
  (56, 142, 60),
  (255, 0, 0),
  (0, 0, 132),
  (132, 0, 0),
  (123, 31, 162),
  (132, 0, 132),
  (0, 0, 0)
]

FLAG_BITMAP = """


_____11
_____1100
_____110000
_____11000000
_____1100000000
_____110000000000
_____1100000000
_____11000000
_____110000
_____1100
_____11
_____11
_____11
____1111"""

MINE_BITMAP = """


_________00
_________00
_____0_000000_0
______00000000
_____0011000000
_____0011000000
___00000000000000
___00000000000000
_____0000000000
_____0000000000
____0_00000000_0
_______000000
_________00
_________00"""

X_BITMAP = """00________________00
_00______________00
__00____________00
___00__________00
____00________00
_____00______00
______00____00
_______00__00
________0000
_________00
_________00
________0000
_______00__00
______00____00
_____00______00
____00________00
___00__________00
__00____________00
_00______________00
00________________00"""

TIME_BITMAP = """
_______11111
________222
_______11111
_____111222111
____11222222211
___1122000002211
___1220003000221
__112000030030211
__122000030300221
__122000033000221
__122000030000221
__112000000000211
___1220000000221
___1122000002211
____11222222211
_____111222111
_______11111"""

MINE_COUNT=20
SQUARE_SIZE=20
SCREEN_W=320
SCREEN_H=200
GRID_W=SCREEN_W//SQUARE_SIZE
GRID_H=SCREEN_H//SQUARE_SIZE

mines = []
digged = []
flagged = []
cursor = [GRID_W//2, GRID_H//2]
origin = [0, 0]
start_time = monotonic()
last_moved = monotonic()

def draw_grid_square(xy, color, fill=True, thick=1):
  x = xy[0]*SQUARE_SIZE
  y = xy[1]*SQUARE_SIZE + (222-SCREEN_H)
  if(fill):
    fill_rect(x, y, SQUARE_SIZE, SQUARE_SIZE, color)
  else:
    draw_rect(x, y, SQUARE_SIZE, SQUARE_SIZE, color, thick)

def draw_rect(x, y, w, h, color, thick=1):
  fill_rect(x, y, w, thick, color) 
  fill_rect(x, y, thick, h, color)
  fill_rect(x, y+h, w, -thick, color)
  fill_rect(x+w, y, -thick, h, color)

def draw_bitmap(bitmap, xy, colors):
  bitmap = bitmap.split("\n")
  for y, row in enumerate(bitmap):
    for x, pixel in enumerate(row):
      if pixel != "_":
        set_pixel(xy[0]*SQUARE_SIZE+x, xy[1]*SQUARE_SIZE+(222-SCREEN_H)+y, colors[int(pixel)])

def adjacent(xy, list):
  n = 0
  for y_off in [-1, 0, 1]:
    for x_off in [-1, 0, 1]:
      if [x_off, y_off] == [0, 0]:
        continue
      if [xy[0]+x_off, xy[1]+y_off] in list:
        n += 1
  return n

def dist_to_origin(xy):
  return sqrt((origin[0] - xy[0])**2 + (origin[1] - xy[1])**2)
  
def dig(xy):
  if xy in flagged:
    flagged.pop(flagged.index(xy))
    draw_flag_counter()
  digged.append(xy.copy())

  if adjacent(xy, mines) > 0:
    draw_cell(xy)
    draw_cursor()
    return
  
  search_digged = []
  search_digged.append(xy.copy())
  search(xy, search_digged)
  origin[0] = xy[0]
  origin[1] = xy[1]
  search_digged.sort(key=dist_to_origin)
  for pos in search_digged:
    draw_cell(pos)
    if pos == cursor:
      draw_cursor()
  draw_flag_counter()

def search(xy, search_digged):
  for y_off in [-1, 0, 1]:
    for x_off in [-1, 0, 1]:
      pos = [xy[0]+x_off, xy[1]+y_off]
      if [x_off, y_off] == [0, 0] or pos in digged or pos[0]>GRID_W-1 or pos[0]<0 or pos[1]>GRID_H-1 or pos[1]<0:
        continue
      if pos in flagged:
        flagged.pop(flagged.index(pos))
      digged.append(pos.copy())
      search_digged.append(pos.copy())
      if adjacent(pos, mines) == 0:
        search(pos, search_digged)

def draw_cell(xy):
  color_i = int(xy[0]%2==0 and xy[1]%2==0 or xy[0]%2!=0 and xy[1]%2!=0)
  if xy in digged:
    draw_grid_square(xy, DIRT_COLORS[color_i], True)
    n = adjacent(xy, mines)
    if(n>0):
      draw_string(str(n), xy[0]*SQUARE_SIZE+5, (222-SCREEN_H)+xy[1]*SQUARE_SIZE+1, NUMBER_COLORS[n], DIRT_COLORS[color_i])
    return
      
  draw_grid_square(xy, GRASS_COLORS[color_i], True)
  if xy in flagged:
    draw_bitmap(FLAG_BITMAP, xy, FLAG_COLORS)

def draw_cursor():
  draw_grid_square(cursor, CURSOR_COLOR, False, 2)

def draw_grid():
  for y in range(GRID_H):
    for x in range(GRID_W):
      draw_cell([x, y])

def draw_flag_counter():
  fill_rect(260, 0, 60, 222-SCREEN_H, BAR_COLOR)
  draw_string(str(MINE_COUNT-len(flagged))+"/"+str(MINE_COUNT),260,3,TEXT_COLOR,BAR_COLOR)

def get_time():
  return "{:.1f}".format(monotonic()-start_time)

def draw_time():
  fill_rect(50, 0, 40, 222-SCREEN_H, BAR_COLOR)
  draw_string(str(get_time()),42,3,TEXT_COLOR,BAR_COLOR)

def game_over(detonated):
  fill_rect(105, 0, 120, 222-SCREEN_H, BAR_COLOR)
  draw_string("YOU LOST !",110,3,TEXT_COLOR,BAR_COLOR)
  origin[0] = cursor[0]
  origin[1] = cursor[1]
  flagged.sort(key=dist_to_origin)
  mines.sort(key=dist_to_origin)
  for xy in flagged:
    if not xy in mines:
      draw_bitmap(X_BITMAP, xy, [(0, 0, 0)])
  for xy in detonated:
    draw_grid_square(xy, MINE_BG_COLOR)
    if xy == cursor:
      draw_cursor()
  for xy in mines:
    if not xy in flagged:
      draw_bitmap(MINE_BITMAP, xy, MINE_COLORS)

def place_mines():
  for i in range(MINE_COUNT):
    pos = [randint(0, GRID_W-1), randint(0, GRID_H-1)]
    while pos in mines or (abs(pos[0]-cursor[0]) <= 1 and abs(pos[1]-cursor[1]) <= 1):
      pos = [randint(0, GRID_W-1), randint(0, GRID_H-1)]
    mines.append(pos)

def chording(xy):
  detonated = []
  for y_off in [-1, 0, 1]:
    for x_off in [-1, 0, 1]:
      pos = [xy[0]+x_off, xy[1]+y_off]
      if [x_off, y_off] == [0, 0] or pos in digged or pos in flagged or pos[0]>GRID_W-1 or pos[0]<0 or pos[1]>GRID_H-1 or pos[1]<0:
        continue
      if pos in mines:
        detonated.append(pos)
        continue
      dig(pos)
  return detonated

fill_rect(0,0,320,222-SCREEN_H,BAR_COLOR)
draw_string("Select mines count:",5,3,TEXT_COLOR,BAR_COLOR)
draw_string(str(MINE_COUNT),215,3,TEXT_COLOR,BAR_COLOR)
draw_string("OK →",275,3,TEXT_COLOR,BAR_COLOR)
draw_grid()

last_changed = monotonic()

while keydown(KEY_OK) or keydown(KEY_EXE):
  pass

while not (keydown(KEY_OK) or keydown(KEY_EXE)):
  if floor(monotonic()*2)%2 == 0:
    fill_rect(200,0,10,222-SCREEN_H,BAR_COLOR)
    fill_rect(240,0,10,222-SCREEN_H,BAR_COLOR)
  else:
    draw_string("<",200,3,TEXT_COLOR,BAR_COLOR)
    draw_string(">",240,3,TEXT_COLOR,BAR_COLOR)

  if monotonic() - last_changed < 0.15:
    continue

  if keydown(KEY_LEFT) or keydown(KEY_RIGHT):
    if keydown(KEY_LEFT) and MINE_COUNT>15:
      MINE_COUNT -= 1
    if keydown(KEY_RIGHT) and MINE_COUNT<99:
      MINE_COUNT += 1
    fill_rect(215,0,25,222-SCREEN_H,BAR_COLOR)
    draw_string(str(MINE_COUNT),215,3,TEXT_COLOR,BAR_COLOR)
    last_changed = monotonic()

while True:
  fill_rect(0,0,320,222-SCREEN_H,BAR_COLOR)
  draw_bitmap(FLAG_BITMAP, [12, -1], FLAG_COLORS)
  draw_bitmap(TIME_BITMAP, [1, -1], TIME_COLORS)
  mines = []
  digged = []
  flagged = []
  cursor = [GRID_W//2, GRID_H//2]
  start_time = monotonic()
  draw_time()
  draw_flag_counter()
  draw_grid()

  for i in range(11):
    draw_string("MINESWEEPER"[:i+1],105,3,TEXT_COLOR,BAR_COLOR)
    sleep(0.05)

  draw_cursor()

  start_time = monotonic()
  last_time = get_time()
  first_dig = True

  while True:
    
    if get_time() != last_time:
      draw_time()
      last_time = get_time()

    # moving cursor
    if monotonic() - last_moved > 0.15:
      pressed = None
      for k in [KEY_RIGHT, KEY_LEFT, KEY_UP, KEY_DOWN]:
        if keydown(k):
          pressed = k
          break
      
      if not pressed == None:
        last_cursor = cursor.copy()

        if pressed == KEY_RIGHT:
          cursor[0] += 1
          if cursor[0] > GRID_W-1:
            cursor[0] = 0
        elif pressed == KEY_LEFT:
          cursor[0] -= 1
          if cursor[0] < 0:
            cursor[0] = GRID_W-1
        elif pressed == KEY_DOWN:
          cursor[1] += 1
          if cursor[1] > GRID_H-1:
            cursor[1] = 0
        elif pressed == KEY_UP:
          cursor[1] -= 1
          if cursor[1] < 0:
            cursor[1] = GRID_H-1

        draw_cursor()
        draw_cell(last_cursor)
        last_moved = monotonic()

    # digging
    if (keydown(KEY_OK) or keydown(KEY_EXE)) and not cursor in flagged:
      if first_dig:
        place_mines()
        first_dig = False
      if cursor in mines:
        game_over([cursor])
        break
      if cursor in digged and adjacent(cursor, flagged) == adjacent(cursor, mines):
        detonated = chording(cursor)
        if detonated:
          game_over(detonated)
          break
      elif not cursor in digged:
        dig(cursor)
      if len(digged)+MINE_COUNT == GRID_W*GRID_H:
        fill_rect(105, 0, 120, 222-SCREEN_H, BAR_COLOR)
        draw_string("YOU WON !",115,3,TEXT_COLOR,BAR_COLOR)
        break
      
      while keydown(KEY_OK) or keydown(KEY_EXE):
        pass
    
    # flagging
    if keydown(KEY_BACKSPACE):
      if cursor in flagged:
        flagged.pop(flagged.index(cursor))
      elif not cursor in digged:
        flagged.append(cursor.copy())
      draw_cell(cursor)
      draw_cursor()
      draw_flag_counter()

      while keydown(KEY_BACKSPACE):
        pass
  
  while keydown(KEY_OK) or keydown(KEY_EXE):
    pass

  while not (keydown(KEY_OK) or keydown(KEY_EXE)):
    pass

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.