Creació de jocs amb PyBadge

Programació Dades pràctiques     Recursos CITCEA
Tutorial Exemples Projectes   Inici

Buscamines

El taulell de joc és un camp minat i cal detectar on estan totes les mines sense que n'esclati cap. Cada cop que es pica en una casella, si no hi ha cap mina, s'hi indica quantes mines hi ha situades a les caselles del voltant; això permet identificar les posicions de les mines. Es pot posar una bandera en les caselles on se suposa que hi ha una mina, per facilitar la cerca. El botó B serveix per descobrir una casella i el botó A posa una bandera.

Les imatges que es fan servir en el joc (puntero.bmp i Buscaminas.bmp) són les següents:

punter       caselles

El programa és el següent:

import board
import displayio
import ugame
import adafruit_imageload
import neopixel
import random
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
import time
# Crear la pantalla principal
pant = board.DISPLAY
# Carregar les imatges del joc
imatges, palette = adafruit_imageload.load("/Buscaminas.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette)
# Carregar la imatge del punter
puntero, palette2 = adafruit_imageload.load("/puntero.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette)
palette2.make_transparent(0)  # Fer el color de fons transparent
# Carregar les fonts personalitzades
font = bitmap_font.load_font("/fonts/ic8x16u.bdf")
font2 = bitmap_font.load_font("/fonts/ic16x16u.bdf")
font3 = bitmap_font.load_font("/fonts/ib16x16u.bdf")
# Inicialitzar la cadena de llums LED
cadena = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
def seleccionar_dificultat():
    # Crear les etiquetes per al menú de selecció de dificultat
    titol = label.Label(font2, text="BUSCAMINES", color=0xFFA500, x=2, y=25)
    dificultat_facil = label.Label(font, text=" ? Fàcil", color=0x0000FF, x=13, y=60)
    dificultat_dificil = label.Label(font, text=" ? Difícil", color=0x0000FF, x=13, y=90)
    # Crear un grup de textos i afegir-hi les etiquetes
    grup_text = displayio.Group()
    grup_text.append(titol)
    grup_text.append(dificultat_facil)
    grup_text.append(dificultat_dificil)
    while True:
        pant.show(grup_text)  # Mostrar les opcions de dificultat
        boto = ugame.buttons.get_pressed()
        if boto & ugame.K_DOWN:
            return "Dificil"  # Retornar "Difícil" si es prem la fletxa avall
        elif boto & ugame.K_UP:
            return "Facil"  # Retornar "Fàcil" si es prem la fletxa amunt
def iniciar_joc(dificultat):
    # Configurar els paràmetres segons la dificultat
    if dificultat == "Facil":
        AMPLADA, ALCADA, NUM_MINES, escala, pos_ini = (
            5,  # Amplada del tauler
            4,  # Alçada del tauler
            random.randint(4, 8),  # Nombre de mines aleatori
            2,  # Escala per ampliar el tauler
            (2, 2),  # Posició inicial del punter
        )
    elif dificultat == "Dificil":
        AMPLADA, ALCADA, NUM_MINES, escala, pos_ini = (
            10,
            8,
            random.randint(15, 20),
            1,
            (4, 3),
        )
    contador_mines = NUM_MINES  # Nombre de mines restants a marcar
    # Crear el tauler lògic i visual
    tauler = [[0 for _ in range(AMPLADA)] for _ in range(ALCADA)]  # Estat del joc
    visual = [[0 for _ in range(AMPLADA)] for _ in range(ALCADA)]  # Estat visible del tauler
    # Crear el TileGrid per mostrar el tauler
    tauler_visual = displayio.TileGrid(imatges, pixel_shader=palette, width=AMPLADA, height=ALCADA, tile_width=16, tile_height=16)
    # Crear el punter
    punter = displayio.TileGrid(puntero, pixel_shader=palette2, width=1, height=1, tile_width=16, tile_height=16)
    # Crear grups visuals
    grup_tauler = displayio.Group(scale=escala)
    grup_tauler.append(tauler_visual)
    grup_punter = displayio.Group(scale=escala)
    grup_punter.append(punter)
    grup = displayio.Group()
    grup.append(grup_tauler)
    grup.append(grup_punter)
    pant.show(grup)
    # Funció per generar mines i calcular números
    def generar_tauler(excloure_x, excloure_y):
        # Evitar generar mines al voltant de la primera selecció
        posicions = [
            (x, y)
            for x in range(AMPLADA)
            for y in range(ALCADA)
            if not (abs(x - excloure_x) <= 1 and abs(y - excloure_y) <= 1)
        ]
        # Col·locar mines en posicions aleatòries
        mines = []
        while len(mines) < NUM_MINES:
            seleccio = random.choice(posicions)
            if seleccio not in mines:
                mines.append(seleccio)
        for x, y in mines:
            tauler[y][x] = -1  # Indicar que hi ha una mina
        # Comptar mines adjacents per a cada cel·la
        for y in range(ALCADA):
            for x in range(AMPLADA):
                if tauler[y][x] != -1:
                    tauler[y][x] = comptar_mines_adjacents(x, y)
    # Comptar el nombre de mines adjacents a una cel·la
    def comptar_mines_adjacents(x, y):
        mines = 0
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                nx, ny = x + dx, y + dy
                if 0 <= nx < AMPLADA and 0 <= ny < ALCADA and tauler[ny][nx] == -1:
                    mines += 1
        return mines
    # Propagar cel·les buides visibles quan s'obri una cel·la sense mines adjacents
    def propagar_buides(x, y):
        pila = [(x, y)]
        while pila:
            cx, cy = pila.pop()
            for dy in range(-1, 2):
                for dx in range(-1, 2):
                    nx, ny = cx + dx, cy + dy
                    if 0 <= nx < AMPLADA and 0 <= ny < ALCADA and visual[ny][nx] == 0:
                        if tauler[ny][nx] == 0:
                            visual[ny][nx] = 1
                            tauler_visual[ny * AMPLADA + nx] = 1
                            pila.append((nx, ny))
                        elif tauler[ny][nx] > 0:
                            visual[ny][nx] = 1
                            tauler_visual[ny * AMPLADA + nx] = tauler[ny][nx] + 1
    # Verificar si el jugador ha guanyat
    def verificar_victoria():
        for y in range(ALCADA):
            for x in range(AMPLADA):
                if tauler[y][x] != -1 and visual[y][x] == 0:
                    return False
        return True
    # Mostrar un missatge al centre de la pantalla
    def mostrar_missatge(font, text, color):
        missatge = label.Label(
            font=font,
            text=text,
            color=color,
            anchor_point=(0.5, 0.5),
            anchored_position=(pant.width // 2, pant.height // 2),
        )
        grup.append(missatge)
        pant.refresh()
        return missatge
    # Funció per pausar el joc
    def pausa():
        pregunta = label.Label(font, text=" Tornar a l'inici? ", color=0xFFA500, x=5, y=25)
        tornar_inici = label.Label(font2, text=" ? SI ", color=0x0000FF, x=13, y=60)
        continuar = label.Label(font2, text=" ? NO ", color=0x0000FF, x=13, y=90)
        grup_pausa = displayio.Group()
        grup_pausa.append(pregunta)
        grup_pausa.append(tornar_inici)
        grup_pausa.append(continuar)
        pant.show(grup_pausa)  # Mostrar pantalla de pausa
        abans = 0
        while True:
            boto = ugame.buttons.get_pressed()
            if not abans & ugame.K_RIGHT and boto & ugame.K_RIGHT:
                reiniciar_joc()
                break
            if not abans & ugame.K_LEFT and boto & ugame.K_LEFT:
                pant.show(grup)
                break
            abans = boto
    # Reiniciar el joc tornant al menú inicial
    def reiniciar_joc():
        nonlocal continuar
        continuar = False
    # Variables inicials del joc
    cx, cy = pos_ini  # Posició inicial del punter
    abans = 0  # Estat anterior dels botons
    primer_moviment = True  # Indica si és el primer moviment
    continuar = True  # Control del bucle principal
    # Carregar efectes de so
    so_explosio = open("explosio.wav", "rb")
    so_victoria = open("victoria.wav", "rb")
    sons = ugame.audio
    sons.mute(False)
    while continuar:
        boto = ugame.buttons.get_pressed()
        # Controlar el moviment del punter
        if not abans & ugame.K_RIGHT and boto & ugame.K_RIGHT and cx < AMPLADA - 1:
            cx += 1
        if not abans & ugame.K_LEFT and boto & ugame.K_LEFT and cx > 0:
            cx -= 1
        if not abans & ugame.K_DOWN and boto & ugame.K_DOWN and cy < ALCADA - 1:
            cy += 1
        if not abans & ugame.K_UP and boto & ugame.K_UP and cy > 0:
            cy -= 1
        punter.x = cx * 16
        punter.y = cy * 16
        # Destapar cel·la amb el botó X
        if not abans & ugame.K_X and boto & ugame.K_X:
            if primer_moviment:
                generar_tauler(cx, cy)
                primer_moviment = False
            if tauler_visual[cy * AMPLADA + cx] == 10:
                contador_mines += 1
            if tauler[cy][cx] == -1:  # Si es trepitja una mina
                tauler_visual[cy * AMPLADA + cx] = 11
                for y in range(ALCADA):
                    for x in range(AMPLADA):
                        if tauler[y][x] == -1:
                            tauler_visual[y * AMPLADA + x] = 11  # Mostrar totes les mines
                grup.remove(grup_punter)
                missatge = mostrar_missatge(font, "Has perdut!", 0xFFFFFF)
                sons.play(so_explosio)
                cadena[0] = (255, 0, 0)
                time.sleep(5)
                cadena[0] = (0, 0, 0)
                grup.remove(missatge)
                reiniciar_joc()
            elif tauler[cy][cx] == 0:  # Si la cel·la és buida
                propagar_buides(cx, cy)
            else:  # Si la cel·la conté un número
                visual[cy][cx] = 1
                tauler_visual[cy * AMPLADA + cx] = tauler[cy][cx] + 1
        # Col·locar o treure una bandera amb el botó O
        if not abans & ugame.K_O and boto & ugame.K_O:
            if visual[cy][cx] == 0:
                if tauler_visual[cy * AMPLADA + cx] == 10:
                    tauler_visual[cy * AMPLADA + cx] = 0
                    contador_mines += 1
                else:
                    tauler_visual[cy * AMPLADA + cx] = 10
                    contador_mines -= 1
        # Mostrar el nombre de mines restants amb el botó SELECT
        if not abans & ugame.K_SELECT and boto & ugame.K_SELECT:
            missatge = mostrar_missatge(font3, str(contador_mines), 0xFFFFFF)
            time.sleep(2)
            grup.remove(missatge)
        # Pausar el joc amb el botó START
        if not abans & ugame.K_START and boto & ugame.K_START:
            pausa()
        # Verificar si el jugador ha guanyat
        if verificar_victoria():
            grup.remove(grup_punter)
            missatge = mostrar_missatge(font, "Has guanyat!", 0x00FF00)
            sons.play(so_victoria)
            cadena[0] = (0, 255, 0)
            time.sleep(5)
            cadena[0] = (0, 0, 0)
            grup.remove(missatge)
            reiniciar_joc()
        abans = boto
while True:
    dificultat = seleccionar_dificultat()  # Seleccionar dificultat
    iniciar_joc(dificultat)  # Iniciar el joc

 

 

 

 

 

 

 

 

 

 

Licencia de Creative Commons
Esta obra de Oriol Boix está licenciada bajo una licencia no importada Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0.