demineur.py

Created by arthurjacquin

Created on April 13, 2020

7.38 KB

Dernière version : minesweeper.py.


# Démineur - Mars 2020
# Arthur Jacquin - arthur062318@gmail.com

"""   Valeurs des cases de la matrice

|        Contexte        | Bombe |                 Non bombe                  |
|     Non découvert      |   9   |    0 à 8 (nombre de bombes adjacentes)     |
|       Découvert        |  19   | 10 à 18 (nombre de bombes adjacentes + 10) |
| Couvert par un drapeau |  29   | 20 à 28 (nombre de bombes adjacentes + 20) |
"""

"""    Améliorations possibles

Fixer le déminage
Intégrer le wait() de tools
"""




# Initialisation

# Modules
from kandinsky import set_pixel, draw_string, fill_rect
from random import choice
from ion import keydown
from tools import *

# Couleurs
imp = (0,0,0) # Titre, curseur, contenu
grey = (70,70,70) # Texte, bordures
light = (220,220,220) # Inconnus
none = (255,255,255) # Vide, background
curs = (0,0,255) # Curseur
numb = ((0,0,255),(0,127,0),(255,0,0),(0,0,127),(127,0,0),(0,127,127),(0,0,0),(127,127,127)) # Chiffres

# Paramètres et outils
Xdomain = range(16)
Ydomain = range(10)
mines = menu("MINESWEEPER", "Lancer la partie", ["Mines",5,1,16,18,20,22,24,26,42], ["Commandes",2," Nav: Flèches"," Déminer: OK","Drapeau: DEL","Rejouer: OK"], ["Crédits",2,"Arthur J.","Vincent R."])[0]
prox = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]



# Fonctions graphiques

def mine(x,y,b,a): # Pixel +4
    fill_rect(x+2+4,y+2+4,9,9,b)
    fill_rect(x+4,y+6+4,13,1,b)
    fill_rect(x+6+4,y+4,1,13,b)
    fill_rect(x+4+4,y+4+4,2,2,(255,255,255))
    for p in [[9,2],[10,3],[10,9],[9,10],[3,10],[2,9],[2,3],[3,2]]:
        set_pixel(x+p[0]+4,y+p[1]+4,a)

def top():
    fill_rect(0,0,320,20,none)
    if etat == "MINESWEEPER":
        draw_string(etat,105,2,imp)
        draw_string((" "+str(compteur)+"/"+(str(mines)+" ")[:2])[-5:],265,2,grey)
        mine(245,0,grey,none)
    else:
        if etat == "YOU WON !": draw_string(etat,28,2,(0,153,0))
        else: draw_string(etat,23,2,(255,0,0))
        draw_string("EXE to PLAY AGAIN",145,2,grey)

def case(X,Y):
    value = MAT[Y][X]
    x, y = 20*X, 20*Y + 22
    fill_rect(x,y,20,20,grey) # Bordures
    if value < 10: # Inconnu
        fill_rect(x+1,y+1,18,18,light)
    elif value == 10: # Vide
        fill_rect(x+1,y+1,18,18,none)
    elif value in range(11,19): # Nombre
        fill_rect(x+1,y+1,18,18,none)
        draw_string(str(value-10),x+5,y+1,numb[value-11])
    elif value == 19: # Bombe découverte
        fill_rect(x+1,y+1,18,18,(255,0,0))
        mine(x,y,imp,(255,0,0))
    elif value > 19: # Drapeau
        fill_rect(x+1,y+1,18,18,light)
        fill_rect(x+10,y+8,2,6,imp)
        fill_rect(x+6,y+14,8,2,imp)
        fill_rect(x+6,y+4,6,4,(255,0,0))
    if cursor == [X,Y]: # Curseur
        fill_rect(x,y,20,3,curs)
        fill_rect(x,y,3,20,curs)
        fill_rect(x,y+17,20,3,curs)
        fill_rect(x+17,y,3,20,curs)




# Fonctionnement

def search(old): # Recherche des cases adjacentes vides
    new = []
    for i in old:
        for p in prox:
            tX, tY = i[0]+p[0], i[1]+p[1]
            if tX in Xdomain and tY in Ydomain:
                if MAT[tY][tX] == 0: new.append([tX,tY])
                if not(MAT[tY][tX] in range(10,19)):
                    MAT[tY][tX] = (MAT[tY][tX])%10 + 10
                    case(tX,tY)
    if new != []: search(new)




