minesweeper.py

Created by ziii

Created on December 19, 2023

5.06 KB

A basic minesweeper game. Grid size can be chosen up to 24*17, as well as the number of bombs. Colors are fully customizable.

How to play:

After executing the script enter use the backspace and numbers to enter size of the grid and the amount of bombs.

Arrows to move cursor.

Ok to see what’s under a tile.

Shift to put or remove a flag on a tile.

You can customize colors in the script, from line 10 to 30 change the rgb values to change the colors of what’s described in the comment on the right.


from kandinsky import fill_rect as f, draw_string as d
from random import randrange
from ion import KEY_LEFT, KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_SHIFT, KEY_OK, KEY_BACKSPACE, keydown
from time import monotonic as now,sleep
def square(col):
  f(ori[0]+pos[0]*size,ori[1]+pos[1]*size,size+1,1,col)
  f(ori[0]+pos[0]*size,ori[1]+(pos[1]+1)*size,size+1,1,col)
  f(ori[0]+pos[0]*size,ori[1]+pos[1]*size+1,1,size-1,col)
  f(ori[0]+(pos[0]+1)*size,ori[1]+pos[1]*size+1,1,size-1,col)
BACKGROUND=(101,132,42)
H_SQUARE=(
(170,215,81),#hidden
(162,209,73))#hidden darker
S_SQUARE=(
(229,194,159),#seen
(215,184,153))#seen darker
BOMB=(219,50,54)
FLAG=(255,0,0)
TEXT=(255,255,255)
SELECTED=(0,0,0)
CURSOR=(0,255,0)
NUM_COLORS=(
(20,94,168),#1
(0,98,0),#2
(168,28,31),#3
(94,11,130),#4
(204,99,0),#5
(0,120,120),#6
(120,0,120),#7
(0,0,0))#8
keys=[[0,48],[1,42],[2,43],[3,44],[4,36],[5,37],[6,38],[7,30],[8,31],[9,32]]
pos=0
menu=["24","17","69"]
time=now()
under=lambda pos,menu,col: f(2,(pos+1)*40-2,len(menu[pos])*10-2,2,col)
def d_menu(pos,menu,u=False):
  f(0,(2*pos+1)*20,50,20,BACKGROUND)
  d(menu[pos],0,(2*pos+1)*20,TEXT,BACKGROUND)
  if u:
    under(pos,menu,SELECTED)
f(0,0,320,222,BACKGROUND)
d("OK TO PLAY",220,0,TEXT,BACKGROUND)
d("WIDTH",0,0,TEXT,BACKGROUND)
d("HEIGHT",0,40,TEXT,BACKGROUND)
d("BOMBS",0,80,TEXT,BACKGROUND)
d_menu(0,menu,u=True)
d_menu(1,menu)
d_menu(2,menu)
while not keydown(KEY_OK):
  if now()-time>0.15:
    time=now()
    if (keydown(KEY_DOWN) or keydown(KEY_UP)):
      d_menu(pos,menu)
      pos=(pos+keydown(KEY_DOWN)-keydown(KEY_UP))%len(menu)
      d_menu(pos,menu,u=True)
    else:
      for key in keys:
        if keydown(key[1]) and len(menu[pos])<(2+(pos>1)):
          menu[pos]+=str(key[0])
          d_menu(pos,menu,u=True)
      if keydown(KEY_BACKSPACE):
        d_menu(pos,menu)
        menu[pos]=menu[pos][:-1]
        d_menu(pos,menu,u=True)
