Jeu « Color Water Sort » pour HP-Prime

Exemple de début de partie
Exemple de milieu de partie
Exemple de fin de partie

Voici une adaptation tactile du célèbre jeu de logique WaterSort Puzzle, spécialement conçue pour la calculatrice HP Prime en langage Python. Le principe est simple, mais diaboliquement addictif : vous devez verser les couleurs d’un tube à l’autre pour que chaque tube contienne qu’une seule couleur.

Au départ, les couleurs sont mélangées dans plusieurs tubes. À chaque tour, vous pouvez déplacer un empilement de couleur d’un tube vers un autre, à condition que la couleur soit identique ou que le tube soit vide. L’objectif est de reconstituer les couleurs uniformément dans chaque tube, sans déborder.

💡 Ce jeu fait appel à la logique, à l’anticipation… et un peu à votre patience !

Fonctionnalités :

  • Interface graphique simple et intuitive adaptée à l’écran de la HP Prime
  • Affichage coloré dynamique (jusqu’à 8 couleurs différentes)
  • Bouton ® pour recommencer le niveau si vous êtes bloqué
  • Détection automatique de victoire

Vous trouverez ci-dessous le code source complet ainsi que le fichier watercolor.hpprgm (fonctionne avec la version 2.1 du 13/04/2023 et les suivantes) :

#python jeu
from hpprime import *
from urandom import choice

couleurs_rgb = {
    "a": 0x845ec2,
    "b": 0xd65db1,
    "c": 0xff6f91,
    "d": 0xff9671,
    "e": 0xffc75f,
    "f": 0xf9f871,
    "g": 0x9bde7e,
    "h": 0x4bbc8e
}
liste_couleurs = list(couleurs_rgb.keys())

LARGEUR_TUBE = 20
HAUTEUR_TUBE = 60
ESPACEMENT_X = 80
ESPACEMENT_Y = 74
MARGE_X = 45
MARGE_Y = 20
COLONNES = 3
LIGNES = 3
TOTAL_COULEURS = 7
NOIR = 0x000000
BLANC = 0xFFFFFF
BG = 0x03132C

def position_tube(index):
    col = index % COLONNES
    lig = index // COLONNES
    x = MARGE_X + col * ESPACEMENT_X
    y = MARGE_Y + lig * ESPACEMENT_Y
    return x, y

def attendre_clic():
    while True:
        f1, _ = eval('mouse')
        if f1:
            while eval('mouse')[0]: pass
            return f1[:2]

def tube_clique(x, y):
    for i in range(9):
        tx, ty = position_tube(i)
        if tx - ESPACEMENT_X / 2 < x < tx + LARGEUR_TUBE + ESPACEMENT_X / 2 and ty <= y <= ty + HAUTEUR_TUBE:
            return i
    return None

def dessiner_tubes(tubes, selectionne=None):
    fillrect(0, 0, 0, 320, 240, BG, BG)
    for i, tube in enumerate(tubes):
        x, y = position_tube(i)
        bordure = 0x00FF00 if i == selectionne else BLANC
        rect(0, x-2, y-2, LARGEUR_TUBE+4, HAUTEUR_TUBE+4, bordure)
        rect(0, x-3, y-3, LARGEUR_TUBE+6, HAUTEUR_TUBE+6, bordure)
        fillrect(0, x, y-3, LARGEUR_TUBE, 3, BG, BG)
        h = HAUTEUR_TUBE // 4
        for j, couleur in enumerate(tube):
            c = couleurs_rgb.get(couleur)
            fillrect(0, x, y + HAUTEUR_TUBE - (j + 1)*h, LARGEUR_TUBE, h, c, c)
    # Bouton recommencer
    textout(0, 270, 110, chr(174), BLANC)

def sommet_identique(tube):
    if not tube: return None, 0
    sommet = tube[-1]
    compteur = 1
    for i in range(len(tube)-2, -1, -1):
        if tube[i] == sommet: compteur += 1
        else: break
    return sommet, compteur

def peut_verser(depuis, vers):
    if not depuis or len(vers) >= 4:
        return False
    couleur, nb = sommet_identique(depuis)
    if not vers: return True
    return vers[-1] == couleur

def verser(depuis, vers):
    if not peut_verser(depuis, vers): return
    couleur, nb = sommet_identique(depuis)
    espace = 4 - len(vers)
    a_verser = min(nb, espace)
    for _ in range(a_verser):
        vers.append(depuis.pop())

def generer_tubes():
    couleurs = []
    for couleur in liste_couleurs[:TOTAL_COULEURS]:
        couleurs += [couleur]*4
    melange = []
    while couleurs:
        c = choice(couleurs)
        couleurs.remove(c)
        melange.append(c)
    tubes = [melange[i*4:(i+1)*4] for i in range(TOTAL_COULEURS)]
    tubes += [[] for _ in range(9 - TOTAL_COULEURS)]
    return tubes

def a_gagne(tubes):
    for tube in tubes:
        if not tube: continue
        if len(tube) != 4: return False
        if any(c != tube[0] for c in tube): return False
    return True

def afficher_message_gagne():
    fillrect(0, 50, 90, 220, 60, BLANC, couleurs_rgb["d"])
    textout(0, 85, 105, "Bravo ! Vous avez gagné", NOIR)
    fillrect(0, 110, 130, 100, 25, BLANC, couleurs_rgb["g"])
    textout(0, 130, 135, "REJOUER", NOIR)

def attendre_redemarrage():
    while True:
        x, y = attendre_clic()
        if 110 <= x <= 210 and 130 <= y <= 155: return

def bouton_redemarrer(x, y):
    return 260 <= x <= 300 and 80 <= y <= 130

def main():
    while True:
        tubes = generer_tubes()
        tubes_depart = [tube[:] for tube in tubes]
        selection = None
        while True:
            dessiner_tubes(tubes, selection)
            if a_gagne(tubes):
                afficher_message_gagne()
                attendre_redemarrage()
                break
            x, y = attendre_clic()
            if bouton_redemarrer(x, y):
                tubes = [tube[:] for tube in tubes_depart]
                selection = None
                continue
            index = tube_clique(x, y)
            if index is None:
                selection = None
                continue
            if selection is None:
                if tubes[index]: selection = index
            elif selection == index:
                selection = None
            else:
                verser(tubes[selection], tubes[index])
                selection = None

main()
#end

EXPORT watercolor()
BEGIN
  wait(.3);
  python(jeu);
END;