# Boucle principale

def play():
    # Initialisation
    global compteur, cursor, etat, cases, MAT
    compteur = mines # Décompte apparent du nombre de bombes restant
    decouv = 0 # Nombres réel de bombes déduites
    cursor = [8,5] # Coordonnées du curseur
    etat = "MINESWEEPER" # Etat de la partie
    MAT = [[0]*len(Xdomain)]*len(Ydomain) # Génération d'une matrice blanche
    
    # Dessin de l'interface
    top()
    fill_rect(0,21,320,1,grey)
    for Y in Ydomain:
        for X in Xdomain: case(X,Y)
    
    # Boucle principale
    while True:
        X, Y = cursor[0], cursor[1]
        result = wait([0,1,2,3,4,17])
        if result < 4: # Déplacement de curseur
            if result==0 and cursor[0]-1 in Xdomain: cursor[0] -= 1
            elif result==1 and cursor[1]-1 in Ydomain: cursor[1] -= 1
            elif result==2 and cursor[1]+1 in Ydomain: cursor[1] += 1
            elif result==3 and cursor[0]+1 in Xdomain: cursor[0] += 1
            case(X,Y)
            case(cursor[0],cursor[1])
        elif result == 4: # Découverte d'une case
            if MAT == [[0]*len(Xdomain)]*len(Ydomain): # Génération de la matrice
                bombes = []
                for i in range(mines):
                    x, y = choice(Xdomain), choice(Ydomain)
                    while (x,y) in bombes or (x,y) == (X,Y):
                        x, y = choice(Xdomain), choice(Ydomain)
                    bombes.append((x,y))
                MAT = []
                for y in Ydomain:
                    column = []
                    for x in Xdomain:
                        if (x,y) in bombes: column.append(9)
                        else: column.append(sum([1*((x+t[0],y+t[1]) in bombes) for t in prox]))
                    MAT.append(column)
            if MAT[Y][X] > 19:
                compteur += 1
                draw_string((" "+str(compteur))[-2:],265,2,grey)
            if MAT[Y][X] in range(11,19): # Déminage automatique
                while True:
                    flags = 0
                    for t in prox:
                        if X+t[0] in Xdomain and Y+t[1] in Ydomain:
                            if MAT[Y+t[1]][X+t[0]] == 9:
                                # Procédure de perte
                                
                                break
                            elif MAT[Y+t[1]][X+t[0]] == 29: flags += 1
                    if MAT[Y][X]-10 == flags:
                        for t in prox:
                            if X+t[0] in Xdomain and Y+t[1] in Ydomain and MAT[Y+t[1]][X+t[0]]<9:
                                MAT[Y+t[1]][X+t[0]] = (MAT[Y+t[1]][X+t[0]])%10+10
                                case(X+t[0],Y+t[1])
                                if MAT[Y+t[1]][X+t[0]]==10: search([[X+t[0],Y+t[1]]])
                    break
            MAT[Y][X] = (MAT[Y][X])%10 + 10
            case(X,Y)
            if MAT[Y][X] == 10: search([[X,Y]]) # Recherche automatique
            elif MAT[Y][X] == 19:
                for x in Xdomain:
                    for y in Ydomain:
                        if (MAT[y][x])%10 == 9:
                            MAT[y][x] = 19
                            case(x,y)
                        elif MAT[y][x] > 19:
                            for i in range(18):
                                fill_rect(20*x+i,20*y+23+i,3,1,imp)
                                fill_rect(20*x+17-i,20*y+23+i,3,1,imp)
                etat = "YOU LOSE !"
                break
        elif result == 17: # Mise en place/Détachement de drapeau
            if MAT[Y][X] < 20: sens = 1
            else: sens = -1
            compteur -= sens
            if (MAT[Y][X])%10 == 9: decouv += sens
            MAT[Y][X] = (MAT[Y][X])%10 + 20*(sens==1)
            draw_string((" "+str(compteur))[-2:],265,2,grey)
            case(X,Y)
        if compteur == 0 and decouv == mines:
            for x in Xdomain:
                for y in Ydomain:
                    if MAT[y][x]<9:
                        MAT[y][x] = (MAT[y][x])%10+10
                        case(x,y)
            etat = "YOU WON !"
            cursor = [42,120]
            case(X,Y)
            break
    top()
    while not(keydown(4)): True
    play()

play()