Tour de Hanoï
De DigiWiki.
- Créer 9 cylindres + 3 pour les tours et 1 rectangle pour le socle (racine).
- Placer le script dans le prim racine.
Enjoy!
// Hanoi v1.0 by Bestmomo Lagan // On affecte un nom au tours, en les distinguant avec un index numérique // On affecte un nom aux disques en les distinguant aussi avec un index numérique // Les disques s'appellent DISQUE0, DISQUE1 ... // Les tours s'appellent TOUR0, TOUR1 ... // Nom générique string NOM_TOURS = "TOUR"; string NOM_DISQUES = "DISQUE"; // Détection des primitives // On doit connaîte les numéros de liaison des tours et des disques // Listes pour mémoriser les numéros de laison list l_tours; list l_disques; // Nombre de tours et de disques integer i_nbr_tours; integer i_nbr_disques; // Fonction de détermination des numéros de liaisons set_prims_link() { // Nombre total de primitives liées integer n_prims = llGetNumberOfPrims(); // Index de fin des noms integer i_tours_length = llStringLength(NOM_TOURS) - 1; integer i_disques_length = llStringLength(NOM_DISQUES) - 1; // Première passe pour compter le nombre de tours et de disques integer i; for(i = 2; i <= n_prims; ++i) { // Nom de la primitive string nom = llList2String(llGetLinkPrimitiveParams(i, [PRIM_NAME]), 0); // Tours if(llGetSubString(nom, 0, i_tours_length) == NOM_TOURS) ++i_nbr_tours; // Disques else if(llGetSubString(nom, 0, i_disques_length) == NOM_DISQUES) ++i_nbr_disques; } // Renseignement des listes à la bonne longueur integer n = i_nbr_tours; while(n--) l_tours += 0; n = i_nbr_disques; while(n--) l_disques += 0; // Deuxième passe pour trouver les numéros de laison for(i = 2; i <= n_prims; ++i) { // Nom de la primitive string nom = llList2String(llGetLinkPrimitiveParams(i, [PRIM_NAME]), 0); // Tours if(llGetSubString(nom, 0, i_tours_length) == NOM_TOURS) { integer index = (integer)llGetSubString(nom, i_tours_length + 1, -1); l_tours = llListReplaceList(l_tours, [i], index, index); } // Disques else if(llGetSubString(nom, 0, i_disques_length) == NOM_DISQUES) { integer index = (integer)llGetSubString(nom, i_disques_length + 1, -1); l_disques = llListReplaceList(l_disques, [i], index, index); } } } // Fonctions pour récupérer un numéro de liaison à partir de son index integer get_tour_link(integer id_tour) { return llList2Integer(l_tours, id_tour); } integer get_disque_link(integer id_disque) { return llList2Integer(l_disques, id_disque); } // Fonction pour récupérer un index à partir d'un numéro de liaison integer get_tour_index(integer tour_link) { return llListFindList(l_tours, [tour_link]); } // Définition des emplacements // On doit connaître l'emplacement des disques pour chaque tour // Epaisseur d'un disque float f_disque_height; set_disque_height() { vector size = llList2Vector(llGetLinkPrimitiveParams(get_disque_link(0), [PRIM_SIZE]), 0); f_disque_height = size.z; } // Hauteur d'une tour float f_tour_height; set_tour_height() { list l = llGetLinkPrimitiveParams(get_tour_link(0), [PRIM_SIZE]); vector size = llList2Vector(l, 0); f_tour_height = size.z; } // Emplacement de stockage des disques vector v_stockage; set_stockage() { list l = llGetLinkPrimitiveParams(get_tour_link(0), [PRIM_POS_LOCAL]); v_stockage = llList2Vector(l, 0) - <.0, .0, f_tour_height / 2.0 + f_disque_height + .01>; } // Emplacement de base des tours list l_tours_bases; set_bases() { integer n = i_nbr_tours; integer i; for(; i < i_nbr_tours; ++i) { list l = llGetLinkPrimitiveParams(get_tour_link(i), [PRIM_POS_LOCAL]); l_tours_bases += llList2Vector(l, 0) - <.0, .0, f_tour_height / 2.0 - f_disque_height / 2.0>; } } // Emplacement avec un index de tour et un index de place vector get_pos(integer id_tour, integer id_place) { vector v_base = llList2Vector(l_tours_bases, id_tour); return v_base + <0, 0, id_place * f_disque_height>; } // Liste de la tour avec son index list get_tour_list(integer i_tour) { if(i_tour == 0) return l_tour1; else if(i_tour == 1) return l_tour2; else return l_tour3; } // Référence du disque supérieur (-1 si pas de disque) integer get_disque_sup(integer i_tour) { list l = get_tour_list(i_tour); integer n = llGetListLength(l); // Index du disque supérieur if(n)return llList2Integer(l, n - 1); // Pas de disque else return -1; } // Récupération base de la tour vector get_base(integer i_tour) { list l = get_tour_list(i_tour); return llList2Vector(l_tours_bases, i_tour); } // Emplacement du disque supérieur vector get_disque_sup_place(integer i_tour) { list l = get_tour_list(i_tour); return get_base(i_tour) + <0, 0, (llGetListLength(l) - 1) * f_disque_height>; } // Emplacement libre en haut de la tour vector get_disque_free_place(integer i_tour) { list l = get_tour_list(i_tour); return get_base(i_tour) + <0, 0, (llGetListLength(l)) * f_disque_height>; } // Emplacement pour déplacement vector get_disque_move(integer i_tour) { return get_base(i_tour) + <0, 0, f_tour_height + f_tour_height / 10.0>; } // Mouvements: Définition des mouvements avec interpolation // Temps de base float TEMPS_BASE = .04; // Durée de transition float TIME = 1.0; // Interpolation sinusoïdale de deux vecteurs vector v_cos(vector v1, vector v2, float t) { float f = (1.0 - llCos(t * PI)) / 2.0; return v1 * (1.0 - f) + v2 * f; } // Déplacement set_move(integer id_disque, vector v1, vector v2) { // Numéro de liaison integer i_link = get_disque_link(id_disque); // Durée d'une étape élémentaire float f_step = 1.0 / (TIME / TEMPS_BASE); // Etapes cumulées float step; // Boucle du mouvement while((step += f_step) <= 1.0) { llSetLinkPrimitiveParamsFast(i_link, [PRIM_POSITION, v_cos(v1, v2, step)]); llSleep(TEMPS_BASE); } } // Gestion du jeu: // Listes d'état d'occupation des tours list l_tour1; list l_tour2; list l_tour3; // Nombre de disques choisis integer i_nbr_disques_jeu; // Index de départ des disques integer i_index; // Modes (0 = repos, 1 = choix jeu , 2 = choix démo, 3 = jeu en cours , 4 = démo en cours) integer i_mode; // Etat du déplacement integer i_move = -1; // Reset des disques reset_disques() { // Vidage des tours l_tour1 = []; l_tour2 = []; l_tour3 = []; // Stockage des disques integer n = i_nbr_disques; while(n--) llSetLinkPrimitiveParamsFast(get_disque_link(n), [PRIM_POSITION, v_stockage]); } // Mise en place initiale init_disques() { reset_disques(); // Mise en place i_index = i_nbr_disques - i_nbr_disques_jeu; integer n; for(n = i_index; n < i_nbr_disques; ++n) { llSetLinkPrimitiveParamsFast(get_disque_link(n), [PRIM_POSITION, get_pos(0, n - i_index)]); l_tour1 += n; } } // Test coup correct integer test_correct(integer i_tour, integer i_disque) { return i_disque > get_disque_sup(i_tour); } // Test de fin de jeu integer test_fin() { return llGetListLength(l_tour3) == i_nbr_disques_jeu; } // Transfert disque entre tours transfert_disque(integer i_tour_depart, integer i_tour_arrivee) { integer i; if(i_tour_depart == 0) i = llList2Integer(l_tour1, -1); else if(i_tour_depart == 1) i = llList2Integer(l_tour2, -1); else if(i_tour_depart == 2) i = llList2Integer(l_tour3, -1); if(i_tour_arrivee == 0) l_tour1 += i; else if(i_tour_arrivee == 1) l_tour2 += i; else if(i_tour_arrivee == 2) l_tour3 += i; if(i_tour_depart == 0) l_tour1 = llDeleteSubList(l_tour1, -1, -1); else if(i_tour_depart == 1) l_tour2 = llDeleteSubList(l_tour2, -1, -1); else if(i_tour_depart == 2) l_tour3 = llDeleteSubList(l_tour3, -1, -1); } // Gestion des menus: // Canal aléatoire integer get_channel() { return ~(integer)llFrand((float)DEBUG_CHANNEL); } // Variables pour menu integer i_ecoute; integer i_canal; integer i_inhibe; float f_timeout = 30.0; key k_ava; // Reset menu reset_menu() { i_inhibe = FALSE; llSetTimerEvent(.0); llListenRemove(i_ecoute); } // Mise en action d'un menu set_menu(key ava, string texte, list menu) { i_inhibe = TRUE; i_canal = get_channel(); k_ava = ava; i_ecoute = llListen(i_canal, "", k_ava, ""); llSetTimerEvent(f_timeout); llDialog(k_ava, texte, menu, i_canal); } // Menus list MENU1 = ["Quitter","Jeu","Démo"]; list MENU2 = ["Retour"," "," ","1","2","3","4","5","6","7","8","9"]; list MENU3 = ["Non","Oui"]; // Textes string TEXTE1 = "Choisissez une option :"; string TEXTE2 = "Choisissez le nombre de disques :"; string TEXTE3 = "Quitter le jeu en cours ?"; // Mode démo: // Déplacement move_disque(integer i_start, integer i_end) { integer i_disque = get_disque_sup(i_start); // Montée set_move(i_disque, get_disque_sup_place(i_start), get_disque_move(i_start)); // Déplacement latéral set_move(i_disque, get_disque_move(i_start), get_disque_move(i_end)); // Descente set_move(i_disque, get_disque_move(i_end), get_disque_free_place(i_end)); // Mise à jour transfert_disque(i_start, i_end); } // Fonction récursive hanoi(integer n, integer i_start, integer i_end, integer i_step) { if(n == 1) move_disque(i_start, i_end); else { hanoi(n - 1, i_start, i_step, i_end); move_disque(i_start, i_end); hanoi(n - 1, i_step, i_end, i_start); } } // Etat par défaut: default { // Initialisations au démarrage du script state_entry() { // Détection des numéros de laison set_prims_link(); // Epaisseur d'un disque set_disque_height(); // Hauteur d'une tour set_tour_height(); // Emplacement de base des tours set_bases(); // Emplacement de stockage des disques set_stockage(); } touch_start(integer total_number) { // Numéro de liaison de la prim touchée integer i_link = llDetectedLinkNumber(0); // Avatar qui a touché key ava = llDetectedKey(0); // Cas du root if(i_link == 1) { if(ava != k_ava) { if(i_inhibe) llInstantMessage(ava, "Désolé mais le menu est déjà utilisé..."); else if(i_mode > 2) llInstantMessage(ava, "Désolé mais un jeu est déjà en cours..."); else set_menu(ava, TEXTE1, MENU1); } else { if(i_mode) set_menu(ava, TEXTE3, MENU3); else set_menu(ava, TEXTE1, MENU1); } } // Cas d'une prim enfant else { // Cas d'une tour if(~llListFindList(l_tours, [i_link])) { // Index de la tour integer i_tour = get_tour_index(i_link); // Même tour (retour en position initiale) if(i_tour == i_move) { // Index du disque supérieur integer i_disque = get_disque_sup(i_tour); // Mouvement s'il y a un disque if(~i_disque) { i_move = -1; set_move(i_disque, get_disque_move(i_tour), get_disque_sup_place(i_tour)); } } // Autres cas else { // Déplacement if(~i_move) { // Index du disque supérieur integer i_disque = get_disque_sup(i_move); // Mouvement si coup correct if(test_correct(i_tour, i_disque)) { // Déplacement latéral set_move(i_disque, get_disque_move(i_move), get_disque_move(i_tour)); // Descente set_move(i_disque, get_disque_move(i_tour), get_disque_free_place(i_tour)); // Mise à jour transfert_disque(i_move, i_tour); i_move = -1; // Test de fin if(test_fin()) { llWhisper(0, "Jeu terminé !"); i_mode = 0; } } // Coup incorrect else llWhisper(0, "Vous ne pouvez pas poser ce disque sur cette tour"); } // Montée du disque else { // Index du disque supérieur integer i_disque = get_disque_sup(i_tour); // Mouvement s'il y a un disque if(~i_disque) { i_move = i_tour; set_move(i_disque, get_disque_sup_place(i_tour), get_disque_move(i_tour)); } } } } } } listen(integer channel, string name, key ava, string message){ reset_menu(); // Menu 1 if(~llListFindList(MENU1, [message])) { if(message != "Quitter") { if(message == "Démo") i_mode = 2; else i_mode = 1; set_menu(ava, TEXTE2, MENU2); } } // Menu 2 else if(~llListFindList(MENU2, [message])) { // Touche neutre if(message == " ") set_menu(ava, TEXTE2, MENU2); // Retour au menu 1 else if(message == "Retour") set_menu(ava, TEXTE1, MENU1); // Nombre de disques choisi, on peut jouer else { i_nbr_disques_jeu = (integer)message; i_mode += 2; init_disques(); if(i_mode == 4) { llSleep(1.0); hanoi(i_nbr_disques_jeu, 0, 2, 1); llWhisper(0, "Démo terminée !"); i_mode = 0; } } } // Menu 3 else if(~llListFindList(MENU3, [message])) { // Retour au menu 1 if(message == "Oui") { i_mode = 0; set_menu(ava, TEXTE1, MENU1); } } } timer() { reset_menu(); llInstantMessage(k_ava, "Délai écoulé, désolé..."); } }