w=max(min(24,int(menu[0])),4)
h=max(min(17,int(menu[1])),4)
bombs=min(int(menu[2]),w*h-9)
size=min(320//w,222//h)
H_E=0
H_B=1
F_E=2
F_B=3
S=4
grid=[[H_E for _ in range(h)]for _ in range(w)]
bombs_count=[[0 for _ in range(h)]for _ in range(w)]
pos=[w//2,h//2]
a=1+size//25
a=(a,(size-3*a-1)//2)
coo=((0,a[0]),(a[0],0),(a[0]+a[1],a[0]),(a[0],a[0]+a[1]),(0,2*a[0]+a[1]),(a[0],2*a[0]+2*a[1]),(a[0]+a[1],2*a[0]+a[1]))
l=((1,1,1,0,1,1,1),(0,0,1,0,0,0,1),(0,1,1,1,1,1,0),(0,1,1,1,0,1,1),(1,0,1,1,0,0,1),(1,1,0,1,0,1,1),(1,1,0,1,1,1,1),(0,1,1,0,0,0,1),(1,1,1,1,1,1,1),(1,1,1,1,0,0,1))
ori=[(320-size*w)//2,(222-size*h)//2]
f(0,0,320,222,BACKGROUND)
for x in range(len(grid)):
  for y in range(len(grid[0])):
    f(ori[0]+x*size+1,ori[1]+y*size+1,size-1,size-1,H_SQUARE[(x+y)%2])
square(CURSOR)
first=1
key_pressing={KEY_OK:0,KEY_SHIFT:0}
key_pressed={k:0 for k in key_pressing}
run=1
sleep(0.3)
time=now()
while run:
  for k in key_pressing:
    key_pressed[k]=0
    if keydown(k):
      if not key_pressing[k]:
        key_pressed[k]=1
      key_pressing[k]=1
    else:
      key_pressing[k]=0
  if now()-time>0.1 and (keydown(KEY_LEFT) or keydown(KEY_UP) or keydown(KEY_DOWN) or keydown(KEY_RIGHT)):
    time=now()
    square(BACKGROUND)
    pos[0]=(pos[0]-keydown(KEY_LEFT)+keydown(KEY_RIGHT))%w
    pos[1]=(pos[1]-keydown(KEY_UP)+keydown(KEY_DOWN))%h
    square(CURSOR)
  elif key_pressed[KEY_SHIFT]:
    if grid[pos[0]][pos[1]] in (H_E,H_B):
      f(ori[0]+pos[0]*size+3,ori[1]+pos[1]*size+3,size-5,size-5,FLAG)
      grid[pos[0]][pos[1]]+=2
    elif grid[pos[0]][pos[1]] in (F_E,F_B):
      f(ori[0]+pos[0]*size+3,ori[1]+pos[1]*size+3,size-5,size-5,H_SQUARE[(pos[0]+pos[1])%2])
      grid[pos[0]][pos[1]]-=2
  elif key_pressed[KEY_OK]:
    if first:
      n=bombs
      while n:
        rand=(randrange(w),randrange(h))
        if grid[rand[0]][rand[1]]!=1 and (pos[0]-rand[0])**2+(pos[1]-rand[1])**2>2:
          grid[rand[0]][rand[1]]=1
          n-=1
          for x in range(rand[0]-1,rand[0]+2):
            if w>x>=0:
              for y in range(rand[1]-1,rand[1]+2):
                if h>y>=0:
                  bombs_count[x][y]+=1
      first=0
    if grid[pos[0]][pos[1]] in (0,1):
      if grid[pos[0]][pos[1]]==H_B:
        square(BACKGROUND)
        for x in range(len(grid)):
          for y in range(len(grid[0])):
            if grid[x][y] in (H_B,F_B):
              f(ori[0]+x*size+1,ori[1]+y*size+1,size-1,size-1,BOMB)
        run=0
      else:
        to_do=[[pos[0],pos[1]]]
        while len(to_do):
          x,y=to_do.pop()
          grid[x][y]=S
          f(ori[0]+x*size+1,ori[1]+y*size+1,size-1,size-1,S_SQUARE[(x+y)%2])
          if bombs_count[x][y]:
            p=(x*size+(1+size)//4,y*size+1)
            for i in range(7):
              if l[bombs_count[x][y]][i]:
                f(ori[0]+coo[i][0]+p[0],ori[1]+coo[i][1]+p[1],a[i%2],a[(i+1)%2],NUM_COLORS[bombs_count[x][y]-1])
          else:
            for x1 in (x+1,x-1,x):
              if w>x1>=0:
                for y1 in (y,y+1,y-1):
                  if h>y1>=0 and grid[x1][y1]!=S and not [x1,y1] in to_do:
                    to_do.append([x1,y1])
        if not True in [H_E in grid[x] or F_E in grid[x] for x in range(w)]:
          run=0
          d("you win !",100,100,TEXT,BACKGROUND)